knife-azure 1.4.0.rc.0 → 1.4.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NDRlZjIwNmQwNWU1NzVlYzA4NGI3MzNjZTJlNmZkMmNlZmEwZDZiNg==
4
+ YzljMjVkNDdjMGI2MWJmMjBlZmU1ZWYxNTY4MDcxY2IxMDI1YzU3YQ==
5
5
  data.tar.gz: !binary |-
6
- MDgxYzQ2YTU2NGFlZDA0ZmE3MmM0M2UzM2NkNzFlZGZkNWU3MzQyYg==
6
+ MDg0MDc2ZTcwMTA4MTViYzI0MWVhYTkwZmZjNzUyOGUxMDcxYzI1ZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MGIxZTg3ZDEzN2ZlNmIzMzhlYTRhZjdlYjY5OTVkMzRkZDNjMWYzZDBiZjFh
10
- NzlhNjRlMTE3ZTQwMGUwYjQxNTc4NDY3ZDNhZDVkZThjMmFlODgwNGZiYWM0
11
- MDY0YWRiMmQ5OTYwNjBmZGE3YWY3ZGU2OGFmMWRmZGNjOGM5YWE=
9
+ OWRhN2NiMjQ3ZjRlM2NiMDVhZTYwMjI5MGY3YjIwMmEyMTJjM2E2MGZkZTUw
10
+ YzU3NDU4ZDY3NjkzYzQwZjFlMmRjYTQyYzRkNWUyMzA3YjUzMjM4NzgwNGQ5
11
+ ZGZhMjdjYzY2YTZhZDZlYjYyZjgyMzJjNmQ5Zjk0YTQ3M2NkNzY=
12
12
  data.tar.gz: !binary |-
13
- NTlkMTM2Mjc3NDQ3ZmNmNmZlOGQwYzk2MGJhM2EyYWIxMjljYzNiMzIxMWU2
14
- NTY0NDE3MTk2MjBhOGVmZTA5MzY0YWZiMWJjY2E0MmJmNTBiY2IyMzNmZDlm
15
- ZjQ4YWQxYTAxMDZlMWYwYjhiYTdmMGFhZTEwNTcxZjMzZWY2MzY=
13
+ NjQ1NWFiYzZjMTU3ZWU0YmNlY2JmYzM0MDI2ZDdlZWNmZTJkZTcxY2IwYzU4
14
+ NGY0MzMyNTE5MjZlNmRlMjI4YmM1Y2RkOTNjZWQyMmE0NGYzNTY4YTE3YWNm
15
+ NDI5ODU3ZTllNWNkM2QwMTcyMGMwNzAyMjk2NWRhMjBiMzdhOWE=
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Knife Azure
2
2
 
3
3
  ## Description
4
- A [knife] (http://docs.opscode.com/knife.html) plugin to create,
4
+ A [knife] (http://docs.chef.io/knife.html) plugin to create,
5
5
  delete, and enumerate
6
- [Windows Azure] (https://www.windowsazure.com)
6
+ [Microsoft Azure] (https://azure.microsoft.com)
7
7
  resources to be managed by Chef.
8
8
 
9
9
  ## Installation
@@ -46,13 +46,17 @@ location in your knife.rb:
46
46
 
47
47
  # List all VM's (including those not be managed by Chef)
48
48
  $ knife azure server list
49
-
49
+
50
+ # Create and bootstrap a Windows VM over winrm (winrm is the default for Windows)
51
+ $ knife azure server create --azure-dns-name MyNewServerName --azure-vm-size Medium -I a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201412.01-en.us-127GB.vhd --azure-service-location 'West US' --winrm-user myuser --winrm-password 'mypassword'
52
+
50
53
  # Create and bootstrap an Ubuntu VM over ssh
51
54
  $ 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
-
53
- # Create and bootstrap a Windows VM over winrm
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'
55
-
55
+
56
+ # Create and bootstrap an Windows VM through the Azure API --
57
+ # No winrm or ssh transport or Internet access required
58
+ $ knife azure server create --azure-dns-name MyNewServerName --azure-vm-size Medium -I a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201412.01-en.us-127GB.vhd --azure-service-location 'West US' --winrm-user myuser --winrm-password 'mypassword' --bootstrap-protocol winrm --bootstrap-protocol cloud-api
59
+
56
60
  # Delete a server and purge it from the Chef server
57
61
  $ knife azure server delete MyNewNode --purge -y
58
62
 
@@ -84,18 +88,18 @@ Outputs a list of all linux images that are available to use for provisioning. Y
84
88
  This subcommand provisions a new server in Azure and then performs a Chef bootstrap. The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server.
85
89
 
86
90
  #### Windows Bootstrapping Requirements
87
- knife-azure depends on knife-windows: https://github.com/opscode/knife-windows
91
+ knife-azure depends on knife-windows: https://github.com/chef/knife-windows
88
92
  to bootstrap Windows machines via winrm (Basic, NTLM and Kerberos authentication) or ssh.
89
93
 
90
- The distro/template to be used for bootstrapping is: https://github.com/opscode/knife-windows/blob/master/lib/chef/knife/bootstrap/windows-chef-client-msi.erb
94
+ The distro/template to be used for bootstrapping is: https://github.com/chef/knife-windows/blob/master/lib/chef/knife/bootstrap/windows-chef-client-msi.erb
91
95
 
92
96
  Windows source images should have the WinRM service enabled and the
93
97
  authentication should be set accordingly (Basic, NTLM and Kerberos). Firewall rules should be added accordingly to the source images. Refer to the link to configure this:
94
- https://github.com/opscode/knife-windows#nodes
98
+ https://github.com/chef/knife-windows#nodes
95
99
 
96
100
  #### Azure-specific Options
97
101
  :azure_dns_name Required. The DNS prefix name that can be used to access the cloud
98
- service which is unique within Windows Azure. If you want to add
102
+ service which is unique within Microsoft Azure. If you want to add
99
103
  new VM to an existing service/deployment, specify an exiting
100
104
  dns-name, along with --azure-connect-to-existing-dns option. Otherwise
101
105
  a new deployment is created.
@@ -105,7 +109,7 @@ https://github.com/opscode/knife-windows#nodes
105
109
  :azure_source_image Required. Specifies the name of the disk image to use to create
106
110
  the virtual machine. Do a "knife azure image list" to see a
107
111
  list of available images.
108
- :azure_storage_account A name for the storage account that is unique within Windows Azure.
112
+ :azure_storage_account A name for the storage account that is unique within Microsoft Azure.
109
113
  Storage account names must be between 3 and 24 characters in
110
114
  length and use numbers and lower-case letters only. This name is
111
115
  the DNS prefix name and can be used to access blobs, queues, and
@@ -29,6 +29,13 @@ class Azure
29
29
  certificate = Certificate.new(@connection)
30
30
  certificate.add_certificate certificate_data, certificate_password, certificate_format, dns_name
31
31
  end
32
+
33
+ def create_ssl_certificate(azure_dns_name)
34
+ cert_params = { output_file: 'winrm', key_length: 2048, cert_validity: 24,
35
+ azure_dns_name: azure_dns_name }
36
+ certificate = Certificate.new(@connection)
37
+ thumbprint = certificate.create_ssl_certificate(cert_params)
38
+ end
32
39
  end
33
40
  end
34
41
 
@@ -92,5 +99,112 @@ class Azure
92
99
  @connection.query_azure("hostedservices/#{dns_name}/certificates", "post", builder.to_xml)
93
100
  end
94
101
 
102
+ ######## SSL certificate generation for knife-azure ssl bootstrap ######
103
+
104
+ def create_ssl_certificate cert_params
105
+ file_path = cert_params[:output_file].sub(/\.(\w+)$/,'')
106
+ path = prompt_for_file_path
107
+ file_path = File.join(path, file_path) unless path.empty?
108
+ cert_params[:domain] = prompt_for_domain
109
+
110
+ rsa_key = generate_keypair cert_params[:key_length]
111
+ cert = generate_certificate(rsa_key, cert_params)
112
+ write_certificate_to_file cert, file_path, rsa_key, cert_params
113
+ puts "*"*70
114
+ puts "Generated Certificates:"
115
+ puts "- #{file_path}.pfx - PKCS12 format keypair. Contains both the public and private keys, usually used on the server."
116
+ puts "- #{file_path}.b64 - Base64 encoded PKCS12 keypair. Contains both the public and private keys, for upload to the Azure REST API."
117
+ puts "- #{file_path}.pem - Base64 encoded public certificate only. Required by the client to connect to the server."
118
+ puts "Certificate Thumbprint: #{@thumbprint.to_s.upcase}"
119
+ puts "*"*70
120
+
121
+ Chef::Config[:knife][:ca_trust_file] = file_path + ".pem" if Chef::Config[:knife][:ca_trust_file].nil?
122
+ cert_data = File.read (file_path + ".b64")
123
+ add_certificate cert_data, @winrm_cert_passphrase, 'pfx', cert_params[:azure_dns_name]
124
+ @thumbprint
125
+ end
126
+
127
+ def generate_keypair key_length
128
+ OpenSSL::PKey::RSA.new(key_length.to_i)
129
+ end
130
+
131
+ def prompt_for_passphrase
132
+ passphrase = ""
133
+ begin
134
+ print "Passphrases do not match. Try again.\n" unless passphrase.empty?
135
+ print "Enter certificate passphrase (empty for no passphrase):"
136
+ passphrase = STDIN.gets
137
+ return passphrase.strip if passphrase == "\n"
138
+ print "Enter same passphrase again:"
139
+ confirm_passphrase = STDIN.gets
140
+ end until passphrase == confirm_passphrase
141
+ passphrase.strip
142
+ end
143
+
144
+ def prompt_for_file_path
145
+ file_path = ''
146
+ counter = 0
147
+ begin
148
+ print "Invalid location! \n" unless file_path.empty?
149
+ print 'Enter the file path for certificates e.g. C:\Windows (empty for current location):'
150
+ file_path = STDIN.gets
151
+ stripped_file_path = file_path.strip
152
+ return stripped_file_path if file_path == "\n"
153
+ counter += 1
154
+ exit(1) if counter == 3
155
+ end until File.directory?(stripped_file_path)
156
+ stripped_file_path
157
+ end
158
+
159
+ def prompt_for_domain
160
+ counter = 0
161
+ begin
162
+ print 'Enter the domain (mandatory):'
163
+ domain = STDIN.gets
164
+ domain = domain.strip
165
+ counter += 1
166
+ exit(1) if counter == 3
167
+ end until !domain.empty?
168
+ domain
169
+ end
170
+
171
+ def generate_certificate(rsa_key, cert_params)
172
+ @hostname = "*"
173
+ if cert_params[:domain]
174
+ @hostname = "*." + cert_params[:domain]
175
+ end
176
+
177
+ #Create a self-signed X509 certificate from the rsa_key (unencrypted)
178
+ cert = OpenSSL::X509::Certificate.new
179
+ cert.version = 2
180
+ cert.serial = Random.rand(65534) + 1 # 2 digit byte range random number for better security aspect
181
+
182
+ cert.subject = OpenSSL::X509::Name.parse "/CN=#{@hostname}"
183
+ cert.issuer = cert.subject
184
+ cert.public_key = rsa_key.public_key
185
+ cert.not_before = Time.now
186
+ cert.not_after = cert.not_before + 2 * 365 * cert_params[:cert_validity].to_i * 60 * 60 # 2 years validity
187
+ ef = OpenSSL::X509::ExtensionFactory.new
188
+ ef.subject_certificate = cert
189
+ ef.issuer_certificate = cert
190
+ cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
191
+ cert.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
192
+ cert.add_extension(ef.create_extension("extendedKeyUsage", "1.3.6.1.5.5.7.3.1", false))
193
+ cert.sign(rsa_key, OpenSSL::Digest::SHA1.new)
194
+ @thumbprint = OpenSSL::Digest::SHA1.new(cert.to_der)
195
+ cert
196
+ end
197
+
198
+ def write_certificate_to_file cert, file_path, rsa_key, cert_params
199
+ File.open(file_path + ".pem", "wb") { |f| f.print cert.to_pem }
200
+ @winrm_cert_passphrase = prompt_for_passphrase unless @winrm_cert_passphrase
201
+ pfx = OpenSSL::PKCS12.create("#{cert_params[:winrm_cert_passphrase]}", "winrmcert", rsa_key, cert)
202
+ File.open(file_path + ".pfx", "wb") { |f| f.print pfx.to_der }
203
+ File.open(file_path + ".b64", "wb") { |f| f.print Base64.strict_encode64(pfx.to_der) }
204
+ end
205
+
206
+ ########## SSL certificate generation ends ###########
207
+
208
+
95
209
  end
96
210
  end
@@ -81,7 +81,11 @@ class Azure
81
81
  if params[:cert_path]
82
82
  cert_data = File.read (params[:cert_path])
83
83
  @connection.certificates.add cert_data, params[:cert_password], 'pfx', params[:azure_dns_name]
84
+ elsif(params[:winrm_transport] == "ssl")
85
+ thumbprint = @connection.certificates.create_ssl_certificate params[:azure_dns_name]
86
+ params[:ssl_cert_fingerprint] = thumbprint.to_s.upcase
84
87
  end
88
+
85
89
  params['deploy_name'] = get_deploy_name_for_hostedservice(params[:azure_dns_name])
86
90
 
87
91
  if params['deploy_name'] != nil
@@ -63,26 +63,55 @@ class Azure
63
63
 
64
64
  def parse(image)
65
65
  @name = image.at_css('Name').content
66
- @affinity_group = image.at_css('AffinityGroup').content
66
+ @affinity_group = image.at_css('AffinityGroup') ? image.at_css('AffinityGroup').content : ""
67
67
  @state = image.at_css('State').content
68
68
  self
69
69
  end
70
70
 
71
71
  def create(params)
72
72
  response = @connection.query_azure('networking/media')
73
- vnets = response.css('VirtualNetworkSite')
74
- vnet = nil
75
- vnets.each { |vn| vnet = vn if vn['name'] == params[:azure_vnet_name] }
76
- add = vnet.nil?
77
- vnet = Nokogiri::XML::Node.new('VirtualNetworkSite', response) if add
78
- vnet['name'] = params[:azure_vnet_name]
79
- vnet['AffinityGroup'] = params[:azure_ag_name]
80
- addr_space = Nokogiri::XML::Node.new('AddressSpace', response)
81
- addr_prefix = Nokogiri::XML::Node.new('AddressPrefix', response)
82
- addr_prefix.content = params[:azure_address_space]
83
- addr_space.children = addr_prefix
84
- vnet.children = addr_space
85
- vnets.last.add_next_sibling(vnet) if add
73
+ if response.at_css("Error") && response.at_css('Code').text == "ResourceNotFound"
74
+ builder = Nokogiri::XML::Builder.new do |xml|
75
+ xml.NetworkConfiguration(
76
+ 'xmlns'=>'http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration'
77
+ ) {
78
+
79
+ xml.VirtualNetworkConfiguration {
80
+ xml.VirtualNetworkSites {
81
+ xml.VirtualNetworkSite('name' => params[:azure_vnet_name], 'AffinityGroup' => params[:azure_ag_name]) {
82
+ if params[:azure_address_space]
83
+ xml.AddressSpace {
84
+ xml.AddressPrefix params[:azure_address_space]
85
+ }
86
+ end
87
+ xml.Subnets{
88
+ xml.Subnet('name' => params[:azure_subnet_name]) {
89
+ xml.AddressPrefix params[:azure_address_space]
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ end
97
+ puts("Creating New Virtual Network: #{params[:azure_vnet_name]}...")
98
+ response = builder
99
+ else
100
+ vnets = response.css('VirtualNetworkSite')
101
+ vnet = nil
102
+ vnets.each { |vn| vnet = vn if vn['name'] == params[:azure_vnet_name] }
103
+ add = vnet.nil?
104
+ vnet = Nokogiri::XML::Node.new('VirtualNetworkSite', response) if add
105
+ vnet['name'] = params[:azure_vnet_name]
106
+ vnet['AffinityGroup'] = params[:azure_ag_name]
107
+ addr_space = Nokogiri::XML::Node.new('AddressSpace', response)
108
+ addr_prefix = Nokogiri::XML::Node.new('AddressPrefix', response)
109
+ addr_prefix.content = params[:azure_address_space]
110
+ addr_space.children = addr_prefix
111
+ vnet.children = addr_space
112
+ vnets.last.add_next_sibling(vnet) if add
113
+ puts("Updating existing Virtual Network: #{params[:azure_vnet_name]}...")
114
+ end
86
115
  @connection.query_azure('networking/media', 'put', response.to_xml)
87
116
  end
88
117
  end
@@ -40,6 +40,7 @@ class Chef
40
40
 
41
41
  def load_winrm_deps
42
42
  require 'winrm'
43
+ require 'em-winrm'
43
44
  require 'chef/knife/winrm'
44
45
  require 'chef/knife/bootstrap_windows_winrm'
45
46
  end
@@ -71,8 +72,7 @@ class Chef
71
72
 
72
73
  option :ssh_port,
73
74
  :long => "--ssh-port PORT",
74
- :description => "The ssh port. Default is 22.",
75
- :default => '22'
75
+ :description => "The ssh port. Default is 22. If --azure-connect-to-existing-dns set then default SSH port is random"
76
76
 
77
77
  option :prerelease,
78
78
  :long => "--prerelease",
@@ -190,6 +190,16 @@ class Chef
190
190
  :long => "--azure-subnet-name SUBNET_NAME",
191
191
  :description => "Optional. Specifies the subnet of virtual machine"
192
192
 
193
+ option :azure_vm_startup_timeout,
194
+ :long => "--azure-vm-startup-timeout TIMEOUT",
195
+ :description => "The number of minutes that knife-azure will wait for the virtual machine to reach the 'provisioning' state. Default is 10.",
196
+ :default => 10
197
+
198
+ option :azure_vm_ready_timeout,
199
+ :long => "--azure-vm-ready-timeout TIMEOUT",
200
+ :description => "The number of minutes that knife-azure will wait for the virtual machine state to transition from 'provisioning' to 'ready'. Default is 15.",
201
+ :default => 15
202
+
193
203
  option :identity_file,
194
204
  :long => "--identity-file FILENAME",
195
205
  :description => "SSH identity file for authentication, optional. It is the RSA private key path. Specify either ssh-password or identity-file"
@@ -225,6 +235,12 @@ class Chef
225
235
  :long => "--cert-path PATH",
226
236
  :description => "SSL Certificate Path"
227
237
 
238
+ option :auto_update_client,
239
+ :long => "--auto-update-client",
240
+ :boolean => true,
241
+ :default => false,
242
+ :description => "Set this flag to enable auto chef client update in azure chef extension. This flag should be used with cloud-api bootstrap protocol only"
243
+
228
244
  def strip_non_ascii(string)
229
245
  string.gsub(/[^0-9a-z ]/i, '')
230
246
  end
@@ -236,12 +252,15 @@ class Chef
236
252
  def wait_until_virtual_machine_ready(retry_interval_in_seconds = 30)
237
253
 
238
254
  vm_status = nil
255
+
239
256
  puts
240
257
 
241
258
  begin
242
- vm_status = wait_for_virtual_machine_state(:vm_status_provisioning, 5, retry_interval_in_seconds)
259
+ azure_vm_startup_timeout = locate_config_value(:azure_vm_startup_timeout).to_i
260
+ azure_vm_ready_timeout = locate_config_value(:azure_vm_ready_timeout).to_i
261
+ vm_status = wait_for_virtual_machine_state(:vm_status_provisioning, azure_vm_startup_timeout, retry_interval_in_seconds)
243
262
  if vm_status != :vm_status_ready
244
- wait_for_virtual_machine_state(:vm_status_ready, 15, retry_interval_in_seconds)
263
+ wait_for_virtual_machine_state(:vm_status_ready, azure_vm_ready_timeout, retry_interval_in_seconds)
245
264
  end
246
265
 
247
266
  msg_server_summary(get_role_server())
@@ -590,7 +609,7 @@ class Chef
590
609
  bootstrap.config[:winrm_user] = locate_config_value(:winrm_user) || 'Administrator'
591
610
  bootstrap.config[:winrm_password] = locate_config_value(:winrm_password)
592
611
  bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
593
-
612
+ bootstrap.config[:winrm_authentication_protocol] = locate_config_value(:winrm_authentication_protocol)
594
613
  bootstrap.config[:winrm_port] = port
595
614
 
596
615
  elsif locate_config_value(:bootstrap_protocol) == 'ssh'
@@ -653,6 +672,7 @@ class Chef
653
672
  ui.error("Specify the VM name using --azure-vm-name option, since you are connecting to existing dns")
654
673
  exit 1
655
674
  end
675
+
656
676
  if locate_config_value(:azure_service_location) && locate_config_value(:azure_affinity_group)
657
677
  ui.error("Cannot specify both --azure-service-location and --azure-affinity-group, use one or the other.")
658
678
  exit 1
@@ -661,6 +681,11 @@ class Chef
661
681
  exit 1
662
682
  end
663
683
 
684
+ if locate_config_value(:winrm_authentication_protocol) && ! %w{basic negotiate kerberos}.include?(locate_config_value(:winrm_authentication_protocol))
685
+ ui.error("Invalid value for --winrm-authentication-protocol option. Use valid protocol values i.e [basic, negotiate, kerberos]")
686
+ exit 1
687
+ end
688
+
664
689
  if !(connection.images.exists?(locate_config_value(:azure_source_image)))
665
690
  ui.error("Image provided is invalid")
666
691
  exit 1
@@ -687,19 +712,22 @@ class Chef
687
712
  :azure_subnet_name => locate_config_value(:azure_subnet_name),
688
713
  :ssl_cert_fingerprint => locate_config_value(:thumbprint),
689
714
  :cert_path => locate_config_value(:cert_path),
690
- :cert_password => locate_config_value(:cert_passphrase)
715
+ :cert_password => locate_config_value(:cert_passphrase),
716
+ :winrm_transport => locate_config_value(:winrm_transport)
691
717
  }
692
718
  # If user is connecting a new VM to an existing dns, then
693
719
  # the VM needs to have a unique public port. Logic below takes care of this.
694
720
  if !is_image_windows? or locate_config_value(:bootstrap_protocol) == 'ssh'
695
- port = locate_config_value(:ssh_port) || '22'
696
- if locate_config_value(:azure_connect_to_existing_dns) && (port == '22')
697
- port = Random.rand(64000) + 1000
721
+ if locate_config_value(:azure_connect_to_existing_dns)
722
+ port = locate_config_value(:ssh_port) || Random.rand(64000) + 1000
723
+ else
724
+ port = locate_config_value(:ssh_port) || '22'
698
725
  end
699
726
  else
700
- port = locate_config_value(:winrm_port) || '5985'
701
- if locate_config_value(:azure_connect_to_existing_dns) && (port == '5985')
702
- port = Random.rand(64000) + 1000
727
+ if locate_config_value(:azure_connect_to_existing_dns)
728
+ port = locate_config_value(:winrm_port) || Random.rand(64000) + 1000
729
+ else
730
+ port = locate_config_value(:winrm_port) || '5985'
703
731
  end
704
732
  end
705
733
 
@@ -724,6 +752,11 @@ class Chef
724
752
  ui.error("WinRM User is compulsory parameter and it cannot be named 'admin*'")
725
753
  exit 1
726
754
  end
755
+ # take cares of when user name contains domain
756
+ # azure add role api doesn't support '\\' in user name
757
+ if locate_config_value(:winrm_user) && locate_config_value(:winrm_user).split("\\").length.eql?(2)
758
+ server_def[:winrm_user] = locate_config_value(:winrm_user).split("\\")[1]
759
+ end
727
760
  else
728
761
  if not locate_config_value(:ssh_user)
729
762
  ui.error("SSH User is compulsory parameter")
@@ -763,13 +796,14 @@ class Chef
763
796
  # get latest version
764
797
  def get_chef_extension_version
765
798
  extensions = @connection.query_azure("resourceextensions/#{get_chef_extension_publisher}/#{get_chef_extension_name}")
766
- extensions.css("Version").max.text.to_f
799
+ extensions.css("Version").max.text.split(".").first + ".*"
767
800
  end
768
801
 
769
802
  def get_chef_extension_public_params
770
803
  pub_config = Hash.new
771
804
  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
805
  pub_config[:runlist] = locate_config_value(:run_list).empty? ? "" : locate_config_value(:run_list).join(",").to_json
806
+ pub_config[:autoUpdateClient] = locate_config_value(:auto_update_client) ? "true" : "false"
773
807
  Base64.encode64(pub_config.to_json)
774
808
  end
775
809
 
@@ -42,6 +42,11 @@ class Chef
42
42
  :description =>
43
43
  'Specifies the address space of the vnet using CIDR notation.'
44
44
 
45
+ option :azure_subnet_name,
46
+ :long => '--azure-subnet-name CIDR',
47
+ :description =>
48
+ 'Specifies the Subnet Name.'
49
+
45
50
  def run
46
51
  $stdout.sync = true
47
52
 
@@ -57,6 +62,7 @@ class Chef
57
62
  azure_vnet_name: locate_config_value(:azure_network_name),
58
63
  azure_ag_name: locate_config_value(:azure_affinity_group),
59
64
  azure_address_space: locate_config_value(:azure_address_space),
65
+ azure_subnet_name: locate_config_value(:azure_subnet_name) || "Subnet-#{Random.rand(10)}"
60
66
  }
61
67
 
62
68
  rsp = connection.vnets.create(params)
@@ -1,6 +1,6 @@
1
1
  module Knife
2
2
  module Azure
3
- VERSION = "1.4.0.rc.0"
3
+ VERSION = "1.4.0.rc.1"
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.4.0.rc.0
4
+ version: 1.4.0.rc.1
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-02 00:00:00.000000000 Z
12
+ date: 2015-02-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -46,6 +46,9 @@ dependencies:
46
46
  - - ! '>='
47
47
  - !ruby/object:Gem::Version
48
48
  version: 11.8.2
49
+ - - <
50
+ - !ruby/object:Gem::Version
51
+ version: '12'
49
52
  type: :development
50
53
  prerelease: false
51
54
  version_requirements: !ruby/object:Gem::Requirement
@@ -53,6 +56,9 @@ dependencies:
53
56
  - - ! '>='
54
57
  - !ruby/object:Gem::Version
55
58
  version: 11.8.2
59
+ - - <
60
+ - !ruby/object:Gem::Version
61
+ version: '12'
56
62
  - !ruby/object:Gem::Dependency
57
63
  name: mixlib-config
58
64
  requirement: !ruby/object:Gem::Requirement