Initial implementation of portainer-cli
Ruby CLI tool for interacting with the Portainer API. Supports listing endpoints/stacks/containers/volumes/networks, creating stacks and containers, and opening an interactive exec session in a container via WebSocket. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'base'
|
||||
|
||||
module PortainerCli
|
||||
module Commands
|
||||
class List
|
||||
include Base
|
||||
|
||||
SUBCOMMANDS = %w[endpoints stacks containers volumes networks].freeze
|
||||
|
||||
def initialize(config, client)
|
||||
@config = config
|
||||
@client = client
|
||||
end
|
||||
|
||||
def run(args)
|
||||
require_config!(@config)
|
||||
sub = args.shift&.downcase
|
||||
|
||||
case sub
|
||||
when 'endpoints', 'envs', 'env'
|
||||
list_endpoints
|
||||
when 'stacks', 'stack'
|
||||
list_stacks
|
||||
when 'containers', 'container', 'ps'
|
||||
endpoint_id = resolve_endpoint_id(args)
|
||||
list_containers(endpoint_id)
|
||||
when 'volumes', 'volume'
|
||||
endpoint_id = resolve_endpoint_id(args)
|
||||
list_volumes(endpoint_id)
|
||||
when 'networks', 'network'
|
||||
endpoint_id = resolve_endpoint_id(args)
|
||||
list_networks(endpoint_id)
|
||||
else
|
||||
puts "Usage: portainer-cli list <#{SUBCOMMANDS.join('|')}> [endpoint-id]"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def list_endpoints
|
||||
data = @client.get('/api/endpoints')
|
||||
rows = data.map do |e|
|
||||
[e['Id'], e['Name'], e['URL'] || e['PublicURL'] || '-', endpoint_status(e['Status'])]
|
||||
end
|
||||
print_table(%w[ID Name URL Status], rows)
|
||||
end
|
||||
|
||||
def list_stacks
|
||||
data = @client.get('/api/stacks')
|
||||
rows = data.map do |s|
|
||||
[s['Id'], s['Name'], s['EndpointId'], stack_status(s['Status'])]
|
||||
end
|
||||
print_table(%w[ID Name Endpoint Status], rows)
|
||||
end
|
||||
|
||||
def list_containers(endpoint_id)
|
||||
data = @client.get("/api/endpoints/#{endpoint_id}/docker/containers/json", all: 1)
|
||||
rows = data.map do |c|
|
||||
name = Array(c['Names']).first&.delete_prefix('/') || '-'
|
||||
image = c['Image']
|
||||
status = c['Status']
|
||||
id = c['Id'][0, 12]
|
||||
[id, name, image, status]
|
||||
end
|
||||
print_table(%w[ID Name Image Status], rows)
|
||||
end
|
||||
|
||||
def list_volumes(endpoint_id)
|
||||
data = @client.get("/api/endpoints/#{endpoint_id}/docker/volumes")
|
||||
vols = data.is_a?(Hash) ? (data['Volumes'] || []) : data
|
||||
rows = vols.map { |v| [v['Name'], v['Driver'], v['Mountpoint']] }
|
||||
print_table(%w[Name Driver Mountpoint], rows)
|
||||
end
|
||||
|
||||
def list_networks(endpoint_id)
|
||||
data = @client.get("/api/endpoints/#{endpoint_id}/docker/networks")
|
||||
rows = data.map { |n| [n['Id'][0, 12], n['Name'], n['Driver'], n['Scope']] }
|
||||
print_table(%w[ID Name Driver Scope], rows)
|
||||
end
|
||||
|
||||
def resolve_endpoint_id(args)
|
||||
id = args.shift
|
||||
unless id
|
||||
puts "Endpoint ID required. Run 'portainer-cli list endpoints' to see IDs."
|
||||
exit 1
|
||||
end
|
||||
id
|
||||
end
|
||||
|
||||
def endpoint_status(code)
|
||||
case code
|
||||
when 1 then green('active')
|
||||
when 2 then red('inactive')
|
||||
else dim(code.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def stack_status(code)
|
||||
case code
|
||||
when 1 then green('active')
|
||||
when 2 then yellow('inactive')
|
||||
else dim(code.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user