knife-azure 1.3.0 → 1.4.0.rc.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +3 -3
- data/lib/azure/certificate.rb +20 -11
- data/lib/azure/deploy.rb +5 -1
- data/lib/azure/image.rb +34 -6
- data/lib/azure/rest.rb +1 -1
- data/lib/azure/role.rb +143 -88
- data/lib/chef/knife/azure_image_list.rb +3 -3
- data/lib/chef/knife/azure_server_create.rb +236 -39
- data/lib/knife-azure/version.rb +1 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NDRlZjIwNmQwNWU1NzVlYzA4NGI3MzNjZTJlNmZkMmNlZmEwZDZiNg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MDgxYzQ2YTU2NGFlZDA0ZmE3MmM0M2UzM2NkNzFlZGZkNWU3MzQyYg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MGIxZTg3ZDEzN2ZlNmIzMzhlYTRhZjdlYjY5OTVkMzRkZDNjMWYzZDBiZjFh
|
10
|
+
NzlhNjRlMTE3ZTQwMGUwYjQxNTc4NDY3ZDNhZDVkZThjMmFlODgwNGZiYWM0
|
11
|
+
MDY0YWRiMmQ5OTYwNjBmZGE3YWY3ZGU2OGFmMWRmZGNjOGM5YWE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NTlkMTM2Mjc3NDQ3ZmNmNmZlOGQwYzk2MGJhM2EyYWIxMjljYzNiMzIxMWU2
|
14
|
+
NTY0NDE3MTk2MjBhOGVmZTA5MzY0YWZiMWJjY2E0MmJmNTBiY2IyMzNmZDlm
|
15
|
+
ZjQ4YWQxYTAxMDZlMWYwYjhiYTdmMGFhZTEwNTcxZjMzZWY2MzY=
|
data/README.md
CHANGED
@@ -48,7 +48,7 @@ location in your knife.rb:
|
|
48
48
|
$ knife azure server list
|
49
49
|
|
50
50
|
# Create and bootstrap an Ubuntu VM over ssh
|
51
|
-
$ knife azure server create -N MyNewNode --azure-vm-size Medium
|
51
|
+
$ knife azure server create -N MyNewNode --azure-vm-size Medium -I b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_1-LTS-amd64-server-20140927-en-us-30GB -m 'West US' --ssh-user myuser --identity-file ~/.ssh/myprivatekey_rsa
|
52
52
|
|
53
53
|
# Create and bootstrap a Windows VM over winrm
|
54
54
|
$ knife azure server create --azure-dns-name MyNewServerName --azure-vm-size Medium --azure-source-image 8fcc3d_Win2012-amd64-30GB --azure-service-location 'West US' --winrm-user myuser --winrm-password 'mypassword' --bootstrap-protocol winrm --distro 'windows-chef-client-msi'
|
@@ -182,8 +182,8 @@ These options may also be configured from knife.rb, as in this example:
|
|
182
182
|
knife[:identity_file]='/path/to/RSA/private/key'
|
183
183
|
knife[:azure_storage_account]='auxpreview104'
|
184
184
|
knife[:azure_os_disk_name]='disk107'
|
185
|
-
knife[:
|
186
|
-
knife[:
|
185
|
+
knife[:tcp-endpoints]='80:80,3389:5678'
|
186
|
+
knife[:udp-endpoints]='123:123'
|
187
187
|
|
188
188
|
#### Options for Bootstrapping a Windows Node in Azure
|
189
189
|
|
data/lib/azure/certificate.rb
CHANGED
@@ -25,6 +25,10 @@ class Azure
|
|
25
25
|
certificate = Certificate.new(@connection)
|
26
26
|
certificate.create(params)
|
27
27
|
end
|
28
|
+
def add(certificate_data, certificate_password, certificate_format, dns_name)
|
29
|
+
certificate = Certificate.new(@connection)
|
30
|
+
certificate.add_certificate certificate_data, certificate_password, certificate_format, dns_name
|
31
|
+
end
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
@@ -41,17 +45,7 @@ class Azure
|
|
41
45
|
# public part of the key
|
42
46
|
@cert_data = generate_public_key_certificate_data({:ssh_key => params[:identity_file],
|
43
47
|
:ssh_key_passphrase => params[:identity_file_passphrase]})
|
44
|
-
|
45
|
-
# Add certificate to the hosted service
|
46
|
-
builder = Nokogiri::XML::Builder.new do |xml|
|
47
|
-
xml.CertificateFile('xmlns'=>'http://schemas.microsoft.com/windowsazure') {
|
48
|
-
xml.Data @cert_data
|
49
|
-
xml.CertificateFormat 'pfx'
|
50
|
-
xml.Password 'knifeazure'
|
51
|
-
}
|
52
|
-
end
|
53
|
-
# Windows Azure API call
|
54
|
-
@connection.query_azure("hostedservices/#{params[:azure_dns_name]}/certificates", "post", builder.to_xml)
|
48
|
+
add_certificate @cert_data, 'knifeazure', 'pfx', params[:azure_dns_name]
|
55
49
|
# Return the fingerprint to be used while adding role
|
56
50
|
@fingerprint
|
57
51
|
end
|
@@ -83,5 +77,20 @@ class Azure
|
|
83
77
|
# Encode the pfx format - upload this certificate
|
84
78
|
Base64.strict_encode64(pfx.to_der)
|
85
79
|
end
|
80
|
+
|
81
|
+
def add_certificate certificate_data, certificate_password, certificate_format, dns_name
|
82
|
+
# Generate XML to call the API
|
83
|
+
# Add certificate to the hosted service
|
84
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
85
|
+
xml.CertificateFile('xmlns'=>'http://schemas.microsoft.com/windowsazure') {
|
86
|
+
xml.Data certificate_data
|
87
|
+
xml.CertificateFormat certificate_format
|
88
|
+
xml.Password certificate_password
|
89
|
+
}
|
90
|
+
end
|
91
|
+
# Windows Azure API call
|
92
|
+
@connection.query_azure("hostedservices/#{dns_name}/certificates", "post", builder.to_xml)
|
93
|
+
end
|
94
|
+
|
86
95
|
end
|
87
96
|
end
|
data/lib/azure/deploy.rb
CHANGED
@@ -78,6 +78,10 @@ class Azure
|
|
78
78
|
if params[:identity_file]
|
79
79
|
params[:fingerprint] = @connection.certificates.create(params)
|
80
80
|
end
|
81
|
+
if params[:cert_path]
|
82
|
+
cert_data = File.read (params[:cert_path])
|
83
|
+
@connection.certificates.add cert_data, params[:cert_password], 'pfx', params[:azure_dns_name]
|
84
|
+
end
|
81
85
|
params['deploy_name'] = get_deploy_name_for_hostedservice(params[:azure_dns_name])
|
82
86
|
|
83
87
|
if params['deploy_name'] != nil
|
@@ -99,7 +103,7 @@ class Azure
|
|
99
103
|
end
|
100
104
|
def delete(rolename)
|
101
105
|
end
|
102
|
-
|
106
|
+
|
103
107
|
def queryDeploy(hostedservicename)
|
104
108
|
deploy = Deploy.new(@connection)
|
105
109
|
deploy.retrieve(hostedservicename)
|
data/lib/azure/image.rb
CHANGED
@@ -23,23 +23,51 @@ class Azure
|
|
23
23
|
end
|
24
24
|
def load
|
25
25
|
@images ||= begin
|
26
|
-
|
26
|
+
osimages = self.get_images("OSImage") #get OSImages
|
27
|
+
vmimages = self.get_images("VMImage") #get VMImages
|
28
|
+
|
29
|
+
all_images = osimages.merge(vmimages)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def all
|
34
|
+
self.load.values
|
35
|
+
end
|
36
|
+
|
37
|
+
# img_type = OSImages or VMImage
|
38
|
+
def get_images(img_type)
|
39
|
+
images = Hash.new
|
40
|
+
|
41
|
+
if(img_type == "OSImage")
|
27
42
|
response = @connection.query_azure('images')
|
28
|
-
|
43
|
+
elsif(img_type == "VMImage")
|
44
|
+
response = @connection.query_azure('vmimages')
|
45
|
+
end
|
46
|
+
|
47
|
+
unless response.to_s.empty?
|
48
|
+
osimages = response.css(img_type)
|
49
|
+
|
29
50
|
osimages.each do |image|
|
30
51
|
item = Image.new(image)
|
31
52
|
images[item.name] = item
|
32
53
|
end
|
33
|
-
images
|
34
54
|
end
|
55
|
+
|
56
|
+
images
|
35
57
|
end
|
36
58
|
|
37
|
-
def
|
38
|
-
self.
|
59
|
+
def is_os_image(image_name)
|
60
|
+
os_images = self.get_images("OSImage").values
|
61
|
+
os_images.detect {|img| img.name == image_name} ? true : false
|
62
|
+
end
|
63
|
+
|
64
|
+
def is_vm_image(image_name)
|
65
|
+
vm_images = self.get_images("VMImage").values
|
66
|
+
vm_images.detect {|img| img.name == image_name} ? true : false
|
39
67
|
end
|
40
68
|
|
41
69
|
def exists?(name)
|
42
|
-
self.all.
|
70
|
+
self.all.detect {|img| img.name == name} ? true : false
|
43
71
|
end
|
44
72
|
|
45
73
|
def find(name)
|
data/lib/azure/rest.rb
CHANGED
@@ -97,7 +97,7 @@ module AzureAPI
|
|
97
97
|
request = Net::HTTP::Put.new(uri.request_uri)
|
98
98
|
end
|
99
99
|
text = verb == 'put'
|
100
|
-
request["x-ms-version"] = "
|
100
|
+
request["x-ms-version"] = "2014-04-01"
|
101
101
|
request["content-type"] = text ? "text/plain" : "application/xml"
|
102
102
|
request["accept"] = "application/xml"
|
103
103
|
request["accept-charset"] = "utf-8"
|
data/lib/azure/role.rb
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
require 'securerandom'
|
19
|
+
|
19
20
|
class Azure
|
20
21
|
class Roles
|
21
22
|
include AzureUtility
|
@@ -100,7 +101,7 @@ class Azure
|
|
100
101
|
if alone_on_hostedservice(role)
|
101
102
|
if !params[:preserve_azure_dns_name] && compmedia
|
102
103
|
servicecall = "hostedservices/#{role.hostedservicename}"
|
103
|
-
else
|
104
|
+
else
|
104
105
|
servicecall = "hostedservices/#{role.hostedservicename}/deployments/#{role.deployname}"
|
105
106
|
end
|
106
107
|
else
|
@@ -127,7 +128,7 @@ class Azure
|
|
127
128
|
for attempt in 0..12
|
128
129
|
break if @connection.query_azure(servicecall, "get").search("AttachedTo").text == ""
|
129
130
|
if attempt == 12 then puts "The associated disk could not be deleted due to time out." else sleep 25 end
|
130
|
-
end
|
131
|
+
end
|
131
132
|
unless params[:preserve_azure_vhd]
|
132
133
|
@connection.query_azure(servicecall, 'delete', '', 'comp=media', wait=params[:wait])
|
133
134
|
else
|
@@ -142,7 +143,7 @@ class Azure
|
|
142
143
|
roles_using_same_service = find_roles_within_hostedservice(params[:azure_dns_name])
|
143
144
|
if roles_using_same_service.size <= 1
|
144
145
|
servicecall = "hostedservices/" + params[:azure_dns_name]
|
145
|
-
@connection.query_azure(servicecall, "delete")
|
146
|
+
@connection.query_azure(servicecall, "delete")
|
146
147
|
end
|
147
148
|
end
|
148
149
|
end
|
@@ -219,122 +220,176 @@ class Azure
|
|
219
220
|
xml.RoleName {xml.text params[:azure_vm_name]}
|
220
221
|
xml.OsVersion('i:nil' => 'true')
|
221
222
|
xml.RoleType 'PersistentVMRole'
|
223
|
+
xml.VMImageName params[:azure_source_image] if params[:is_vm_image]
|
224
|
+
|
222
225
|
xml.ConfigurationSets {
|
223
226
|
if params[:os_type] == 'Linux'
|
224
|
-
|
225
227
|
xml.ConfigurationSet('i:type' => 'LinuxProvisioningConfigurationSet') {
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
228
|
+
xml.ConfigurationSetType 'LinuxProvisioningConfiguration'
|
229
|
+
xml.HostName params[:azure_vm_name]
|
230
|
+
xml.UserName params[:ssh_user]
|
231
|
+
unless params[:identity_file].nil?
|
232
|
+
xml.DisableSshPasswordAuthentication 'true'
|
233
|
+
xml.SSH {
|
234
|
+
xml.PublicKeys {
|
235
|
+
xml.PublicKey {
|
236
|
+
xml.Fingerprint params[:fingerprint].to_s.upcase
|
237
|
+
xml.Path '/home/' + params[:ssh_user] + '/.ssh/authorized_keys'
|
238
|
+
}
|
236
239
|
}
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
end
|
240
|
+
}
|
241
|
+
else
|
242
|
+
xml.UserPassword params[:ssh_password]
|
243
|
+
xml.DisableSshPasswordAuthentication 'false'
|
244
|
+
end
|
243
245
|
}
|
244
246
|
elsif params[:os_type] == 'Windows'
|
245
247
|
xml.ConfigurationSet('i:type' => 'WindowsProvisioningConfigurationSet') {
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
248
|
+
xml.ConfigurationSetType 'WindowsProvisioningConfiguration'
|
249
|
+
xml.ComputerName params[:azure_vm_name]
|
250
|
+
xml.AdminPassword params[:admin_password]
|
251
|
+
xml.ResetPasswordOnFirstLogon 'false'
|
252
|
+
xml.EnableAutomaticUpdates 'false'
|
253
|
+
if params[:bootstrap_proto].downcase == 'winrm'
|
254
|
+
if params[:ssl_cert_fingerprint]
|
255
|
+
xml.StoredCertificateSettings {
|
256
|
+
xml.CertificateSetting {
|
257
|
+
xml.StoreLocation "LocalMachine"
|
258
|
+
xml.StoreName "My"
|
259
|
+
xml.Thumbprint params[:ssl_cert_fingerprint]
|
260
|
+
}
|
261
|
+
}
|
262
|
+
end
|
263
|
+
xml.WinRM {
|
264
|
+
xml.Listeners {
|
265
|
+
if params[:ssl_cert_fingerprint]
|
266
|
+
xml.Listener {
|
267
|
+
xml.CertificateThumbprint params[:ssl_cert_fingerprint]
|
268
|
+
xml.Protocol 'Https'
|
269
|
+
}
|
270
|
+
else
|
271
|
+
xml.Listener {
|
272
|
+
xml.Protocol 'Http'
|
273
|
+
}
|
274
|
+
end
|
275
|
+
}
|
257
276
|
}
|
258
|
-
|
259
|
-
|
260
|
-
end
|
277
|
+
end
|
278
|
+
xml.AdminUsername params[:winrm_user]
|
261
279
|
}
|
262
280
|
end
|
263
281
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
xml.Name 'SSH'
|
271
|
-
xml.Port params[:port]
|
272
|
-
xml.Protocol 'TCP'
|
273
|
-
}
|
274
|
-
elsif params[:bootstrap_proto].downcase == 'winrm' and params[:os_type] == 'Windows'
|
275
|
-
xml.InputEndpoint {
|
282
|
+
xml.ConfigurationSet('i:type' => 'NetworkConfigurationSet') {
|
283
|
+
xml.ConfigurationSetType 'NetworkConfiguration'
|
284
|
+
xml.InputEndpoints {
|
285
|
+
|
286
|
+
if params[:os_type] == 'Windows' and (params[:bootstrap_proto].downcase == 'winrm' or params[:bootstrap_proto].downcase == 'cloud-api')
|
287
|
+
xml.InputEndpoint {
|
276
288
|
xml.LocalPort '5985'
|
277
289
|
xml.Name 'WinRM'
|
278
290
|
xml.Port params[:port]
|
279
291
|
xml.Protocol 'TCP'
|
280
292
|
}
|
281
|
-
|
282
|
-
|
283
|
-
if params[:tcp_endpoints]
|
284
|
-
params[:tcp_endpoints].split(',').each do |endpoint|
|
285
|
-
ports = endpoint.split(':')
|
286
|
-
if !(ports.length > 1 && ports[1] == params[:port] || ports.length == 1 && ports[0] == params[:port])
|
293
|
+
else
|
287
294
|
xml.InputEndpoint {
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
295
|
+
xml.LocalPort '22'
|
296
|
+
xml.Name 'SSH'
|
297
|
+
xml.Port params[:port]
|
298
|
+
xml.Protocol 'TCP'
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
if params[:tcp_endpoints]
|
303
|
+
params[:tcp_endpoints].split(',').each do |endpoint|
|
304
|
+
ports = endpoint.split(':')
|
305
|
+
if !(ports.length > 1 && ports[1] == params[:port] || ports.length == 1 && ports[0] == params[:port])
|
306
|
+
xml.InputEndpoint {
|
307
|
+
xml.LocalPort ports[0]
|
308
|
+
xml.Name 'tcpport_' + ports[0] + '_' + params[:azure_vm_name]
|
309
|
+
if ports.length > 1
|
310
|
+
xml.Port ports[1]
|
311
|
+
else
|
312
|
+
xml.Port ports[0]
|
313
|
+
end
|
314
|
+
xml.Protocol 'TCP'
|
315
|
+
}
|
292
316
|
else
|
293
|
-
|
317
|
+
warn_message = ports.length > 1 ? "#{ports.join(':')} because this ports are" : "#{ports[0]} because this port is"
|
318
|
+
puts("Skipping tcp-endpoints: #{warn_message} already in use by ssh/winrm endpoint in current VM.")
|
294
319
|
end
|
295
|
-
|
296
|
-
}
|
297
|
-
else
|
298
|
-
warn_message = ports.length > 1 ? "#{ports.join(':')} because this ports are" : "#{ports[0]} because this port is"
|
299
|
-
puts("Skipping tcp-endpoints: #{warn_message} already in use by ssh/winrm endpoint in current VM.")
|
320
|
+
end
|
300
321
|
end
|
301
|
-
end
|
302
|
-
end
|
303
322
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
323
|
+
if params[:udp_endpoints]
|
324
|
+
params[:udp_endpoints].split(',').each do |endpoint|
|
325
|
+
ports = endpoint.split(':')
|
326
|
+
xml.InputEndpoint {
|
327
|
+
xml.LocalPort ports[0]
|
328
|
+
xml.Name 'udpport_' + ports[0] + '_' + params[:azure_vm_name]
|
329
|
+
if ports.length > 1
|
330
|
+
xml.Port ports[1]
|
331
|
+
else
|
332
|
+
xml.Port ports[0]
|
333
|
+
end
|
334
|
+
xml.Protocol 'UDP'
|
335
|
+
}
|
314
336
|
end
|
315
|
-
|
337
|
+
end
|
338
|
+
}
|
339
|
+
if params[:azure_subnet_name]
|
340
|
+
xml.SubnetNames {
|
341
|
+
xml.SubnetName params[:azure_subnet_name]
|
316
342
|
}
|
317
343
|
end
|
318
|
-
end
|
319
344
|
}
|
320
|
-
if params[:azure_subnet_name]
|
321
|
-
xml.SubnetNames {
|
322
|
-
xml.SubnetName params[:azure_subnet_name]
|
323
|
-
}
|
324
|
-
end
|
325
|
-
}
|
326
345
|
}
|
346
|
+
|
327
347
|
if params[:azure_availability_set]
|
328
348
|
xml.AvailabilitySetName params[:azure_availability_set]
|
329
349
|
end
|
350
|
+
# Azure resource extension support
|
351
|
+
if params[:bootstrap_proto] == 'cloud-api'
|
352
|
+
xml.ResourceExtensionReferences {
|
353
|
+
xml.ResourceExtensionReference {
|
354
|
+
xml.ReferenceName params[:chef_extension]
|
355
|
+
xml.Publisher params[:chef_extension_publisher]
|
356
|
+
xml.Name params[:chef_extension]
|
357
|
+
xml.Version params[:chef_extension_version]
|
358
|
+
xml.ResourceExtensionParameterValues {
|
359
|
+
if params[:chef_extension_public_param]
|
360
|
+
xml.ResourceExtensionParameterValue {
|
361
|
+
xml.Key "PublicParams"
|
362
|
+
xml.Value params[:chef_extension_public_param]
|
363
|
+
xml.Type "Public"
|
364
|
+
}
|
365
|
+
end
|
366
|
+
if params[:chef_extension_private_param]
|
367
|
+
xml.ResourceExtensionParameterValue {
|
368
|
+
xml.Key "PrivateParams"
|
369
|
+
xml.Value params[:chef_extension_private_param]
|
370
|
+
xml.Type "Private"
|
371
|
+
}
|
372
|
+
end
|
373
|
+
}
|
374
|
+
xml.State "Enable"
|
375
|
+
}
|
376
|
+
}
|
377
|
+
end
|
378
|
+
|
330
379
|
xml.Label Base64.encode64(params[:azure_vm_name]).strip
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
xml.
|
335
|
-
|
336
|
-
|
380
|
+
|
381
|
+
#OSVirtualHardDisk not required in case azure_source_image is a VMImage
|
382
|
+
unless(params[:is_vm_image])
|
383
|
+
xml.OSVirtualHardDisk {
|
384
|
+
disk_name = params[:azure_os_disk_name] || "disk_" + SecureRandom.uuid
|
385
|
+
xml.DiskName disk_name
|
386
|
+
xml.MediaLink 'http://' + params[:azure_storage_account] + '.blob.core.windows.net/vhds/' + disk_name + '.vhd'
|
387
|
+
xml.SourceImageName params[:azure_source_image]
|
388
|
+
}
|
389
|
+
end
|
390
|
+
|
337
391
|
xml.RoleSize params[:azure_vm_size]
|
392
|
+
xml.ProvisionGuestAgent true if params[:bootstrap_proto] == 'cloud-api'
|
338
393
|
}
|
339
394
|
end
|
340
395
|
builder.doc
|
@@ -44,8 +44,8 @@ class Chef
|
|
44
44
|
|
45
45
|
validate!
|
46
46
|
|
47
|
-
image_labels = !locate_config_value(:show_all_fields) ? ['Name', 'OS', 'Location'] : ['Name', 'Category', 'Label', 'OS', 'Location']
|
48
|
-
image_list = image_labels.map {|label| ui.color(label, :bold)}
|
47
|
+
image_labels = !locate_config_value(:show_all_fields) ? ['Name', 'OS', 'Location'] : ['Name', 'Category', 'Label', 'OS', 'Location']
|
48
|
+
image_list = image_labels.map {|label| ui.color(label, :bold)}
|
49
49
|
items = connection.images.all
|
50
50
|
|
51
51
|
image_items = image_labels.map {|item| item.downcase }
|
@@ -54,7 +54,7 @@ class Chef
|
|
54
54
|
end
|
55
55
|
|
56
56
|
puts "\n"
|
57
|
-
puts h.list(image_list, :uneven_columns_across, !locate_config_value(:show_all_fields) ? 3 : 5)
|
57
|
+
puts h.list(image_list, :uneven_columns_across, !locate_config_value(:show_all_fields) ? 3 : 5)
|
58
58
|
|
59
59
|
end
|
60
60
|
end
|
@@ -40,7 +40,6 @@ class Chef
|
|
40
40
|
|
41
41
|
def load_winrm_deps
|
42
42
|
require 'winrm'
|
43
|
-
require 'em-winrm'
|
44
43
|
require 'chef/knife/winrm'
|
45
44
|
require 'chef/knife/bootstrap_windows_winrm'
|
46
45
|
end
|
@@ -51,7 +50,7 @@ class Chef
|
|
51
50
|
|
52
51
|
option :bootstrap_protocol,
|
53
52
|
:long => "--bootstrap-protocol protocol",
|
54
|
-
:description => "Protocol to bootstrap windows servers. options: winrm
|
53
|
+
:description => "Protocol to bootstrap windows servers. options: 'winrm' or 'ssh' or 'cloud-api'.",
|
55
54
|
:default => "winrm"
|
56
55
|
|
57
56
|
option :chef_node_name,
|
@@ -62,7 +61,8 @@ class Chef
|
|
62
61
|
option :ssh_user,
|
63
62
|
:short => "-x USERNAME",
|
64
63
|
:long => "--ssh-user USERNAME",
|
65
|
-
:description => "The ssh username"
|
64
|
+
:description => "The ssh username",
|
65
|
+
:default => "root"
|
66
66
|
|
67
67
|
option :ssh_password,
|
68
68
|
:short => "-P PASSWORD",
|
@@ -167,12 +167,12 @@ class Chef
|
|
167
167
|
option :tcp_endpoints,
|
168
168
|
:short => "-t PORT_LIST",
|
169
169
|
:long => "--tcp-endpoints PORT_LIST",
|
170
|
-
:description => "Comma
|
170
|
+
:description => "Comma-separated list of TCP local and public ports to open e.g. '80:80,433:5000'"
|
171
171
|
|
172
172
|
option :udp_endpoints,
|
173
173
|
:short => "-u PORT_LIST",
|
174
174
|
:long => "--udp-endpoints PORT_LIST",
|
175
|
-
:description => "Comma
|
175
|
+
:description => "Comma-separated list of UDP local and public ports to open e.g. '80:80,433:5000'"
|
176
176
|
|
177
177
|
option :azure_connect_to_existing_dns,
|
178
178
|
:short => "-c",
|
@@ -213,6 +213,18 @@ class Chef
|
|
213
213
|
:description => "A JSON string to be added to the first run of chef-client",
|
214
214
|
:proc => lambda { |o| JSON.parse(o) }
|
215
215
|
|
216
|
+
option :thumbprint,
|
217
|
+
:long => "--thumbprint THUMBPRINT",
|
218
|
+
:description => "The thumprint of the ssl certificate"
|
219
|
+
|
220
|
+
option :cert_passphrase,
|
221
|
+
:long => "--cert-passphrase PASSWORD",
|
222
|
+
:description => "SSL Certificate Password"
|
223
|
+
|
224
|
+
option :cert_path,
|
225
|
+
:long => "--cert-path PATH",
|
226
|
+
:description => "SSL Certificate Path"
|
227
|
+
|
216
228
|
def strip_non_ascii(string)
|
217
229
|
string.gsub(/[^0-9a-z ]/i, '')
|
218
230
|
end
|
@@ -222,6 +234,7 @@ class Chef
|
|
222
234
|
end
|
223
235
|
|
224
236
|
def wait_until_virtual_machine_ready(retry_interval_in_seconds = 30)
|
237
|
+
|
225
238
|
vm_status = nil
|
226
239
|
puts
|
227
240
|
|
@@ -230,6 +243,24 @@ class Chef
|
|
230
243
|
if vm_status != :vm_status_ready
|
231
244
|
wait_for_virtual_machine_state(:vm_status_ready, 15, retry_interval_in_seconds)
|
232
245
|
end
|
246
|
+
|
247
|
+
msg_server_summary(get_role_server())
|
248
|
+
|
249
|
+
if locate_config_value(:bootstrap_protocol) == "cloud-api"
|
250
|
+
extension_status = wait_for_resource_extension_state(:wagent_provisioning, 5, retry_interval_in_seconds)
|
251
|
+
|
252
|
+
if extension_status != :extension_installing
|
253
|
+
extension_status = wait_for_resource_extension_state(:extension_installing, 5, retry_interval_in_seconds)
|
254
|
+
end
|
255
|
+
|
256
|
+
if extension_status != :extension_provisioning
|
257
|
+
extension_status = wait_for_resource_extension_state(:extension_provisioning, 10, retry_interval_in_seconds)
|
258
|
+
end
|
259
|
+
|
260
|
+
if extension_status != :extension_ready
|
261
|
+
wait_for_resource_extension_state(:extension_ready, 5, retry_interval_in_seconds)
|
262
|
+
end
|
263
|
+
end
|
233
264
|
rescue Exception => e
|
234
265
|
Chef::Log.error("#{e.to_s}")
|
235
266
|
raise 'Verify connectivity to Azure and subscription resource limit compliance (e.g. maximum CPU core limits) and try again.'
|
@@ -265,6 +296,37 @@ class Chef
|
|
265
296
|
vm_status
|
266
297
|
end
|
267
298
|
|
299
|
+
def wait_for_resource_extension_state(extension_status_goal, total_wait_time_in_minutes, retry_interval_in_seconds)
|
300
|
+
|
301
|
+
extension_status_ordering = {:extension_status_not_detected => 0, :wagent_provisioning => 1, :extension_installing => 2, :extension_provisioning => 3, :extension_ready => 4}
|
302
|
+
|
303
|
+
status_description = {:extension_status_not_detected => 'any', :wagent_provisioning => 'wagent provisioning', :extension_installing => "installing", :extension_provisioning => "provisioning", :extension_ready => "ready" }
|
304
|
+
|
305
|
+
print ui.color("Waiting for Resource Extension to reach status '#{status_description[extension_status_goal]}'", :magenta)
|
306
|
+
|
307
|
+
max_polling_attempts = (total_wait_time_in_minutes * 60) / retry_interval_in_seconds
|
308
|
+
polling_attempts = 0
|
309
|
+
|
310
|
+
wait_start_time = Time.now
|
311
|
+
|
312
|
+
begin
|
313
|
+
extension_status = get_extension_status()
|
314
|
+
extension_ready = extension_status_ordering[extension_status[:status]] >= extension_status_ordering[extension_status_goal]
|
315
|
+
print '.'
|
316
|
+
sleep retry_interval_in_seconds if !extension_ready
|
317
|
+
polling_attempts += 1
|
318
|
+
end until extension_ready || polling_attempts >= max_polling_attempts
|
319
|
+
|
320
|
+
if ! extension_ready
|
321
|
+
raise Chef::Exceptions::CommandTimeout, "Resource extension state '#{status_description[extension_status_goal]}' not reached after #{total_wait_time_in_minutes} minutes. #{extension_status[:message]}"
|
322
|
+
end
|
323
|
+
|
324
|
+
elapsed_time_in_minutes = ((Time.now - wait_start_time) / 60).round(2)
|
325
|
+
print ui.color("Resource extension state '#{status_description[extension_status_goal]}' reached after #{elapsed_time_in_minutes} minutes.\n", :cyan)
|
326
|
+
|
327
|
+
extension_status[:status]
|
328
|
+
end
|
329
|
+
|
268
330
|
def get_virtual_machine_status()
|
269
331
|
role = get_role_server()
|
270
332
|
unless role.nil?
|
@@ -280,6 +342,53 @@ class Chef
|
|
280
342
|
return :vm_status_not_detected
|
281
343
|
end
|
282
344
|
|
345
|
+
def get_extension_status()
|
346
|
+
deployment_name = connection.deploys.get_deploy_name_for_hostedservice(locate_config_value(:azure_dns_name))
|
347
|
+
deployment = connection.query_azure("hostedservices/#{locate_config_value(:azure_dns_name)}/deployments/#{deployment_name}")
|
348
|
+
extension_status = Hash.new
|
349
|
+
|
350
|
+
if deployment.at_css('Deployment Name') != nil
|
351
|
+
role_list_xml = deployment.css('RoleInstanceList RoleInstance')
|
352
|
+
role_list_xml.each do |role|
|
353
|
+
if role.at_css("RoleName").text == locate_config_value(:azure_vm_name)
|
354
|
+
lnx_waagent_fail_msg = "Failed to deserialize the status reported by the Guest Agent"
|
355
|
+
waagent_status_msg = role.at_css("GuestAgentStatus FormattedMessage Message").text
|
356
|
+
|
357
|
+
if role.at_css("GuestAgentStatus Status").text == "Ready"
|
358
|
+
extn_status = role.at_css("ResourceExtensionStatusList Status").text
|
359
|
+
|
360
|
+
Chef::Log.debug("Resource extension status is #{extn_status}")
|
361
|
+
|
362
|
+
if extn_status == "Installing"
|
363
|
+
extension_status[:status] = :extension_installing
|
364
|
+
extension_status[:message] = role.at_css("ResourceExtensionStatusList FormattedMessage Message").text
|
365
|
+
elsif extn_status == "NotReady"
|
366
|
+
extension_status[:status] = :extension_provisioning
|
367
|
+
extension_status[:message] = role.at_css("ResourceExtensionStatusList FormattedMessage Message").text
|
368
|
+
elsif extn_status == "Ready"
|
369
|
+
extension_status[:status] = :extension_ready
|
370
|
+
extension_status[:message] = role.at_css("ResourceExtensionStatusList FormattedMessage Message").text
|
371
|
+
else
|
372
|
+
extension_status[:status] = :extension_status_not_detected
|
373
|
+
end
|
374
|
+
# This fix is for linux waagent issue: api unable to deserialize the waagent status.
|
375
|
+
elsif role.at_css("GuestAgentStatus Status").text == "NotReady" and waagent_status_msg == lnx_waagent_fail_msg
|
376
|
+
extension_status[:status] = :extension_ready
|
377
|
+
else
|
378
|
+
extension_status[:status] = :wagent_provisioning
|
379
|
+
extension_status[:message] = role.at_css("GuestAgentStatus Message").text
|
380
|
+
end
|
381
|
+
else
|
382
|
+
extension_status[:status] = :extension_status_not_detected
|
383
|
+
end
|
384
|
+
end
|
385
|
+
else
|
386
|
+
extension_status[:status] = :extension_status_not_detected
|
387
|
+
end
|
388
|
+
|
389
|
+
return extension_status
|
390
|
+
end
|
391
|
+
|
283
392
|
def get_role_server()
|
284
393
|
deploy = connection.deploys.queryDeploy(locate_config_value(:azure_dns_name))
|
285
394
|
deploy.find_role(locate_config_value(:azure_vm_name))
|
@@ -341,6 +450,8 @@ class Chef
|
|
341
450
|
Chef::Log.info("validating...")
|
342
451
|
validate!
|
343
452
|
|
453
|
+
ssh_override_winrm if %w(ssh cloud-api).include?(locate_config_value(:bootstrap_protocol)) and !is_image_windows?
|
454
|
+
|
344
455
|
Chef::Log.info("creating...")
|
345
456
|
|
346
457
|
config[:azure_dns_name] = get_dns_name(locate_config_value(:azure_dns_name))
|
@@ -352,7 +463,7 @@ class Chef
|
|
352
463
|
if connection.hosts.exists?(locate_config_value(:azure_dns_name))
|
353
464
|
remove_hosted_service_on_failure = nil
|
354
465
|
end
|
355
|
-
|
466
|
+
|
356
467
|
#If Storage Account is not specified, check if the geographic location has one to re-use
|
357
468
|
if not locate_config_value(:azure_storage_account)
|
358
469
|
storage_accts = connection.storageaccounts.all
|
@@ -369,14 +480,13 @@ class Chef
|
|
369
480
|
remove_storage_service_on_failure = nil
|
370
481
|
else
|
371
482
|
remove_storage_service_on_failure = locate_config_value(:azure_storage_account)
|
372
|
-
end
|
483
|
+
end
|
373
484
|
end
|
374
485
|
|
375
486
|
begin
|
376
487
|
connection.deploys.create(create_server_def)
|
377
488
|
wait_until_virtual_machine_ready()
|
378
489
|
server = get_role_server()
|
379
|
-
fqdn = server.publicipaddress
|
380
490
|
rescue Exception => e
|
381
491
|
Chef::Log.error("Failed to create the server -- exception being rescued: #{e.to_s}")
|
382
492
|
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
@@ -386,6 +496,12 @@ class Chef
|
|
386
496
|
|
387
497
|
msg_server_summary(server)
|
388
498
|
|
499
|
+
bootstrap_exec(server) unless locate_config_value(:bootstrap_protocol) == 'cloud-api'
|
500
|
+
end
|
501
|
+
|
502
|
+
def bootstrap_exec(server)
|
503
|
+
fqdn = server.publicipaddress
|
504
|
+
|
389
505
|
if is_image_windows?
|
390
506
|
# Set distro to windows-chef-client-msi
|
391
507
|
config[:distro] = "windows-chef-client-msi" if (config[:distro].nil? || config[:distro] == "chef-full")
|
@@ -409,7 +525,7 @@ class Chef
|
|
409
525
|
puts("done")
|
410
526
|
}
|
411
527
|
end
|
412
|
-
|
528
|
+
|
413
529
|
puts("\n")
|
414
530
|
bootstrap_for_windows_node(server,fqdn, port).run
|
415
531
|
else
|
@@ -461,7 +577,6 @@ class Chef
|
|
461
577
|
bootstrap
|
462
578
|
end
|
463
579
|
|
464
|
-
|
465
580
|
def bootstrap_for_windows_node(server, fqdn, port)
|
466
581
|
if locate_config_value(:bootstrap_protocol) == 'winrm'
|
467
582
|
|
@@ -523,15 +638,31 @@ class Chef
|
|
523
638
|
:azure_source_image,
|
524
639
|
:azure_vm_size,
|
525
640
|
])
|
641
|
+
|
642
|
+
if locate_config_value(:winrm_password) and (locate_config_value(:winrm_password).length <= 6 and locate_config_value(:winrm_password).length >= 72)
|
643
|
+
ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
|
644
|
+
exit 1
|
645
|
+
end
|
646
|
+
|
647
|
+
if locate_config_value(:ssh_password) and (locate_config_value(:ssh_password).length <= 6 and locate_config_value(:ssh_password).length >= 72)
|
648
|
+
ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
|
649
|
+
exit 1
|
650
|
+
end
|
651
|
+
|
526
652
|
if locate_config_value(:azure_connect_to_existing_dns) && locate_config_value(:azure_vm_name).nil?
|
527
653
|
ui.error("Specify the VM name using --azure-vm-name option, since you are connecting to existing dns")
|
528
654
|
exit 1
|
529
655
|
end
|
530
656
|
if locate_config_value(:azure_service_location) && locate_config_value(:azure_affinity_group)
|
531
|
-
ui.error("Cannot specify both --
|
657
|
+
ui.error("Cannot specify both --azure-service-location and --azure-affinity-group, use one or the other.")
|
532
658
|
exit 1
|
533
659
|
elsif locate_config_value(:azure_service_location).nil? && locate_config_value(:azure_affinity_group).nil?
|
534
|
-
ui.error("Must specify either --
|
660
|
+
ui.error("Must specify either --azure-service-location or --azure-affinity-group.")
|
661
|
+
exit 1
|
662
|
+
end
|
663
|
+
|
664
|
+
if !(connection.images.exists?(locate_config_value(:azure_source_image)))
|
665
|
+
ui.error("Image provided is invalid")
|
535
666
|
exit 1
|
536
667
|
end
|
537
668
|
end
|
@@ -553,58 +684,101 @@ class Chef
|
|
553
684
|
:azure_availability_set => locate_config_value(:azure_availability_set),
|
554
685
|
:azure_affinity_group => locate_config_value(:azure_affinity_group),
|
555
686
|
:azure_network_name => locate_config_value(:azure_network_name),
|
556
|
-
:azure_subnet_name => locate_config_value(:azure_subnet_name)
|
687
|
+
:azure_subnet_name => locate_config_value(:azure_subnet_name),
|
688
|
+
:ssl_cert_fingerprint => locate_config_value(:thumbprint),
|
689
|
+
:cert_path => locate_config_value(:cert_path),
|
690
|
+
:cert_password => locate_config_value(:cert_passphrase)
|
557
691
|
}
|
558
692
|
# If user is connecting a new VM to an existing dns, then
|
559
693
|
# the VM needs to have a unique public port. Logic below takes care of this.
|
560
694
|
if !is_image_windows? or locate_config_value(:bootstrap_protocol) == 'ssh'
|
561
695
|
port = locate_config_value(:ssh_port) || '22'
|
562
696
|
if locate_config_value(:azure_connect_to_existing_dns) && (port == '22')
|
563
|
-
|
697
|
+
port = Random.rand(64000) + 1000
|
564
698
|
end
|
565
699
|
else
|
566
700
|
port = locate_config_value(:winrm_port) || '5985'
|
567
701
|
if locate_config_value(:azure_connect_to_existing_dns) && (port == '5985')
|
568
|
-
|
702
|
+
port = Random.rand(64000) + 1000
|
569
703
|
end
|
570
704
|
end
|
705
|
+
|
571
706
|
server_def[:port] = port
|
572
707
|
|
708
|
+
if locate_config_value(:bootstrap_protocol) == 'cloud-api'
|
709
|
+
server_def[:chef_extension] = get_chef_extension_name
|
710
|
+
server_def[:chef_extension_publisher] = get_chef_extension_publisher
|
711
|
+
server_def[:chef_extension_version] = get_chef_extension_version
|
712
|
+
server_def[:chef_extension_public_param] = get_chef_extension_public_params
|
713
|
+
server_def[:chef_extension_private_param] = get_chef_extension_private_params
|
714
|
+
else
|
715
|
+
if is_image_windows?
|
716
|
+
if not locate_config_value(:winrm_password) or not locate_config_value(:bootstrap_protocol)
|
717
|
+
ui.error("WinRM Password and Bootstrapping Protocol are compulsory parameters")
|
718
|
+
exit 1
|
719
|
+
end
|
720
|
+
# We can specify the AdminUsername after API version 2013-03-01. However, in this API version,
|
721
|
+
# the AdminUsername is a required parameter.
|
722
|
+
# Also, the user name cannot be Administrator, Admin, Admin1 etc, for enhanced security (provided by Azure)
|
723
|
+
if locate_config_value(:winrm_user).nil? || locate_config_value(:winrm_user).downcase =~ /admin*/
|
724
|
+
ui.error("WinRM User is compulsory parameter and it cannot be named 'admin*'")
|
725
|
+
exit 1
|
726
|
+
end
|
727
|
+
else
|
728
|
+
if not locate_config_value(:ssh_user)
|
729
|
+
ui.error("SSH User is compulsory parameter")
|
730
|
+
exit 1
|
731
|
+
end
|
732
|
+
unless locate_config_value(:ssh_password) or locate_config_value(:identity_file)
|
733
|
+
ui.error("Specify either SSH Key or SSH Password")
|
734
|
+
exit 1
|
735
|
+
end
|
736
|
+
end
|
737
|
+
end
|
573
738
|
if is_image_windows?
|
574
739
|
server_def[:os_type] = 'Windows'
|
575
|
-
if not locate_config_value(:winrm_password) or not locate_config_value(:bootstrap_protocol)
|
576
|
-
ui.error("WinRM Password and Bootstrapping Protocol are compulsory parameters")
|
577
|
-
exit 1
|
578
|
-
end
|
579
|
-
# We can specify the AdminUsername after API version 2013-03-01. However, in this API version,
|
580
|
-
# the AdminUsername is a required parameter.
|
581
|
-
# Also, the user name cannot be Administrator, Admin, Admin1 etc, for enhanced security (provided by Azure)
|
582
|
-
if locate_config_value(:winrm_user).nil? || locate_config_value(:winrm_user).downcase =~ /admin*/
|
583
|
-
ui.error("WinRM User is compulsory parameter and it cannot be named 'admin*'")
|
584
|
-
exit
|
585
|
-
end
|
586
740
|
server_def[:admin_password] = locate_config_value(:winrm_password)
|
587
741
|
server_def[:bootstrap_proto] = locate_config_value(:bootstrap_protocol)
|
588
742
|
else
|
589
743
|
server_def[:os_type] = 'Linux'
|
590
|
-
server_def[:bootstrap_proto] = 'ssh'
|
591
|
-
if not locate_config_value(:ssh_user)
|
592
|
-
ui.error("SSH User is compulsory parameter")
|
593
|
-
exit 1
|
594
|
-
end
|
595
|
-
unless locate_config_value(:ssh_password) or locate_config_value(:identity_file)
|
596
|
-
ui.error("Specify either SSH Key or SSH Password")
|
597
|
-
exit 1
|
598
|
-
end
|
599
|
-
|
744
|
+
server_def[:bootstrap_proto] = locate_config_value(:bootstrap_protocol) || 'ssh'
|
600
745
|
server_def[:ssh_user] = locate_config_value(:ssh_user)
|
601
746
|
server_def[:ssh_password] = locate_config_value(:ssh_password)
|
602
747
|
server_def[:identity_file] = locate_config_value(:identity_file)
|
603
748
|
server_def[:identity_file_passphrase] = locate_config_value(:identity_file_passphrase)
|
604
749
|
end
|
750
|
+
|
751
|
+
server_def[:is_vm_image] = connection.images.is_vm_image(locate_config_value(:azure_source_image))
|
605
752
|
server_def
|
606
753
|
end
|
607
754
|
|
755
|
+
def get_chef_extension_name
|
756
|
+
extension_name = is_image_windows? ? "ChefClient" : "LinuxChefClient"
|
757
|
+
end
|
758
|
+
|
759
|
+
def get_chef_extension_publisher
|
760
|
+
publisher = "Chef.Bootstrap.WindowsAzure"
|
761
|
+
end
|
762
|
+
|
763
|
+
# get latest version
|
764
|
+
def get_chef_extension_version
|
765
|
+
extensions = @connection.query_azure("resourceextensions/#{get_chef_extension_publisher}/#{get_chef_extension_name}")
|
766
|
+
extensions.css("Version").max.text.to_f
|
767
|
+
end
|
768
|
+
|
769
|
+
def get_chef_extension_public_params
|
770
|
+
pub_config = Hash.new
|
771
|
+
pub_config[:client_rb] = "chef_server_url \t #{Chef::Config[:chef_server_url].to_json}\nvalidation_client_name\t#{Chef::Config[:validation_client_name].to_json}"
|
772
|
+
pub_config[:runlist] = locate_config_value(:run_list).empty? ? "" : locate_config_value(:run_list).join(",").to_json
|
773
|
+
Base64.encode64(pub_config.to_json)
|
774
|
+
end
|
775
|
+
|
776
|
+
def get_chef_extension_private_params
|
777
|
+
pri_config = Hash.new
|
778
|
+
pri_config[:validation_key] = File.read(Chef::Config[:validation_key])
|
779
|
+
Base64.encode64(pri_config.to_json)
|
780
|
+
end
|
781
|
+
|
608
782
|
def cleanup_and_exit(remove_hosted_service_on_failure, remove_storage_service_on_failure)
|
609
783
|
ui.warn("Cleaning up resources...")
|
610
784
|
|
@@ -619,8 +793,32 @@ class Chef
|
|
619
793
|
end
|
620
794
|
exit 1
|
621
795
|
end
|
622
|
-
|
796
|
+
|
623
797
|
private
|
798
|
+
|
799
|
+
def ssh_override_winrm
|
800
|
+
# unchanged ssh_user and changed winrm_user, override ssh_user
|
801
|
+
if locate_config_value(:ssh_user).eql?(options[:ssh_user][:default]) &&
|
802
|
+
!locate_config_value(:winrm_user).eql?(options[:winrm_user][:default])
|
803
|
+
config[:ssh_user] = locate_config_value(:winrm_user)
|
804
|
+
end
|
805
|
+
# unchanged ssh_port and changed winrm_port, override ssh_port
|
806
|
+
if locate_config_value(:ssh_port).eql?(options[:ssh_port][:default]) &&
|
807
|
+
!locate_config_value(:winrm_port).eql?(options[:winrm_port][:default])
|
808
|
+
config[:ssh_port] = locate_config_value(:winrm_port)
|
809
|
+
end
|
810
|
+
# unset ssh_password and set winrm_password, override ssh_password
|
811
|
+
if locate_config_value(:ssh_password).nil? &&
|
812
|
+
!locate_config_value(:winrm_password).nil?
|
813
|
+
config[:ssh_password] = locate_config_value(:winrm_password)
|
814
|
+
end
|
815
|
+
# unset identity_file and set kerberos_keytab_file, override identity_file
|
816
|
+
if locate_config_value(:identity_file).nil? &&
|
817
|
+
!locate_config_value(:kerberos_keytab_file).nil?
|
818
|
+
config[:identity_file] = locate_config_value(:kerberos_keytab_file)
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
624
822
|
# This is related to Windows VM's specifically and computer name
|
625
823
|
# length limits for legacy computer accounts
|
626
824
|
MAX_VM_NAME_CHARACTERS = 15
|
@@ -631,10 +829,9 @@ class Chef
|
|
631
829
|
if locate_config_value(:azure_vm_name).nil?
|
632
830
|
azure_dns_name = prefix + SecureRandom.hex(( MAX_VM_NAME_CHARACTERS - prefix.length)/2)
|
633
831
|
else
|
634
|
-
azure_dns_name =
|
832
|
+
azure_dns_name = locate_config_value(:azure_vm_name)
|
635
833
|
end
|
636
834
|
end
|
637
|
-
|
638
835
|
end
|
639
836
|
end
|
640
837
|
end
|
data/lib/knife-azure/version.rb
CHANGED
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.
|
4
|
+
version: 1.4.0.rc.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: 2014-
|
12
|
+
date: 2014-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ! '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.
|
34
|
+
version: 0.8.2
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - ! '>='
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.
|
41
|
+
version: 0.8.2
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: chef
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - ~>
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 0.2.9
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: knife-cloud
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 1.0.0
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 1.0.0
|
84
98
|
description: A plugin to the Chef knife tool for creating instances on the Microsoft
|
85
99
|
Azure platform
|
86
100
|
email: oss@getchef.com
|