Module: Terraspace::Cloud::Api::HttpMethods

Extended by:
Memoist
Includes:
Util
Included in:
Terraspace::Cloud::Api
Defined in:
lib/terraspace/cloud/api/http_methods.rb

Instance Method Summary collapse

Methods included from Util::Pretty

#pretty_path, #pretty_time

Methods included from Util::Sure

#sure?

Methods included from Util::Logging

#logger

Instance Method Details

#build_request(klass, url, data = {}) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/terraspace/cloud/api/http_methods.rb', line 36

def build_request(klass, url, data={})
  req = klass.new(url) # url includes query string and uri.path does not, must used url
  set_headers!(req)
  if [Net::HTTP::Delete, Net::HTTP::Patch, Net::HTTP::Post, Net::HTTP::Put].include?(klass)
    text = JSON.dump(data)
    req.body = text
    req.content_length = text.bytesize
  end

  logger.debug "API klass: #{klass}"
  logger.debug "API url: #{url}"
  logger.debug "API data: #{data}"

  req
end

#checkObject



123
124
125
# File 'lib/terraspace/cloud/api/http_methods.rb', line 123

def check
  Terraspace::Check.new
end

#delete(path, data = {}) ⇒ Object



119
120
121
# File 'lib/terraspace/cloud/api/http_methods.rb', line 119

def delete(path, data={})
  request(Net::HTTP::Delete, path, data)
end

#get(path, data = {}) ⇒ Object



99
100
101
102
103
104
105
# File 'lib/terraspace/cloud/api/http_methods.rb', line 99

def get(path, data={})
  unless data.empty?
    separator = path.include?('?') ? '&' : '?'
    path += separator + data.to_query
  end
  request(Net::HTTP::Get, path)
end

#httpObject



85
86
87
88
89
90
91
# File 'lib/terraspace/cloud/api/http_methods.rb', line 85

def http
  uri = URI(endpoint)
  http = Net::HTTP.new(uri.host, uri.port)
  http.open_timeout = http.read_timeout = 30
  http.use_ssl = true if uri.scheme == 'https'
  http
end

#load_json(url, resp) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/terraspace/cloud/api/http_methods.rb', line 61

def load_json(url, resp)
  uri = URI(url)

  logger.debug "resp.code #{resp.code}"
  logger.debug "resp.body #{resp.body}" # {"errors":[{"message":"403 Forbidden"}]}

  if parseable?(resp.code)
    JSON.load(resp.body)
  else
    logger.error "Error: #{url}"
    logger.error "Error: Non-successful http response status code: #{resp.code}"
    # logger.debug "Error: Non-successful http response body: #{resp.body}"
    logger.error "headers: #{resp.each_header.to_h.inspect}"
    logger.error "Terraspace Cloud API #{url}"
    raise "Terraspace Cloud API called failed: #{uri.host}"
  end
end

#parseable?(http_code) ⇒ Boolean

Note: 422 is Unprocessable Entity. This means an invalid data payload was sent. We want that to error and raise

Returns:

  • (Boolean)


81
82
83
# File 'lib/terraspace/cloud/api/http_methods.rb', line 81

def parseable?(http_code)
  http_code =~ /^20/ || http_code =~ /^40/
end

#patch(path, data = {}) ⇒ Object



115
116
117
# File 'lib/terraspace/cloud/api/http_methods.rb', line 115

def patch(path, data={})
  request(Net::HTTP::Patch, path, data)
end

#post(path, data = {}) ⇒ Object



107
108
109
# File 'lib/terraspace/cloud/api/http_methods.rb', line 107

def post(path, data={})
  request(Net::HTTP::Post, path, data)
end

#put(path, data = {}) ⇒ Object



111
112
113
# File 'lib/terraspace/cloud/api/http_methods.rb', line 111

def put(path, data={})
  request(Net::HTTP::Put, path, data)
end

#request(klass, path, data = {}) ⇒ Object

Always translate raw json response to ruby Hash



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/terraspace/cloud/api/http_methods.rb', line 7

def request(klass, path, data={})
  exit_on_error = data.delete(:exit_on_error) # for cani logic
  url = url(path)
  check.ok!(cloud: true) unless check.ok?
  data = data.merge(versions: check.versions)
  req = build_request(klass, url, data)
  retries = 0
  begin
    resp = http.request(req) # send request
  rescue Errno::ECONNREFUSED, Errno::EAFNOSUPPORT
    delay = 2 ** retries
    logger.info "Unable to connect to #{url}. Delay for #{delay}s and trying again."
    sleep(delay)
    retries += 1
    # Final retry time: 2 * 4 = 16s
    # Total retry time: 2 ** 4 + 2 ** 3 + 2 ** 2 + 2 ** 1 + 2 ** 0 = 31s
    if retries < 5 # max_retries is 4
      retry
    else
      logger.error "Error connecting to #{url}"
      message = "#{$!.class}: #{$!.message}"
      raise Terraspace::NetworkError.new(message)
    end
  end
  result = load_json(url, resp)
  Cani.new(result).handle(exit_on_error) if data[:cani]
  result
end

#set_headers!(req) ⇒ Object



52
53
54
55
# File 'lib/terraspace/cloud/api/http_methods.rb', line 52

def set_headers!(req)
  req['Authorization'] = "Bearer #{token}" if token
  req['Content-Type'] = 'application/json'
end

#tokenObject



57
58
59
# File 'lib/terraspace/cloud/api/http_methods.rb', line 57

def token
  ENV['TS_TOKEN']
end

#url(path) ⇒ Object

API does not include the /. IE: app.terraform.io/api/v2



95
96
97
# File 'lib/terraspace/cloud/api/http_methods.rb', line 95

def url(path)
  "#{endpoint}/#{path}"
end