knife-azure 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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