Class: Kitchen::Driver::Vra

Inherits:
Base
  • Object
show all
Defined in:
lib/kitchen/driver/vra.rb

Overview

rubocop:disable Metrics/ClassLength

Instance Method Summary collapse

Instance Method Details

#c_loadObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/kitchen/driver/vra.rb', line 96

def c_load
  if File.exist? '.kitchen/cached_vra'
    encrypted = File.read('.kitchen/cached_vra')
    iv_user = Base64.decode64(encrypted.split(':')[0] + '\n')
    username = Base64.decode64(encrypted.split(':')[1] + "\n")
    iv_pwd = Base64.decode64(encrypted.split(':')[2] + "\n")
    password = Base64.decode64(encrypted.split(':')[3] + "\n")
    cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
    cipher.decrypt
    cipher.key = Digest::SHA1.hexdigest(config[:base_url])
    cipher.iv = iv_user
    config[:username] = cipher.update(username) + cipher.final
    cipher.iv = iv_pwd
    config[:password] = cipher.update(password) + cipher.final
  end
rescue
  puts 'Failed to load cached credentials'
end

#c_saveObject



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/kitchen/driver/vra.rb', line 78

def c_save
  cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
  cipher.encrypt
  cipher.key = Digest::SHA1.hexdigest(config[:base_url])
  iv_user = cipher.random_iv
  cipher.iv = iv_user
  username = cipher.update(config[:username]) + cipher.final
  iv_pwd = cipher.random_iv
  cipher.iv = iv_pwd
  password = cipher.update(config[:password]) + cipher.final
  output = "#{Base64.encode64(iv_user).strip!}:#{Base64.encode64(username).strip!}:#{Base64.encode64(iv_pwd).strip!}:#{Base64.encode64(password).strip!}"
  file = File.open('.kitchen/cached_vra', 'w')
  file.write(output)
  file.close
rescue
  puts 'Unable to save credentials'
end

#catalog_requestObject



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/kitchen/driver/vra.rb', line 207

def catalog_request
  if config[:catalog_name] != nil
     info('Fetching Catalog ID by Catalog Name')
     response =  vra_client.catalog.fetch_catalog_items(config[:catalog_name])
     parsed_json = JSON.parse(response.body)
     begin
       config[:catalog_id] = parsed_json['content'][0]['catalogItemId']
     rescue
       puts "Unable to retrieve Catalog ID from Catalog Name: #{config[:catalog_name]}"
     end
  end

  catalog_request = vra_client.catalog.request(config[:catalog_id])

  catalog_request.cpus          = config[:cpus]
  catalog_request.memory        = config[:memory]
  catalog_request.requested_for = config[:requested_for]
  catalog_request.lease_days    = config[:lease_days]    unless config[:lease_days].nil?
  catalog_request.notes         = config[:notes]         unless config[:notes].nil?
  catalog_request.subtenant_id  = config[:subtenant_id]  unless config[:subtenant_id].nil?

  config[:extra_parameters].each do |key, value_data|
    catalog_request.set_parameters(key, value_data)
  end

  catalog_request
end

#check_config(force_change = false) ⇒ Object



68
69
70
71
72
73
74
75
76
# File 'lib/kitchen/driver/vra.rb', line 68

def check_config(force_change = false)
  config[:username] = config[:username] || ENV['VRA_USER_NAME']
  config[:password] = config[:password] || ENV['VRA_USER_PASSWORD']
  c_load if config[:username].nil? && config[:password].nil?

  config[:username] = ask('Enter Username: ') if config[:username].nil? || force_change
  config[:password] = ask('Enter password: ') { |q| q.echo = '*' } if config[:password].nil? || force_change
  c_save if config[:cache_credentials]
end

#create(state) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
# File 'lib/kitchen/driver/vra.rb', line 115

def create(state)
  return if state[:resource_id]

  server = request_server
  state[:resource_id] = server.id
  state[:hostname]    = hostname_for(server)
  state[:ssh_key]     = config[:private_key_path] unless config[:private_key_path].nil?

  wait_for_server(state, server)
  info("Server #{server.id} (#{server.name}) ready.")
end

#destroy(state) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/kitchen/driver/vra.rb', line 183

def destroy(state)
  return if state[:resource_id].nil?

  begin
    server = vra_client.resources.by_id(state[:resource_id])
  rescue ::Vra::Exception::NotFound
    warn("No server found with ID #{state[:resource_id]}, assuming it has been destroyed already.")
    return
  end

  begin
    destroy_request = server.destroy
  rescue ::Vra::Exception::NotFound
    info('Server not found, or no destroy action available, perhaps because it is already destroyed.')
    return
  end
  info("Destroy request #{destroy_request.id} submitted.")
  wait_for_request(destroy_request)
  info('Destroy request complete.')
  
  File.delete('.kitchen/cached_vra') if File.exist?('.kitchen/cached_vra')
  info('Removed cached file')
end

#hostname_for(server) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/kitchen/driver/vra.rb', line 127

def hostname_for(server)
  if config[:use_dns]
    raise 'No server name returned for the vRA request' if server.name.nil?
    return config[:dns_suffix] ? "#{server.name}.#{config[:dns_suffix]}" : server.name
  end

  ip_address = server.ip_addresses.first
  if ip_address.nil?
    warn("Server #{server.id} has no IP address. Falling back to server name (#{server.name})...")
    server.name
  else
    ip_address
  end
end

#nameObject



64
65
66
# File 'lib/kitchen/driver/vra.rb', line 64

def name
  'vRA'
end

#request_serverObject



142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/kitchen/driver/vra.rb', line 142

def request_server
  info('Building vRA catalog request...')
   = catalog_request.submit
  info("Catalog request #{.id} submitted.")

  wait_for_request()
  raise "The vRA request failed: #{.completion_details}" if .failed?

  servers = .resources.select(&:vm?)
  raise 'The vRA request created more than one server. The catalog blueprint should only return one.' if servers.size > 1
  raise 'the vRA request did not create any servers.' if servers.size.zero?

  servers.first
end

#vra_clientObject



235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/kitchen/driver/vra.rb', line 235

def vra_client
  check_config config[:cache_credentials]
  @client ||= ::Vra::Client.new(
    base_url:   config[:base_url],
    username:   config[:username],
    password:   config[:password],
    tenant:     config[:tenant],
    verify_ssl: config[:verify_ssl]
  )
rescue => _e
  check_config true
end

#wait_for_request(request) ⇒ Object



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/kitchen/driver/vra.rb', line 248

def wait_for_request(request)
  # config = check_config config

  last_status = ''
  wait_time   = config[:request_timeout]
  sleep_time  = config[:request_refresh_rate]
  Timeout.timeout(wait_time) do
    loop do
      request.refresh
      break if request.completed?

      unless last_status == request.status
        last_status = request.status
        info("Current request status: #{request.status}")
      end

      sleep sleep_time
    end
  end
rescue Timeout::Error
  error("Request did not complete in #{wait_time} seconds. Check the Requests tab in the vRA UI for more information.")
  raise
end

#wait_for_server(state, server) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/kitchen/driver/vra.rb', line 157

def wait_for_server(state, server)
  info("Server #{server.id} (#{server.name}) created. Waiting until ready...")

  try = 0
  sleep_time = 0

  begin
    instance.transport.connection(state).wait_until_ready
  rescue => e
    warn("Server #{server.id} (#{server.name}) not reachable: #{e.class} -- #{e.message}")

    try += 1
    sleep_time += 5 if sleep_time < 30

    if try > config[:server_ready_retries]
      error('Retries exceeded. Destroying server...')
      destroy(state)
      raise
    else
      warn("Sleeping #{sleep_time} seconds and retrying...")
      sleep sleep_time
      retry
    end
  end
end