knife-azure 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -201
  3. data/README.md +37 -654
  4. data/lib/azure/resource_management/ARM_deployment_template.rb +87 -50
  5. data/lib/azure/resource_management/ARM_interface.rb +236 -516
  6. data/lib/azure/resource_management/vnet_config.rb +254 -0
  7. data/lib/azure/resource_management/windows_credentials.rb +109 -61
  8. data/lib/azure/service_management/ASM_interface.rb +17 -1
  9. data/lib/azure/service_management/certificate.rb +37 -13
  10. data/lib/azure/service_management/connection.rb +0 -0
  11. data/lib/azure/service_management/deploy.rb +0 -0
  12. data/lib/azure/service_management/disk.rb +0 -0
  13. data/lib/azure/service_management/host.rb +0 -0
  14. data/lib/azure/service_management/image.rb +0 -0
  15. data/lib/azure/service_management/rest.rb +0 -0
  16. data/lib/azure/service_management/role.rb +0 -0
  17. data/lib/azure/service_management/utility.rb +0 -0
  18. data/lib/chef/knife/azure_base.rb +100 -0
  19. data/lib/chef/knife/azure_image_list.rb +0 -0
  20. data/lib/chef/knife/azure_server_create.rb +0 -98
  21. data/lib/chef/knife/azure_server_delete.rb +0 -0
  22. data/lib/chef/knife/azure_server_list.rb +0 -0
  23. data/lib/chef/knife/azure_server_show.rb +0 -0
  24. data/lib/chef/knife/azurerm_base.rb +42 -9
  25. data/lib/chef/knife/azurerm_server_create.rb +31 -24
  26. data/lib/chef/knife/azurerm_server_delete.rb +1 -10
  27. data/lib/chef/knife/azurerm_server_list.rb +5 -1
  28. data/lib/chef/knife/azurerm_server_show.rb +5 -1
  29. data/lib/chef/knife/bootstrap/bootstrap_options.rb +12 -18
  30. data/lib/chef/knife/bootstrap/bootstrapper.rb +34 -15
  31. data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +21 -24
  32. data/lib/chef/knife/bootstrap_azure.rb +58 -0
  33. data/lib/chef/knife/bootstrap_azurerm.rb +40 -50
  34. data/lib/knife-azure/version.rb +1 -1
  35. metadata +27 -12
@@ -36,6 +36,45 @@ module Azure::ARM
36
36
  hints_json
37
37
  end
38
38
 
39
+ def tcp_ports(tcp_ports, vm_name)
40
+ tcp_ports = tcp_ports.split(",")
41
+ sec_grp_json =
42
+ {
43
+ "apiVersion" => "[variables('apiVersion')]",
44
+ "type" => "Microsoft.Network/networkSecurityGroups",
45
+ "name" => "[variables('secgrpname')]",
46
+ "location" => "[resourceGroup().location]",
47
+ "properties" => {
48
+ "securityRules" => [
49
+ ]
50
+ }
51
+ }
52
+ #Security Rule priority can be set between 100 and 4096
53
+ rule_no = 300
54
+ incremental=0
55
+ for port in tcp_ports
56
+ rule_no = rule_no + 2
57
+ sec_grp_json["properties"]["securityRules"].push(
58
+ {
59
+ "name" => vm_name + '_rule_' + incremental.to_s,
60
+ "properties"=> {
61
+ "description" => "Port Provided by user",
62
+ "protocol" => "Tcp",
63
+ "sourcePortRange" => "*",
64
+ "destinationPortRange" => port,
65
+ "sourceAddressPrefix" => "*",
66
+ "destinationAddressPrefix" => "*",
67
+ "access" => "Allow",
68
+ "priority" => rule_no,
69
+ "direction" => "Inbound"
70
+ }
71
+ }
72
+ )
73
+ incremental=incremental+1
74
+ end
75
+ sec_grp_json
76
+ end
77
+
39
78
  def create_deployment_template(params)
40
79
  if params[:chef_extension_public_param][:bootstrap_options][:chef_node_name]
41
80
  chef_node_name = "[concat(parameters('chef_node_name'),copyIndex())]"
@@ -62,6 +101,7 @@ module Azure::ARM
62
101
  # Extension Variables
63
102
  extName = "[concat(variables('vmName'),copyIndex(),'/', variables('vmExtensionName'))]"
64
103
  depExt = "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'), copyIndex())]"
104
+
65
105
  else
66
106
  # publicIPAddresses Resource Variables
67
107
  publicIPAddressName = "[variables('publicIPAddressName')]"
@@ -85,6 +125,11 @@ module Azure::ARM
85
125
  depExt = "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]"
86
126
  end
87
127
 
128
+ # NetworkSecurityGroups Resource Variables
129
+ sec_grp_name = "[variables('secgrpname')]"
130
+ sec_grp = "[concat('Microsoft.Network/networkSecurityGroups/', variables('secgrpname'))]"
131
+ sec_grp_id = "[resourceId('Microsoft.Network/networkSecurityGroups/', variables('secgrpname'))]"
132
+
88
133
  resource_ids = {}
89
134
  hint_names = params[:chef_extension_public_param][:hints]
90
135
 
@@ -176,24 +221,6 @@ module Azure::ARM
176
221
  "metadata"=> {
177
222
  "description"=> "Optional Run List to Execute"
178
223
  }
179
- },
180
- "autoUpdateClient" => {
181
- "type" => "string",
182
- "metadata" => {
183
- "description" => "Optional Flag for auto update"
184
- }
185
- },
186
- "deleteChefConfig" => {
187
- "type" => "string",
188
- "metadata" => {
189
- "description" => "Optional Flag for deleteChefConfig"
190
- }
191
- },
192
- "uninstallChefClient" => {
193
- "type" => "string",
194
- "metadata" => {
195
- "description" => "Optional Flag for uninstallChefClient"
196
- }
197
224
  },
198
225
  "chef_node_name" => {
199
226
  "type" => "string",
@@ -270,16 +297,15 @@ module Azure::ARM
270
297
  "imageOffer"=> "#{params[:azure_image_reference_offer]}",
271
298
  "OSDiskName"=> "#{params[:azure_os_disk_name]}",
272
299
  "nicName"=> "#{params[:azure_vm_name]}",
273
- "addressPrefix"=> "10.0.0.0/16",
274
300
  "subnetName"=> "#{params[:azure_vnet_subnet_name]}",
275
- "subnetPrefix"=> "10.0.0.0/24",
276
301
  "storageAccountType"=> "#{params[:azure_storage_account_type]}",
277
302
  "publicIPAddressName"=> "#{params[:azure_vm_name]}",
278
303
  "publicIPAddressType"=> "Dynamic",
279
304
  "vmStorageAccountContainerName"=> "#{params[:azure_vm_name]}",
280
305
  "vmName"=> "#{params[:azure_vm_name]}",
281
306
  "vmSize"=> "#{params[:vm_size]}",
282
- "virtualNetworkName"=> "#{params[:azure_vnet_name]}",
307
+ "virtualNetworkName"=> "#{params[:vnet_config][:virtualNetworkName]}",
308
+ "secgrpname" => "#{params[:azure_sec_group_name]}",
283
309
  "vnetID"=> "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
284
310
  "subnetRef"=> "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
285
311
  "apiVersion"=> "2015-06-15",
@@ -319,18 +345,9 @@ module Azure::ARM
319
345
  "location"=> "[resourceGroup().location]",
320
346
  "properties"=> {
321
347
  "addressSpace"=> {
322
- "addressPrefixes"=> [
323
- "[variables('addressPrefix')]"
324
- ]
348
+ "addressPrefixes"=> params[:vnet_config][:addressPrefixes]
325
349
  },
326
- "subnets"=> [
327
- {
328
- "name"=> "[variables('subnetName')]",
329
- "properties"=> {
330
- "addressPrefix"=> "[variables('subnetPrefix')]"
331
- }
332
- }
333
- ]
350
+ "subnets"=> params[:vnet_config][:subnets]
334
351
  }
335
352
  },
336
353
  {
@@ -440,6 +457,7 @@ module Azure::ARM
440
457
  "publisher" => "#{params[:chef_extension_publisher]}",
441
458
  "type" => "#{params[:chef_extension]}",
442
459
  "typeHandlerVersion" => "#{params[:chef_extension_version]}",
460
+ "autoUpgradeMinorVersion" => "#{params[:auto_upgrade_minor_version]}",
443
461
  "settings" => {
444
462
  "bootstrap_options" => {
445
463
  "chef_node_name" => chef_node_name,
@@ -448,13 +466,9 @@ module Azure::ARM
448
466
  "bootstrap_version" => "[parameters('bootstrap_version')]",
449
467
  "node_ssl_verify_mode" => "[parameters('node_ssl_verify_mode')]",
450
468
  "node_verify_api_cert" => "[parameters('node_verify_api_cert')]",
451
- "encrypted_data_bag_secret" => "[parameters('encrypted_data_bag_secret')]",
452
469
  "bootstrap_proxy" => "[parameters('bootstrap_proxy')]"
453
470
  },
454
471
  "runlist" => "[parameters('runlist')]",
455
- "autoUpdateClient" => "[parameters('autoUpdateClient')]",
456
- "deleteChefConfig" => "[parameters('deleteChefConfig')]",
457
- "uninstallChefClient" => "[parameters('uninstallChefClient')]",
458
472
  "validation_key_format" => "[parameters('validation_key_format')]",
459
473
  "hints" => hints_json,
460
474
  "client_rb" => "[parameters('client_rb')]",
@@ -462,14 +476,46 @@ module Azure::ARM
462
476
  },
463
477
  "protectedSettings" => {
464
478
  "validation_key" => "[parameters('validation_key')]",
465
- "autoUpgradeMinorVersion" => "#{params[:auto_upgrade_minor_version]}",
466
479
  "client_pem" => "[parameters('client_pem')]",
467
- "chef_server_crt" => "[parameters('chef_server_crt')]"
480
+ "chef_server_crt" => "[parameters('chef_server_crt')]",
481
+ "encrypted_data_bag_secret" => "[parameters('encrypted_data_bag_secret')]"
468
482
  }
469
483
  }
470
484
  }
471
485
  ]
472
486
  }
487
+
488
+ if params[:tcp_endpoints]
489
+ sec_grp_json = tcp_ports(params[:tcp_endpoints], params[:azure_vm_name])
490
+ template['resources'].insert(1,sec_grp_json)
491
+ length = template['resources'].length.to_i - 1
492
+ for i in 0..length do
493
+ if template['resources'][i]['type'] == "Microsoft.Network/virtualNetworks"
494
+ template['resources'][i] = template['resources'][i].merge({"dependsOn" => [sec_grp]})
495
+ end
496
+ if template['resources'][i]['type'] == "Microsoft.Network/networkInterfaces"
497
+ template['resources'][i]['properties'] = template['resources'][i]['properties'].merge({"networkSecurityGroup" => {"id" => sec_grp_id}})
498
+ end
499
+ end
500
+ end
501
+
502
+ if params[:chef_extension_public_param][:extendedLogs] == "true"
503
+ template['resources'].each do |resource|
504
+ if resource['type'] == 'Microsoft.Compute/virtualMachines/extensions'
505
+ resource['properties']['settings']['extendedLogs'] = params[:chef_extension_public_param][:extendedLogs]
506
+ end
507
+ end
508
+ end
509
+
510
+ if params[:chef_extension_public_param][:chef_service_interval]
511
+ template['resources'].each do |resource|
512
+ if resource['type'] == 'Microsoft.Compute/virtualMachines/extensions'
513
+ resource['properties']['settings']['chef_service_interval'] = params[:chef_extension_public_param][:chef_service_interval]
514
+ end
515
+ end
516
+ end
517
+
518
+ template
473
519
  end
474
520
 
475
521
  def create_deployment_parameters(params, platform)
@@ -506,6 +552,9 @@ module Azure::ARM
506
552
  "chef_server_crt" => {
507
553
  "value" => "#{params[:chef_extension_private_param][:chef_server_crt]}"
508
554
  },
555
+ "encrypted_data_bag_secret" => {
556
+ "value" => "#{params[:chef_extension_private_param][:encrypted_data_bag_secret]}"
557
+ },
509
558
  "chef_server_url"=> {
510
559
  "value" => "#{params[:chef_extension_public_param][:bootstrap_options][:chef_server_url]}"
511
560
  },
@@ -518,24 +567,12 @@ module Azure::ARM
518
567
  "node_verify_api_cert" => {
519
568
  "value" => "#{params[:chef_extension_public_param][:bootstrap_options][:node_verify_api_cert]}"
520
569
  },
521
- "encrypted_data_bag_secret" => {
522
- "value" => "#{params[:chef_extension_public_param][:bootstrap_options][:encrypted_data_bag_secret]}"
523
- },
524
570
  "bootstrap_proxy" => {
525
571
  "value" => "#{params[:chef_extension_public_param][:bootstrap_options][:bootstrap_proxy]}"
526
572
  },
527
573
  "runlist" => {
528
574
  "value" => "#{params[:chef_extension_public_param][:runlist]}"
529
575
  },
530
- "autoUpdateClient" => {
531
- "value" => "#{params[:chef_extension_public_param][:autoUpdateClient]}"
532
- },
533
- "deleteChefConfig" => {
534
- "value" => "#{params[:chef_extension_public_param][:deleteChefConfig]}"
535
- },
536
- "uninstallChefClient" => {
537
- "value" => "#{params[:chef_extension_public_param][:uninstallChefClient]}"
538
- },
539
576
  "chef_node_name" => {
540
577
  "value"=> "#{params[:chef_extension_public_param][:bootstrap_options][:chef_node_name]}"
541
578
  },
@@ -16,6 +16,7 @@
16
16
  require 'azure/azure_interface'
17
17
  require 'azure/resource_management/ARM_base'
18
18
  require 'azure/resource_management/ARM_deployment_template'
19
+ require 'azure/resource_management/vnet_config'
19
20
  require 'azure_mgmt_resources'
20
21
  require 'azure_mgmt_compute'
21
22
  require 'azure_mgmt_storage'
@@ -26,6 +27,7 @@ module Azure
26
27
  class ARMInterface < AzureInterface
27
28
  include Azure::ARM::ARMBase
28
29
  include Azure::ARM::ARMDeploymentTemplate
30
+ include Azure::ARM::VnetConfig
29
31
 
30
32
  include Azure::ARM::Resources
31
33
  include Azure::ARM::Resources::Models
@@ -88,59 +90,42 @@ module Azure
88
90
  end
89
91
 
90
92
  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
93
+ if resource_group_name.nil?
94
+ servers = compute_management_client.virtual_machines.list_all.value
95
+ else
96
+ servers = compute_management_client.virtual_machines.list(resource_group_name).value
97
+ end
97
98
 
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
99
+ cols = ['VM Name', 'Resource Group Name', 'Location', 'Provisioning State', 'OS Type']
100
+ rows = []
101
+
102
+ servers.each do |server|
103
+ rows << server.name.to_s
104
+ rows << server.id.split('/')[4].downcase
105
+ rows << server.location.to_s
106
+ rows << begin
107
+ state = server.properties.provisioning_state.to_s.downcase
108
+ case state
109
+ when 'failed'
110
+ ui.color(state, :red)
111
+ when 'succeeded'
112
+ ui.color(state, :green)
113
+ else
114
+ ui.color(state, :yellow)
118
115
  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
116
+ end
117
+ rows << server.properties.storage_profile.os_disk.os_type.to_s
134
118
  end
119
+ display_list(ui, cols, rows)
135
120
  end
136
121
 
137
122
  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
123
+ server = compute_management_client.virtual_machines.get(resource_group_name, vm_name)
124
+ if server && server.name == vm_name
140
125
  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)
126
+ msg_pair(ui, 'VM Name', server.name)
127
+ msg_pair(ui, 'VM Size', server.properties.hardware_profile.vm_size)
128
+ msg_pair(ui, 'VM OS', server.properties.storage_profile.os_disk.os_type)
144
129
  puts "\n"
145
130
 
146
131
  begin
@@ -153,9 +138,8 @@ module Azure
153
138
  ui.info 'Deleting ..'
154
139
 
155
140
  begin
156
- print '.'
157
- promise = compute_management_client.virtual_machines.delete(resource_group_name, vm_name)
158
- end until promise.value!.body.nil?
141
+ server_detail = compute_management_client.virtual_machines.delete(resource_group_name, vm_name)
142
+ end until server_detail.value!.body.nil?
159
143
 
160
144
  puts "\n"
161
145
  ui.warn "Deleted server #{vm_name}"
@@ -163,90 +147,102 @@ module Azure
163
147
  end
164
148
 
165
149
  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
150
+ server = find_server(resource_group, name)
151
+ if server
152
+ network_interface_name = server.properties.network_profile.network_interfaces[0].id.split('/')[-1]
153
+ network_interface_data = network_resource_client.network_interfaces.get(resource_group, network_interface_name)
154
+ public_ip_id_data = network_interface_data.properties.ip_configurations[0].properties.public_ipaddress
155
+ unless public_ip_id_data.nil?
156
+ public_ip_name = public_ip_id_data.id.split('/')[-1]
157
+ public_ip_data = network_resource_client.public_ipaddresses.get(resource_group, public_ip_name)
158
+ else
159
+ public_ip_data = nil
160
+ end
185
161
 
186
- details << ui.color('Provisioning State', :bold, :cyan)
187
- details << server.properties.provisioning_state
162
+ details = Array.new
163
+ details << ui.color('Server Name', :bold, :cyan)
164
+ details << server.name
188
165
 
189
- details << ui.color('Location', :bold, :cyan)
190
- details << server.location
166
+ details << ui.color('Size', :bold, :cyan)
167
+ details << server.properties.hardware_profile.vm_size
191
168
 
192
- details << ui.color('Publisher', :bold, :cyan)
193
- details << server.properties.storage_profile.image_reference.publisher
169
+ details << ui.color('Provisioning State', :bold, :cyan)
170
+ details << server.properties.provisioning_state
194
171
 
195
- details << ui.color('Offer', :bold, :cyan)
196
- details << server.properties.storage_profile.image_reference.offer
172
+ details << ui.color('Location', :bold, :cyan)
173
+ details << server.location
197
174
 
198
- details << ui.color('Sku', :bold, :cyan)
199
- details << server.properties.storage_profile.image_reference.sku
175
+ details << ui.color('Publisher', :bold, :cyan)
176
+ details << server.properties.storage_profile.image_reference.publisher
200
177
 
201
- details << ui.color('Version', :bold, :cyan)
202
- details << server.properties.storage_profile.image_reference.version
178
+ details << ui.color('Offer', :bold, :cyan)
179
+ details << server.properties.storage_profile.image_reference.offer
203
180
 
204
- details << ui.color('OS Type', :bold, :cyan)
205
- details << server.properties.storage_profile.os_disk.os_type
181
+ details << ui.color('Sku', :bold, :cyan)
182
+ details << server.properties.storage_profile.image_reference.sku
206
183
 
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
184
+ details << ui.color('Version', :bold, :cyan)
185
+ details << server.properties.storage_profile.image_reference.version
213
186
 
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
187
+ details << ui.color('OS Type', :bold, :cyan)
188
+ details << server.properties.storage_profile.os_disk.os_type
220
189
 
221
- puts ui.list(details, :columns_across, 2)
190
+ details << ui.color('Public IP address', :bold, :cyan)
191
+ unless public_ip_data.nil?
192
+ details << public_ip_data.properties.ip_address
193
+ else
194
+ details << ' -- '
222
195
  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
196
 
233
- unless result.nil?
234
- server = result.body
197
+ details << ui.color('FQDN', :bold, :cyan)
198
+ unless public_ip_data.nil? or public_ip_data.properties.dns_settings.nil?
199
+ details << public_ip_data.properties.dns_settings.fqdn
235
200
  else
236
- ui.error("There is no server with name #{name} or resource_group #{resource_group}. Please provide correct details.")
201
+ details << ' -- '
237
202
  end
238
- rescue => error
239
- ui.error("#{error.body["error"]["message"]}")
203
+
204
+ puts ui.list(details, :columns_across, 2)
240
205
  end
241
- server
242
206
  end
243
207
 
244
- def virtual_machine_exist?(resource_group_name, vm_name)
245
- !compute_management_client.virtual_machines.get(resource_group_name, vm_name).value.nil?
208
+ def find_server(resource_group, name)
209
+ compute_management_client.virtual_machines.get(resource_group, name)
246
210
  end
247
211
 
212
+ def virtual_machine_exist?(resource_group_name, vm_name)
213
+ begin
214
+ compute_management_client.virtual_machines.get(resource_group_name, vm_name)
215
+ return true
216
+ rescue MsRestAzure::AzureOperationError => error
217
+ if error.body
218
+ err_json = JSON.parse(error.response.body)
219
+ if err_json['error']['code'] == "ResourceNotFound"
220
+ return false
221
+ else
222
+ raise error
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ def security_group_exist?(resource_group_name, security_group_name)
229
+ begin
230
+ network_resource_client.network_security_groups.get(resource_group_name, security_group_name)
231
+ return true
232
+ rescue MsRestAzure::AzureOperationError => error
233
+ if error.body
234
+ err_json = JSON.parse(error.response.body)
235
+ if err_json['error']['code'] == "ResourceNotFound"
236
+ return false
237
+ else
238
+ raise error
239
+ end
240
+ end
241
+ end
242
+ end
243
+
248
244
  def resource_group_exist?(resource_group_name)
249
- resource_management_client.resource_groups.check_existence(resource_group_name).value!.body
245
+ resource_management_client.resource_groups.check_existence(resource_group_name)
250
246
  end
251
247
 
252
248
  def platform(image_reference)
@@ -260,6 +256,69 @@ module Azure
260
256
  end
261
257
  end
262
258
 
259
+ def parse_substatus_code(code, index)
260
+ code.split('/')[index]
261
+ end
262
+
263
+ def fetch_substatus(resource_group_name, virtual_machine_name, chef_extension_name)
264
+ substatuses = compute_management_client.virtual_machine_extensions.get(
265
+ resource_group_name,
266
+ virtual_machine_name,
267
+ chef_extension_name,
268
+ 'instanceView'
269
+ ).properties.instance_view.substatuses
270
+
271
+ return nil if substatuses.nil?
272
+
273
+ substatuses.each do |substatus|
274
+ if parse_substatus_code(substatus.code, 1) == 'Chef Client run logs'
275
+ return substatus
276
+ end
277
+ end
278
+
279
+ return nil
280
+ end
281
+
282
+ def fetch_chef_client_logs(resource_group_name, virtual_machine_name, chef_extension_name, fetch_process_start_time, fetch_process_wait_timeout = 30)
283
+ ## fetch substatus field which contains the chef-client run logs ##
284
+ substatus = fetch_substatus(resource_group_name, virtual_machine_name, chef_extension_name)
285
+
286
+ unless substatus.nil?
287
+ ## chef-client run logs becomes available ##
288
+ status = parse_substatus_code(substatus.code, 2)
289
+ message = substatus.message
290
+
291
+ puts "\n\n******** Please find the chef-client run details below ********\n\n"
292
+ print "----> chef-client run status: "
293
+ case status
294
+ when 'succeeded'
295
+ ## chef-client run succeeded ##
296
+ color = :green
297
+ when 'failed'
298
+ ## chef-client run failed ##
299
+ color = :red
300
+ when 'transitioning'
301
+ ## chef-client run did not complete within maximum timeout of 30 minutes ##
302
+ ## fetch whatever logs available under the chef-client.log file ##
303
+ color = :yellow
304
+ end
305
+ puts "#{ui.color(status, color, :bold)}"
306
+ puts "----> chef-client run logs: "
307
+ puts "\n#{message}\n" ## message field of substatus contains the chef-client run logs ##
308
+ else
309
+ ## unavailability of the substatus field indicates that chef-client run is not completed yet on the server ##
310
+ fetch_process_wait_time = ((Time.now - fetch_process_start_time) / 60).round
311
+ if fetch_process_wait_time <= fetch_process_wait_timeout
312
+ print "#{ui.color('.', :bold)}"
313
+ sleep 30
314
+ fetch_chef_client_logs(resource_group_name, virtual_machine_name, chef_extension_name, fetch_process_start_time, fetch_process_wait_timeout)
315
+ else
316
+ ## wait time exceeded 30 minutes timeout ##
317
+ ui.error "\nchef-client run logs could not be fetched since fetch process exceeded wait timeout of #{fetch_process_wait_timeout} minutes.\n"
318
+ end
319
+ end
320
+ end
321
+
263
322
  def create_server(params = {})
264
323
  platform(params[:azure_image_reference_offer])
265
324
  # resource group creation
@@ -273,22 +332,50 @@ module Azure
273
332
  Chef::Log.info("Resource Group name is: #{resource_group.name}")
274
333
  Chef::Log.info("Resource Group ID is: #{resource_group.id}")
275
334
  end
276
-
335
+
277
336
  # virtual machine creation
278
337
  if virtual_machine_exist?(params[:azure_resource_group_name], params[:azure_vm_name])
279
338
  ui.log("INFO:Virtual Machine #{params[:azure_vm_name]} already exist under the Resource Group #{params[:azure_resource_group_name]}. Exiting for now.")
280
339
  else
281
340
  params[:chef_extension_version] = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
282
341
  params[:vm_size] = get_vm_size(params[:azure_vm_size])
342
+ params[:vnet_config] = create_vnet_config(
343
+ params[:azure_resource_group_name],
344
+ params[:azure_vnet_name],
345
+ params[:azure_vnet_subnet_name]
346
+ )
347
+ if params[:tcp_endpoints]
348
+ if @platform == 'Windows'
349
+ params[:tcp_endpoints] = params[:tcp_endpoints] + ",3389"
350
+ else
351
+ params[:tcp_endpoints] = params[:tcp_endpoints] + ",22,16001"
352
+ end
353
+ random_no = rand(100..1000)
354
+ params[:azure_sec_group_name] = params[:azure_vm_name] + '_sec_grp_' + random_no.to_s
355
+ if security_group_exist?(params[:azure_resource_group_name], params[:azure_sec_group_name])
356
+ random_no = rand(100..1000)
357
+ params[:azure_sec_group_name] = params[:azure_vm_name] + '_sec_grp_' + random_no.to_s
358
+ end
359
+ end
360
+
283
361
  ui.log("Creating Virtual Machine....")
284
362
  deployment = create_virtual_machine_using_template(params)
285
363
  ui.log("Virtual Machine creation successfull.") unless deployment.nil?
286
-
364
+
287
365
  unless deployment.nil?
288
366
  ui.log("Deployment name is: #{deployment.name}")
289
367
  ui.log("Deployment ID is: #{deployment.id}")
290
368
  deployment.properties.dependencies.each do |deploy|
291
369
  if deploy.resource_type == "Microsoft.Compute/virtualMachines"
370
+ if params[:chef_extension_public_param][:extendedLogs] == "true"
371
+ print "\n\nWaiting for the first chef-client run on virtual machine #{deploy.resource_name}"
372
+ fetch_chef_client_logs(params[:azure_resource_group_name],
373
+ deploy.resource_name,
374
+ params[:chef_extension],
375
+ Time.now
376
+ )
377
+ end
378
+
292
379
  ui.log("VM Details ...")
293
380
  ui.log("-------------------------------")
294
381
  ui.log("Virtual Machine name is: #{deploy.resource_name}")
@@ -300,32 +387,6 @@ module Azure
300
387
  end
301
388
  end
302
389
 
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
390
  def vm_public_ip(params = {})
330
391
  network_resource_client.public_ipaddresses.get(
331
392
  params[:azure_resource_group_name],
@@ -346,11 +407,10 @@ module Azure
346
407
  resource_group.location = params[:azure_service_location]
347
408
 
348
409
  begin
349
- resource_group = resource_management_client.resource_groups.create_or_update(resource_group.name, resource_group).value!.body
410
+ resource_group = resource_management_client.resource_groups.create_or_update(resource_group.name, resource_group)
350
411
  rescue Exception => e
351
412
  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}")
413
+ common_arm_rescue_block(e)
354
414
  end
355
415
 
356
416
  resource_group
@@ -372,357 +432,6 @@ module Azure
372
432
  deployment
373
433
  end
374
434
 
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
435
  def create_vm_extension(params)
727
436
  vm_ext_props = VirtualMachineExtensionProperties.new
728
437
  vm_ext_props.publisher = params[:chef_extension_publisher]
@@ -731,12 +440,12 @@ module Azure
731
440
  vm_ext_props.auto_upgrade_minor_version = false
732
441
  vm_ext_props.settings = params[:chef_extension_public_param]
733
442
  vm_ext_props.protected_settings = params[:chef_extension_private_param]
734
-
443
+
735
444
  vm_ext = VirtualMachineExtension.new
736
445
  vm_ext.name = params[:chef_extension]
737
446
  vm_ext.location = params[:azure_service_location]
738
447
  vm_ext.properties = vm_ext_props
739
-
448
+
740
449
  begin
741
450
  vm_extension = compute_management_client.virtual_machine_extensions.create_or_update(
742
451
  params[:azure_resource_group_name],
@@ -744,22 +453,9 @@ module Azure
744
453
  vm_ext.name,
745
454
  vm_ext
746
455
  ).value!.body
747
- rescue Exception => e
456
+ rescue Exception => error
748
457
  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}")
458
+ common_arm_rescue_block(error)
763
459
  end
764
460
 
765
461
  vm_extension
@@ -776,7 +472,7 @@ module Azure
776
472
  ext_version = compute_management_client.virtual_machine_extension_images.list_versions(
777
473
  params[:azure_service_location],
778
474
  params[:chef_extension_publisher],
779
- params[:chef_extension]).value!.body.last.name
475
+ params[:chef_extension]).last.name
780
476
  ext_version_split_values = ext_version.split(".")
781
477
  ext_version = ext_version_split_values[0] + "." + ext_version_split_values[1]
782
478
  ext_version
@@ -784,12 +480,36 @@ module Azure
784
480
 
785
481
  def delete_resource_group(resource_group_name)
786
482
  ui.info 'Resource group deletion takes some time. Please wait ...'
483
+
787
484
  begin
788
- print '.'
789
- promise = resource_management_client.resource_groups.delete(resource_group_name)
790
- end until promise.value!.body.nil?
485
+ server = resource_management_client.resource_groups.delete(resource_group_name)
486
+ end until server.value!.body.nil?
791
487
  puts "\n"
792
488
  end
489
+
490
+ def common_arm_rescue_block(error)
491
+ if error.class == MsRestAzure::AzureOperationError && error.body
492
+ err_json = JSON.parse(error.response.body)
493
+ err_details = err_json["error"]["details"] if err_json["error"]
494
+ if err_details
495
+ err_details.each do |err|
496
+ ui.error(JSON.parse(err["message"])["error"]["message"])
497
+ end
498
+ else
499
+ ui.error(err_json["error"]["message"])
500
+ end
501
+ Chef::Log.debug(error.response.body)
502
+ else
503
+ begin
504
+ JSON.parse(error.message)
505
+ Chef::Log.debug("#{error.message}")
506
+ rescue JSON::ParserError => e
507
+ ui.error("#{error.message}")
508
+ end
509
+ ui.error("Something went wrong. Please use -VV option for more details.")
510
+ Chef::Log.debug("#{error.backtrace.join("\n")}")
511
+ end
512
+ end
793
513
  end
794
514
  end
795
515
  end