knife-azure 1.6.0.rc.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +304 -8
  3. data/lib/azure/azure_interface.rb +81 -0
  4. data/lib/azure/custom_errors.rb +35 -0
  5. data/lib/azure/helpers.rb +44 -0
  6. data/lib/azure/resource_management/ARM_base.rb +29 -0
  7. data/lib/azure/resource_management/ARM_deployment_template.rb +561 -0
  8. data/lib/azure/resource_management/ARM_interface.rb +795 -0
  9. data/lib/azure/resource_management/windows_credentials.rb +136 -0
  10. data/lib/azure/service_management/ASM_interface.rb +301 -0
  11. data/lib/azure/{ag.rb → service_management/ag.rb} +2 -2
  12. data/lib/azure/{certificate.rb → service_management/certificate.rb} +2 -2
  13. data/lib/azure/service_management/connection.rb +102 -0
  14. data/lib/azure/{deploy.rb → service_management/deploy.rb} +8 -2
  15. data/lib/azure/{disk.rb → service_management/disk.rb} +2 -2
  16. data/lib/azure/{host.rb → service_management/host.rb} +2 -2
  17. data/lib/azure/{image.rb → service_management/image.rb} +2 -2
  18. data/lib/azure/{loadbalancer.rb → service_management/loadbalancer.rb} +4 -18
  19. data/lib/azure/{rest.rb → service_management/rest.rb} +15 -10
  20. data/lib/azure/{role.rb → service_management/role.rb} +174 -6
  21. data/lib/azure/{storageaccount.rb → service_management/storageaccount.rb} +2 -2
  22. data/lib/azure/{utility.rb → service_management/utility.rb} +0 -0
  23. data/lib/azure/{vnet.rb → service_management/vnet.rb} +2 -2
  24. data/lib/chef/knife/azure_ag_create.rb +3 -6
  25. data/lib/chef/knife/azure_ag_list.rb +2 -16
  26. data/lib/chef/knife/azure_base.rb +89 -22
  27. data/lib/chef/knife/azure_image_list.rb +3 -7
  28. data/lib/chef/knife/azure_internal-lb_create.rb +2 -5
  29. data/lib/chef/knife/azure_internal-lb_list.rb +2 -16
  30. data/lib/chef/knife/azure_server_create.rb +122 -501
  31. data/lib/chef/knife/azure_server_delete.rb +15 -38
  32. data/lib/chef/knife/azure_server_list.rb +2 -27
  33. data/lib/chef/knife/azure_server_show.rb +4 -60
  34. data/lib/chef/knife/azure_vnet_create.rb +2 -7
  35. data/lib/chef/knife/azure_vnet_list.rb +2 -17
  36. data/lib/chef/knife/azurerm_base.rb +228 -0
  37. data/lib/chef/knife/azurerm_server_create.rb +393 -0
  38. data/lib/chef/knife/azurerm_server_delete.rb +121 -0
  39. data/lib/chef/knife/azurerm_server_list.rb +18 -0
  40. data/lib/chef/knife/azurerm_server_show.rb +37 -0
  41. data/lib/chef/knife/bootstrap/bootstrap_options.rb +105 -0
  42. data/lib/chef/knife/bootstrap/bootstrapper.rb +343 -0
  43. data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +116 -0
  44. data/lib/chef/knife/bootstrap_azure.rb +110 -0
  45. data/lib/chef/knife/bootstrap_azurerm.rb +116 -0
  46. data/lib/knife-azure/version.rb +1 -2
  47. metadata +132 -16
  48. data/lib/azure/connection.rb +0 -99
@@ -0,0 +1,795 @@
1
+ # License:: Apache License, Version 2.0
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+ require 'azure/azure_interface'
17
+ require 'azure/resource_management/ARM_base'
18
+ require 'azure/resource_management/ARM_deployment_template'
19
+ require 'azure_mgmt_resources'
20
+ require 'azure_mgmt_compute'
21
+ require 'azure_mgmt_storage'
22
+ require 'azure_mgmt_network'
23
+
24
+ module Azure
25
+ class ResourceManagement
26
+ class ARMInterface < AzureInterface
27
+ include Azure::ARM::ARMBase
28
+ include Azure::ARM::ARMDeploymentTemplate
29
+
30
+ include Azure::ARM::Resources
31
+ include Azure::ARM::Resources::Models
32
+
33
+ include Azure::ARM::Compute
34
+ include Azure::ARM::Compute::Models
35
+
36
+ include Azure::ARM::Storage
37
+ include Azure::ARM::Storage::Models
38
+
39
+ include Azure::ARM::Network
40
+ include Azure::ARM::Network::Models
41
+
42
+ attr_accessor :connection
43
+
44
+ def initialize(params = {})
45
+ if params[:azure_client_secret]
46
+ token_provider = MsRestAzure::ApplicationTokenProvider.new(params[:azure_tenant_id], params[:azure_client_id], params[:azure_client_secret])
47
+ else
48
+ token_provider = MsRest::StringTokenProvider.new(params[:token],params[:tokentype])
49
+ end
50
+ @credentials = MsRest::TokenCredentials.new(token_provider)
51
+ @azure_subscription_id = params[:azure_subscription_id]
52
+ super
53
+ end
54
+
55
+ def resource_management_client
56
+ @resource_management_client ||= begin
57
+ resource_management_client = ResourceManagementClient.new(@credentials)
58
+ resource_management_client.subscription_id = @azure_subscription_id
59
+ resource_management_client
60
+ end
61
+ end
62
+
63
+ def compute_management_client
64
+ @compute_management_client ||= begin
65
+ compute_management_client = ComputeManagementClient.new(@credentials)
66
+ compute_management_client.subscription_id = @azure_subscription_id
67
+ compute_management_client
68
+ end
69
+ end
70
+
71
+ def storage_management_client
72
+ @storage_management_client ||= begin
73
+ storage_management_client = StorageManagementClient.new(@credentials)
74
+ storage_management_client.subscription_id = @azure_subscription_id
75
+ storage_management_client
76
+ end
77
+ end
78
+
79
+ def network_resource_client
80
+ @network_resource_client ||= begin
81
+ network_resource_client = NetworkManagementClient.new(@credentials)
82
+ network_resource_client.subscription_id = @azure_subscription_id
83
+ network_resource_client
84
+ end
85
+ end
86
+
87
+ def list_images
88
+ end
89
+
90
+ def list_servers(resource_group_name = nil)
91
+ begin
92
+ if resource_group_name.nil?
93
+ promise = compute_management_client.virtual_machines.list_all
94
+ else
95
+ promise = compute_management_client.virtual_machines.list(resource_group_name)
96
+ end
97
+
98
+ result = promise.value!
99
+ servers = result.body.value
100
+
101
+ cols = ['VM Name', 'Resource Group Name', 'Location', 'Provisioning State', 'OS Type']
102
+ rows = []
103
+
104
+ servers.each do |server|
105
+ rows << server.name.to_s
106
+ rows << server.id.split('/')[4].downcase
107
+ rows << server.location.to_s
108
+ rows << begin
109
+ state = server.properties.provisioning_state.to_s.downcase
110
+ case state
111
+ when 'failed'
112
+ ui.color(state, :red)
113
+ when 'succeeded'
114
+ ui.color(state, :green)
115
+ else
116
+ ui.color(state, :yellow)
117
+ end
118
+ end
119
+ rows << server.properties.storage_profile.os_disk.os_type.to_s
120
+ end
121
+ display_list(ui, cols, rows)
122
+ rescue => error
123
+ if error.class == MsRestAzure::AzureOperationError && error.body
124
+ if error.body['error']['code']
125
+ ui.error("#{error.body['error']['message']}")
126
+ else
127
+ ui.error(error.body)
128
+ end
129
+ else
130
+ ui.error("#{error.message}")
131
+ Chef::Log.debug("#{error.backtrace.join("\n")}")
132
+ end
133
+ exit
134
+ end
135
+ end
136
+
137
+ def delete_server(resource_group_name, vm_name)
138
+ promise = compute_management_client.virtual_machines.get(resource_group_name, vm_name)
139
+ if promise.value! && promise.value!.body.name == vm_name
140
+ puts "\n\n"
141
+ msg_pair(ui, 'VM Name', promise.value!.body.name)
142
+ msg_pair(ui, 'VM Size', promise.value!.body.properties.hardware_profile.vm_size)
143
+ msg_pair(ui, 'VM OS', promise.value!.body.properties.storage_profile.os_disk.os_type)
144
+ puts "\n"
145
+
146
+ begin
147
+ ui.confirm('Do you really want to delete this server')
148
+ rescue SystemExit # Need to handle this as confirming with N/n raises SystemExit exception
149
+ server = nil # Cleanup is implicitly performed in other cloud plugins
150
+ exit!
151
+ end
152
+
153
+ ui.info 'Deleting ..'
154
+
155
+ begin
156
+ print '.'
157
+ promise = compute_management_client.virtual_machines.delete(resource_group_name, vm_name)
158
+ end until promise.value!.body.nil?
159
+
160
+ puts "\n"
161
+ ui.warn "Deleted server #{vm_name}"
162
+ end
163
+ end
164
+
165
+ def show_server(name, resource_group)
166
+ begin
167
+ server = find_server(resource_group, name)
168
+ if server
169
+ network_interface_name = server.properties.network_profile.network_interfaces[0].id.split('/')[-1]
170
+ network_interface_data = network_resource_client.network_interfaces.get(resource_group, network_interface_name).value!.body
171
+ public_ip_id_data = network_interface_data.properties.ip_configurations[0].properties.public_ipaddress
172
+ unless public_ip_id_data.nil?
173
+ public_ip_name = public_ip_id_data.id.split('/')[-1]
174
+ public_ip_data = network_resource_client.public_ipaddresses.get(resource_group, public_ip_name).value!.body
175
+ else
176
+ public_ip_data = nil
177
+ end
178
+
179
+ details = Array.new
180
+ details << ui.color('Server Name', :bold, :cyan)
181
+ details << server.name
182
+
183
+ details << ui.color('Size', :bold, :cyan)
184
+ details << server.properties.hardware_profile.vm_size
185
+
186
+ details << ui.color('Provisioning State', :bold, :cyan)
187
+ details << server.properties.provisioning_state
188
+
189
+ details << ui.color('Location', :bold, :cyan)
190
+ details << server.location
191
+
192
+ details << ui.color('Publisher', :bold, :cyan)
193
+ details << server.properties.storage_profile.image_reference.publisher
194
+
195
+ details << ui.color('Offer', :bold, :cyan)
196
+ details << server.properties.storage_profile.image_reference.offer
197
+
198
+ details << ui.color('Sku', :bold, :cyan)
199
+ details << server.properties.storage_profile.image_reference.sku
200
+
201
+ details << ui.color('Version', :bold, :cyan)
202
+ details << server.properties.storage_profile.image_reference.version
203
+
204
+ details << ui.color('OS Type', :bold, :cyan)
205
+ details << server.properties.storage_profile.os_disk.os_type
206
+
207
+ details << ui.color('Public IP address', :bold, :cyan)
208
+ unless public_ip_data.nil?
209
+ details << public_ip_data.properties.ip_address
210
+ else
211
+ details << ' -- '
212
+ end
213
+
214
+ details << ui.color('FQDN', :bold, :cyan)
215
+ unless public_ip_data.nil? or public_ip_data.properties.dns_settings.nil?
216
+ details << public_ip_data.properties.dns_settings.fqdn
217
+ else
218
+ details << ' -- '
219
+ end
220
+
221
+ puts ui.list(details, :columns_across, 2)
222
+ end
223
+ rescue => error
224
+ puts "#{error.body["error"]["message"]}"
225
+ end
226
+ end
227
+
228
+ def find_server(resource_group, name)
229
+ begin
230
+ promise = compute_management_client.virtual_machines.get(resource_group, name)
231
+ result = promise.value!
232
+
233
+ unless result.nil?
234
+ server = result.body
235
+ else
236
+ ui.error("There is no server with name #{name} or resource_group #{resource_group}. Please provide correct details.")
237
+ end
238
+ rescue => error
239
+ ui.error("#{error.body["error"]["message"]}")
240
+ end
241
+ server
242
+ end
243
+
244
+ def virtual_machine_exist?(resource_group_name, vm_name)
245
+ !compute_management_client.virtual_machines.get(resource_group_name, vm_name).value.nil?
246
+ end
247
+
248
+ def resource_group_exist?(resource_group_name)
249
+ resource_management_client.resource_groups.check_existence(resource_group_name).value!.body
250
+ end
251
+
252
+ def platform(image_reference)
253
+ @platform ||= begin
254
+ if image_reference =~ /WindowsServer.*/
255
+ platform = 'Windows'
256
+ else
257
+ platform = 'Linux'
258
+ end
259
+ platform
260
+ end
261
+ end
262
+
263
+ def create_server(params = {})
264
+ platform(params[:azure_image_reference_offer])
265
+ # resource group creation
266
+ if resource_group_exist?(params[:azure_resource_group_name])
267
+ ui.log("INFO:Resource Group #{params[:azure_resource_group_name]} already exist. Skipping its creation.")
268
+ ui.log("INFO:Adding new VM #{params[:azure_vm_name]} to this resource group.")
269
+ else
270
+ ui.log("Creating ResourceGroup....\n\n")
271
+ resource_group = create_resource_group(params)
272
+ Chef::Log.info("ResourceGroup creation successfull.")
273
+ Chef::Log.info("Resource Group name is: #{resource_group.name}")
274
+ Chef::Log.info("Resource Group ID is: #{resource_group.id}")
275
+ end
276
+
277
+ # virtual machine creation
278
+ if virtual_machine_exist?(params[:azure_resource_group_name], params[:azure_vm_name])
279
+ ui.log("INFO:Virtual Machine #{params[:azure_vm_name]} already exist under the Resource Group #{params[:azure_resource_group_name]}. Exiting for now.")
280
+ else
281
+ params[:chef_extension_version] = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
282
+ params[:vm_size] = get_vm_size(params[:azure_vm_size])
283
+ ui.log("Creating Virtual Machine....")
284
+ deployment = create_virtual_machine_using_template(params)
285
+ ui.log("Virtual Machine creation successfull.") unless deployment.nil?
286
+
287
+ unless deployment.nil?
288
+ ui.log("Deployment name is: #{deployment.name}")
289
+ ui.log("Deployment ID is: #{deployment.id}")
290
+ deployment.properties.dependencies.each do |deploy|
291
+ if deploy.resource_type == "Microsoft.Compute/virtualMachines"
292
+ ui.log("VM Details ...")
293
+ ui.log("-------------------------------")
294
+ ui.log("Virtual Machine name is: #{deploy.resource_name}")
295
+ ui.log("Virtual Machine ID is: #{deploy.id}")
296
+ show_server(deploy.resource_name, params[:azure_resource_group_name])
297
+ end
298
+ end
299
+ end
300
+ end
301
+ end
302
+
303
+ def vm_details(virtual_machine, vm_extension, params)
304
+ vm_details = OpenStruct.new
305
+ vm_details.publicipaddress = vm_public_ip(params)
306
+
307
+ if @platform == 'Windows'
308
+ vm_details.rdpport = vm_default_port(params)
309
+ else
310
+ vm_details.sshport = vm_default_port(params)
311
+ end
312
+
313
+ vm_details.id = virtual_machine.id
314
+ vm_details.name = virtual_machine.name
315
+ vm_details.locationname = params[:azure_service_location].gsub(/[ ]/,'').downcase
316
+ vm_details.ostype = virtual_machine.properties.storage_profile.os_disk.os_type
317
+ vm_details.provisioningstate = virtual_machine.properties.provisioning_state
318
+ vm_details.resources = OpenStruct.new
319
+ vm_details.resources.id = vm_extension.id
320
+ vm_details.resources.name = vm_extension.name
321
+ vm_details.resources.publisher = vm_extension.properties.publisher
322
+ vm_details.resources.type = vm_extension.properties.type
323
+ vm_details.resources.type_handler_version = vm_extension.properties.type_handler_version
324
+ vm_details.resources.provisioning_state = vm_extension.properties.provisioning_state
325
+
326
+ vm_details
327
+ end
328
+
329
+ def vm_public_ip(params = {})
330
+ network_resource_client.public_ipaddresses.get(
331
+ params[:azure_resource_group_name],
332
+ params[:azure_vm_name]
333
+ ).value!.body.properties.ip_address
334
+ end
335
+
336
+ def vm_default_port(params = {})
337
+ network_resource_client.network_security_groups.get(
338
+ params[:azure_resource_group_name],
339
+ params[:azure_vm_name]
340
+ ).value!.body.properties.security_rules[0].properties.destination_port_range
341
+ end
342
+
343
+ def create_resource_group(params = {})
344
+ resource_group = ResourceGroup.new()
345
+ resource_group.name = params[:azure_resource_group_name]
346
+ resource_group.location = params[:azure_service_location]
347
+
348
+ begin
349
+ resource_group = resource_management_client.resource_groups.create_or_update(resource_group.name, resource_group).value!.body
350
+ rescue Exception => e
351
+ Chef::Log.error("Failed to create the Resource Group -- exception being rescued: #{e.to_s}")
352
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
353
+ Chef::Log.debug("#{backtrace_message}")
354
+ end
355
+
356
+ resource_group
357
+ end
358
+
359
+ def create_virtual_machine_using_template(params)
360
+ template = create_deployment_template(params)
361
+ parameters = create_deployment_parameters(params, @platform)
362
+
363
+ deploy_prop = DeploymentProperties.new
364
+ deploy_prop.template = template
365
+ deploy_prop.parameters = parameters
366
+ deploy_prop.mode = 'Incremental'
367
+
368
+ deploy_params = Deployment.new
369
+ deploy_params.properties = deploy_prop
370
+
371
+ deployment = resource_management_client.deployments.create_or_update(params[:azure_resource_group_name], "#{params[:azure_vm_name]}_deploy", deploy_params).value!.body
372
+ deployment
373
+ end
374
+
375
+ def create_virtual_machine(params)
376
+ os_profile = OSProfile.new
377
+ os_profile.computer_name = params[:azure_vm_name]
378
+ os_profile.secrets = []
379
+
380
+ if @platform == 'Windows'
381
+ windows_config = WindowsConfiguration.new
382
+ windows_config.provision_vmagent = true
383
+ windows_config.enable_automatic_updates = true
384
+
385
+ os_profile.admin_username = params[:winrm_user]
386
+ os_profile.admin_password = params[:admin_password]
387
+ os_profile.windows_configuration = windows_config
388
+ else
389
+ linux_config = LinuxConfiguration.new
390
+ linux_config.disable_password_authentication = false
391
+
392
+ os_profile.admin_username = params[:ssh_user]
393
+ os_profile.admin_password = params[:ssh_password]
394
+ os_profile.linux_configuration = linux_config
395
+ end
396
+
397
+ hardware_profile = HardwareProfile.new
398
+ hardware_profile.vm_size = get_vm_size(params[:azure_vm_size])
399
+
400
+ vm_props = VirtualMachineProperties.new
401
+ vm_props.os_profile = os_profile
402
+ vm_props.hardware_profile = hardware_profile
403
+ vm_props.storage_profile = create_storage_profile(params)
404
+ vm_props.network_profile = create_network_profile(params)
405
+
406
+ vm_params = VirtualMachine.new
407
+ vm_params.name = params[:azure_vm_name]
408
+ vm_params.type = 'Microsoft.Compute/virtualMachines'
409
+ vm_params.properties = vm_props
410
+ vm_params.location = params[:azure_service_location]
411
+
412
+ begin
413
+ virtual_machine = compute_management_client.virtual_machines.create_or_update(params[:azure_resource_group_name], vm_params.name, vm_params).value!.body
414
+ rescue Exception => e
415
+ ui.log("Failed to create the virtual machine, use verbose mode for more details")
416
+ Chef::Log.error("Failed to create the Virtual Machine -- exception being rescued: #{e.to_s}")
417
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
418
+ Chef::Log.debug("#{backtrace_message}")
419
+ end
420
+
421
+ virtual_machine
422
+ end
423
+
424
+ def create_storage_profile(params)
425
+ ui.log("Creating Storage Account.... \n\n ")
426
+ storage_account = create_storage_account(
427
+ params[:azure_storage_account],
428
+ params[:azure_service_location],
429
+ params[:azure_storage_account_type],
430
+ params[:azure_resource_group_name]
431
+ )
432
+
433
+ virtual_hard_disk = get_vhd(
434
+ params[:azure_storage_account],
435
+ params[:azure_os_disk_name]
436
+ )
437
+
438
+ ui.log("StorageAccount creation successfull.")
439
+ storage_profile = StorageProfile.new
440
+ storage_profile.image_reference = get_image_reference(
441
+ params[:azure_image_reference_publisher],
442
+ params[:azure_image_reference_offer],
443
+ params[:azure_image_reference_sku],
444
+ params[:azure_image_reference_version]
445
+ )
446
+ storage_profile.os_disk = get_os_disk(
447
+ virtual_hard_disk,
448
+ params[:azure_os_disk_name],
449
+ params[:azure_os_disk_caching],
450
+ params[:azure_os_disk_create_option]
451
+ )
452
+
453
+ storage_profile
454
+ end
455
+
456
+ def create_storage_account(storage_account_name, location, storage_account_type, resource_group_name)
457
+ storage_props = Azure::ARM::Storage::Models::StorageAccountPropertiesCreateParameters.new
458
+ storage_props.account_type = storage_account_type
459
+
460
+ storage_params = Azure::ARM::Storage::Models::StorageAccountCreateParameters.new
461
+ storage_params.location = location
462
+ storage_params.properties = storage_props
463
+
464
+ storage = storage_management_client.storage_accounts.create(resource_group_name, storage_account_name, storage_params).value!.body
465
+ storage
466
+ end
467
+
468
+ def get_vhd(storage_account_name, os_disk_name)
469
+ virtual_hard_disk = VirtualHardDisk.new
470
+ virtual_hard_disk.uri = "http://#{storage_account_name}.blob.core.windows.net/vhds/#{os_disk_name}.vhd"
471
+ virtual_hard_disk
472
+ end
473
+
474
+ def get_image_reference(publisher, offer, sku, version)
475
+ image_reference = ImageReference.new
476
+ image_reference.publisher = publisher
477
+ image_reference.offer = offer
478
+ image_reference.sku = sku
479
+ image_reference.version = version
480
+ image_reference
481
+ end
482
+
483
+ def get_os_disk(virtual_hard_disk, os_disk_name, os_disk_caching, os_disk_create_option)
484
+ os_disk = OSDisk.new
485
+ os_disk.name = os_disk_name
486
+ os_disk.vhd = virtual_hard_disk
487
+ os_disk.caching = os_disk_caching
488
+ os_disk.create_option = os_disk_create_option
489
+ os_disk
490
+ end
491
+
492
+ def vnet_exist?(resource_group_name, vnet_name)
493
+ begin
494
+ network_resource_client.virtual_networks.get(resource_group_name, vnet_name).value!.body
495
+ rescue
496
+ return false
497
+ end
498
+ end
499
+
500
+ def subnet_exist?(resource_group_name, vnet_name, subnet_name)
501
+ begin
502
+ network_resource_client.subnets.get(resource_group_name, vnet_name, subnet_name).value!.body
503
+ rescue
504
+ return false
505
+ end
506
+ end
507
+
508
+ def create_network_profile(params)
509
+ if vnet_exist?(params[:azure_resource_group_name], params[:azure_vnet_name])
510
+ vnet = network_resource_client.virtual_networks.get(params[:azure_resource_group_name], params[:azure_vnet_name]).value!.body
511
+ Chef::Log.info("Found existing vnet #{vnet.name}...")
512
+ else
513
+ ui.log("Creating VirtualNetwork....\n\n")
514
+ vnet = create_virtual_network(
515
+ params[:azure_resource_group_name],
516
+ params[:azure_vnet_name],
517
+ params[:azure_service_location]
518
+ )
519
+ Chef::Log.info("VirtualNetwork creation successfull.")
520
+ end
521
+
522
+ Chef::Log.info("Virtual Network name is: #{vnet.name}")
523
+
524
+ Chef::Log.info("Virtual Network ID is: #{vnet.id}")
525
+
526
+ if subnet_exist?(params[:azure_resource_group_name], vnet.name, params[:azure_vnet_subnet_name])
527
+ sbn = network_resource_client.subnets.get(params[:azure_resource_group_name], vnet.name, params[:azure_vnet_subnet_name]).value!.body
528
+
529
+ Chef::Log.info("Found subnet #{sbn.name} under virtual network #{vnet.name} ...")
530
+
531
+ else
532
+ ui.log("Creating Subnet....\n\n")
533
+ sbn = create_subnet(
534
+ params[:azure_resource_group_name],
535
+ params[:azure_vnet_subnet_name],
536
+ vnet
537
+ )
538
+ Chef::Log.info("Subnet creation successfull.")
539
+ end
540
+
541
+ Chef::Log.info("Subnet name is: #{sbn.name}")
542
+ Chef::Log.info("Subnet ID is: #{sbn.id}")
543
+
544
+ ui.log("Creating NetworkInterface....\n\n")
545
+ nic = create_network_interface(
546
+ params[:azure_resource_group_name],
547
+ params[:azure_vm_name],
548
+ params[:azure_service_location],
549
+ sbn
550
+ )
551
+ Chef::Log.info("NetworkInterface creation successfull.")
552
+ Chef::Log.info("Network Interface name is: #{nic.name}")
553
+ Chef::Log.info("Network Interface ID is: #{nic.id}")
554
+
555
+ network_profile = NetworkProfile.new
556
+ network_profile.network_interfaces = [nic]
557
+ network_profile
558
+ end
559
+
560
+ def create_virtual_network(resource_group_name, virtual_network_name, service_location)
561
+ address_space = AddressSpace.new
562
+ address_space.address_prefixes = ['10.0.0.0/16']
563
+
564
+ vnet_props = VirtualNetworkPropertiesFormat.new
565
+ vnet_props.address_space = address_space
566
+
567
+ vnet_params = VirtualNetwork.new
568
+ vnet_params.name = virtual_network_name
569
+ vnet_params.location = service_location
570
+ vnet_params.properties = vnet_props
571
+
572
+ begin
573
+ vnet = network_resource_client.virtual_networks.create_or_update(resource_group_name, vnet_params.name, vnet_params).value!.body
574
+ rescue Exception => e
575
+ Chef::Log.error("Failed to create the Virtual Network -- exception being rescued: #{e.to_s}")
576
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
577
+ Chef::Log.debug("#{backtrace_message}")
578
+ end
579
+ vnet
580
+ end
581
+
582
+ def create_subnet(resource_group_name, subnet_name, virtual_network)
583
+ sbn_prop = SubnetPropertiesFormat.new
584
+ sbn_prop.address_prefix = '10.0.1.0/24'
585
+
586
+ sbn_params = Subnet.new
587
+ sbn_params.name = subnet_name
588
+ sbn_params.properties = sbn_prop
589
+
590
+ begin
591
+ sbn = network_resource_client.subnets.create_or_update(resource_group_name, virtual_network.name, sbn_params.name, sbn_params).value!.body
592
+ rescue Exception => e
593
+ Chef::Log.error("Failed to create the Subnet -- exception being rescued: #{e.to_s}")
594
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
595
+ Chef::Log.debug("#{backtrace_message}")
596
+ end
597
+ sbn
598
+ end
599
+
600
+ def create_network_interface(resource_group_name, vm_name, service_location, subnet)
601
+ network_ip_configuration_properties = NetworkInterfaceIPConfigurationPropertiesFormat.new
602
+ network_ip_configuration_properties.private_ipallocation_method = 'Dynamic'
603
+
604
+ network_ip_configuration_properties.public_ipaddress = create_public_ip_config(
605
+ resource_group_name,
606
+ vm_name,
607
+ service_location
608
+ )
609
+
610
+ network_ip_configuration_properties.subnet = subnet
611
+
612
+ network_interface_ip_configuration = NetworkInterfaceIPConfiguration.new
613
+ network_interface_ip_configuration.properties = network_ip_configuration_properties
614
+ network_interface_ip_configuration.name = vm_name
615
+
616
+ network_interface_props_format = NetworkInterfacePropertiesFormat.new
617
+ network_interface_props_format.ip_configurations = [network_interface_ip_configuration]
618
+ network_interface_props_format.network_security_group = create_network_security_group(
619
+ resource_group_name,
620
+ vm_name,
621
+ service_location
622
+ )
623
+
624
+ network_interface = NetworkInterface.new
625
+ network_interface.location = service_location
626
+ network_interface.name = vm_name
627
+ network_interface.properties = network_interface_props_format
628
+
629
+ begin
630
+ nic = network_resource_client.network_interfaces.create_or_update(resource_group_name, network_interface.name, network_interface).value!.body
631
+ rescue Exception => e
632
+ Chef::Log.error("Failed to create the Network Interface -- exception being rescued: #{e.to_s}")
633
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
634
+ Chef::Log.debug("#{backtrace_message}")
635
+ end
636
+
637
+ nic
638
+ end
639
+
640
+ def create_public_ip_config(resource_group_name, vm_name, service_location)
641
+ public_ip_props = PublicIPAddressPropertiesFormat.new
642
+ public_ip_props.public_ipallocation_method = 'Dynamic'
643
+
644
+ public_ip = PublicIPAddress.new
645
+ public_ip.name = vm_name
646
+ public_ip.location = service_location
647
+ public_ip.properties = public_ip_props
648
+
649
+ begin
650
+ public_ip_address = network_resource_client.public_ipaddresses.create_or_update(
651
+ resource_group_name,
652
+ public_ip.name,
653
+ public_ip
654
+ ).value!.body
655
+ rescue Exception => e
656
+ Chef::Log.error("Failed to create the Public IP Address -- exception being rescued: #{e.to_s}")
657
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
658
+ Chef::Log.debug("#{backtrace_message}")
659
+ end
660
+
661
+ public_ip_address
662
+ end
663
+
664
+ def create_network_security_group(resource_group_name, vm_name, service_location)
665
+ network_security_group_prop_format = NetworkSecurityGroupPropertiesFormat.new
666
+ network_security_group = NetworkSecurityGroup.new
667
+ network_security_group.name = vm_name
668
+ network_security_group.location = service_location
669
+ network_security_group.properties = network_security_group_prop_format
670
+
671
+ begin
672
+ nsg = network_resource_client.network_security_groups.create_or_update(
673
+ resource_group_name,
674
+ network_security_group.name,
675
+ network_security_group
676
+ ).value!.body
677
+ rescue Exception => e
678
+ Chef::Log.error("Failed to create the Network Security Group -- exception being rescued: #{e.to_s}")
679
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
680
+ Chef::Log.debug("#{backtrace_message}")
681
+ end
682
+
683
+ security_rules = []
684
+ if @platform == 'Windows'
685
+ security_rules << add_security_rule('3389', "RDP", 1000, resource_group_name, vm_name, network_security_group)
686
+ else
687
+ security_rules << add_security_rule("22", "SSH", 1000, resource_group_name, vm_name, network_security_group)
688
+ end
689
+ network_security_group_prop_format.default_security_rules = security_rules
690
+
691
+ nsg
692
+ end
693
+
694
+ def add_security_rule(port, description, priority, resource_group_name, vm_name, network_security_group)
695
+ security_rule_props = SecurityRulePropertiesFormat.new
696
+ security_rule_props.description = description
697
+ security_rule_props.destination_port_range = port
698
+ security_rule_props.protocol = "Tcp"
699
+ security_rule_props.source_port_range = "*"
700
+ security_rule_props.source_address_prefix = "*"
701
+ security_rule_props.destination_address_prefix = "*"
702
+ security_rule_props.access = "Allow"
703
+ security_rule_props.priority = priority
704
+ security_rule_props.direction = "Inbound"
705
+
706
+ security_rule = SecurityRule.new
707
+ security_rule.name = vm_name
708
+ security_rule.properties = security_rule_props
709
+
710
+ begin
711
+ security_rule = network_resource_client.security_rules.create_or_update(
712
+ resource_group_name,
713
+ network_security_group.name,
714
+ security_rule.name,
715
+ security_rule
716
+ ).value!.body
717
+ rescue Exception => e
718
+ Chef::Log.error("Failed to create the Security Rule -- exception being rescued: #{e.to_s}")
719
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
720
+ Chef::Log.debug("#{backtrace_message}")
721
+ end
722
+
723
+ security_rule
724
+ end
725
+
726
+ def create_vm_extension(params)
727
+ vm_ext_props = VirtualMachineExtensionProperties.new
728
+ vm_ext_props.publisher = params[:chef_extension_publisher]
729
+ vm_ext_props.type = params[:chef_extension]
730
+ vm_ext_props.type_handler_version = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
731
+ vm_ext_props.auto_upgrade_minor_version = false
732
+ vm_ext_props.settings = params[:chef_extension_public_param]
733
+ vm_ext_props.protected_settings = params[:chef_extension_private_param]
734
+
735
+ vm_ext = VirtualMachineExtension.new
736
+ vm_ext.name = params[:chef_extension]
737
+ vm_ext.location = params[:azure_service_location]
738
+ vm_ext.properties = vm_ext_props
739
+
740
+ begin
741
+ vm_extension = compute_management_client.virtual_machine_extensions.create_or_update(
742
+ params[:azure_resource_group_name],
743
+ params[:azure_vm_name],
744
+ vm_ext.name,
745
+ vm_ext
746
+ ).value!.body
747
+ rescue Exception => e
748
+ Chef::Log.error("Failed to create the Virtual Machine Extension -- exception being rescued.")
749
+
750
+ if e.class == MsRestAzure::AzureOperationError && e.body
751
+ if e.body['error']['code'] == 'DeploymentFailed'
752
+ ui.error("#{error.body['error']['message']}")
753
+ else
754
+ ui.error(e.body)
755
+ end
756
+ else
757
+ ui.error("#{error.message}")
758
+ Chef::Log.debug("#{error.backtrace.join("\n")}")
759
+ end
760
+
761
+ backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
762
+ Chef::Log.debug("#{backtrace_message}")
763
+ end
764
+
765
+ vm_extension
766
+ end
767
+
768
+ def extension_already_installed?(server)
769
+ server.resources.each do |extension|
770
+ return true if (extension.properties.type == "ChefClient" || extension.properties.type == "LinuxChefClient")
771
+ end if server.resources
772
+ false
773
+ end
774
+
775
+ def get_latest_chef_extension_version(params)
776
+ ext_version = compute_management_client.virtual_machine_extension_images.list_versions(
777
+ params[:azure_service_location],
778
+ params[:chef_extension_publisher],
779
+ params[:chef_extension]).value!.body.last.name
780
+ ext_version_split_values = ext_version.split(".")
781
+ ext_version = ext_version_split_values[0] + "." + ext_version_split_values[1]
782
+ ext_version
783
+ end
784
+
785
+ def delete_resource_group(resource_group_name)
786
+ ui.info 'Resource group deletion takes some time. Please wait ...'
787
+ begin
788
+ print '.'
789
+ promise = resource_management_client.resource_groups.delete(resource_group_name)
790
+ end until promise.value!.body.nil?
791
+ puts "\n"
792
+ end
793
+ end
794
+ end
795
+ end