Class: ControlplaneApiDirect

Inherits:
Object
  • Object
show all
Defined in:
lib/core/controlplane_api_direct.rb

Constant Summary collapse

API_METHODS =
{
  get: Net::HTTP::Get,
  patch: Net::HTTP::Patch,
  post: Net::HTTP::Post,
  put: Net::HTTP::Put,
  delete: Net::HTTP::Delete
}.freeze
API_HOSTS =
{ api: "https://api.cpln.io", logs: "https://logs.cpln.io" }.freeze
API_TOKEN_REGEX =

API_TOKEN_REGEX = Regexp.union(

/^[\w.]{155}$/, # CPLN_TOKEN format
/^[\w\-._]{1134}$/ # 'cpln profile token' format

).freeze

/^[\w\-._]+$/.freeze
API_TOKEN_EXPIRY_SECONDS =
300

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.traceObject

Returns the value of attribute trace.



44
45
46
# File 'lib/core/controlplane_api_direct.rb', line 44

def trace
  @trace
end

Class Method Details

.parse_org(url) ⇒ Object

rubocop:enable Style/ClassVars



131
132
133
# File 'lib/core/controlplane_api_direct.rb', line 131

def self.parse_org(url)
  url.match(%r{^/org/([^/]+)})[1]
end

.reset_api_tokenObject



126
127
128
# File 'lib/core/controlplane_api_direct.rb', line 126

def self.reset_api_token
  remove_class_variable(:@@api_token) if defined?(@@api_token)
end

Instance Method Details

#api_host(host) ⇒ Object



81
82
83
84
85
86
87
88
# File 'lib/core/controlplane_api_direct.rb', line 81

def api_host(host)
  case host
  when :api
    ENV.fetch("CPLN_ENDPOINT", API_HOSTS[host])
  else
    API_HOSTS[host]
  end
end

#api_tokenObject

rubocop:disable Style/ClassVars



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/core/controlplane_api_direct.rb', line 91

def api_token # rubocop:disable Metrics/MethodLength
  return @@api_token if defined?(@@api_token)

  @@api_token = {
    token: ENV.fetch("CPLN_TOKEN", nil),
    comes_from_profile: false
  }
  if @@api_token[:token].nil?
    @@api_token = {
      token: Shell.cmd("cpln", "profile", "token")[:output].chomp,
      comes_from_profile: true
    }
  end
  return @@api_token if @@api_token[:token].match?(API_TOKEN_REGEX)

  raise "Unknown API token format. " \
        "Please re-run 'cpln profile login' or set the correct CPLN_TOKEN env variable."
end

#call(url, method:, host: :api, body: nil) ⇒ Object

rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/core/controlplane_api_direct.rb', line 47

def call(url, method:, host: :api, body: nil) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
  trace = ControlplaneApiDirect.trace
  uri = URI("#{api_host(host)}#{url}")
  request = API_METHODS[method].new(uri)
  request["Content-Type"] = "application/json"

  refresh_api_token if should_refresh_api_token?

  request["Authorization"] = api_token[:token]
  request.body = body.to_json if body

  Shell.debug(method.upcase, "#{uri} #{body&.to_json}")

  http = Net::HTTP.new(uri.hostname, uri.port)
  http.use_ssl = uri.scheme == "https"
  http.set_debug_output(RedactedDebugOutput.new) if trace

  response = http.start { |ht| ht.request(request) }

  case response
  when Net::HTTPOK
    JSON.parse(response.body)
  when Net::HTTPAccepted
    true
  when Net::HTTPNotFound
    nil
  when Net::HTTPForbidden
    org = self.class.parse_org(url)
    raise("Double check your org #{org}. #{response} #{response.body}")
  else
    raise("#{response} #{response.body}")
  end
end

#refresh_api_tokenObject



122
123
124
# File 'lib/core/controlplane_api_direct.rb', line 122

def refresh_api_token
  @@api_token[:token] = Shell.cmd("cpln", "profile", "token")[:output].chomp
end

#should_refresh_api_token?Boolean

Returns true when the token is about to expire in 5 minutes



111
112
113
114
115
116
117
118
119
120
# File 'lib/core/controlplane_api_direct.rb', line 111

def should_refresh_api_token?
  return false unless api_token[:comes_from_profile]

  payload, = JWT.decode(api_token[:token], nil, false)
  difference_in_seconds = payload["exp"] - Time.now.to_i

  difference_in_seconds <= API_TOKEN_EXPIRY_SECONDS
rescue JWT::DecodeError
  false
end