knife-azure 1.7.0 → 1.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c7f62c21c7c40eabb96c27a4b3de2b33a4616457
4
- data.tar.gz: 25c860f8aa805e2e83909ffeb7d0804e3d6ead15
3
+ metadata.gz: ea0e76928647e01eb3f500a3a8d907c9445545ac
4
+ data.tar.gz: 986e61a68caaa29728a7f3293cbfa39f958ebcd9
5
5
  SHA512:
6
- metadata.gz: a7ec459dcbf6f9ecf514a9db49a1eb0f9544fffaa48ddcfd9ea38fbe56d564a6b3b3a0baf2403c957978e3866b5ac3237e631ec355082fada69160682a55f710
7
- data.tar.gz: 7f95bfe8dc727323a8b8b5de4d7e4ce0efa49e75c592539f37709b6fb68247a7b4d39d90bba70f66bcfa29900dba5c867b022aa6b732d8c3da6fcbb4c836327a
6
+ metadata.gz: 35b24edba5370648f1377069c2d1c497373467ec15526125749dacdc37260eeefada00acdfe0ff581ee06f72ae4a73e5fed4285e8fbd02ca2d526d8caaef2df0
7
+ data.tar.gz: 93bf2f05f813fd46e94acb8d3f5293874026437e6b8a92327bd31e46f51264924e219bbb99fd08ea89aff90304c6a1e0880a991fb245edadc4871af53d8c7946
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  A [knife] (<http://docs.chef.io/knife.html>) plugin to create, delete, and enumerate [Microsoft Azure] (<https://azure.microsoft.com>) resources to be managed by Chef.
8
8
 
9
- NOTE: You may also want to consider using the [azure-xplat-cli](https://github.com/Azure/azure-xplat-cli), this application is written by the Azure team and has many other integrations with Azure. If click [here](https://github.com/chef-partners/azure-chef-extension/blob/master/examples/azure-xplat-cli-examples.md) you'll see deeper examples of using the Chef extension and Azure.
9
+ NOTE: You may also want to consider using the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli), this application is written by the Azure team and has many other integrations with Azure. If click [here](https://github.com/chef-partners/azure-chef-extension/blob/master/examples/azure-xplat-cli-examples.md) you'll see deeper examples of using the Chef extension and Azure.
10
10
 
11
11
  ## Installation
12
12
 
@@ -26,31 +26,29 @@ Depending on your system's configuration, you may need to run this command with
26
26
 
27
27
  ## Modes
28
28
 
29
- `knife-azure 1.6.0` onwards, we are adding support for Azure Resource Manager. You can easily switch between the
29
+ `knife-azure 1.6.0` onwards supports Azure Resource Manager (preferred). You can easily switch between:
30
30
 
31
- - Service management: commands using the Azure service management API
32
31
  - Resource manager: commands using the Azure Resource Manager API
32
+ - Service management: commands using the Azure service management API
33
33
 
34
- They are not designed to work together. Commands starting with `knife azure` use ASM mode, while commands starting with `knife azurerm` use ARM mode.
35
-
36
- PLEASE NOTE that `Azuererm` subcommands are experimental and of alpha quality. Not suitable for production use. Please use ASM subcommands for production.
34
+ They are not designed to work together. Commands starting with `knife azurerm` use ARM mode, while commands starting with `knife azure` use ASM mode.
37
35
 
38
36
  ## Configuration
39
37
 
40
- 1. [ASM Configuration] (docs/configuration.md#asm-mode)
41
- 2. [ARM Configuration] (docs/configuration.md#arm-mode)
38
+ 1. [ARM Configuration](docs/configuration.md#arm-mode)
39
+ 1. [ASM Configuration](docs/configuration.md#asm-mode)
42
40
 
43
41
  ## Detailed Usage
44
42
 
45
- 1. [ASM Mode] (docs/ASM.md)
46
- 2. [ARM Mode] (docs/ARM.md)
43
+ 1. [ARM Mode](docs/ARM.md)
44
+ 1. [ASM Mode](docs/ASM.md)
47
45
 
48
- ## Bootstrap existing VM to install the chef-client using chef-extension :
46
+ ## Bootstrap existing VM to install the chef-client using chef-extension
49
47
 
50
- We have added a utility in ASM and ARM to bootstrap existing VM. This will install the chef-client using chef extension on your VM.
48
+ We have added a utility in ARM and ASM to bootstrap existing VM. This will install the chef-client using chef extension on your VM.
51
49
 
52
- 1. [Bootstrap Doc for ASM Mode] (docs/bootstrap.md#asm-mode)
53
- 2. [Bootstrap Doc for ARM Mode] (docs/bootstrap.md#arm-mode)
50
+ 1. [Bootstrap Doc for ARM Mode](docs/bootstrap.md#arm-mode)
51
+ 1. [Bootstrap Doc for ASM Mode](docs/bootstrap.md#asm-mode)
54
52
 
55
53
  ## Contributing
56
54
 
@@ -78,6 +78,7 @@ module Azure::ARM
78
78
  def create_deployment_template(params)
79
79
  if params[:chef_extension_public_param][:bootstrap_options][:chef_node_name]
80
80
  chef_node_name = "[concat(parameters('chef_node_name'),copyIndex())]"
81
+ chef_node_name = "[parameters('chef_node_name')]" if params[:server_count].to_i==1
81
82
  end
82
83
 
83
84
  if(params[:server_count].to_i > 1)
@@ -160,6 +161,15 @@ module Azure::ARM
160
161
  "description"=> "Password for the Virtual Machine."
161
162
  }
162
163
  },
164
+ "availabilitySetName" => {
165
+ "type" => "string"
166
+ },
167
+ "availabilitySetPlatformFaultDomainCount" => {
168
+ "type" => "string"
169
+ },
170
+ "availabilitySetPlatformUpdateDomainCount" => {
171
+ "type" => "string"
172
+ },
163
173
  "numberOfInstances" => {
164
174
  "type" => "int",
165
175
  "defaultValue" => 1,
@@ -192,12 +202,7 @@ module Azure::ARM
192
202
  "description"=> "JSON Escaped Validation Key"
193
203
  }
194
204
  },
195
- "client_pem" => {
196
- "type"=> "string",
197
- "metadata"=> {
198
- "description"=> "Required for validtorless bootstrap."
199
- }
200
- },
205
+
201
206
  "chef_server_crt" => {
202
207
  "type"=> "string",
203
208
  "metadata"=> {
@@ -221,6 +226,12 @@ module Azure::ARM
221
226
  "metadata"=> {
222
227
  "description"=> "Optional Run List to Execute"
223
228
  }
229
+ },
230
+ "environment"=> {
231
+ "type"=> "string",
232
+ "metadata"=> {
233
+ "description"=> "Chef environment for the node (VM) in the Chef Organization"
234
+ }
224
235
  },
225
236
  "chef_node_name" => {
226
237
  "type" => "string",
@@ -466,7 +477,8 @@ module Azure::ARM
466
477
  "bootstrap_version" => "[parameters('bootstrap_version')]",
467
478
  "node_ssl_verify_mode" => "[parameters('node_ssl_verify_mode')]",
468
479
  "node_verify_api_cert" => "[parameters('node_verify_api_cert')]",
469
- "bootstrap_proxy" => "[parameters('bootstrap_proxy')]"
480
+ "bootstrap_proxy" => "[parameters('bootstrap_proxy')]",
481
+ "environment" => "[parameters('environment')]"
470
482
  },
471
483
  "runlist" => "[parameters('runlist')]",
472
484
  "validation_key_format" => "[parameters('validation_key_format')]",
@@ -476,7 +488,6 @@ module Azure::ARM
476
488
  },
477
489
  "protectedSettings" => {
478
490
  "validation_key" => "[parameters('validation_key')]",
479
- "client_pem" => "[parameters('client_pem')]",
480
491
  "chef_server_crt" => "[parameters('chef_server_crt')]",
481
492
  "encrypted_data_bag_secret" => "[parameters('encrypted_data_bag_secret')]"
482
493
  }
@@ -485,6 +496,28 @@ module Azure::ARM
485
496
  ]
486
497
  }
487
498
 
499
+ if params[:azure_availability_set]
500
+ set_val = {
501
+ "name" => "[parameters('availabilitySetName')]",
502
+ "type" => "Microsoft.Compute/availabilitySets",
503
+ "apiVersion" => "[variables('apiVersion')]",
504
+ "location" => "[resourceGroup().location]",
505
+ "properties" => {
506
+ "platformFaultDomainCount" => "[parameters('availabilitySetPlatformFaultDomainCount')]",
507
+ "platformUpdateDomainCount" => "[parameters('availabilitySetPlatformUpdateDomainCount')]"
508
+ }
509
+ }
510
+
511
+ length = template['resources'].length.to_i - 1
512
+ for i in 0..length do
513
+ if template['resources'][i]['type'] == "Microsoft.Compute/virtualMachines"
514
+ template['resources'][i]['dependsOn'] << "[concat('Microsoft.Compute/availabilitySets/', parameters('availabilitySetName'))]"
515
+ template['resources'][i]['properties'].merge!({"availabilitySet" => { "id" => "[resourceId('Microsoft.Compute/availabilitySets', parameters('availabilitySetName'))]"}})
516
+ end
517
+ end
518
+ template['resources'].insert(length, set_val)
519
+ end
520
+
488
521
  if params[:tcp_endpoints]
489
522
  sec_grp_json = tcp_ports(params[:tcp_endpoints], params[:azure_vm_name])
490
523
  template['resources'].insert(1,sec_grp_json)
@@ -507,14 +540,40 @@ module Azure::ARM
507
540
  end
508
541
  end
509
542
 
510
- if params[:chef_extension_public_param][:chef_service_interval]
543
+ if params[:chef_extension_public_param][:chef_daemon_interval]
511
544
  template['resources'].each do |resource|
512
545
  if resource['type'] == 'Microsoft.Compute/virtualMachines/extensions'
513
- resource['properties']['settings']['chef_service_interval'] = params[:chef_extension_public_param][:chef_service_interval]
546
+ resource['properties']['settings']['chef_daemon_interval'] = params[:chef_extension_public_param][:chef_daemon_interval]
514
547
  end
515
548
  end
516
549
  end
517
550
 
551
+ if params[:chef_extension_public_param][:daemon]
552
+ template['resources'].each do |resource|
553
+ if resource['type'] == 'Microsoft.Compute/virtualMachines/extensions'
554
+ resource['properties']['settings']['daemon'] = params[:chef_extension_public_param][:daemon]
555
+ end
556
+ end
557
+ end
558
+ if params[:server_count].to_i > 1 && params[:chef_extension_private_param][:validation_key].nil?
559
+ template["resources"].last["properties"]["protectedSettings"]["client_pem"] = "[parameters(concat('client_pem',copyIndex()))]"
560
+ 0.upto (params[:server_count].to_i-1) do |count|
561
+ template["parameters"]["client_pem" + count.to_s] = {
562
+ "type"=> "string",
563
+ "metadata"=> {
564
+ "description"=> "Required for validtorless bootstrap."
565
+ }
566
+ }
567
+ end
568
+ else
569
+ template["resources"].last["properties"]["protectedSettings"]["client_pem"] = "[parameters('client_pem')]"
570
+ template["parameters"]["client_pem"] = {
571
+ "type"=> "string",
572
+ "metadata"=> {
573
+ "description"=> "Required for validtorless bootstrap."
574
+ }
575
+ }
576
+ end
518
577
  template
519
578
  end
520
579
 
@@ -534,6 +593,15 @@ module Azure::ARM
534
593
  "adminPassword"=> {
535
594
  "value"=> "#{admin_password}"
536
595
  },
596
+ "availabilitySetName" => {
597
+ "value" => "#{params[:azure_availability_set]}"
598
+ },
599
+ "availabilitySetPlatformFaultDomainCount" => {
600
+ "value" => "2"
601
+ },
602
+ "availabilitySetPlatformUpdateDomainCount" => {
603
+ "value" => "5"
604
+ },
537
605
  "dnsLabelPrefix"=> {
538
606
  "value"=> "#{params[:azure_vm_name]}"
539
607
  },
@@ -546,9 +614,7 @@ module Azure::ARM
546
614
  "validation_key"=> {
547
615
  "value"=> "#{params[:chef_extension_private_param][:validation_key]}"
548
616
  },
549
- "client_pem" => {
550
- "value" => "#{params[:chef_extension_private_param][:client_pem]}"
551
- },
617
+
552
618
  "chef_server_crt" => {
553
619
  "value" => "#{params[:chef_extension_private_param][:chef_server_crt]}"
554
620
  },
@@ -573,6 +639,9 @@ module Azure::ARM
573
639
  "runlist" => {
574
640
  "value" => "#{params[:chef_extension_public_param][:runlist]}"
575
641
  },
642
+ "environment" => {
643
+ "value" => "#{params[:chef_extension_public_param][:bootstrap_options][:environment]}"
644
+ },
576
645
  "chef_node_name" => {
577
646
  "value"=> "#{params[:chef_extension_public_param][:bootstrap_options][:chef_node_name]}"
578
647
  },
@@ -592,7 +661,18 @@ module Azure::ARM
592
661
  "value" => "#{params[:disablePasswordAuthentication]}"
593
662
  }
594
663
  }
664
+ if params[:server_count].to_i > 1 && params[:chef_extension_private_param][:validation_key].nil?
665
+ 0.upto (params[:server_count].to_i-1) do |count|
666
+ parameters["client_pem#{count.to_s}"] = {
667
+ "value" => "#{params[:chef_extension_private_param][("client_pem" + count.to_s).to_sym]}"
668
+ }
669
+ end
670
+ else
671
+ parameters["client_pem"] = {
672
+ "value" => "#{params[:chef_extension_private_param][:client_pem]}"
673
+ }
674
+ end
675
+ parameters
595
676
  end
596
-
597
677
  end
598
678
  end
@@ -91,9 +91,9 @@ module Azure
91
91
 
92
92
  def list_servers(resource_group_name = nil)
93
93
  if resource_group_name.nil?
94
- servers = compute_management_client.virtual_machines.list_all.value
94
+ servers = compute_management_client.virtual_machines.list_all
95
95
  else
96
- servers = compute_management_client.virtual_machines.list(resource_group_name).value
96
+ servers = compute_management_client.virtual_machines.list(resource_group_name)
97
97
  end
98
98
 
99
99
  cols = ['VM Name', 'Resource Group Name', 'Location', 'Provisioning State', 'OS Type']
@@ -104,7 +104,7 @@ module Azure
104
104
  rows << server.id.split('/')[4].downcase
105
105
  rows << server.location.to_s
106
106
  rows << begin
107
- state = server.properties.provisioning_state.to_s.downcase
107
+ state = server.provisioning_state.to_s.downcase
108
108
  case state
109
109
  when 'failed'
110
110
  ui.color(state, :red)
@@ -114,7 +114,7 @@ module Azure
114
114
  ui.color(state, :yellow)
115
115
  end
116
116
  end
117
- rows << server.properties.storage_profile.os_disk.os_type.to_s
117
+ rows << server.storage_profile.os_disk.os_type.to_s
118
118
  end
119
119
  display_list(ui, cols, rows)
120
120
  end
@@ -124,8 +124,8 @@ module Azure
124
124
  if server && server.name == vm_name
125
125
  puts "\n\n"
126
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)
127
+ msg_pair(ui, 'VM Size', server.hardware_profile.vm_size)
128
+ msg_pair(ui, 'VM OS', server.storage_profile.os_disk.os_type)
129
129
  puts "\n"
130
130
 
131
131
  begin
@@ -139,7 +139,7 @@ module Azure
139
139
 
140
140
  begin
141
141
  server_detail = compute_management_client.virtual_machines.delete(resource_group_name, vm_name)
142
- end until server_detail.value!.body.nil?
142
+ end until server_detail.nil?
143
143
 
144
144
  puts "\n"
145
145
  ui.warn "Deleted server #{vm_name}"
@@ -149,9 +149,9 @@ module Azure
149
149
  def show_server(name, resource_group)
150
150
  server = find_server(resource_group, name)
151
151
  if server
152
- network_interface_name = server.properties.network_profile.network_interfaces[0].id.split('/')[-1]
152
+ network_interface_name = server.network_profile.network_interfaces[0].id.split('/')[-1]
153
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
154
+ public_ip_id_data = network_interface_data.ip_configurations[0].public_ipaddress
155
155
  unless public_ip_id_data.nil?
156
156
  public_ip_name = public_ip_id_data.id.split('/')[-1]
157
157
  public_ip_data = network_resource_client.public_ipaddresses.get(resource_group, public_ip_name)
@@ -164,39 +164,39 @@ module Azure
164
164
  details << server.name
165
165
 
166
166
  details << ui.color('Size', :bold, :cyan)
167
- details << server.properties.hardware_profile.vm_size
167
+ details << server.hardware_profile.vm_size
168
168
 
169
169
  details << ui.color('Provisioning State', :bold, :cyan)
170
- details << server.properties.provisioning_state
170
+ details << server.provisioning_state
171
171
 
172
172
  details << ui.color('Location', :bold, :cyan)
173
173
  details << server.location
174
174
 
175
175
  details << ui.color('Publisher', :bold, :cyan)
176
- details << server.properties.storage_profile.image_reference.publisher
176
+ details << server.storage_profile.image_reference.publisher
177
177
 
178
178
  details << ui.color('Offer', :bold, :cyan)
179
- details << server.properties.storage_profile.image_reference.offer
179
+ details << server.storage_profile.image_reference.offer
180
180
 
181
181
  details << ui.color('Sku', :bold, :cyan)
182
- details << server.properties.storage_profile.image_reference.sku
182
+ details << server.storage_profile.image_reference.sku
183
183
 
184
184
  details << ui.color('Version', :bold, :cyan)
185
- details << server.properties.storage_profile.image_reference.version
185
+ details << server.storage_profile.image_reference.version
186
186
 
187
187
  details << ui.color('OS Type', :bold, :cyan)
188
- details << server.properties.storage_profile.os_disk.os_type
188
+ details << server.storage_profile.os_disk.os_type
189
189
 
190
190
  details << ui.color('Public IP address', :bold, :cyan)
191
191
  unless public_ip_data.nil?
192
- details << public_ip_data.properties.ip_address
192
+ details << public_ip_data.ip_address
193
193
  else
194
194
  details << ' -- '
195
195
  end
196
196
 
197
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
198
+ unless public_ip_data.nil? or public_ip_data.dns_settings.nil?
199
+ details << public_ip_data.dns_settings.fqdn
200
200
  else
201
201
  details << ' -- '
202
202
  end
@@ -210,37 +210,37 @@ module Azure
210
210
  end
211
211
 
212
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
-
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
+
244
244
  def resource_group_exist?(resource_group_name)
245
245
  resource_management_client.resource_groups.check_existence(resource_group_name)
246
246
  end
@@ -266,8 +266,8 @@ module Azure
266
266
  virtual_machine_name,
267
267
  chef_extension_name,
268
268
  'instanceView'
269
- ).properties.instance_view.substatuses
270
-
269
+ ).instance_view.substatuses
270
+
271
271
  return nil if substatuses.nil?
272
272
 
273
273
  substatuses.each do |substatus|
@@ -332,7 +332,7 @@ module Azure
332
332
  Chef::Log.info("Resource Group name is: #{resource_group.name}")
333
333
  Chef::Log.info("Resource Group ID is: #{resource_group.id}")
334
334
  end
335
-
335
+
336
336
  # virtual machine creation
337
337
  if virtual_machine_exist?(params[:azure_resource_group_name], params[:azure_vm_name])
338
338
  ui.log("INFO:Virtual Machine #{params[:azure_vm_name]} already exist under the Resource Group #{params[:azure_resource_group_name]}. Exiting for now.")
@@ -344,24 +344,24 @@ module Azure
344
344
  params[:azure_vnet_name],
345
345
  params[:azure_vnet_subnet_name]
346
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
-
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
+
361
361
  ui.log("Creating Virtual Machine....")
362
362
  deployment = create_virtual_machine_using_template(params)
363
363
  ui.log("Virtual Machine creation successfull.") unless deployment.nil?
364
-
364
+
365
365
  unless deployment.nil?
366
366
  ui.log("Deployment name is: #{deployment.name}")
367
367
  ui.log("Deployment ID is: #{deployment.id}")
@@ -428,31 +428,27 @@ module Azure
428
428
  deploy_params = Deployment.new
429
429
  deploy_params.properties = deploy_prop
430
430
 
431
- deployment = resource_management_client.deployments.create_or_update(params[:azure_resource_group_name], "#{params[:azure_vm_name]}_deploy", deploy_params).value!.body
431
+ deployment = resource_management_client.deployments.create_or_update(params[:azure_resource_group_name], "#{params[:azure_vm_name]}_deploy", deploy_params)
432
432
  deployment
433
433
  end
434
434
 
435
435
  def create_vm_extension(params)
436
- vm_ext_props = VirtualMachineExtensionProperties.new
437
- vm_ext_props.publisher = params[:chef_extension_publisher]
438
- vm_ext_props.type = params[:chef_extension]
439
- vm_ext_props.type_handler_version = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
440
- vm_ext_props.auto_upgrade_minor_version = false
441
- vm_ext_props.settings = params[:chef_extension_public_param]
442
- vm_ext_props.protected_settings = params[:chef_extension_private_param]
443
-
444
436
  vm_ext = VirtualMachineExtension.new
445
437
  vm_ext.name = params[:chef_extension]
446
438
  vm_ext.location = params[:azure_service_location]
447
- vm_ext.properties = vm_ext_props
448
-
439
+ vm_ext.publisher = params[:chef_extension_publisher]
440
+ vm_ext.virtual_machine_extension_type = params[:chef_extension]
441
+ vm_ext.type_handler_version = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
442
+ vm_ext.auto_upgrade_minor_version = false
443
+ vm_ext.settings = params[:chef_extension_public_param]
444
+ vm_ext.protected_settings = params[:chef_extension_private_param]
449
445
  begin
450
446
  vm_extension = compute_management_client.virtual_machine_extensions.create_or_update(
451
447
  params[:azure_resource_group_name],
452
448
  params[:azure_vm_name],
453
449
  vm_ext.name,
454
450
  vm_ext
455
- ).value!.body
451
+ )
456
452
  rescue Exception => error
457
453
  Chef::Log.error("Failed to create the Virtual Machine Extension -- exception being rescued.")
458
454
  common_arm_rescue_block(error)
@@ -463,7 +459,7 @@ module Azure
463
459
 
464
460
  def extension_already_installed?(server)
465
461
  server.resources.each do |extension|
466
- return true if (extension.properties.type == "ChefClient" || extension.properties.type == "LinuxChefClient")
462
+ return true if (extension.virtual_machine_extension_type == "ChefClient" || extension.virtual_machine_extension_type == "LinuxChefClient")
467
463
  end if server.resources
468
464
  false
469
465
  end
@@ -483,7 +479,7 @@ module Azure
483
479
 
484
480
  begin
485
481
  server = resource_management_client.resource_groups.delete(resource_group_name)
486
- end until server.value!.body.nil?
482
+ end until server.nil?
487
483
  puts "\n"
488
484
  end
489
485
 
@@ -493,7 +489,11 @@ module Azure
493
489
  err_details = err_json["error"]["details"] if err_json["error"]
494
490
  if err_details
495
491
  err_details.each do |err|
496
- ui.error(JSON.parse(err["message"])["error"]["message"])
492
+ begin
493
+ ui.error(JSON.parse(err["message"])["error"]["message"])
494
+ rescue JSON::ParserError => e
495
+ ui.error(err["message"])
496
+ end
497
497
  end
498
498
  else
499
499
  ui.error(err_json["error"]["message"])
@@ -27,7 +27,7 @@ module Azure::ARM
27
27
  list = []
28
28
  address_space = IPAddress(address_prefix)
29
29
  subnets_list.each do |sbn|
30
- subnet_address_prefix = IPAddress(sbn.properties.address_prefix)
30
+ subnet_address_prefix = IPAddress(sbn.address_prefix)
31
31
 
32
32
  ## check if the subnet belongs to this address space or not ##
33
33
  list << sbn if address_space.include? subnet_address_prefix
@@ -53,7 +53,7 @@ module Azure::ARM
53
53
 
54
54
  ## lists all subnets under a virtual network or lists subnets of only a particular address space ##
55
55
  def subnets_list(resource_group_name, vnet_name, address_prefix = nil)
56
- list = network_resource_client.subnets.list(resource_group_name, vnet_name).value
56
+ list = network_resource_client.subnets.list(resource_group_name, vnet_name)
57
57
  !address_prefix.nil? && !list.empty? ? subnets_list_for_specific_address_space(address_prefix, list) : list
58
58
  end
59
59
 
@@ -69,12 +69,12 @@ module Azure::ARM
69
69
 
70
70
  ## return all the address prefixes under a virtual network ##
71
71
  def vnet_address_spaces(vnet)
72
- vnet.properties.address_space.address_prefixes
72
+ vnet.address_space.address_prefixes
73
73
  end
74
74
 
75
75
  ## return address prefix of a subnet ##
76
76
  def subnet_address_prefix(subnet)
77
- subnet.properties.address_prefix
77
+ subnet.address_prefix
78
78
  end
79
79
 
80
80
  ## sort available networks pool in ascending order based on the network's
@@ -87,14 +87,14 @@ module Azure::ARM
87
87
  ## sort existing subnets in ascending order based on their cidr prefix or
88
88
  ## netmask to have subnets with larger networks on the top ##
89
89
  def sort_subnets_by_cidr_prefix(subnets)
90
- subnets.sort_by { |sbn| [ subnet_address_prefix(sbn).split('/')[1] ].map(&:to_i) }
90
+ subnets.sort_by.with_index { |sbn, i| [subnet_address_prefix(sbn).split("/")[1].to_i, i] }
91
91
  end
92
92
 
93
93
  ## sort used networks pool in descending order based on the number of hosts
94
94
  ## it contains, this helps to keep larger networks on top thereby eliminating
95
95
  ## more number of entries in available_networks_pool at a faster pace ##
96
96
  def sort_used_networks_by_hosts_size(used_network)
97
- used_network.sort_by { |nwrk| -nwrk.hosts.size }
97
+ used_network.sort_by.with_index { |nwrk, i| [-nwrk.hosts.size, i] }
98
98
  end
99
99
 
100
100
  ## return the cidr prefix or netmask of the given subnet ##
@@ -77,7 +77,7 @@ module Azure::ARM
77
77
  include Chef::Mixin::WideString
78
78
  include ReadCred
79
79
 
80
- def token_details_for_windows
80
+ def token_details_from_WCM
81
81
  begin
82
82
  target = target_name
83
83
 
@@ -194,6 +194,7 @@ class Chef
194
194
  def parse_azure_profile(filename, errors)
195
195
  require 'openssl'
196
196
  require 'uri'
197
+ errors = [] if errors.nil?
197
198
  azure_profile = File.read(File.expand_path(filename))
198
199
  azure_profile = JSON.parse(azure_profile)
199
200
  default_subscription = get_default_subscription(azure_profile)
@@ -374,7 +374,7 @@ class Chef
374
374
  extension_status[:status] = :extension_status_not_detected
375
375
  end
376
376
  # This fix is for linux waagent issue: api unable to deserialize the waagent status.
377
- elsif role.at_css('GuestAgentStatus Status').text == 'NotReady' and waagent_status_msg == lnx_waagent_fail_msg
377
+ elsif (role.at_css('GuestAgentStatus Status').text == 'NotReady') && (waagent_status_msg == lnx_waagent_fail_msg)
378
378
  extension_status[:status] = :extension_ready
379
379
  else
380
380
  extension_status[:status] = :wagent_provisioning
@@ -424,12 +424,12 @@ class Chef
424
424
  end
425
425
 
426
426
  def validate_params!
427
- if locate_config_value(:winrm_password) and (locate_config_value(:winrm_password).length <= 6 and locate_config_value(:winrm_password).length >= 72)
427
+ if locate_config_value(:winrm_password) && (locate_config_value(:winrm_password).length <= 6 && locate_config_value(:winrm_password).length >= 72)
428
428
  ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
429
429
  exit 1
430
430
  end
431
431
 
432
- if locate_config_value(:ssh_password) and (locate_config_value(:ssh_password).length <= 6 and locate_config_value(:ssh_password).length >= 72)
432
+ if locate_config_value(:ssh_password) && (locate_config_value(:ssh_password).length <= 6 && locate_config_value(:ssh_password).length >= 72)
433
433
  ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
434
434
  exit 1
435
435
  end
@@ -458,8 +458,8 @@ class Chef
458
458
  end
459
459
 
460
460
  # Validate join domain requirements.
461
- if locate_config_value(:azure_domain_name) or locate_config_value(:azure_domain_user)
462
- if locate_config_value(:azure_domain_user).nil? or locate_config_value(:azure_domain_passwd).nil?
461
+ if locate_config_value(:azure_domain_name) || locate_config_value(:azure_domain_user)
462
+ if locate_config_value(:azure_domain_user).nil? || locate_config_value(:azure_domain_passwd).nil?
463
463
  ui.error("Must specify both --azure-domain-user and --azure-domain-passwd.")
464
464
  exit 1
465
465
  end
@@ -474,6 +474,20 @@ class Chef
474
474
  ui.error("--extended-logs option works with --bootstrap-protocol cloud-api")
475
475
  exit 1
476
476
  end
477
+
478
+ if locate_config_value(:daemon)
479
+ unless is_image_windows?
480
+ raise ArgumentError, "The daemon option is only support for Windows nodes."
481
+ end
482
+
483
+ unless locate_config_value(:bootstrap_protocol) == 'cloud-api'
484
+ raise ArgumentError, "--daemon option works with --bootstrap-protocol cloud-api"
485
+ end
486
+
487
+ unless %w{none service task}.include?(locate_config_value(:daemon))
488
+ raise ArgumentError, "Invalid value for --daemon option. Use valid daemon values i.e 'none', 'service' and 'task'."
489
+ end
490
+ end
477
491
  end
478
492
 
479
493
  def create_server_def
@@ -89,7 +89,7 @@ class Chef
89
89
  object.destroy
90
90
  ui.warn("Deleted #{type_name} #{name}")
91
91
  rescue Net::HTTPServerException
92
- ui.warn("Could not find a #{type_name} named #{name} to delete!")
92
+ ui.warn("Could not find a #{type_name} named #{name} to delete. Please provide --node-name option and it's value")
93
93
  end
94
94
  end
95
95
 
@@ -20,12 +20,18 @@
20
20
  require 'chef/knife'
21
21
  require 'azure/resource_management/ARM_interface'
22
22
  require 'mixlib/shellout'
23
+ require 'chef/mixin/shell_out'
23
24
  require 'time'
24
25
  require 'json'
25
26
 
26
27
  class Chef
27
28
  class Knife
28
29
  module AzurermBase
30
+ include Chef::Mixin::ShellOut
31
+
32
+ ## azure-xplat-cli versio that introduced deprecation of Windows Credentials
33
+ ## Manager (WCM) usage for authentication credentials storage purpose ##
34
+ XPLAT_VERSION_WITH_WCM_DEPRECATED ||= "0.10.5"
29
35
 
30
36
  if Chef::Platform.windows?
31
37
  require 'azure/resource_management/windows_credentials'
@@ -65,7 +71,6 @@ class Chef
65
71
 
66
72
  # validates ARM mandatory keys
67
73
  def validate_arm_keys!(*keys)
68
- Chef::Log.warn('Azurerm subcommands are experimental and of alpha quality. Not suitable for production use. Please use ASM subcommands for production.')
69
74
  parse_publish_settings_file(locate_config_value(:azure_publish_settings_file)) if(locate_config_value(:azure_publish_settings_file) != nil)
70
75
  keys.push(:azure_subscription_id)
71
76
 
@@ -98,7 +103,31 @@ class Chef
98
103
  token_details
99
104
  end
100
105
 
106
+ def current_xplat_cli_version
107
+ shell_out!("azure -v", { returns: [0] }).stdout
108
+ end
109
+
110
+ def is_old_xplat?
111
+ Gem::Version.new(current_xplat_cli_version) < Gem::Version.new(XPLAT_VERSION_WITH_WCM_DEPRECATED)
112
+ end
113
+
114
+ def is_WCM_env_var_set?
115
+ ENV['AZURE_USE_SECURE_TOKEN_STORAGE'].nil? ? false : true
116
+ end
117
+
118
+ def token_details_for_windows
119
+ if is_old_xplat?
120
+ token_details_from_WCM
121
+ else
122
+ is_WCM_env_var_set? ? token_details_from_WCM : token_details_from_accessToken_file
123
+ end
124
+ end
125
+
101
126
  def token_details_for_linux
127
+ token_details_from_accessToken_file
128
+ end
129
+
130
+ def token_details_from_accessToken_file
102
131
  home_dir = File.expand_path('~')
103
132
  file = File.read(home_dir + '/.azure/accessTokens.json')
104
133
  file = JSON.parse(file)
@@ -146,7 +175,12 @@ class Chef
146
175
 
147
176
  def validate_azure_login
148
177
  err_string = "Please run XPLAT's 'azure login' command OR specify azure_tenant_id, azure_subscription_id, azure_client_id, azure_client_secret in your knife.rb"
149
- if Chef::Platform.windows?
178
+
179
+ ## Older versions of the Azure CLI on Windows stored credentials in a unique way
180
+ ## in Windows Credentails Manager (WCM).
181
+ ## Newer versions use the same pattern across platforms where credentials gets
182
+ ## stored in ~/.azure/accessTokens.json file.
183
+ if Chef::Platform.windows? && (is_old_xplat? || is_WCM_env_var_set?)
150
184
  # cmdkey command is used for accessing windows credential manager
151
185
  xplat_creds_cmd = Mixlib::ShellOut.new("cmdkey /list | findstr AzureXplatCli")
152
186
  result = xplat_creds_cmd.run_command
@@ -256,6 +290,51 @@ class Chef
256
290
  end
257
291
  puts "\n"
258
292
  end
293
+
294
+ def validate_params!
295
+ if locate_config_value(:azure_vnet_subnet_name) && !locate_config_value(:azure_vnet_name)
296
+ raise ArgumentError, "When --azure-vnet-subnet-name is specified, the --azure-vnet-name must also be specified."
297
+ end
298
+
299
+ if locate_config_value(:azure_vnet_subnet_name) == 'GatewaySubnet'
300
+ raise ArgumentError, 'GatewaySubnet cannot be used as the name for --azure-vnet-subnet-name option. GatewaySubnet can only be used for virtual network gateways.'
301
+ end
302
+
303
+ if locate_config_value(:node_ssl_verify_mode) && !["none", "peer"].include?(locate_config_value(:node_ssl_verify_mode))
304
+ raise ArgumentError, "Invalid value '#{locate_config_value(:node_ssl_verify_mode)}' for --node-ssl-verify-mode. Use Valid values i.e 'none', 'peer'."
305
+ end
306
+
307
+ if is_image_windows?
308
+ if locate_config_value(:winrm_user).nil? || locate_config_value(:winrm_password).nil?
309
+ raise ArgumentError, "Please provide --winrm-user and --winrm-password options for Windows option."
310
+ end
311
+ end
312
+
313
+ if !is_image_windows?
314
+ if (locate_config_value(:azure_vm_name).match /^(?=.*[a-zA-Z-])([a-zA-z0-9-]{1,64})$/).nil?
315
+ raise ArgumentError, "VM name can only contain alphanumeric and hyphen(-) characters and maximun length cannot exceed 64 charachters."
316
+ end
317
+ elsif (locate_config_value(:azure_vm_name).match /^(?=.*[a-zA-Z-])([a-zA-z0-9-]{1,15})$/).nil?
318
+ raise ArgumentError, "VM name can only contain alphanumeric and hyphen(-) characters and maximun length cannot exceed 15 charachters."
319
+ end
320
+
321
+ if locate_config_value(:server_count).to_i > 5
322
+ raise ArgumentError, "Maximum allowed value of --server-count is 5."
323
+ end
324
+
325
+ if locate_config_value(:daemon)
326
+ unless is_image_windows?
327
+ raise ArgumentError, "The daemon option is only support for Windows nodes."
328
+ end
329
+
330
+ unless %w{none service task}.include?(locate_config_value(:daemon))
331
+ raise ArgumentError, "Invalid value for --daemon option. Use valid daemon values i.e 'none', 'service' and 'task'."
332
+ end
333
+ end
334
+
335
+ config[:ohai_hints] = format_ohai_hints(locate_config_value(:ohai_hints))
336
+ validate_ohai_hints if ! locate_config_value(:ohai_hints).casecmp('default').zero?
337
+ end
259
338
  end
260
339
  end
261
340
  end
@@ -49,6 +49,10 @@ class Chef
49
49
  :long => "--ssh-port PORT",
50
50
  :description => "The ssh port. Default is 22."
51
51
 
52
+ option :node_ssl_verify_mode,
53
+ :long => "--node-ssl-verify-mode [peer|none]",
54
+ :description => "Whether or not to verify the SSL cert for all HTTPS requests."
55
+
52
56
  option :winrm_user,
53
57
  :short => "-x USERNAME",
54
58
  :long => "--winrm-user USERNAME",
@@ -130,6 +134,10 @@ class Chef
130
134
  :default => 'Small',
131
135
  :proc => Proc.new { |si| Chef::Config[:knife][:azure_vm_size] = si }
132
136
 
137
+ option :azure_availability_set,
138
+ :long => "--azure-availability-set NAME",
139
+ :description => "Optional. Name of availability set to add virtual machine into."
140
+
133
141
  option :azure_vnet_name,
134
142
  :long => "--azure-vnet-name VNET_NAME",
135
143
  :description => "Optional. Specifies the virtual network name.
@@ -221,6 +229,7 @@ class Chef
221
229
  :azure_image_reference_sku => locate_config_value(:azure_image_reference_sku),
222
230
  :azure_image_reference_version => locate_config_value(:azure_image_reference_version),
223
231
  :winrm_user => locate_config_value(:winrm_user),
232
+ :azure_availability_set => locate_config_value(:azure_availability_set),
224
233
  :azure_vnet_name => locate_config_value(:azure_vnet_name),
225
234
  :azure_vnet_subnet_name => locate_config_value(:azure_vnet_subnet_name),
226
235
  :ssl_cert_fingerprint => locate_config_value(:thumbprint),
@@ -230,9 +239,10 @@ class Chef
230
239
  :server_count => locate_config_value(:server_count)
231
240
  }
232
241
 
233
- if locate_config_value(:tcp_endpoints)
234
- server_def[:tcp_endpoints] = locate_config_value(:tcp_endpoints)
235
- end
242
+ server_def[:tcp_endpoints] = locate_config_value(:tcp_endpoints) if locate_config_value(:tcp_endpoints)
243
+
244
+ # We assign azure_vm_name to chef_node_name If node name is nill because storage account name is combination of hash value and node name.
245
+ config[:chef_node_name] ||= locate_config_value(:azure_vm_name)
236
246
 
237
247
  server_def[:azure_storage_account] = locate_config_value(:azure_vm_name) if server_def[:azure_storage_account].nil?
238
248
  server_def[:azure_storage_account] = server_def[:azure_storage_account].gsub(/[!@#$%^&*()_-]/,'')
@@ -291,37 +301,6 @@ class Chef
291
301
  end
292
302
  end
293
303
 
294
- def validate_params!
295
- if locate_config_value(:azure_vnet_subnet_name) && !locate_config_value(:azure_vnet_name)
296
- raise ArgumentError, "When --azure-vnet-subnet-name is specified, the --azure-vnet-name must also be specified."
297
- end
298
-
299
- if locate_config_value(:azure_vnet_subnet_name) == 'GatewaySubnet'
300
- raise ArgumentError, 'GatewaySubnet cannot be used as the name for --azure-vnet-subnet-name option. GatewaySubnet can only be used for virtual network gateways.'
301
- end
302
-
303
- if is_image_windows?
304
- if locate_config_value(:winrm_user).nil? || locate_config_value(:winrm_password).nil?
305
- raise ArgumentError, "Please provide --winrm-user and --winrm-password options for Windows option."
306
- end
307
- end
308
-
309
- if !is_image_windows?
310
- if (locate_config_value(:azure_vm_name).match /^(?=.*[a-zA-Z-])([a-zA-z0-9-]{1,64})$/).nil?
311
- raise ArgumentError, "VM name can only contain alphanumeric and hyphen(-) characters and maximun length cannot exceed 64 charachters."
312
- end
313
- elsif (locate_config_value(:azure_vm_name).match /^(?=.*[a-zA-Z-])([a-zA-z0-9-]{1,15})$/).nil?
314
- raise ArgumentError, "VM name can only contain alphanumeric and hyphen(-) characters and maximun length cannot exceed 15 charachters."
315
- end
316
-
317
- if locate_config_value(:server_count).to_i > 5
318
- raise ArgumentError, "Maximum allowed value of --server-count is 5."
319
- end
320
-
321
- config[:ohai_hints] = format_ohai_hints(locate_config_value(:ohai_hints))
322
- validate_ohai_hints if ! locate_config_value(:ohai_hints).casecmp('default').zero?
323
- end
324
-
325
304
  private
326
305
 
327
306
  def ssh_override_winrm
@@ -84,14 +84,21 @@ class Chef
84
84
  :default => false,
85
85
  :description => "Optional. Provide this option when --bootstrap-protocol is set to 'cloud-api'. It shows chef converge logs in detail."
86
86
 
87
- option :chef_service_interval,
88
- :long => "--chef-service-interval INTERVAL",
87
+ option :chef_daemon_interval,
88
+ :long => "--chef-daemon-interval INTERVAL",
89
89
  :description => "Optional. Provide this option when --bootstrap-protocol is set to 'cloud-api'.
90
90
  It specifies the frequency (in minutes) at which the chef-service runs.
91
91
  Pass 0 if you don't want the chef-service to be installed on the target machine."
92
92
 
93
+ option :daemon,
94
+ :long => "--daemon DAEMON",
95
+ :description => "Optional. Configures the chef-client service for unattended execution. Requires --bootstrap-protocol to be 'cloud-api' and the node platform to be Windows.
96
+ Options: 'none' or 'service' or 'task'.
97
+ none - Currently prevents the chef-client service from being configured as a service.
98
+ service - Configures the chef-client to run automatically in the background as a service.
99
+ task - Configures the chef-client to run automatically in the background as a scheduled task."
93
100
  end
94
- end
101
+ end
95
102
  end
96
103
  end
97
104
  end
@@ -284,7 +284,8 @@ class Chef
284
284
  pub_config[:custom_json_attr] = locate_config_value(:json_attributes) || {}
285
285
  pub_config[:extendedLogs] = locate_config_value(:extended_logs) ? "true" : "false"
286
286
  pub_config[:hints] = ohai_hints if @service.instance_of?(Azure::ResourceManagement::ARMInterface) && !locate_config_value(:ohai_hints).nil?
287
- pub_config[:chef_service_interval] = locate_config_value(:chef_service_interval) if locate_config_value(:chef_service_interval)
287
+ pub_config[:chef_daemon_interval] = locate_config_value(:chef_daemon_interval) if locate_config_value(:chef_daemon_interval)
288
+ pub_config[:daemon] = locate_config_value(:daemon) if locate_config_value(:daemon)
288
289
 
289
290
  # bootstrap attributes
290
291
  pub_config[:bootstrap_options] = {}
@@ -296,7 +297,6 @@ class Chef
296
297
  pub_config[:bootstrap_options][:bootstrap_version] = locate_config_value(:bootstrap_version) if locate_config_value(:bootstrap_version)
297
298
  pub_config[:bootstrap_options][:node_ssl_verify_mode] = locate_config_value(:node_ssl_verify_mode) if locate_config_value(:node_ssl_verify_mode)
298
299
  pub_config[:bootstrap_options][:bootstrap_proxy] = locate_config_value(:bootstrap_proxy) if locate_config_value(:bootstrap_proxy)
299
-
300
300
  pub_config
301
301
  end
302
302
 
@@ -317,26 +317,37 @@ class Chef
317
317
  cli_secret_file || cli_secret || knife_secret_file || knife_secret
318
318
  end
319
319
 
320
+ def create_node_and_client_pem
321
+ client_builder = Chef::Knife::Bootstrap::ClientBuilder.new(
322
+ chef_config: Chef::Config,
323
+ knife_config: config,
324
+ ui: ui,
325
+ )
326
+ client_builder.run
327
+ client_builder.client_path
328
+ end
329
+
320
330
  def get_chef_extension_private_params
321
331
  pri_config = Hash.new
322
332
 
323
333
  # validator less bootstrap support for bootstrap protocol cloud-api
324
334
  if (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
325
-
326
335
  if Chef::VERSION.split('.').first.to_i == 11
327
336
  ui.error('Unable to find validation key. Please verify your configuration file for validation_key config value.')
328
337
  exit 1
329
338
  end
330
-
331
- client_builder = Chef::Knife::Bootstrap::ClientBuilder.new(
332
- chef_config: Chef::Config,
333
- knife_config: config,
334
- ui: ui,
335
- )
336
-
337
- client_builder.run
338
- key_path = client_builder.client_path
339
- pri_config[:client_pem] = File.read(key_path)
339
+ if config[:server_count].to_i > 1
340
+ node_name = config[:chef_node_name]
341
+ 0.upto (config[:server_count].to_i-1) do |count|
342
+ config[:chef_node_name] = node_name + count.to_s
343
+ key_path = create_node_and_client_pem
344
+ pri_config[("client_pem" + count.to_s).to_sym] = File.read(key_path)
345
+ end
346
+ config[:chef_node_name] = node_name
347
+ else
348
+ key_path = create_node_and_client_pem
349
+ pri_config[:client_pem] = File.read(key_path)
350
+ end
340
351
  else
341
352
  pri_config[:validation_key] = File.read(Chef::Config[:validation_key])
342
353
  end
@@ -17,7 +17,7 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  #
20
- # Bootstrap options listed here are supported only for cloud-api protocol.
20
+ # Bootstrap options listed here are supported only for cloud-api protocol ARM mode.
21
21
  #
22
22
 
23
23
  class Chef
@@ -99,11 +99,18 @@ class Chef
99
99
  :default => false,
100
100
  :description => "Optional. It shows chef convergence logs in detail."
101
101
 
102
- option :chef_service_interval,
103
- :long => "--chef-service-interval INTERVAL",
102
+ option :chef_daemon_interval,
103
+ :long => "--chef-daemon-interval INTERVAL",
104
104
  :description => "Optional. It specifies the frequency (in minutes) at which the chef-service runs.
105
105
  Pass 0 if you don't want the chef-service to be installed on the target machine."
106
106
 
107
+ option :daemon,
108
+ :long => "--daemon DAEMON",
109
+ :description => "Optional. Configures the chef-client service for unattended execution. Requires --bootstrap-protocol to be 'cloud-api' and the node platform to be Windows.
110
+ Options: 'none' or 'service' or 'task'.
111
+ none - Currently prevents the chef-client service from being configured as a service.
112
+ service - Configures the chef-client to run automatically in the background as a service.
113
+ task - Configures the chef-client to run automatically in the background as a scheduled task."
107
114
  end
108
115
  end
109
116
  end
@@ -73,17 +73,17 @@ class Chef
73
73
  raise "Virtual machine #{server.name} already has Chef extension installed on it."
74
74
  else
75
75
  ext_params = Hash.new
76
- case server.properties.storage_profile.os_disk.os_type.downcase
76
+ case server.storage_profile.os_disk.os_type.downcase
77
77
  when 'windows'
78
78
  ext_params[:chef_extension] = 'ChefClient'
79
79
  when 'linux'
80
- if ['ubuntu', 'debian', 'rhel', 'centos'].any? { |platform| server.properties.storage_profile.image_reference.offer.downcase.include? platform }
80
+ if ['ubuntu', 'debian', 'rhel', 'centos'].any? { |platform| server.storage_profile.image_reference.offer.downcase.include? platform }
81
81
  ext_params[:chef_extension] = 'LinuxChefClient'
82
82
  else
83
- raise "Offer #{server.properties.storage_profile.image_reference.offer} is not supported in the extension."
83
+ raise "Offer #{server.storage_profile.image_reference.offer} is not supported in the extension."
84
84
  end
85
85
  else
86
- raise "OS type #{server.properties.storage_profile.os_disk.os_type} is not supported."
86
+ raise "OS type #{server.storage_profile.os_disk.os_type} is not supported."
87
87
  end
88
88
 
89
89
  ext_params[:azure_resource_group_name] = locate_config_value(:azure_resource_group_name)
@@ -1,6 +1,6 @@
1
1
  module Knife
2
2
  module Azure
3
- VERSION = "1.7.0"
3
+ VERSION = "1.8.0"
4
4
  MAJOR, MINOR, TINY = VERSION.split('.')
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-azure
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Barry Davis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-11-25 00:00:00.000000000 Z
12
+ date: 2017-09-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -45,70 +45,70 @@ dependencies:
45
45
  requirements:
46
46
  - - '='
47
47
  - !ruby/object:Gem::Version
48
- version: 0.3.1
48
+ version: 0.9.0
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - '='
54
54
  - !ruby/object:Gem::Version
55
- version: 0.3.1
55
+ version: 0.9.0
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: azure_mgmt_compute
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - '='
61
61
  - !ruby/object:Gem::Version
62
- version: 0.3.1
62
+ version: 0.9.0
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - '='
68
68
  - !ruby/object:Gem::Version
69
- version: 0.3.1
69
+ version: 0.9.0
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: azure_mgmt_storage
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - '='
75
75
  - !ruby/object:Gem::Version
76
- version: 0.3.1
76
+ version: 0.9.0
77
77
  type: :runtime
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - '='
82
82
  - !ruby/object:Gem::Version
83
- version: 0.3.1
83
+ version: 0.9.0
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: azure_mgmt_network
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
88
  - - '='
89
89
  - !ruby/object:Gem::Version
90
- version: 0.3.1
90
+ version: 0.9.0
91
91
  type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - '='
96
96
  - !ruby/object:Gem::Version
97
- version: 0.3.1
97
+ version: 0.9.0
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: listen
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - '='
102
+ - - "~>"
103
103
  - !ruby/object:Gem::Version
104
- version: 3.0.6
104
+ version: '3.0'
105
105
  type: :runtime
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - '='
109
+ - - "~>"
110
110
  - !ruby/object:Gem::Version
111
- version: 3.0.6
111
+ version: '3.0'
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: ipaddress
114
114
  requirement: !ruby/object:Gem::Requirement
@@ -141,9 +141,6 @@ dependencies:
141
141
  name: chef
142
142
  requirement: !ruby/object:Gem::Requirement
143
143
  requirements:
144
- - - "~>"
145
- - !ruby/object:Gem::Version
146
- version: '12.0'
147
144
  - - ">="
148
145
  - !ruby/object:Gem::Version
149
146
  version: 12.2.1
@@ -151,9 +148,6 @@ dependencies:
151
148
  prerelease: false
152
149
  version_requirements: !ruby/object:Gem::Requirement
153
150
  requirements:
154
- - - "~>"
155
- - !ruby/object:Gem::Version
156
- version: '12.0'
157
151
  - - ">="
158
152
  - !ruby/object:Gem::Version
159
153
  version: 12.2.1
@@ -288,7 +282,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
288
282
  version: '0'
289
283
  requirements: []
290
284
  rubyforge_project:
291
- rubygems_version: 2.6.7
285
+ rubygems_version: 2.6.10
292
286
  signing_key:
293
287
  specification_version: 4
294
288
  summary: A plugin to the Chef knife tool for creating instances on the Microsoft Azure