diff --git a/lib/portainer_cli.rb b/lib/portainer_cli.rb index 08f2ae2..9e6b414 100644 --- a/lib/portainer_cli.rb +++ b/lib/portainer_cli.rb @@ -36,7 +36,7 @@ module PortainerCli portainer-cli exec Open interactive shell (manual endpoint) --shell SHELL Shell to use (default: /bin/sh) - Config file: ~/.portainer-cli/config.yml + Config file: ~/.config/portainer-cli/config.yml HELP def self.run(argv) diff --git a/lib/portainer_cli/commands/create.rb b/lib/portainer_cli/commands/create.rb index e50ea68..38f23c5 100644 --- a/lib/portainer_cli/commands/create.rb +++ b/lib/portainer_cli/commands/create.rb @@ -2,6 +2,7 @@ require_relative 'base' require 'optparse' +require 'shellwords' module PortainerCli module Commands @@ -55,6 +56,7 @@ module PortainerCli end env_vars = opts[:env].map do |pair| + error("Invalid --env '#{pair}': expected KEY=VALUE") unless pair.include?('=') k, v = pair.split('=', 2) { 'name' => k, 'value' => v.to_s } end @@ -90,7 +92,11 @@ module PortainerCli port_bindings = {} exposed_ports = {} opts[:ports].each do |mapping| - host_port, cont_port = mapping.split(':', 2) + parts = mapping.split(':', 2) + error("Invalid --port '#{mapping}': expected HOST:CONTAINER (e.g. 8080:80)") unless parts.size == 2 + host_port, cont_port = parts + error("Invalid --port '#{mapping}': missing host port") if host_port.empty? + error("Invalid --port '#{mapping}': missing container port") if cont_port.empty? cont_key = "#{cont_port}/tcp" exposed_ports[cont_key] = {} port_bindings[cont_key] = [{ 'HostPort' => host_port }] @@ -102,7 +108,7 @@ module PortainerCli 'ExposedPorts' => exposed_ports, 'HostConfig' => { 'PortBindings' => port_bindings } } - body['Cmd'] = opts[:cmd].split(' ') if opts[:cmd] + body['Cmd'] = Shellwords.split(opts[:cmd]) if opts[:cmd] query = opts[:name] ? "?name=#{URI.encode_www_form_component(opts[:name])}" : '' result = @client.post("/api/endpoints/#{opts[:endpoint]}/docker/containers/create#{query}", body) diff --git a/lib/portainer_cli/websocket_exec.rb b/lib/portainer_cli/websocket_exec.rb index 5eb4215..9661c5e 100644 --- a/lib/portainer_cli/websocket_exec.rb +++ b/lib/portainer_cli/websocket_exec.rb @@ -40,11 +40,19 @@ module PortainerCli ssl = OpenSSL::SSL::SSLSocket.new(raw, ctx) ssl.hostname = @url.host ssl.sync_close = true - ssl.connect + begin + ssl.connect + rescue OpenSSL::SSL::SSLError => e + raw.close rescue nil + hint = @ssl_verify ? " (try: portainer-cli configure → answer 'n' to SSL verification)" : "" + raise "SSL connection failed: #{e.message}#{hint}" + end ssl else raw end + rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError => e + raise "Cannot connect to #{@url.host}:#{@url.port} — #{e.message}" end def perform_handshake(socket)