Class: Kitchen::Driver::Vcair

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Vcair

Returns a new instance of Vcair.



49
50
51
52
# File 'lib/kitchen/driver/vcair.rb', line 49

def initialize(config)
  super
  Fog.timeout = config[:wait_for].to_i
end

Instance Attribute Details

#vapp_idObject

Returns the value of attribute vapp_id.



28
29
30
# File 'lib/kitchen/driver/vcair.rb', line 28

def vapp_id
  @vapp_id
end

Instance Method Details

#adjust_hardwareObject



136
137
138
139
# File 'lib/kitchen/driver/vcair.rb', line 136

def adjust_hardware
  vm.cpu    = config[:cpus] if config[:cpus]
  vm.memory = config[:memory] if config[:memory]
end

#attach_networkObject



156
157
158
159
# File 'lib/kitchen/driver/vcair.rb', line 156

def attach_network
  task = vcloud_client.put_network_connection_system_section_vapp(vm.id, attach_network_payload)
  vcloud_client.process_task(task.body)
end

#attach_network_payloadObject



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

def attach_network_payload
  {
    PrimaryNetworkConnectionIndex: 0,
    NetworkConnection: [
      {
        network: network.name,
        needsCustomization: true,
        NetworkConnectionIndex: 0,
        IsConnected: true,
        IpAddressAllocationMode: 'POOL'
      }
    ]
  }
end

#catalogObject



204
205
206
207
208
209
210
211
212
213
# File 'lib/kitchen/driver/vcair.rb', line 204

def catalog
  catalog = if config[:catalog_id]
              org.catalogs.get(config[:catalog_id])
            else
              org.catalogs.get_by_name(config[:catalog_name])
            end

  raise 'Unable to find catalog - check your catalog_id or catalog_name' if catalog.nil?
  catalog
end

#create(state) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/kitchen/driver/vcair.rb', line 58

def create(state)
  return unless state[:vapp_id].nil?

  validate!

  create_server(state)
  vm.wait_for { ready? }
  state[:hostname] = vm.ip_address

  info("Server #{state[:hostname]} is powered on. Waiting for it to be ready...")
  wait_for_server(state)
end

#create_server(state) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/kitchen/driver/vcair.rb', line 108

def create_server(state)
  self.vapp_id = instantiate
  state[:vapp_id] = vapp_id

  info("vApp ID #{vapp_id} created.")

  info('Validating the vApp...')
  unless validate_vapp
    destroy(state)
    return
  end

  info('Updating the VM customization...')
  update_customization

  info('Adjusting VM hardware...')
  adjust_hardware

  info('Attaching it to the network...')
  attach_network

  info('Tagging the VM...')
  tag_vm

  info('Powering on the VM...')
  power_on
end

#customizationObject



334
335
336
# File 'lib/kitchen/driver/vcair.rb', line 334

def customization
  @customization ||= vm.customization
end

#destroy(state) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/kitchen/driver/vcair.rb', line 71

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

  validate!

  self.vapp_id = state[:vapp_id]

  info("Destroying vApp #{vapp_id}...")
  begin
    vapp
  rescue Fog::Compute::VcloudDirector::Forbidden
    warn("Unable to locate vApp <#{state[:vapp_id]}> - assuming it is already destroyed.")
    return
  end

  info('Powering off the vApp...')
  vapp.power_off

  info('Undeploying the vApp...')
  vapp.undeploy

  info('Deleting the vApp...')
  vapp.destroy

  info("vApp <#{state[:vapp_id]}> destroyed.")
end

#fog_server_defObject



181
182
183
184
185
186
187
188
189
190
191
# File 'lib/kitchen/driver/vcair.rb', line 181

def fog_server_def
  {
    provider: 'vclouddirector',
    vcloud_director_username:      vcloud_username,
    vcloud_director_password:      config[:vcair_password],
    vcloud_director_host:          config[:vcair_api_host],
    vcloud_director_api_version:   config[:vcair_api_version],
    vcloud_director_show_progress: false,
    path:                          config[:vcair_api_path]
  }
end

#generate_node_nameObject



245
246
247
248
249
250
251
# File 'lib/kitchen/driver/vcair.rb', line 245

def generate_node_name
  # SecureRandom.hex generates a string 2x the argument.
  # We need the name to be 15 chars or less to play nicely
  # with windows, so we're generating a 12-char random
  # string prefixed with "tk-"
  'tk-' + SecureRandom.hex(6)
end

#imageObject



193
194
195
196
197
198
199
200
201
202
# File 'lib/kitchen/driver/vcair.rb', line 193

def image
  image = if config[:image_id]
            catalog.catalog_items.get(config[:image_id])
          else
            catalog.catalog_items.get_by_name(config[:image_name])
          end

  raise 'Unable to find image - check your image_id or image_name' if image.nil?
  image
end

#instantiateObject



307
308
309
# File 'lib/kitchen/driver/vcair.rb', line 307

def instantiate
  image.instantiate(node_name, instantiate_config)
end

#instantiate_configObject



253
254
255
256
257
258
259
# File 'lib/kitchen/driver/vcair.rb', line 253

def instantiate_config
  {
    vdc_id: vdc.id,
    network_id: network.id,
    description: node_description
  }
end

#nameObject



54
55
56
# File 'lib/kitchen/driver/vcair.rb', line 54

def name
  'vCloudAir'
end

#networkObject



226
227
228
229
230
231
232
233
234
235
# File 'lib/kitchen/driver/vcair.rb', line 226

def network
  network = if config[:network_id]
              org.networks.get(config[:network_id])
            else
              org.networks.get_by_name(config[:network_name])
            end

  raise 'Unable to find network - check your network_id or network_name' if network.nil?
  network
end

#node_descriptionObject



237
238
239
# File 'lib/kitchen/driver/vcair.rb', line 237

def node_description
  config[:node_description] || "Test Kitchen: #{node_name}"
end

#node_nameObject



241
242
243
# File 'lib/kitchen/driver/vcair.rb', line 241

def node_name
  config[:node_name] || generate_node_name
end

#orgObject



104
105
106
# File 'lib/kitchen/driver/vcair.rb', line 104

def org
  @org ||= vcloud_client.organizations.get_by_name(config[:vcair_org])
end

#power_onObject



165
166
167
# File 'lib/kitchen/driver/vcair.rb', line 165

def power_on
  vapp.power_on
end


261
262
263
264
# File 'lib/kitchen/driver/vcair.rb', line 261

def print_error_and_exit(message)
  error(message)
  fail message
end

#save_customizationObject



365
366
367
368
# File 'lib/kitchen/driver/vcair.rb', line 365

def save_customization
  customization.enabled = true
  customization.save
end

#set_customization_computer_nameObject



361
362
363
# File 'lib/kitchen/driver/vcair.rb', line 361

def set_customization_computer_name
  customization.computer_name = node_name
end

#set_customization_passwordObject



349
350
351
352
353
354
355
356
357
358
359
# File 'lib/kitchen/driver/vcair.rb', line 349

def set_customization_password
  if config[:vm_password]
    customization.admin_password          = config[:vm_password]
    customization.admin_password_auto     = false
    customization.reset_password_required = false
  else
    customization.admin_password          = nil
    customization.admin_password_auto     = true
    customization.reset_password_required = false
  end
end

#set_customization_scriptObject



345
346
347
# File 'lib/kitchen/driver/vcair.rb', line 345

def set_customization_script
  customization.script = ::File.read(config[:customization_script])
end

#tag_vmObject



161
162
163
# File 'lib/kitchen/driver/vcair.rb', line 161

def tag_vm
  vm.tags.create('created-by', 'test-kitchen')
end

#update_customizationObject



338
339
340
341
342
343
# File 'lib/kitchen/driver/vcair.rb', line 338

def update_customization
  set_customization_script if config[:customization_script]
  set_customization_password
  set_customization_computer_name
  save_customization
end

#validate!Object



266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/kitchen/driver/vcair.rb', line 266

def validate!
  %w(vdc catalog image network).each do |param|
    validate_parameter_pair!(param)
  end

  [ :org, :vdc, :catalog, :image, :network].each do |method|
    validate_method!(method)
  end

  validate_customization_script!
  validate_computer_name!
end

#validate_computer_name!Object



293
294
295
296
297
298
# File 'lib/kitchen/driver/vcair.rb', line 293

def validate_computer_name!
  # regex proudly modified after stealing from:
  # http://stackoverflow.com/questions/2063213/regular-expression-for-validating-dns-label-host-name
  print_error_and_exit('Node name is not valid - must be 15 characters or less, and be a valid Windows node name') unless
    node_name =~ /^(?![0-9]+$)(?!-)[a-zA-Z0-9-]{,15}(?<!-)$/
end

#validate_customization_script!Object



300
301
302
303
304
305
# File 'lib/kitchen/driver/vcair.rb', line 300

def validate_customization_script!
  return unless config[:customization_script]

  print_error_and_exit("Customization script #{config[:customization_script]} is not found or not readable.") unless
    ::File.readable?(config[:customization_script])
end

#validate_method!(method) ⇒ Object



287
288
289
290
291
# File 'lib/kitchen/driver/vcair.rb', line 287

def validate_method!(method)
  send(method)
rescue => e
  raise "Unable to validate #{method} - check your configuration and try again. #{e.class} -- #{e.message}"
end

#validate_parameter_pair!(param) ⇒ Object



279
280
281
282
283
284
285
# File 'lib/kitchen/driver/vcair.rb', line 279

def validate_parameter_pair!(param)
  id_key   = param + '_id'
  name_key = param + '_name'

  print_error_and_exit("No #{param} found. You must specify #{id_key} or #{name_key}.") if
    config[id_key.to_sym].nil? && config[name_key.to_sym].nil?
end

#validate_vappObject



319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/kitchen/driver/vcair.rb', line 319

def validate_vapp
  vms = vapp.vms
  if vms.empty?
    error('vApp created, but did not contain any VMs')
    return false
  end

  if vms.size > 1
    error('vApp created, but contained more than one VM')
    return false
  end

  true
end

#vappObject



311
312
313
# File 'lib/kitchen/driver/vcair.rb', line 311

def vapp
  @vapp ||= vdc.vapps.get(vapp_id)
end

#vcloud_clientObject



98
99
100
101
102
# File 'lib/kitchen/driver/vcair.rb', line 98

def vcloud_client
  @vcloud_client ||= Fog::Compute.new(fog_server_def)
rescue Excon::Errors::Unauthorized => e
  raise "Connection failure, please check your username and password. -- #{e.message}"
end

#vcloud_usernameObject



177
178
179
# File 'lib/kitchen/driver/vcair.rb', line 177

def vcloud_username
  [ config[:vcair_username], config[:vcair_org] ].join('@')
end

#vdcObject



215
216
217
218
219
220
221
222
223
224
# File 'lib/kitchen/driver/vcair.rb', line 215

def vdc
  vdc = if config[:vdc_id]
          org.vdcs.get(config[:vdc_id])
        else
          org.vdcs.get_by_name(config[:vdc_name])
        end

  raise 'Unable to find VDC - check your vdc_id or vdc_name' if vdc.nil?
  vdc
end

#vmObject



315
316
317
# File 'lib/kitchen/driver/vcair.rb', line 315

def vm
  @vm ||= vapp.vms.first
end

#wait_for_server(state) ⇒ Object



169
170
171
172
173
174
175
# File 'lib/kitchen/driver/vcair.rb', line 169

def wait_for_server(state)
  instance.transport.connection(state).wait_until_ready
rescue
  error("Server #{vapp.id} (#{vm.name}) not reachable. Destroying server...")
  destroy(state)
  raise
end