Class: Vra::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/vra/client.rb

Constant Summary collapse

REFRESH_TOKEN_URL =
'/csp/gateway/am/api/login?access_token'
ACCESS_TOKEN_URL =
'/iaas/api/login'
ROLES_URL =
'/csp/gateway/am/api/loggedin/user/orgs'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Client

Returns a new instance of Client.



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/vra/client.rb', line 32

def initialize(opts)
  @base_url      = opts[:base_url]
  @username      = opts[:username]
  @password      = PasswordMasker.new(opts[:password])
  @tenant        = opts[:tenant]
  @verify_ssl    = opts.fetch(:verify_ssl, true)
  @refresh_token = PasswordMasker.new(nil)
  @access_token  = PasswordMasker.new(nil)
  @page_size     = opts.fetch(:page_size, 20)

  validate_client_options!
end

Instance Attribute Details

#page_sizeObject

Returns the value of attribute page_size.



30
31
32
# File 'lib/vra/client.rb', line 30

def page_size
  @page_size
end

Instance Method Details

#access_tokenObject

client methods



63
64
65
# File 'lib/vra/client.rb', line 63

def access_token
  @access_token.value
end

#access_token=(value) ⇒ Object



71
72
73
# File 'lib/vra/client.rb', line 71

def access_token=(value)
  @access_token.value = value
end

#authorize!Object



96
97
98
99
100
# File 'lib/vra/client.rb', line 96

def authorize!
  generate_access_token unless authorized?

  raise Vra::Exception::Unauthorized, 'Unable to authorize against vRA' unless authorized?
end

#authorized?Boolean

Returns:

  • (Boolean)


102
103
104
105
106
107
# File 'lib/vra/client.rb', line 102

def authorized?
  return false if @access_token.value.nil?

  response = http_head(ROLES_URL, :skip_auth)
  response.success?
end

#catalogObject

methods to other classes



50
51
52
# File 'lib/vra/client.rb', line 50

def catalog
  @catalog ||= Vra::Catalog.new(self)
end

#deploymentsObject



54
55
56
# File 'lib/vra/client.rb', line 54

def deployments
  @deployments ||= Vra::Deployments.new(self)
end

#full_url(path) ⇒ Object



132
133
134
# File 'lib/vra/client.rb', line 132

def full_url(path)
  "#{@base_url}#{path}"
end

#generate_access_tokenObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/vra/client.rb', line 109

def generate_access_token
  @refresh_token.value = nil
  @access_token.value = nil
  validate_client_options!

  # VRA 8 has a two-step authentication process - This probably breaks VRA7, who knows?!?
  # First step: Sending Username/Password to get a Refresh Token
  refresh_response = http_post(REFRESH_TOKEN_URL,
                       FFI_Yajl::Encoder.encode(token_params),
                       :skip_auth)
  raise Vra::Exception::Unauthorized, "Unable to get the refresh token: #{refresh_response.body}" unless refresh_response.success_ok?

  refresh_response_body = FFI_Yajl::Parser.parse(refresh_response.body)
  @refresh_token.value = refresh_response_body['refresh_token']

  # Second Step: Sending the refresh token to a separate endpoint to get an Access Token
  access_response = http_post(ACCESS_TOKEN_URL, "{ \"refreshToken\": \"#{@refresh_token.value}\" }", :skip_auth)
  raise Vra::Exception::Unauthorized, "Unable to get the access token: #{access_response.body}" unless access_response.success_ok?

  access_response_body = FFI_Yajl::Parser.parse(access_response.body)
  @access_token.value = access_response_body['token']
end

#get_parsed(path) ⇒ Object



166
167
168
# File 'lib/vra/client.rb', line 166

def get_parsed(path)
  FFI_Yajl::Parser.parse(http_get!(path))
end

#http_delete(path, skip_auth = nil) ⇒ Object



162
163
164
# File 'lib/vra/client.rb', line 162

def http_delete(path, skip_auth = nil)
  http_fetch(:delete, path, skip_auth)
end

#http_fetch(method, path, skip_auth = nil) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/vra/client.rb', line 136

def http_fetch(method, path, skip_auth = nil)
  authorize! unless skip_auth

  response = Vra::Http.execute(method: method,
                               url: full_url(path),
                               headers: request_headers,
                               verify_ssl: @verify_ssl)
rescue => e
  raise_http_exception(e, path)
else
  response
end

#http_get(path, skip_auth = nil) ⇒ Object



153
154
155
# File 'lib/vra/client.rb', line 153

def http_get(path, skip_auth = nil)
  http_fetch(:get, path, skip_auth)
end

#http_get!(path) ⇒ Object



157
158
159
160
# File 'lib/vra/client.rb', line 157

def http_get!(path)
  response = http_get(path)
  response.body
end

#http_get_paginated_array!(path, filter = nil) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/vra/client.rb', line 170

def http_get_paginated_array!(path, filter = nil)
  items = []
  page = 0
  base_path = path + "?$top=#{page_size}"
  base_path += "&#{filter}" if filter

  loop do
    response = get_parsed("#{base_path}&$skip=#{page * page_size}")
    items += response["content"]

    page += 1
    break if page >= response["totalPages"]
  end

  if items.uniq!
    raise Vra::Exception::DuplicateItemsDetected,
          "Duplicate items were returned by the vRA API. " \
          "Increase your page size to avoid this vRA API bug. " \
          "See https://github.com/chef-partners/vmware-vra-gem#pagination " \
          "for more information."
  end

  items
end

#http_head(path, skip_auth = nil) ⇒ Object



149
150
151
# File 'lib/vra/client.rb', line 149

def http_head(path, skip_auth = nil)
  http_fetch(:head, path, skip_auth)
end

#http_post(path, payload, skip_auth = nil) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/vra/client.rb', line 195

def http_post(path, payload, skip_auth = nil)
  authorize! unless skip_auth

  response = Vra::Http.execute(method: :post,
                               url: full_url(path),
                               headers: request_headers,
                               payload: payload,
                               verify_ssl: @verify_ssl)
rescue => e
  raise_http_exception(e, path)
else
  response
end

#http_post!(path, payload) ⇒ Object



209
210
211
212
# File 'lib/vra/client.rb', line 209

def http_post!(path, payload)
  response = http_post(path, payload)
  response.body
end

#raise_http_exception(caught_exception, path) ⇒ Object

Raises:

  • (exception)


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/vra/client.rb', line 214

def raise_http_exception(caught_exception, path)
  raise unless caught_exception.respond_to?(:http_code)

  klass = if caught_exception.http_code == 404
            Vra::Exception::HTTPNotFound
          else
            Vra::Exception::HTTPError
          end

  exception = klass.new(code: caught_exception.http_code,
                        body: caught_exception.response,
                        klass: caught_exception.class,
                        path: path)

  message = exception.errors.empty? ? caught_exception.message : exception.errors.join(", ")
  raise exception, message
end

#refresh_tokenObject



67
68
69
# File 'lib/vra/client.rb', line 67

def refresh_token
  @refresh_token.value
end

#refresh_token=(value) ⇒ Object



75
76
77
# File 'lib/vra/client.rb', line 75

def refresh_token=(value)
  @refresh_token.value = value
end

#request_headersObject



87
88
89
90
91
92
93
94
# File 'lib/vra/client.rb', line 87

def request_headers
  headers                   = {}
  headers['Accept']         = 'application/json'
  headers['Content-Type']   = 'application/json'
  headers['Authorization']  = 'Bearer ' + @access_token.value unless @access_token.value.nil?

  headers
end

#token_paramsObject



79
80
81
82
83
84
85
# File 'lib/vra/client.rb', line 79

def token_params
  {
    'username': @username,
    'password': @password.value,
    'tenant': @tenant
  }
end

#valid_uri?(uri) ⇒ Boolean

Returns:

  • (Boolean)


239
240
241
242
243
244
# File 'lib/vra/client.rb', line 239

def valid_uri?(uri)
  uri = URI.parse(uri)
  uri.is_a?(URI::HTTP)
rescue URI::InvalidURIError
  false
end

#validate_client_options!Object

Raises:

  • (ArgumentError)


232
233
234
235
236
237
# File 'lib/vra/client.rb', line 232

def validate_client_options!
  raise ArgumentError, "Username and password are required" if @username.nil? || @password.value.nil?
  raise ArgumentError, "A tenant is required" if @tenant.nil?
  raise ArgumentError, "A base URL is required" if @base_url.nil?
  raise ArgumentError, "Base URL #{@base_url} is not a valid URI." unless valid_uri?(@base_url)
end