knife-azure 1.9.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/azure/azure_interface.rb +2 -3
  3. data/lib/azure/custom_errors.rb +1 -1
  4. data/lib/azure/helpers.rb +1 -1
  5. data/lib/azure/resource_management/ARM_deployment_template.rb +157 -162
  6. data/lib/azure/resource_management/ARM_interface.rb +72 -73
  7. data/lib/azure/resource_management/vnet_config.rb +11 -10
  8. data/lib/azure/resource_management/windows_credentials.rb +19 -19
  9. data/lib/azure/service_management/ASM_interface.rb +6 -5
  10. data/lib/azure/service_management/ag.rb +11 -11
  11. data/lib/azure/service_management/certificate.rb +7 -5
  12. data/lib/azure/service_management/connection.rb +10 -10
  13. data/lib/azure/service_management/deploy.rb +12 -14
  14. data/lib/azure/service_management/disk.rb +4 -2
  15. data/lib/azure/service_management/host.rb +7 -4
  16. data/lib/azure/service_management/image.rb +4 -4
  17. data/lib/azure/service_management/loadbalancer.rb +2 -2
  18. data/lib/azure/service_management/rest.rb +9 -8
  19. data/lib/azure/service_management/role.rb +67 -70
  20. data/lib/azure/service_management/storageaccount.rb +5 -3
  21. data/lib/azure/service_management/utility.rb +1 -1
  22. data/lib/azure/service_management/vnet.rb +1 -1
  23. data/lib/chef/knife/azure_ag_create.rb +13 -13
  24. data/lib/chef/knife/azure_ag_list.rb +1 -1
  25. data/lib/chef/knife/azure_base.rb +49 -66
  26. data/lib/chef/knife/azure_image_list.rb +6 -6
  27. data/lib/chef/knife/azure_internal-lb_create.rb +14 -14
  28. data/lib/chef/knife/azure_internal-lb_list.rb +1 -1
  29. data/lib/chef/knife/azure_server_create.rb +233 -268
  30. data/lib/chef/knife/azure_server_delete.rb +31 -31
  31. data/lib/chef/knife/azure_server_list.rb +1 -1
  32. data/lib/chef/knife/azure_server_show.rb +1 -1
  33. data/lib/chef/knife/azure_vnet_create.rb +15 -19
  34. data/lib/chef/knife/azure_vnet_list.rb +1 -1
  35. data/lib/chef/knife/azurerm_base.rb +39 -28
  36. data/lib/chef/knife/azurerm_server_create.rb +112 -177
  37. data/lib/chef/knife/azurerm_server_delete.rb +13 -13
  38. data/lib/chef/knife/azurerm_server_list.rb +1 -1
  39. data/lib/chef/knife/azurerm_server_show.rb +1 -1
  40. data/lib/chef/knife/bootstrap/bootstrapper.rb +34 -238
  41. data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +77 -76
  42. data/lib/chef/knife/bootstrap_azure.rb +56 -33
  43. data/lib/chef/knife/bootstrap_azurerm.rb +46 -29
  44. data/lib/knife-azure/version.rb +18 -1
  45. metadata +28 -16
  46. data/lib/chef/knife/bootstrap/bootstrap_options.rb +0 -105
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Author:: Aiman Alsari (aiman.alsari@gmail.com)
3
- # Copyright:: Copyright 2013-2018 Chef Software, Inc.
3
+ # Copyright:: Copyright 2010-2019, Chef Software Inc.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -2,7 +2,7 @@
2
2
  # Author:: Barry Davis (barryd@jetstreamsoftware.com)
3
3
  # Author:: Adam Jacob (<adam@chef.io>)
4
4
  # Author:: Seth Chisamore (<schisamo@chef.io>)
5
- # Copyright:: Copyright 2010-2018 Chef Software, Inc.
5
+ # Copyright:: Copyright 2010-2019, Chef Software Inc.
6
6
  # License:: Apache License, Version 2.0
7
7
  #
8
8
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,216 +19,211 @@
19
19
  #
20
20
 
21
21
  require "chef/knife/azure_base"
22
- require "chef/knife/winrm_base"
23
22
  require "securerandom"
24
- require "chef/knife/bootstrap/bootstrap_options"
23
+ require "chef/knife/bootstrap"
24
+ require "chef/knife/bootstrap/client_builder"
25
+ require "chef/knife/bootstrap/common_bootstrap_options"
25
26
  require "chef/knife/bootstrap/bootstrapper"
26
27
 
27
28
  class Chef
28
29
  class Knife
29
- class AzureServerCreate < Knife
30
-
30
+ class AzureServerCreate < Knife::Bootstrap
31
31
  include Knife::AzureBase
32
- include Knife::WinrmBase
33
- include Knife::Bootstrap::BootstrapOptions
32
+ include Knife::Bootstrap::CommonBootstrapOptions
34
33
  include Knife::Bootstrap::Bootstrapper
35
34
 
36
35
  deps do
37
36
  require "readline"
38
37
  require "chef/json_compat"
39
38
  require "chef/knife/bootstrap"
40
- require "chef/knife/bootstrap_windows_ssh"
41
39
  require "chef/knife/core/windows_bootstrap_context"
42
40
  Chef::Knife::Bootstrap.load_deps
43
41
  end
44
42
 
45
43
  banner "knife azure server create (options)"
46
44
 
47
- attr_accessor :initial_sleep_delay
45
+ SUPPORTED_CONNECTION_PROTOCOLS = %w{ssh winrm cloud-api}.freeze
48
46
 
49
- option :bootstrap_protocol,
50
- :long => "--bootstrap-protocol protocol",
51
- :description => "Protocol to bootstrap windows servers. options: 'winrm' or 'ssh' or 'cloud-api'.",
52
- :default => "winrm"
53
-
54
- option :ssh_user,
55
- :short => "-x USERNAME",
56
- :long => "--ssh-user USERNAME",
57
- :description => "The ssh username",
58
- :default => "root"
59
-
60
- option :ssh_password,
61
- :short => "-P PASSWORD",
62
- :long => "--ssh-password PASSWORD",
63
- :description => "The ssh password"
64
-
65
- option :ssh_port,
66
- :long => "--ssh-port PORT",
67
- :description => "The ssh port. Default is 22. If --azure-connect-to-existing-dns set then default SSH port is random"
68
-
69
- option :node_ssl_verify_mode,
70
- :long => "--node-ssl-verify-mode [peer|none]",
71
- :description => "Whether or not to verify the SSL cert for all HTTPS requests.",
72
- :proc => Proc.new { |v|
73
- valid_values = %w{none peer}
74
- unless valid_values.include?(v)
75
- raise "Invalid value '#{v}' for --node-ssl-verify-mode. Valid values are: #{valid_values.join(", ")}"
76
- end
77
- }
78
-
79
- option :node_verify_api_cert,
80
- :long => "--[no-]node-verify-api-cert",
81
- :description => "Verify the SSL cert for HTTPS requests to the Chef server API.",
82
- :boolean => true
83
-
84
- option :azure_storage_account,
85
- :short => "-a NAME",
86
- :long => "--azure-storage-account NAME",
87
- :description => "Required for advanced server-create option.
88
- A name for the storage account that is unique within Windows Azure. Storage account names must be
89
- between 3 and 24 characters in length and use numbers and lower-case letters only.
90
- This name is the DNS prefix name and can be used to access blobs, queues, and tables in the storage account.
91
- For example: http://ServiceName.blob.core.windows.net/mycontainer/"
92
-
93
- option :azure_vm_name,
94
- :long => "--azure-vm-name NAME",
95
- :description => "Required for advanced server-create option.
96
- Specifies the name for the virtual machine. The name must be unique within the deployment. The azure vm name cannot be more than 15 characters long"
97
-
98
- option :azure_service_location,
99
- :short => "-m LOCATION",
100
- :long => "--azure-service-location LOCATION",
101
- :description => "Required if not using an Affinity Group. Specifies the geographic location - the name of the data center location that is valid for your subscription.
102
- Eg: West US, East US, East Asia, Southeast Asia, North Europe, West Europe",
103
- :proc => Proc.new { |lo| Chef::Config[:knife][:azure_service_location] = lo }
47
+ attr_accessor :initial_sleep_delay
104
48
 
105
49
  option :azure_affinity_group,
106
- :short => "-a GROUP",
107
- :long => "--azure-affinity-group GROUP",
108
- :description => "Required if not using a Service Location. Specifies Affinity Group the VM should belong to."
50
+ short: "-a GROUP",
51
+ long: "--azure-affinity-group GROUP",
52
+ description: "Required if not using a Service Location. Specifies Affinity Group the VM should belong to."
109
53
 
110
54
  option :azure_dns_name,
111
- :short => "-d DNS_NAME",
112
- :long => "--azure-dns-name DNS_NAME",
113
- :description => "The DNS prefix name that can be used to access the cloud service which is unique within Windows Azure. Default is 'azure-dns-any_random_text'(e.g: azure-dns-be9b0f6f-7dda-456f-b2bf-4e28a3bc0add).
55
+ short: "-d DNS_NAME",
56
+ long: "--azure-dns-name DNS_NAME",
57
+ description: "The DNS prefix name that can be used to access the cloud service which is unique within Windows Azure. Default is 'azure-dns-any_random_text'(e.g: azure-dns-be9b0f6f-7dda-456f-b2bf-4e28a3bc0add).
114
58
  If you want to add new VM to an existing service/deployment, specify an exiting dns-name,
115
59
  along with --azure-connect-to-existing-dns option.
116
60
  Otherwise a new deployment is created. For example, if the DNS of cloud service is MyService you could access the cloud service
117
61
  by calling: http://DNS_NAME.cloudapp.net"
118
62
 
119
- option :azure_os_disk_name,
120
- :short => "-o DISKNAME",
121
- :long => "--azure-os-disk-name DISKNAME",
122
- :description => "Optional. Specifies the friendly name of the disk containing the guest OS image in the image repository."
123
-
124
63
  option :azure_source_image,
125
- :short => "-I IMAGE",
126
- :long => "--azure-source-image IMAGE",
127
- :description => "Required. Specifies the name of the disk image to use to create the virtual machine.
64
+ short: "-I IMAGE",
65
+ long: "--azure-source-image IMAGE",
66
+ description: "Required. Specifies the name of the disk image to use to create the virtual machine.
128
67
  Do a \"knife azure image list\" to see a list of available images."
129
68
 
130
- option :azure_vm_size,
131
- :short => "-z SIZE",
132
- :long => "--azure-vm-size SIZE",
133
- :description => "Optional. Size of virtual machine. Default is Standard_A1_v2.
134
- Eg: Standard_A1_v2, Standard_F2, Standard_G1 etc.",
135
- :default => "Standard_A1_v2",
136
- :proc => Proc.new { |si| Chef::Config[:knife][:azure_vm_size] = si }
137
-
138
- option :azure_availability_set,
139
- :long => "--azure-availability-set NAME",
140
- :description => "Optional. Name of availability set to add virtual machine into."
141
-
142
- option :tcp_endpoints,
143
- :short => "-t PORT_LIST",
144
- :long => "--tcp-endpoints PORT_LIST",
145
- :description => "Comma-separated list of TCP local and public ports to open e.g. '80:80,433:5000'"
146
-
147
69
  option :udp_endpoints,
148
- :short => "-u PORT_LIST",
149
- :long => "--udp-endpoints PORT_LIST",
150
- :description => "Comma-separated list of UDP local and public ports to open e.g. '80:80,433:5000'"
70
+ short: "-u PORT_LIST",
71
+ long: "--udp-endpoints PORT_LIST",
72
+ description: "Comma-separated list of UDP local and public ports to open e.g. '80:80,433:5000'"
151
73
 
152
74
  option :azure_connect_to_existing_dns,
153
- :short => "-c",
154
- :long => "--azure-connect-to-existing-dns",
155
- :boolean => true,
156
- :default => false,
157
- :description => "Set this flag to add the new VM to an existing deployment/service. Must give the name of the existing
75
+ short: "-c",
76
+ long: "--azure-connect-to-existing-dns",
77
+ boolean: true,
78
+ default: false,
79
+ description: "Set this flag to add the new VM to an existing deployment/service. Must give the name of the existing
158
80
  DNS correctly in the --dns-name option"
159
81
 
160
82
  option :azure_network_name,
161
- :long => "--azure-network-name NETWORK_NAME",
162
- :description => "Optional. Specifies the network of virtual machine"
83
+ long: "--azure-network-name NETWORK_NAME",
84
+ description: "Optional. Specifies the network of virtual machine"
163
85
 
164
86
  option :azure_subnet_name,
165
- :long => "--azure-subnet-name SUBNET_NAME",
166
- :description => "Optional. Specifies the subnet of virtual machine"
87
+ long: "--azure-subnet-name SUBNET_NAME",
88
+ description: "Optional. Specifies the subnet of virtual machine"
167
89
 
168
90
  option :azure_vm_startup_timeout,
169
- :long => "--azure-vm-startup-timeout TIMEOUT",
170
- :description => "The number of minutes that knife-azure will wait for the virtual machine to reach the 'provisioning' state. Default is 10.",
171
- :default => 10
91
+ long: "--azure-vm-startup-timeout TIMEOUT",
92
+ description: "The number of minutes that knife-azure will wait for the virtual machine to reach the 'provisioning' state. Default is 10.",
93
+ default: 10
172
94
 
173
95
  option :azure_vm_ready_timeout,
174
- :long => "--azure-vm-ready-timeout TIMEOUT",
175
- :description => "The number of minutes that knife-azure will wait for the virtual machine state to transition from 'provisioning' to 'ready'. Default is 15.",
176
- :default => 15
96
+ long: "--azure-vm-ready-timeout TIMEOUT",
97
+ description: "The number of minutes that knife-azure will wait for the virtual machine state to transition from 'provisioning' to 'ready'. Default is 15.",
98
+ default: 15
177
99
 
178
100
  option :auth_timeout,
179
- :long => "--windows-auth-timeout MINUTES",
180
- :description => "The maximum time in minutes to wait to for authentication over the transport to the node to succeed. The default value is 25 minutes.",
181
- :default => 25
182
-
183
- option :identity_file,
184
- :long => "--identity-file FILENAME",
185
- :description => "SSH identity file for authentication, optional. It is the RSA private key path. Specify either ssh-password or identity-file"
101
+ long: "--windows-auth-timeout MINUTES",
102
+ description: "The maximum time in minutes to wait to for authentication over the transport to the node to succeed. The default value is 25 minutes.",
103
+ default: 25
186
104
 
187
105
  option :identity_file_passphrase,
188
- :long => "--identity-file-passphrase PASSWORD",
189
- :description => "SSH key passphrase. Optional, specify if passphrase for identity-file exists"
190
-
191
- option :thumbprint,
192
- :long => "--thumbprint THUMBPRINT",
193
- :description => "The thumprint of the ssl certificate"
194
-
195
- option :cert_passphrase,
196
- :long => "--cert-passphrase PASSWORD",
197
- :description => "SSL Certificate Password"
198
-
199
- option :cert_path,
200
- :long => "--cert-path PATH",
201
- :description => "SSL Certificate Path"
106
+ long: "--identity-file-passphrase PASSWORD",
107
+ description: "SSH key passphrase. Optional, specify if passphrase for identity-file exists"
202
108
 
203
109
  option :winrm_max_timeout,
204
- :long => "--winrm-max-timeout MINUTES",
205
- :description => "Set winrm maximum command timeout in minutes, useful for long bootstraps"
110
+ long: "--winrm-max-timeout MINUTES",
111
+ description: "Set winrm maximum command timeout in minutes, useful for long bootstraps"
206
112
 
207
- option :winrm_max_memorypershell,
208
- :long => "--winrm-max-memory-per-shell",
209
- :description => "Set winrm max memory per shell in MB"
113
+ option :winrm_max_memory_per_shell,
114
+ long: "--winrm-max-memory-per-shell",
115
+ description: "Set winrm max memory per shell in MB"
210
116
 
211
117
  option :azure_domain_name,
212
- :long => "--azure-domain-name DOMAIN_NAME",
213
- :description => "Optional. Specifies the domain name to join. If the domains name is not specified, --azure-domain-user must specify the user principal name (UPN) format (user@fully-qualified-DNS-domain) or the fully-qualified-DNS-domain\\username format"
118
+ long: "--azure-domain-name DOMAIN_NAME",
119
+ description: 'Optional. Specifies the domain name to join. If the domains name is not specified, --azure-domain-user must specify the user principal name (UPN) format (user@fully-qualified-DNS-domain) or the fully-qualified-DNS-domain\\username format'
214
120
 
215
121
  option :azure_domain_ou_dn,
216
- :long => "--azure-domain-ou-dn DOMAIN_OU_DN",
217
- :description => "Optional. Specifies the (LDAP) X 500-distinguished name of the organizational unit (OU) in which the computer account is created. This account is in Active Directory on a domain controller in the domain to which the computer is being joined. Example: OU=HR,dc=opscode,dc=com"
122
+ long: "--azure-domain-ou-dn DOMAIN_OU_DN",
123
+ description: "Optional. Specifies the (LDAP) X 500-distinguished name of the organizational unit (OU) in which the computer account is created. This account is in Active Directory on a domain controller in the domain to which the computer is being joined. Example: OU=HR,dc=opscode,dc=com"
218
124
 
219
125
  option :azure_domain_user,
220
- :long => "--azure-domain-user DOMAIN_USER_NAME",
221
- :description => 'Optional. Specifies the username who has access to join the domain.
126
+ long: "--azure-domain-user DOMAIN_USER_NAME",
127
+ description: 'Optional. Specifies the username who has access to join the domain.
222
128
  Supported format: username(if domain is already specified in --azure-domain-name option),
223
129
  fully-qualified-DNS-domain\username, user@fully-qualified-DNS-domain'
224
130
 
225
131
  option :azure_domain_passwd,
226
- :long => "--azure-domain-passwd DOMAIN_PASSWD",
227
- :description => "Optional. Specifies the password for domain user who has access to join the domain."
132
+ long: "--azure-domain-passwd DOMAIN_PASSWD",
133
+ description: "Optional. Specifies the password for domain user who has access to join the domain."
134
+
135
+ # Overriding this option to provide "cloud-api" in SUPPORTED_CONNECTION_PROTOCOLS
136
+ option :connection_protocol,
137
+ short: "-o PROTOCOL",
138
+ long: "--connection-protocol PROTOCOL",
139
+ description: "The protocol to use to connect to the target node.",
140
+ in: SUPPORTED_CONNECTION_PROTOCOLS
141
+
142
+ # run() would be executing from parent class
143
+ # Chef::Knife::Bootstrap, defined in core.
144
+ # Required methods have been overridden here
145
+ #### run() execution begins ####
146
+
147
+ def plugin_setup!; end
148
+
149
+ def validate_name_args!; end
150
+
151
+ # Ensure a valid protocol is provided for target host connection
152
+ #
153
+ # The method call will cause the program to exit(1) if:
154
+ # * Conflicting protocols are given via the target URI and the --protocol option
155
+ # * The protocol is not a supported protocol
156
+ #
157
+ # @note we are overriding this method here to consider "cloud-api" as valid protocol
158
+ #
159
+ # @return [TrueClass] If options are valid.
160
+ def validate_protocol!
161
+ from_cli = config[:connection_protocol]
162
+ if from_cli && connection_protocol != from_cli
163
+ # Hanging indent to align with the ERROR: prefix
164
+ ui.error <<~EOM
165
+ The URL '#{host_descriptor}' indicates protocol is '#{connection_protocol}'
166
+ while the --protocol flag specifies '#{from_cli}'. Please include
167
+ only one or the other.
168
+ EOM
169
+ exit 1
170
+ end
171
+
172
+ unless SUPPORTED_CONNECTION_PROTOCOLS.include?(connection_protocol)
173
+ ui.error <<~EOM
174
+ Unsupported protocol '#{connection_protocol}'.
175
+
176
+ Supported protocols are: #{SUPPORTED_CONNECTION_PROTOCOLS.join(" ")}
177
+ EOM
178
+ exit 1
179
+ end
180
+ true
181
+ end
182
+
183
+ def plugin_validate_options!
184
+ Chef::Log.info("Validating...")
185
+ validate_asm_keys!(:azure_source_image)
186
+ validate_params!
187
+ end
188
+
189
+ def plugin_create_instance!
190
+ Chef::Log.info("Creating...")
191
+ set_defaults
192
+ server_def = create_server_def
193
+ vm_details = service.create_server(server_def)
194
+
195
+ wait_until_virtual_machine_ready
196
+
197
+ config[:connection_port] = server_def[:port]
198
+ config[:connection_protocol] = server_def[:connection_protocol]
199
+ config[:chef_node_name] = locate_config_value(:chef_node_name) || server_name
200
+ rescue => error
201
+ ui.error("Something went wrong. Please use -VV option for more details.")
202
+ Chef::Log.debug(error.backtrace.join("\n").to_s)
203
+ exit 1
204
+ end
205
+
206
+ def server_name
207
+ @server_name ||= if @server.nil?
208
+ nil
209
+ elsif !@server.hostedservicename.nil?
210
+ @server.hostedservicename + ".cloudapp.net"
211
+ else
212
+ @server.ipaddress
213
+ end
214
+ end
215
+
216
+ alias host_descriptor server_name
228
217
 
229
- option :azure_extension_client_config,
230
- :long => "--azure-extension-client-config CLIENT_PATH",
231
- :description => "Optional. Path to a client.rb file for use by the bootstrapped node. Only honored when --bootstrap-protocol is set to `cloud-api`."
218
+ def plugin_finalize
219
+ if locate_config_value(:connection_protocol) == "cloud-api" && locate_config_value(:extended_logs)
220
+ print "\nWaiting for the first chef-client run"
221
+ fetch_chef_client_logs(Time.now, 30)
222
+ end
223
+ msg_server_summary(@server)
224
+ end
225
+
226
+ #### run() execution ends ####
232
227
 
233
228
  def wait_until_virtual_machine_ready(retry_interval_in_seconds = 30)
234
229
  vm_status = nil
@@ -245,9 +240,9 @@ class Chef
245
240
  end
246
241
  end
247
242
 
248
- msg_server_summary(service.get_role_server(locate_config_value(:azure_dns_name), locate_config_value(:azure_vm_name)))
243
+ msg_server_summary(@server)
249
244
 
250
- if locate_config_value(:bootstrap_protocol) == "cloud-api"
245
+ if locate_config_value(:connection_protocol) == "cloud-api"
251
246
  extension_status = wait_for_resource_extension_state(:wagent_provisioning, 5, retry_interval_in_seconds)
252
247
 
253
248
  if extension_status != :extension_installing
@@ -269,10 +264,10 @@ class Chef
269
264
  end
270
265
 
271
266
  def wait_for_virtual_machine_state(vm_status_goal, total_wait_time_in_minutes, retry_interval_in_seconds)
272
- vm_status_ordering = { :vm_status_not_detected => 0, :vm_status_provisioning => 1, :vm_status_ready => 2 }
273
- vm_status_description = { :vm_status_not_detected => "any", :vm_status_provisioning => "provisioning", :vm_status_ready => "ready" }
267
+ vm_status_ordering = { vm_status_not_detected: 0, vm_status_provisioning: 1, vm_status_ready: 2 }
268
+ vm_status_description = { vm_status_not_detected: "any", vm_status_provisioning: "provisioning", vm_status_ready: "ready" }
274
269
 
275
- print ui.color("Waiting for virtual machine to reach status '#{vm_status_description[vm_status_goal]}'", :magenta)
270
+ print ui.color("\nWaiting for virtual machine to reach status '#{vm_status_description[vm_status_goal]}'\n", :magenta)
276
271
 
277
272
  total_wait_time_in_seconds = total_wait_time_in_minutes * 60
278
273
  max_polling_attempts = total_wait_time_in_seconds / retry_interval_in_seconds
@@ -281,28 +276,28 @@ class Chef
281
276
  wait_start_time = Time.now
282
277
 
283
278
  begin
284
- vm_status = get_virtual_machine_status()
279
+ vm_status = get_virtual_machine_status
285
280
  vm_ready = vm_status_ordering[vm_status] >= vm_status_ordering[vm_status_goal]
286
281
  print "."
287
- sleep retry_interval_in_seconds if !vm_ready
282
+ sleep retry_interval_in_seconds unless vm_ready
288
283
  polling_attempts += 1
289
284
  end until vm_ready || polling_attempts >= max_polling_attempts
290
285
 
291
- if ! vm_ready
286
+ unless vm_ready
292
287
  raise Chef::Exceptions::CommandTimeout, "Virtual machine state '#{vm_status_description[vm_status_goal]}' not reached after #{total_wait_time_in_minutes} minutes."
293
288
  end
294
289
 
295
290
  elapsed_time_in_minutes = ((Time.now - wait_start_time) / 60).round(2)
296
- print ui.color("vm state '#{vm_status_description[vm_status_goal]}' reached after #{elapsed_time_in_minutes} minutes.\n", :cyan)
291
+ print ui.color("\nvm state '#{vm_status_description[vm_status_goal]}' reached after #{elapsed_time_in_minutes} minutes.\n", :cyan)
297
292
  vm_status
298
293
  end
299
294
 
300
295
  def wait_for_resource_extension_state(extension_status_goal, total_wait_time_in_minutes, retry_interval_in_seconds)
301
- extension_status_ordering = { :extension_status_not_detected => 0, :wagent_provisioning => 1, :extension_installing => 2, :extension_provisioning => 3, :extension_ready => 4 }
296
+ extension_status_ordering = { extension_status_not_detected: 0, wagent_provisioning: 1, extension_installing: 2, extension_provisioning: 3, extension_ready: 4 }
302
297
 
303
- status_description = { :extension_status_not_detected => "any", :wagent_provisioning => "wagent provisioning", :extension_installing => "installing", :extension_provisioning => "provisioning", :extension_ready => "ready" }
298
+ status_description = { extension_status_not_detected: "any", wagent_provisioning: "wagent provisioning", extension_installing: "installing", extension_provisioning: "provisioning", extension_ready: "ready" }
304
299
 
305
- print ui.color("Waiting for Resource Extension to reach status '#{status_description[extension_status_goal]}'", :magenta)
300
+ print ui.color("\nWaiting for Resource Extension to reach status '#{status_description[extension_status_goal]}'\n", :magenta)
306
301
 
307
302
  max_polling_attempts = (total_wait_time_in_minutes * 60) / retry_interval_in_seconds
308
303
  polling_attempts = 0
@@ -310,42 +305,44 @@ class Chef
310
305
  wait_start_time = Time.now
311
306
 
312
307
  begin
313
- extension_status = get_extension_status()
308
+ extension_status = get_extension_status
314
309
  extension_ready = extension_status_ordering[extension_status[:status]] >= extension_status_ordering[extension_status_goal]
315
310
  print "."
316
- sleep retry_interval_in_seconds if !extension_ready
311
+ sleep retry_interval_in_seconds unless extension_ready
317
312
  polling_attempts += 1
318
313
  end until extension_ready || polling_attempts >= max_polling_attempts
319
314
 
320
- if ! extension_ready
315
+ unless extension_ready
321
316
  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
317
  end
323
318
 
324
319
  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)
320
+ print ui.color("\nResource extension state '#{status_description[extension_status_goal]}' reached after #{elapsed_time_in_minutes} minutes.\n", :cyan)
326
321
 
327
322
  extension_status[:status]
328
323
  end
329
324
 
330
325
  def get_virtual_machine_status
331
- role = service.get_role_server(locate_config_value(:azure_dns_name), locate_config_value(:azure_vm_name))
332
- unless role.nil?
333
- Chef::Log.debug("Role status is #{role.status}")
334
- if "ReadyRole".eql? role.status.to_s
335
- return :vm_status_ready
336
- elsif "Provisioning".eql? role.status.to_s
337
- return :vm_status_provisioning
326
+ @server = service.get_role_server(locate_config_value(:azure_dns_name), locate_config_value(:azure_vm_name))
327
+ if @server.nil?
328
+ :vm_status_not_detected
329
+ else
330
+ Chef::Log.debug("Role status is #{@server.status}")
331
+ case @server.status.to_s
332
+ when "ReadyRole"
333
+ :vm_status_ready
334
+ when "Provisioning"
335
+ :vm_status_provisioning
338
336
  else
339
- return :vm_status_not_detected
337
+ :vm_status_not_detected
340
338
  end
341
339
  end
342
- :vm_status_not_detected
343
340
  end
344
341
 
345
342
  def get_extension_status
346
343
  deployment_name = service.deployment_name(locate_config_value(:azure_dns_name))
347
344
  deployment = service.deployment("hostedservices/#{locate_config_value(:azure_dns_name)}/deployments/#{deployment_name}")
348
- extension_status = Hash.new
345
+ extension_status = {}
349
346
 
350
347
  if deployment.at_css("Deployment Name") != nil
351
348
  role_list_xml = deployment.css("RoleInstanceList RoleInstance")
@@ -385,57 +382,34 @@ class Chef
385
382
  extension_status
386
383
  end
387
384
 
388
- def run
389
- $stdout.sync = true
390
- storage = nil
391
- Chef::Log.info("validating...")
392
- validate_asm_keys!(:azure_source_image)
393
- validate_params!
394
- ssh_override_winrm if !is_image_windows?
395
- Chef::Log.info("creating...")
396
- config[:azure_dns_name] = get_dns_name(locate_config_value(:azure_dns_name))
397
- config[:azure_vm_name] = locate_config_value(:azure_dns_name) unless locate_config_value(:azure_vm_name)
398
- config[:chef_node_name] = locate_config_value(:azure_vm_name) unless locate_config_value(:chef_node_name)
399
- service.create_server(create_server_def)
400
- wait_until_virtual_machine_ready()
401
- if locate_config_value(:bootstrap_protocol) == "cloud-api" && locate_config_value(:extended_logs)
402
- print "\n\nWaiting for the first chef-client run"
403
- fetch_chef_client_logs(Time.now, 30)
404
- end
405
- server = service.get_role_server(locate_config_value(:azure_dns_name), locate_config_value(:azure_vm_name))
406
- msg_server_summary(server)
407
-
408
- bootstrap_exec(server) unless locate_config_value(:bootstrap_protocol) == "cloud-api"
409
- end
410
-
411
385
  def create_server_def
412
386
  server_def = {
413
- :azure_storage_account => locate_config_value(:azure_storage_account),
414
- :azure_api_host_name => locate_config_value(:azure_api_host_name),
415
- :azure_dns_name => locate_config_value(:azure_dns_name),
416
- :azure_vm_name => locate_config_value(:azure_vm_name),
417
- :azure_service_location => locate_config_value(:azure_service_location),
418
- :azure_os_disk_name => locate_config_value(:azure_os_disk_name),
419
- :azure_source_image => locate_config_value(:azure_source_image),
420
- :azure_vm_size => locate_config_value(:azure_vm_size),
421
- :tcp_endpoints => locate_config_value(:tcp_endpoints),
422
- :udp_endpoints => locate_config_value(:udp_endpoints),
423
- :bootstrap_proto => locate_config_value(:bootstrap_protocol),
424
- :azure_connect_to_existing_dns => locate_config_value(:azure_connect_to_existing_dns),
425
- :winrm_user => locate_config_value(:winrm_user),
426
- :azure_availability_set => locate_config_value(:azure_availability_set),
427
- :azure_affinity_group => locate_config_value(:azure_affinity_group),
428
- :azure_network_name => locate_config_value(:azure_network_name),
429
- :azure_subnet_name => locate_config_value(:azure_subnet_name),
430
- :ssl_cert_fingerprint => locate_config_value(:thumbprint),
431
- :cert_path => locate_config_value(:cert_path),
432
- :cert_password => locate_config_value(:cert_passphrase),
433
- :winrm_transport => locate_config_value(:winrm_transport),
434
- :winrm_max_timeout => locate_config_value(:winrm_max_timeout).to_i * 60 * 1000, #converting minutes to milliseconds
435
- :winrm_max_memoryPerShell => locate_config_value(:winrm_max_memory_per_shell)
387
+ azure_storage_account: locate_config_value(:azure_storage_account),
388
+ azure_api_host_name: locate_config_value(:azure_api_host_name),
389
+ azure_dns_name: locate_config_value(:azure_dns_name),
390
+ azure_vm_name: locate_config_value(:azure_vm_name),
391
+ azure_service_location: locate_config_value(:azure_service_location),
392
+ azure_os_disk_name: locate_config_value(:azure_os_disk_name),
393
+ azure_source_image: locate_config_value(:azure_source_image),
394
+ azure_vm_size: locate_config_value(:azure_vm_size),
395
+ tcp_endpoints: locate_config_value(:tcp_endpoints),
396
+ udp_endpoints: locate_config_value(:udp_endpoints),
397
+ connection_protocol: locate_config_value(:connection_protocol),
398
+ azure_connect_to_existing_dns: locate_config_value(:azure_connect_to_existing_dns),
399
+ connection_user: locate_config_value(:connection_user),
400
+ azure_availability_set: locate_config_value(:azure_availability_set),
401
+ azure_affinity_group: locate_config_value(:azure_affinity_group),
402
+ azure_network_name: locate_config_value(:azure_network_name),
403
+ azure_subnet_name: locate_config_value(:azure_subnet_name),
404
+ ssl_cert_fingerprint: locate_config_value(:thumbprint),
405
+ cert_path: locate_config_value(:cert_path),
406
+ cert_password: locate_config_value(:cert_passphrase),
407
+ winrm_ssl: locate_config_value(:winrm_ssl),
408
+ winrm_max_timeout: locate_config_value(:winrm_max_timeout).to_i * 60 * 1000, # converting minutes to milliseconds
409
+ winrm_max_memory_per_shell: locate_config_value(:winrm_max_memory_per_shell),
436
410
  }
437
411
 
438
- if locate_config_value(:bootstrap_protocol) == "cloud-api"
412
+ if locate_config_value(:connection_protocol) == "cloud-api"
439
413
  server_def[:chef_extension] = get_chef_extension_name
440
414
  server_def[:chef_extension_publisher] = get_chef_extension_publisher
441
415
  server_def[:chef_extension_version] = get_chef_extension_version
@@ -443,28 +417,23 @@ class Chef
443
417
  server_def[:chef_extension_private_param] = get_chef_extension_private_params
444
418
  else
445
419
  if is_image_windows?
446
- if (not locate_config_value(:winrm_password)) || (not locate_config_value(:bootstrap_protocol))
447
- ui.error("WinRM Password and Bootstrapping Protocol are compulsory parameters")
448
- exit 1
449
- end
450
420
  # We can specify the AdminUsername after API version 2013-03-01. However, in this API version,
451
421
  # the AdminUsername is a required parameter.
452
422
  # Also, the user name cannot be Administrator, Admin, Admin1 etc, for enhanced security (provided by Azure)
453
- if locate_config_value(:winrm_user).nil? || locate_config_value(:winrm_user).downcase =~ /admin*/
454
- ui.error("WinRM User is compulsory parameter and it cannot be named 'admin*'")
423
+ if locate_config_value(:connection_user).nil? || locate_config_value(:connection_user).downcase =~ /admin*/
424
+ ui.error("Connection User is compulsory parameter and it cannot be named 'admin*'")
455
425
  exit 1
456
- end
457
426
  # take cares of when user name contains domain
458
427
  # azure add role api doesn't support '\\' in user name
459
- if locate_config_value(:winrm_user) && locate_config_value(:winrm_user).split("\\").length.eql?(2)
460
- server_def[:winrm_user] = locate_config_value(:winrm_user).split("\\")[1]
428
+ elsif locate_config_value(:connection_user).split('\\').length.eql?(2)
429
+ server_def[:connection_user] = locate_config_value(:connection_user).split('\\')[1]
461
430
  end
462
431
  else
463
- if not locate_config_value(:ssh_user)
464
- ui.error("SSH User is compulsory parameter")
432
+ unless locate_config_value(:connection_user)
433
+ ui.error("Connection User is compulsory parameter")
465
434
  exit 1
466
435
  end
467
- unless locate_config_value(:ssh_password) || locate_config_value(:identity_file)
436
+ unless locate_config_value(:connection_password) || locate_config_value(:ssh_identity_file)
468
437
  ui.error("Specify either SSH Key or SSH Password")
469
438
  exit 1
470
439
  end
@@ -473,24 +442,24 @@ class Chef
473
442
 
474
443
  if is_image_windows?
475
444
  server_def[:os_type] = "Windows"
476
- server_def[:admin_password] = locate_config_value(:winrm_password)
477
- server_def[:bootstrap_proto] = locate_config_value(:bootstrap_protocol)
445
+ server_def[:admin_password] = locate_config_value(:connection_password)
446
+ server_def[:connection_protocol] = locate_config_value(:connection_protocol) || "winrm"
478
447
  else
479
448
  server_def[:os_type] = "Linux"
480
- server_def[:bootstrap_proto] = (locate_config_value(:bootstrap_protocol) == "winrm") ? "ssh" : locate_config_value(:bootstrap_protocol)
481
- server_def[:ssh_user] = locate_config_value(:ssh_user)
482
- server_def[:ssh_password] = locate_config_value(:ssh_password)
483
- server_def[:identity_file] = locate_config_value(:identity_file)
449
+ server_def[:connection_protocol] = locate_config_value(:connection_protocol).nil? || locate_config_value(:connection_protocol) == "winrm" ? "ssh" : locate_config_value(:connection_protocol)
450
+ server_def[:connection_user] = locate_config_value(:connection_user)
451
+ server_def[:connection_password] = locate_config_value(:connection_password)
452
+ server_def[:ssh_identity_file] = locate_config_value(:ssh_identity_file)
484
453
  server_def[:identity_file_passphrase] = locate_config_value(:identity_file_passphrase)
485
454
  end
486
455
 
487
456
  azure_connect_to_existing_dns = locate_config_value(:azure_connect_to_existing_dns)
488
- if is_image_windows? && server_def[:bootstrap_proto] == "winrm"
489
- port = locate_config_value(:winrm_port) || "5985"
490
- port = locate_config_value(:winrm_port) || Random.rand(64000) + 1000 if azure_connect_to_existing_dns
491
- elsif server_def[:bootstrap_proto] == "ssh"
492
- port = locate_config_value(:ssh_port) || "22"
493
- port = locate_config_value(:ssh_port) || Random.rand(64000) + 1000 if azure_connect_to_existing_dns
457
+ if is_image_windows? && server_def[:connection_protocol] == "winrm"
458
+ port = locate_config_value(:connection_port) || "5985"
459
+ port = locate_config_value(:connection_port) || Random.rand(64000) + 1000 if azure_connect_to_existing_dns
460
+ elsif server_def[:connection_protocol] == "ssh"
461
+ port = locate_config_value(:connection_port) || "22"
462
+ port = locate_config_value(:connection_port) || Random.rand(64000) + 1000 if azure_connect_to_existing_dns
494
463
  end
495
464
 
496
465
  server_def[:port] = port
@@ -525,27 +494,22 @@ class Chef
525
494
 
526
495
  private
527
496
 
528
- def ssh_override_winrm
529
- # unchanged ssh_user and changed winrm_user, override ssh_user
530
- if locate_config_value(:ssh_user).eql?(options[:ssh_user][:default]) &&
531
- !locate_config_value(:winrm_user).eql?(options[:winrm_user][:default])
532
- config[:ssh_user] = locate_config_value(:winrm_user)
533
- end
534
- # unchanged ssh_port and changed winrm_port, override ssh_port
535
- if locate_config_value(:ssh_port).eql?(options[:ssh_port][:default]) &&
536
- !locate_config_value(:winrm_port).eql?(options[:winrm_port][:default])
537
- config[:ssh_port] = locate_config_value(:winrm_port)
538
- end
539
- # unset ssh_password and set winrm_password, override ssh_password
540
- if locate_config_value(:ssh_password).nil? &&
541
- !locate_config_value(:winrm_password).nil?
542
- config[:ssh_password] = locate_config_value(:winrm_password)
497
+ def set_defaults
498
+ set_configs
499
+ end
500
+
501
+ def set_configs
502
+ unless locate_config_value(:connection_user).nil?
503
+ config[:connection_user] = locate_config_value(:connection_user)
543
504
  end
544
- # unset identity_file and set _file, override identity_file
545
- if locate_config_value(:identity_file).nil? &&
546
- !locate_config_value(:kerberos_keytab_file).nil?
547
- config[:identity_file] = locate_config_value(:kerberos_keytab_file)
505
+
506
+ unless locate_config_value(:connection_password).nil?
507
+ config[:connection_password] = locate_config_value(:connection_password)
548
508
  end
509
+
510
+ config[:azure_dns_name] = get_dns_name(locate_config_value(:azure_dns_name))
511
+ config[:azure_vm_name] = locate_config_value(:azure_dns_name) unless locate_config_value(:azure_vm_name)
512
+ config[:chef_node_name] = locate_config_value(:azure_vm_name) unless locate_config_value(:chef_node_name)
549
513
  end
550
514
 
551
515
  # This is related to Windows VM's specifically and computer name
@@ -555,10 +519,11 @@ class Chef
555
519
  # generate a random dns_name if azure_dns_name is empty
556
520
  def get_dns_name(azure_dns_name, prefix = "az-")
557
521
  return azure_dns_name unless azure_dns_name.nil?
522
+
558
523
  if locate_config_value(:azure_vm_name).nil?
559
- azure_dns_name = prefix + SecureRandom.hex(( MAX_VM_NAME_CHARACTERS - prefix.length) / 2)
524
+ (prefix + SecureRandom.hex((MAX_VM_NAME_CHARACTERS - prefix.length) / 2))
560
525
  else
561
- azure_dns_name = locate_config_value(:azure_vm_name)
526
+ locate_config_value(:azure_vm_name)
562
527
  end
563
528
  end
564
529
  end