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.



22
23
24
# File 'lib/core/controlplane_api_direct.rb', line 22

def trace
  @trace
end

Class Method Details

.parse_org(url) ⇒ Object

rubocop:enable Style/ClassVars



109
110
111
# File 'lib/core/controlplane_api_direct.rb', line 109

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

.reset_api_tokenObject



104
105
106
# File 'lib/core/controlplane_api_direct.rb', line 104

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

Instance Method Details

#api_host(host) ⇒ Object



59
60
61
62
63
64
65
66
# File 'lib/core/controlplane_api_direct.rb', line 59

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



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/core/controlplane_api_direct.rb', line 69

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: `cpln profile token`.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



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/core/controlplane_api_direct.rb', line 25

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($stdout) 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



100
101
102
# File 'lib/core/controlplane_api_direct.rb', line 100

def refresh_api_token
  @@api_token[:token] = `cpln profile token`.chomp
end

#should_refresh_api_token?Boolean

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

Returns:

  • (Boolean)


89
90
91
92
93
94
95
96
97
98
# File 'lib/core/controlplane_api_direct.rb', line 89

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