knife-azure 1.9.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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