Class: Vra::Client

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

Overview

rubocop:disable ClassLength

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Client

Returns a new instance of Client.



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/vra/client.rb', line 28

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)
  @bearer_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.



26
27
28
# File 'lib/vra/client.rb', line 26

def page_size
  @page_size
end

Instance Method Details

#authorize!Object



86
87
88
89
90
# File 'lib/vra/client.rb', line 86

def authorize!
  generate_bearer_token unless authorized?

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

#authorized?Boolean

Returns:

  • (Boolean)


92
93
94
95
96
97
98
99
100
101
# File 'lib/vra/client.rb', line 92

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

  response = http_head("/identity/api/tokens/#{@bearer_token.value}", :skip_auth)
  if response.code == 204
    true
  else
    false
  end
end

#bearer_tokenObject

client methods



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

def bearer_token
  @bearer_token.value
end

#bearer_token=(value) ⇒ Object



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

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

#bearer_token_request_bodyObject



70
71
72
73
74
75
76
# File 'lib/vra/client.rb', line 70

def bearer_token_request_body
  {
    'username' => @username,
    'password' => @password.value,
    'tenant'   => @tenant
  }
end

#catalogObject

methods to other classes



45
46
47
# File 'lib/vra/client.rb', line 45

def catalog
  Vra::Catalog.new(self)
end

#full_url(path) ⇒ Object



115
116
117
# File 'lib/vra/client.rb', line 115

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

#generate_bearer_tokenObject



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/vra/client.rb', line 103

def generate_bearer_token
  @bearer_token.value = nil
  validate_client_options!

  response = http_post('/identity/api/tokens', bearer_token_request_body.to_json, :skip_auth)
  if response.code != 200
    raise Vra::Exception::Unauthorized, "Unable to get bearer token: #{response.body}"
  end

  @bearer_token.value = FFI_Yajl::Parser.parse(response.body)['id']
end

#http_get(path, skip_auth = nil) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/vra/client.rb', line 132

def http_get(path, skip_auth=nil)
  authorize! unless skip_auth

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

#http_get!(path) ⇒ Object



145
146
147
148
# File 'lib/vra/client.rb', line 145

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

#http_get_paginated_array!(path) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/vra/client.rb', line 150

def http_get_paginated_array!(path)
  items = []
  page = 1
  base_path = path + "?limit=#{page_size}"

  loop do
    response = FFI_Yajl::Parser.parse(http_get!("#{base_path}&page=#{page}"))
    items += response['content']

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

  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.' if items.uniq!

  items
end

#http_head(path, skip_auth = nil) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/vra/client.rb', line 119

def http_head(path, skip_auth=nil)
  authorize! unless skip_auth

  response = RestClient::Request.execute(method: :head,
                                         url: full_url(path),
                                         headers: request_headers,
                                         verify_ssl: @verify_ssl)
rescue => e
  raise Vra::Exception::HTTPError, "head #{path} failed: #{e.class}: #{e.message}"
else
  response
end

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



172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/vra/client.rb', line 172

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

  response = RestClient::Request.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



186
187
188
189
# File 'lib/vra/client.rb', line 186

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

#raise_http_exception(caught_exception, path) ⇒ Object

Raises:

  • (exception)


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

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

  if caught_exception.http_code == 404
    klass = Vra::Exception::HTTPNotFound
  else
    klass = 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

#request_headersObject



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

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

#requests(*args) ⇒ Object



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

def requests(*args)
  Vra::Requests.new(self, *args)
end

#resources(*args) ⇒ Object



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

def resources(*args)
  Vra::Resources.new(self, *args)
end

#valid_uri?(uri) ⇒ Boolean

Returns:

  • (Boolean)


216
217
218
219
220
221
# File 'lib/vra/client.rb', line 216

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

#validate_client_options!Object

Raises:

  • (ArgumentError)


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

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