knife-azure 1.7.0 → 1.8.0

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