Files
portainer-cli/lib/portainer_cli/client.rb
T
grzlus c59deca51e Add ssl_verify config option to fix certificate errors
Raw OpenSSL sockets don't find the system CA bundle the same way Net::HTTP
does. ssl_verify (default: true) is now a config setting that applies to
both HTTP REST calls and WebSocket connections. Set via `portainer-cli configure`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 13:07:07 +01:00

107 lines
2.4 KiB
Ruby

# frozen_string_literal: true
require 'net/http'
require 'json'
require 'uri'
require 'openssl'
module PortainerCli
class Client
class ApiError < StandardError
attr_reader :code
def initialize(msg, code)
super(msg)
@code = code
end
end
def initialize(config)
@config = config
@base = URI.parse(config.url.chomp('/'))
end
def get(path, params = {})
request(:get, path, params: params)
end
def post(path, body = nil)
request(:post, path, body: body)
end
def delete(path)
request(:delete, path)
end
# Returns the raw websocket URL (ws:// or wss://) for exec sessions
def websocket_url(path, params = {})
uri = ws_uri(path)
uri.query = URI.encode_www_form(params) unless params.empty?
uri.to_s
end
def auth_header
@config.auth_header
end
private
def request(method, path, params: {}, body: nil)
uri = http_uri(path)
uri.query = URI.encode_www_form(params) unless params.empty?
http = build_http(uri)
req = build_request(method, uri, body)
resp = http.request(req)
handle_response(resp)
end
def build_http(uri)
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == 'https'
http.use_ssl = true
http.verify_mode = @config.ssl_verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
end
http.open_timeout = 10
http.read_timeout = 30
http
end
def build_request(method, uri, body)
klass = {
get: Net::HTTP::Get,
post: Net::HTTP::Post,
delete: Net::HTTP::Delete
}.fetch(method)
req = klass.new(uri)
req['Content-Type'] = 'application/json'
req['Accept'] = 'application/json'
@config.auth_header.each { |k, v| req[k] = v }
req.body = JSON.generate(body) if body
req
end
def handle_response(resp)
code = resp.code.to_i
raise ApiError.new("HTTP #{code}: #{resp.body}", code) if code >= 400
return nil if resp.body.nil? || resp.body.empty?
JSON.parse(resp.body)
rescue JSON::ParserError
resp.body
end
def http_uri(path)
URI.parse("#{@base}#{path}")
end
def ws_uri(path)
scheme = @base.scheme == 'https' ? 'wss' : 'ws'
URI.parse("#{scheme}://#{@base.host}:#{@base.port}#{path}")
end
end
end