knife-azure 4.0.0 → 5.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba6a2397f4641337ac1c0e35e060bdec8878111da9ca1d41d5207e15a0209b71
4
- data.tar.gz: fb2691f81f0ba4c79d3dd86e7d04ff1ec92b85da1dfda35641b8b65d8b8f1025
3
+ metadata.gz: b2b0c8e7095b9f0880e4d35af2728b7c71119ef5fd22138cc4e5f6ad37ab467b
4
+ data.tar.gz: a853c153d5d15328a0026c84f91c552329e72c87dc5935c32760435f10bff6f9
5
5
  SHA512:
6
- metadata.gz: c9f8f4ba4b588eeca8037853e842cae06e7cb699fc758fbe83c3e0e7b6d05ae67319a65bb85e4a97fc34c28c5590dad65980856052883be1becf2bd4bbf7d9b9
7
- data.tar.gz: c7f1e891b81df8dc594a349ddffb61b9fb0fb6d8cc90ff3d6a972b82b1e2a199fa2b8a89631f86cf41678d9ae5dd8949806d21a0c76365d1e57db6d7750f3d5c
6
+ metadata.gz: 352cf2e4f22eaed979e964367e98e0e9c80a18e1b44352207f9bad659e8197a4355b4f9ff4393bd85248c5ffeceff672424902428385e17800aad36a8201600d
7
+ data.tar.gz: d9956696c10ce1e4c0a96d9d8d46826c8d4d8fe448778c274d1c658ac9485d136871f5843c7b952fbc92ba235ba784952a3241bc303b758ffc18af06c4d2a6fa
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright:: Copyright (c) Chef Software Inc.
2
+ # Copyright:: Copyright (c) 2012-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
3
3
  # License:: Apache License, Version 2.0
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright:: Copyright (c) Chef Software Inc.
2
+ # Copyright:: Copyright (c) 2012-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
3
3
  # License:: Apache License, Version 2.0
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
data/lib/azure/helpers.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Author:: vasundhara.jagdale@clogeny.com
3
- # Copyright:: Copyright (c) Chef Software Inc.
3
+ # Copyright:: Copyright (c) 2012-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Author:: Nimisha Sharad (nimisha.sharad@clogeny.com)
3
- # Copyright:: Copyright (c) Chef Software Inc.
3
+ # Copyright:: Copyright (c) 2012-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -94,8 +94,8 @@ module Azure::ARM
94
94
  vmId = "[resourceId('Microsoft.Compute/virtualMachines', concat(variables('vmName'),copyIndex()))]"
95
95
  depVm2 = "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), copyIndex())]"
96
96
  computerName = "[concat(variables('vmName'),copyIndex())]"
97
- uri = "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/',concat(variables('vmName'),copyIndex()),'.vhd')]"
98
97
  netid = "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'), copyIndex()))]"
98
+ osDiskName = "[concat(variables('OSDiskName'),copyIndex())]"
99
99
 
100
100
  # Extension Variables
101
101
  extName = "[concat(variables('vmName'),copyIndex(),'/', variables('vmExtensionName'))]"
@@ -117,8 +117,8 @@ module Azure::ARM
117
117
  vmId = "[resourceId('Microsoft.Compute/virtualMachines', variables('vmName'))]"
118
118
  depVm2 = "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
119
119
  computerName = "[variables('vmName')]"
120
- uri = "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/',variables('vmName'),'.vhd')]"
121
120
  netid = "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
121
+ osDiskName = "[variables('OSDiskName')]"
122
122
 
123
123
  # Extension Variables
124
124
  extName = "[concat(variables('vmName'),'/', variables('vmExtensionName'))]"
@@ -252,12 +252,41 @@ module Azure::ARM
252
252
  "description" => "Optional. Path to a client.rb file for use by the bootstrapped node.",
253
253
  },
254
254
  },
255
+ "CHEF_LICENSE" => {
256
+ "type" => "string",
257
+ "defaultValue" => "accept-no-persist",
258
+ "metadata" => {
259
+ "description" => "Optional. Chef Infra license acceptance value read and exported as an " \
260
+ "environment variable by the VM extension's own bootstrap script, so it also covers " \
261
+ "the extension's separate chef-apply cron-setup step (which does not read client_rb).",
262
+ },
263
+ },
255
264
  "bootstrap_version" => {
256
265
  "type" => "string",
257
266
  "metadata" => {
258
267
  "description" => "Optional. The version of Chef to install.",
259
268
  },
260
269
  },
270
+ "chef_license_key" => {
271
+ # securestring keeps this out of ARM deployment history/logs and the
272
+ # Azure Portal's deployment "Inputs" view (same treatment as
273
+ # adminPassword above). Per chef-partners/azure-chef-extension#413
274
+ # (version 1210.15.11.1, rolled out to all regions for both
275
+ # ChefClient and LinuxChefClient), the VM extension's install
276
+ # scripts now decrypt protectedSettings for this value and prefer
277
+ # it over the deprecated publicSettings location, so it is
278
+ # forwarded via the "protectedSettings" block below instead of
279
+ # plain "settings" - delivered to the VM CMS/PKCS7-encrypted and
280
+ # decrypted locally, the same treatment already given to
281
+ # validation_key/chef_server_crt/encrypted_data_bag_secret.
282
+ "type" => "securestring",
283
+ "metadata" => {
284
+ "description" => "Optional. Chef/Progress license key, forwarded to the VM extension's " \
285
+ "install.sh as chef_license_key so it can download Chef Infra Client from the licensed " \
286
+ "endpoints. When omitted, the extension falls back to the unlicensed omnitruck.chef.io " \
287
+ "download host with a warning.",
288
+ },
289
+ },
261
290
  "custom_json_attr" => {
262
291
  "type" => "string",
263
292
  "metadata" => {
@@ -302,7 +331,6 @@ module Azure::ARM
302
331
  },
303
332
  },
304
333
  "variables" => {
305
- "storageAccountName" => "[concat(uniquestring(resourceGroup().id), '#{params[:azure_storage_account]}')]",
306
334
  "imagePublisher" => "#{params[:azure_image_reference_publisher]}",
307
335
  "imageOffer" => "#{params[:azure_image_reference_offer]}",
308
336
  "OSDiskName" => "#{params[:azure_os_disk_name]}",
@@ -311,7 +339,6 @@ module Azure::ARM
311
339
  "storageAccountType" => "#{params[:azure_storage_account_type]}",
312
340
  "publicIPAddressName" => "#{params[:azure_vm_name]}",
313
341
  "publicIPAddressType" => "Dynamic",
314
- "vmStorageAccountContainerName" => "#{params[:azure_vm_name]}",
315
342
  "vmName" => "#{params[:azure_vm_name]}",
316
343
  "vmSize" => "#{params[:vm_size]}",
317
344
  "virtualNetworkName" => "#{params[:vnet_config][:virtualNetworkName]}",
@@ -323,15 +350,12 @@ module Azure::ARM
323
350
  "sshKeyPath" => "[concat('/home/',parameters('adminUserName'),'/.ssh/authorized_keys')]",
324
351
  },
325
352
  "resources" => [
326
- {
327
- "type" => "Microsoft.Storage/storageAccounts",
328
- "name" => "[variables('storageAccountName')]",
329
- "apiVersion" => "[variables('apiVersion')]",
330
- "location" => "[resourceGroup().location]",
331
- "properties" => {
332
- "accountType" => "[variables('storageAccountType')]",
333
- },
334
- },
353
+ # NOTE: Managed disks are used for the OS disk below, so no separate
354
+ # Microsoft.Storage/storageAccounts resource is created here. Existing
355
+ # deployments created with an unmanaged-disk storage account continue to
356
+ # function as-is; this only affects new VM deployments. See Azure's
357
+ # migration guide if you want to move existing VMs to managed disks:
358
+ # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/convert-unmanaged-to-managed-disks
335
359
  {
336
360
  "apiVersion" => "[variables('apiVersion')]",
337
361
  "type" => "Microsoft.Network/publicIPAddresses",
@@ -391,7 +415,15 @@ module Azure::ARM
391
415
  },
392
416
  },
393
417
  {
394
- "apiVersion" => "[variables('apiVersion')]",
418
+ # NOTE: apiVersion "2020-12-01" is required, not just for managed disk
419
+ # support and managed boot diagnostics (both available since
420
+ # "2020-06-01", using Azure's managed-storage boot diagnostics instead
421
+ # of the storage account this template no longer creates), but also
422
+ # for the StandardSSD_ZRS/Premium_ZRS managed disk SKUs accepted by
423
+ # --azure-storage-account-type, which older API versions reject at
424
+ # deployment time. Don't switch this back to an older apiVersion
425
+ # without re-verifying managed disk, ZRS, and boot diagnostics support.
426
+ "apiVersion" => "2020-12-01",
395
427
  "type" => "Microsoft.Compute/virtualMachines",
396
428
  "name" => vmName,
397
429
  "location" => "[resourceGroup().location]",
@@ -400,7 +432,6 @@ module Azure::ARM
400
432
  "count" => "[parameters('numberOfInstances')]",
401
433
  },
402
434
  "dependsOn" => [
403
- "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
404
435
  depVm2,
405
436
  ],
406
437
  "properties" => {
@@ -430,12 +461,12 @@ module Azure::ARM
430
461
  "version" => "[parameters('imageVersion')]",
431
462
  },
432
463
  "osDisk" => {
433
- "name" => "[variables('OSDiskName')]",
434
- "vhd" => {
435
- "uri" => uri,
436
- },
464
+ "name" => osDiskName,
437
465
  "caching" => "ReadWrite",
438
466
  "createOption" => "FromImage",
467
+ "managedDisk" => {
468
+ "storageAccountType" => "[variables('storageAccountType')]",
469
+ },
439
470
  },
440
471
  },
441
472
  "networkProfile" => {
@@ -447,8 +478,11 @@ module Azure::ARM
447
478
  },
448
479
  "diagnosticsProfile" => {
449
480
  "bootDiagnostics" => {
481
+ # Managed boot diagnostics: no storageUri is provided (or needed)
482
+ # since apiVersion 2020-12-01+ provisions Azure-managed storage
483
+ # for boot diagnostics automatically, instead of the storage
484
+ # account this template no longer creates.
450
485
  "enabled" => "true",
451
- "storageUri" => "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]",
452
486
  },
453
487
  },
454
488
  },
@@ -486,11 +520,17 @@ module Azure::ARM
486
520
  "hints" => hints_json,
487
521
  "client_rb" => "[parameters('client_rb')]",
488
522
  "custom_json_attr" => "[parameters('custom_json_attr')]",
523
+ "CHEF_LICENSE" => "[parameters('CHEF_LICENSE')]",
489
524
  },
490
525
  "protectedSettings" => {
491
526
  "validation_key" => "[parameters('validation_key')]",
492
527
  "chef_server_crt" => "[parameters('chef_server_crt')]",
493
528
  "encrypted_data_bag_secret" => "[parameters('encrypted_data_bag_secret')]",
529
+ # Per chef-partners/azure-chef-extension#413 (version
530
+ # 1210.15.11.1, rolled out to all regions), the extension's
531
+ # install scripts decrypt this from protectedSettings and
532
+ # prefer it over the deprecated publicSettings location.
533
+ "chef_license_key" => "[parameters('chef_license_key')]",
494
534
  },
495
535
  },
496
536
  },
@@ -501,8 +541,17 @@ module Azure::ARM
501
541
  set_val = {
502
542
  "name" => "[parameters('availabilitySetName')]",
503
543
  "type" => "Microsoft.Compute/availabilitySets",
504
- "apiVersion" => "[variables('apiVersion')]",
544
+ # NOTE: variables('apiVersion') ("2015-06-15") is intentionally not used
545
+ # here. That old API version (and the absence of an explicit "Aligned"
546
+ # sku) creates a classic (unmanaged-disk-only) availability set, which
547
+ # Azure rejects VMs with managed OS disks from joining. Managed-disk
548
+ # compatible ("Aligned") availability sets require apiVersion
549
+ # 2016-04-30-preview or later plus this explicit sku.
550
+ "apiVersion" => "2020-12-01",
505
551
  "location" => "[resourceGroup().location]",
552
+ "sku" => {
553
+ "name" => "Aligned",
554
+ },
506
555
  "properties" => {
507
556
  "platformFaultDomainCount" => "[parameters('availabilitySetPlatformFaultDomainCount')]",
508
557
  "platformUpdateDomainCount" => "[parameters('availabilitySetPlatformUpdateDomainCount')]",
@@ -644,6 +693,12 @@ module Azure::ARM
644
693
  "client_rb" => {
645
694
  "value" => "#{params[:chef_extension_public_param][:client_rb]}",
646
695
  },
696
+ "CHEF_LICENSE" => {
697
+ "value" => "#{params[:chef_extension_public_param][:CHEF_LICENSE]}",
698
+ },
699
+ "chef_license_key" => {
700
+ "value" => "#{params[:chef_extension_private_param][:chef_license_key]}",
701
+ },
647
702
  "bootstrap_version" => {
648
703
  "value" => "#{params[:chef_extension_public_param][:bootstrap_options][:bootstrap_version]}",
649
704
  },
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright:: Copyright (c) Chef Software Inc.
2
+ # Copyright:: Copyright (c) 2012-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
3
3
  # License:: Apache License, Version 2.0
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,11 @@
18
18
  require_relative "../azure_interface"
19
19
  require_relative "ARM_deployment_template"
20
20
  require_relative "vnet_config"
21
- require "azure_mgmt_resources"
22
- require "azure_mgmt_compute"
23
- require "azure_mgmt_storage"
24
- require "azure_mgmt_network"
21
+ require_relative "rest/environments"
22
+ require_relative "rest/errors"
23
+ require_relative "rest/token_provider"
24
+ require_relative "rest/http"
25
+ require_relative "rest/arm_client"
25
26
 
26
27
  module Azure
27
28
  class ResourceManagement
@@ -29,60 +30,23 @@ module Azure
29
30
  include Azure::ARM::ARMDeploymentTemplate
30
31
  include Azure::ARM::VnetConfig
31
32
 
32
- include Azure::Resources::Mgmt::V2018_05_01
33
- include Azure::Resources::Mgmt::V2018_05_01::Models
34
-
35
- include Azure::Compute::Mgmt::V2018_06_01
36
- include Azure::Compute::Mgmt::V2018_06_01::Models
37
-
38
- include Azure::Storage::Mgmt::V2018_07_01
39
- include Azure::Storage::Mgmt::V2018_07_01::Models
40
-
41
- include Azure::Network::Mgmt::V2018_08_01
42
- include Azure::Network::Mgmt::V2018_08_01::Models
33
+ # Backwards-compatible alias so existing rescue clauses and consumers can
34
+ # keep referring to a single error type for Azure API failures.
35
+ OperationError = Azure::ResourceManagement::Rest::OperationError
43
36
 
44
37
  attr_accessor :connection
45
38
 
46
39
  def initialize(params = {})
47
- token_provider = if params[:azure_client_secret]
48
- MsRestAzure::ApplicationTokenProvider.new(params[:azure_tenant_id], params[:azure_client_id], params[:azure_client_secret])
49
- else
50
- MsRest::StringTokenProvider.new(params[:token], params[:tokentype])
51
- end
52
- @credentials = MsRest::TokenCredentials.new(token_provider)
40
+ @environment = Azure::ResourceManagement::Rest::Environments.from_name(params[:azure_environment])
41
+ @token_provider = Azure::ResourceManagement::Rest::TokenProvider.new(params, @environment)
53
42
  @azure_subscription_id = params[:azure_subscription_id]
54
43
  super
55
44
  end
56
45
 
57
- def resource_management_client
58
- @resource_management_client ||= begin
59
- resource_management_client = ResourceManagementClient.new(@credentials)
60
- resource_management_client.subscription_id = @azure_subscription_id
61
- resource_management_client
62
- end
63
- end
64
-
65
- def compute_management_client
66
- @compute_management_client ||= begin
67
- compute_management_client = ComputeManagementClient.new(@credentials)
68
- compute_management_client.subscription_id = @azure_subscription_id
69
- compute_management_client
70
- end
71
- end
72
-
73
- def storage_management_client
74
- @storage_management_client ||= begin
75
- storage_management_client = StorageManagementClient.new(@credentials)
76
- storage_management_client.subscription_id = @azure_subscription_id
77
- storage_management_client
78
- end
79
- end
80
-
81
- def network_resource_client
82
- @network_resource_client ||= begin
83
- network_resource_client = NetworkManagementClient.new(@credentials)
84
- network_resource_client.subscription_id = @azure_subscription_id
85
- network_resource_client
46
+ def arm_client
47
+ @arm_client ||= begin
48
+ http = Azure::ResourceManagement::Rest::Http.new(@token_provider, environment: @environment)
49
+ Azure::ResourceManagement::Rest::ArmClient.new(@azure_subscription_id, http, @environment)
86
50
  end
87
51
  end
88
52
 
@@ -90,9 +54,9 @@ module Azure
90
54
 
91
55
  def list_servers(resource_group_name = nil)
92
56
  servers = if resource_group_name.nil?
93
- compute_management_client.virtual_machines.list_all
57
+ arm_client.list_all_virtual_machines
94
58
  else
95
- compute_management_client.virtual_machines.list(resource_group_name)
59
+ arm_client.list_virtual_machines(resource_group_name)
96
60
  end
97
61
 
98
62
  cols = ["VM Name", "Resource Group Name", "Location", "Provisioning State", "OS Type"]
@@ -119,7 +83,7 @@ module Azure
119
83
  end
120
84
 
121
85
  def delete_server(resource_group_name, vm_name)
122
- server = compute_management_client.virtual_machines.get(resource_group_name, vm_name)
86
+ server = arm_client.get_virtual_machine(resource_group_name, vm_name)
123
87
  if server && server.name == vm_name
124
88
  puts "\n\n"
125
89
  msg_pair(ui, "VM Name", server.name)
@@ -136,9 +100,7 @@ module Azure
136
100
 
137
101
  ui.info "Deleting .."
138
102
 
139
- begin
140
- server_detail = compute_management_client.virtual_machines.delete(resource_group_name, vm_name)
141
- end until server_detail.nil?
103
+ arm_client.delete_virtual_machine(resource_group_name, vm_name)
142
104
 
143
105
  puts "\n"
144
106
  ui.warn "Deleted server #{vm_name}"
@@ -149,13 +111,13 @@ module Azure
149
111
  server = find_server(resource_group, name)
150
112
  if server
151
113
  network_interface_name = server.network_profile.network_interfaces[0].id.split("/")[-1]
152
- network_interface_data = network_resource_client.network_interfaces.get(resource_group, network_interface_name)
114
+ network_interface_data = arm_client.get_network_interface(resource_group, network_interface_name)
153
115
  public_ip_id_data = network_interface_data.ip_configurations[0].public_ipaddress
154
116
  if public_ip_id_data.nil?
155
117
  public_ip_data = nil
156
118
  else
157
119
  public_ip_name = public_ip_id_data.id.split("/")[-1]
158
- public_ip_data = network_resource_client.public_ipaddresses.get(resource_group, public_ip_name)
120
+ public_ip_data = arm_client.get_public_ip_address(resource_group, public_ip_name)
159
121
  end
160
122
 
161
123
  details = []
@@ -205,13 +167,13 @@ module Azure
205
167
  end
206
168
 
207
169
  def find_server(resource_group, name)
208
- compute_management_client.virtual_machines.get(resource_group, name)
170
+ arm_client.get_virtual_machine(resource_group, name)
209
171
  end
210
172
 
211
173
  def virtual_machine_exist?(resource_group_name, vm_name)
212
- compute_management_client.virtual_machines.get(resource_group_name, vm_name)
174
+ arm_client.get_virtual_machine(resource_group_name, vm_name)
213
175
  true
214
- rescue MsRestAzure::AzureOperationError => e
176
+ rescue OperationError => e
215
177
  if e.body
216
178
  err_json = JSON.parse(e.response.body)
217
179
  if err_json["error"]["code"] == "ResourceNotFound"
@@ -223,9 +185,9 @@ module Azure
223
185
  end
224
186
 
225
187
  def security_group_exist?(resource_group_name, security_group_name)
226
- network_resource_client.network_security_groups.get(resource_group_name, security_group_name)
188
+ arm_client.get_network_security_group(resource_group_name, security_group_name)
227
189
  true
228
- rescue MsRestAzure::AzureOperationError => e
190
+ rescue OperationError => e
229
191
  if e.body
230
192
  err_json = JSON.parse(e.response.body)
231
193
  if err_json["error"]["code"] == "ResourceNotFound"
@@ -236,8 +198,30 @@ module Azure
236
198
  end
237
199
  end
238
200
 
201
+ # Returns the sku name (e.g. "Aligned") of an existing availability set, nil if it
202
+ # exists but is a legacy "Classic" set (which has no sku property at all), or the
203
+ # :not_found symbol if it doesn't exist yet. Used to detect the case where a caller
204
+ # reuses an existing Classic availability set name: since Azure availability set
205
+ # SKUs are immutable once created, redeploying it as "Aligned" (required for managed
206
+ # disks) would fail remotely with a cryptic ARM error instead of the actionable one
207
+ # raised in validate_params!.
208
+ def existing_availability_set_sku(resource_group_name, availability_set_name)
209
+ availability_set = arm_client.get_availability_set(resource_group_name, availability_set_name)
210
+ availability_set.sku && availability_set.sku.name
211
+ rescue OperationError => e
212
+ if e.body
213
+ err_json = JSON.parse(e.response.body)
214
+ # ResourceNotFound: the resource group exists but the availability set doesn't.
215
+ # ResourceGroupNotFound: the resource group itself doesn't exist yet (e.g. when
216
+ # creating a VM + availability set together in a brand-new resource group).
217
+ # Both mean "no existing availability set to conflict with".
218
+ return :not_found if %w{ResourceNotFound ResourceGroupNotFound}.include?(err_json["error"]["code"])
219
+ end
220
+ raise e
221
+ end
222
+
239
223
  def resource_group_exist?(resource_group_name)
240
- resource_management_client.resource_groups.check_existence(resource_group_name)
224
+ arm_client.resource_group_exist?(resource_group_name)
241
225
  end
242
226
 
243
227
  def platform(image_reference)
@@ -256,7 +240,7 @@ module Azure
256
240
  end
257
241
 
258
242
  def fetch_substatus(resource_group_name, virtual_machine_name, chef_extension_name)
259
- substatuses = compute_management_client.virtual_machine_extensions.get(
243
+ substatuses = arm_client.get_vm_extension(
260
244
  resource_group_name,
261
245
  virtual_machine_name,
262
246
  chef_extension_name,
@@ -381,27 +365,12 @@ module Azure
381
365
  end
382
366
  end
383
367
 
384
- def vm_public_ip(params = {})
385
- network_resource_client.public_ipaddresses.get(
386
- params[:azure_resource_group_name],
387
- params[:azure_vm_name]
388
- ).value!.body.properties.ip_address
389
- end
390
-
391
- def vm_default_port(params = {})
392
- network_resource_client.network_security_groups.get(
393
- params[:azure_resource_group_name],
394
- params[:azure_vm_name]
395
- ).value!.body.properties.security_rules[0].properties.destination_port_range
396
- end
397
-
398
368
  def create_resource_group(params = {})
399
- resource_group = ResourceGroup.new
400
- resource_group.name = params[:azure_resource_group_name]
401
- resource_group.location = params[:azure_service_location]
402
-
403
369
  begin
404
- resource_group = resource_management_client.resource_groups.create_or_update(resource_group.name, resource_group)
370
+ resource_group = arm_client.create_resource_group(
371
+ params[:azure_resource_group_name],
372
+ params[:azure_service_location]
373
+ )
405
374
  rescue Exception => e
406
375
  Chef::Log.error("Failed to create the Resource Group -- exception being rescued: #{e}")
407
376
  common_arm_rescue_block(e)
@@ -414,33 +383,38 @@ module Azure
414
383
  template = create_deployment_template(params)
415
384
  parameters = create_deployment_parameters(params)
416
385
 
417
- deploy_prop = DeploymentProperties.new
418
- deploy_prop.template = template
419
- deploy_prop.parameters = parameters
420
- deploy_prop.mode = "Incremental"
421
-
422
- deploy_params = Deployment.new
423
- deploy_params.properties = deploy_prop
386
+ deployment_body = {
387
+ "properties" => {
388
+ "template" => template,
389
+ "parameters" => parameters,
390
+ "mode" => "Incremental",
391
+ },
392
+ }
424
393
 
425
- resource_management_client.deployments.create_or_update(params[:azure_resource_group_name], "#{params[:azure_vm_name]}_deploy", deploy_params)
394
+ arm_client.create_deployment(params[:azure_resource_group_name], "#{params[:azure_vm_name]}_deploy", deployment_body)
426
395
  end
427
396
 
428
397
  def create_vm_extension(params)
429
- vm_ext = VirtualMachineExtension.new
430
- vm_ext.name = params[:chef_extension]
431
- vm_ext.location = params[:azure_service_location]
432
- vm_ext.publisher = params[:chef_extension_publisher]
433
- vm_ext.virtual_machine_extension_type = params[:chef_extension]
434
- vm_ext.type_handler_version = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
435
- vm_ext.auto_upgrade_minor_version = false
436
- vm_ext.settings = params[:chef_extension_public_param]
437
- vm_ext.protected_settings = params[:chef_extension_private_param]
398
+ extension_name = params[:chef_extension]
399
+ extension_body = {
400
+ "name" => extension_name,
401
+ "location" => params[:azure_service_location],
402
+ "properties" => {
403
+ "publisher" => params[:chef_extension_publisher],
404
+ "type" => extension_name,
405
+ "typeHandlerVersion" => params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version],
406
+ "autoUpgradeMinorVersion" => false,
407
+ "settings" => params[:chef_extension_public_param],
408
+ "protectedSettings" => params[:chef_extension_private_param],
409
+ },
410
+ }
411
+
438
412
  begin
439
- vm_extension = compute_management_client.virtual_machine_extensions.create_or_update(
413
+ vm_extension = arm_client.create_vm_extension(
440
414
  params[:azure_resource_group_name],
441
415
  params[:azure_vm_name],
442
- vm_ext.name,
443
- vm_ext
416
+ extension_name,
417
+ extension_body
444
418
  )
445
419
  rescue Exception => e
446
420
  Chef::Log.error("Failed to create the Virtual Machine Extension -- exception being rescued.")
@@ -453,14 +427,21 @@ module Azure
453
427
  def extension_already_installed?(server)
454
428
  if server.resources
455
429
  server.resources.each do |extension|
456
- return true if extension.virtual_machine_extension_type == "ChefClient" || extension.virtual_machine_extension_type == "LinuxChefClient"
430
+ # Azure returns the extension handler name (ChefClient/LinuxChefClient)
431
+ # as the nested properties.type field, not a top-level
432
+ # virtual_machine_extension_type attribute -- that name was an
433
+ # artifact of the retired azure_mgmt_compute SDK's generated
434
+ # model, which doesn't exist on the raw ARM JSON this REST
435
+ # client wraps.
436
+ extension_type = extension.properties && extension.properties.type
437
+ return true if extension_type == "ChefClient" || extension_type == "LinuxChefClient"
457
438
  end
458
439
  end
459
440
  false
460
441
  end
461
442
 
462
443
  def get_latest_chef_extension_version(params)
463
- ext_version = compute_management_client.virtual_machine_extension_images.list_versions(
444
+ ext_version = arm_client.list_vm_extension_versions(
464
445
  params[:azure_service_location],
465
446
  params[:chef_extension_publisher],
466
447
  params[:chef_extension]
@@ -472,24 +453,39 @@ module Azure
472
453
  def delete_resource_group(resource_group_name)
473
454
  ui.info "Resource group deletion takes some time. Please wait ..."
474
455
 
475
- begin
476
- server = resource_management_client.resource_groups.delete(resource_group_name)
477
- end until server.nil?
456
+ arm_client.delete_resource_group(resource_group_name)
478
457
  puts "\n"
479
458
  end
480
459
 
481
460
  def common_arm_rescue_block(error)
482
- if error.class == MsRestAzure::AzureOperationError && error.body
483
- err_json = JSON.parse(error.response.body)
484
- err_details = err_json["error"]["details"] if err_json["error"]
485
- if err_details
486
- err_details.each do |err|
487
- ui.error(JSON.parse(err["message"])["error"]["message"])
488
- rescue JSON::ParserError => e
489
- ui.error(err["message"])
461
+ if error.is_a?(OperationError) && error.body
462
+ err_json = begin
463
+ JSON.parse(error.response.body)
464
+ rescue JSON::ParserError, TypeError
465
+ nil
466
+ end
467
+ unless err_json.is_a?(Hash)
468
+ ui.error(error.message)
469
+ Chef::Log.debug(error.response.body)
470
+ return
471
+ end
472
+
473
+ arm_error = err_json["error"]
474
+ if arm_error.is_a?(Hash)
475
+ err_details = arm_error["details"]
476
+ if err_details
477
+ err_details.each do |err|
478
+ ui.error(JSON.parse(err["message"])["error"]["message"])
479
+ rescue JSON::ParserError => e
480
+ ui.error(err["message"])
481
+ end
482
+ else
483
+ ui.error(arm_error["message"])
490
484
  end
491
485
  else
492
- ui.error(err_json["error"]["message"])
486
+ # OAuth token endpoint errors are flat: the "error" value is a
487
+ # string code and the human-readable text is in "error_description".
488
+ ui.error(err_json["error_description"] || arm_error || error.message)
493
489
  end
494
490
  Chef::Log.debug(error.response.body)
495
491
  else