knife-azure 3.0.0 → 4.0.0
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.
- checksums.yaml +4 -4
- data/lib/azure/custom_errors.rb +1 -1
- data/lib/azure/resource_management/ARM_deployment_template.rb +5 -5
- data/lib/azure/resource_management/ARM_interface.rb +8 -12
- data/lib/azure/resource_management/windows_credentials.rb +7 -8
- data/lib/chef/knife/azurerm_server_create.rb +2 -2
- data/lib/chef/knife/azurerm_server_delete.rb +1 -1
- data/lib/chef/knife/bootstrap/bootstrapper.rb +10 -11
- data/lib/chef/knife/bootstrap_azurerm.rb +1 -1
- data/lib/chef/knife/helpers/azurerm_base.rb +17 -19
- data/lib/knife-azure/version.rb +1 -1
- metadata +30 -43
- data/lib/azure/service_management/ASM_interface.rb +0 -310
- data/lib/azure/service_management/ag.rb +0 -99
- data/lib/azure/service_management/certificate.rb +0 -235
- data/lib/azure/service_management/connection.rb +0 -102
- data/lib/azure/service_management/deploy.rb +0 -221
- data/lib/azure/service_management/disk.rb +0 -68
- data/lib/azure/service_management/host.rb +0 -184
- data/lib/azure/service_management/image.rb +0 -94
- data/lib/azure/service_management/loadbalancer.rb +0 -78
- data/lib/azure/service_management/rest.rb +0 -125
- data/lib/azure/service_management/role.rb +0 -717
- data/lib/azure/service_management/storageaccount.rb +0 -127
- data/lib/azure/service_management/utility.rb +0 -40
- data/lib/azure/service_management/vnet.rb +0 -134
- data/lib/chef/knife/azure_ag_create.rb +0 -73
- data/lib/chef/knife/azure_ag_list.rb +0 -35
- data/lib/chef/knife/azure_image_list.rb +0 -56
- data/lib/chef/knife/azure_internal-lb_create.rb +0 -74
- data/lib/chef/knife/azure_internal-lb_list.rb +0 -35
- data/lib/chef/knife/azure_server_create.rb +0 -531
- data/lib/chef/knife/azure_server_delete.rb +0 -136
- data/lib/chef/knife/azure_server_list.rb +0 -38
- data/lib/chef/knife/azure_server_show.rb +0 -41
- data/lib/chef/knife/azure_vnet_create.rb +0 -74
- data/lib/chef/knife/azure_vnet_list.rb +0 -35
- data/lib/chef/knife/bootstrap_azure.rb +0 -191
- data/lib/chef/knife/helpers/azure_base.rb +0 -394
@@ -1,74 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Aiman Alsari (aiman.alsari@gmail.com)
|
3
|
-
# Copyright:: Copyright (c) Chef Software Inc.
|
4
|
-
# License:: Apache License, Version 2.0
|
5
|
-
#
|
6
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License.
|
8
|
-
# You may obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
# See the License for the specific language governing permissions and
|
16
|
-
# limitations under the License.
|
17
|
-
#
|
18
|
-
|
19
|
-
require_relative "helpers/azure_base"
|
20
|
-
|
21
|
-
class Chef
|
22
|
-
class Knife
|
23
|
-
class AzureInternalLbCreate < Knife
|
24
|
-
include Knife::AzureBase
|
25
|
-
|
26
|
-
banner "knife azure internal lb create (options)"
|
27
|
-
|
28
|
-
option :azure_load_balancer,
|
29
|
-
short: "-n NAME",
|
30
|
-
long: "--azure-load-balancer NAME",
|
31
|
-
description: "Required. Specifies new load balancer name."
|
32
|
-
|
33
|
-
option :azure_lb_static_vip,
|
34
|
-
long: "--azure-lb-static-vip VIP",
|
35
|
-
description: "Optional. The Virtual IP that will be used for the load balancer."
|
36
|
-
|
37
|
-
option :azure_subnet_name,
|
38
|
-
long: "--azure-subnet-name SUBNET_NAME",
|
39
|
-
description: "Required if static VIP is set. Specifies the subnet name "\
|
40
|
-
"the load balancer is located in."
|
41
|
-
|
42
|
-
option :azure_dns_name,
|
43
|
-
long: "--azure-dns-name DNS_NAME",
|
44
|
-
description: "The DNS prefix name that will be used to add this load balancer to. This must be an existing service/deployment."
|
45
|
-
|
46
|
-
def run
|
47
|
-
$stdout.sync = true
|
48
|
-
|
49
|
-
Chef::Log.info("validating...")
|
50
|
-
validate_asm_keys!(:azure_load_balancer)
|
51
|
-
|
52
|
-
params = {
|
53
|
-
azure_load_balancer: config[:azure_load_balancer],
|
54
|
-
azure_lb_static_vip: config[:azure_lb_static_vip],
|
55
|
-
azure_subnet_name: config[:azure_subnet_name],
|
56
|
-
azure_dns_name: config[:azure_dns_name],
|
57
|
-
}
|
58
|
-
|
59
|
-
rsp = service.create_internal_lb(params)
|
60
|
-
print "\n"
|
61
|
-
if rsp.at_css("Status").nil?
|
62
|
-
if rsp.at_css("Code").nil? || rsp.at_css("Message").nil?
|
63
|
-
puts "Unknown Error. try -VV"
|
64
|
-
else
|
65
|
-
puts "#{rsp.at_css("Code").content}: "\
|
66
|
-
"#{rsp.at_css("Message").content}"
|
67
|
-
end
|
68
|
-
else
|
69
|
-
puts "Creation status: #{rsp.at_css("Status").content}"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Aiman Alsari (aiman.alsari@gmail.com)
|
3
|
-
# Copyright:: Copyright (c) Chef Software Inc.
|
4
|
-
# License:: Apache License, Version 2.0
|
5
|
-
#
|
6
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License.
|
8
|
-
# You may obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
# See the License for the specific language governing permissions and
|
16
|
-
# limitations under the License.
|
17
|
-
#
|
18
|
-
|
19
|
-
require_relative "helpers/azure_base"
|
20
|
-
|
21
|
-
class Chef
|
22
|
-
class Knife
|
23
|
-
class AzureInternalLbList < Knife
|
24
|
-
include Knife::AzureBase
|
25
|
-
|
26
|
-
banner "knife azure internal lb list (options)"
|
27
|
-
|
28
|
-
def run
|
29
|
-
$stdout.sync = true
|
30
|
-
validate_asm_keys!
|
31
|
-
service.list_internal_lb
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,531 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Author:: Adam Jacob (<adam@chef.io>)
|
4
|
-
# Author:: Seth Chisamore (<schisamo@chef.io>)
|
5
|
-
# Copyright:: Copyright (c) Chef Software Inc.
|
6
|
-
# License:: Apache License, Version 2.0
|
7
|
-
#
|
8
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
-
# you may not use this file except in compliance with the License.
|
10
|
-
# You may obtain a copy of the License at
|
11
|
-
#
|
12
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
-
#
|
14
|
-
# Unless required by applicable law or agreed to in writing, software
|
15
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
-
# See the License for the specific language governing permissions and
|
18
|
-
# limitations under the License.
|
19
|
-
#
|
20
|
-
|
21
|
-
require_relative "helpers/azure_base"
|
22
|
-
require "chef/knife/bootstrap"
|
23
|
-
require "chef/knife/bootstrap/client_builder"
|
24
|
-
require_relative "bootstrap/common_bootstrap_options"
|
25
|
-
require_relative "bootstrap/bootstrapper"
|
26
|
-
|
27
|
-
class Chef
|
28
|
-
class Knife
|
29
|
-
class AzureServerCreate < Knife::Bootstrap
|
30
|
-
include Knife::AzureBase
|
31
|
-
include Knife::Bootstrap::CommonBootstrapOptions
|
32
|
-
include Knife::Bootstrap::Bootstrapper
|
33
|
-
|
34
|
-
deps do
|
35
|
-
require "securerandom"
|
36
|
-
require "readline"
|
37
|
-
require "chef/json_compat"
|
38
|
-
require "chef/knife/bootstrap"
|
39
|
-
require "chef/knife/core/windows_bootstrap_context"
|
40
|
-
Chef::Knife::Bootstrap.load_deps
|
41
|
-
end
|
42
|
-
|
43
|
-
banner "knife azure server create (options)"
|
44
|
-
|
45
|
-
SUPPORTED_CONNECTION_PROTOCOLS = %w{ssh winrm cloud-api}.freeze
|
46
|
-
|
47
|
-
attr_accessor :initial_sleep_delay
|
48
|
-
|
49
|
-
option :azure_affinity_group,
|
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."
|
53
|
-
|
54
|
-
option :azure_dns_name,
|
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).
|
58
|
-
If you want to add new VM to an existing service/deployment, specify an exiting dns-name,
|
59
|
-
along with --azure-connect-to-existing-dns option.
|
60
|
-
Otherwise a new deployment is created. For example, if the DNS of cloud service is MyService you could access the cloud service
|
61
|
-
by calling: http://DNS_NAME.cloudapp.net"
|
62
|
-
|
63
|
-
option :azure_source_image,
|
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.
|
67
|
-
Do a \"knife azure image list\" to see a list of available images."
|
68
|
-
|
69
|
-
option :udp_endpoints,
|
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'"
|
73
|
-
|
74
|
-
option :azure_connect_to_existing_dns,
|
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
|
80
|
-
DNS correctly in the --dns-name option"
|
81
|
-
|
82
|
-
option :azure_network_name,
|
83
|
-
long: "--azure-network-name NETWORK_NAME",
|
84
|
-
description: "Optional. Specifies the network of virtual machine"
|
85
|
-
|
86
|
-
option :azure_subnet_name,
|
87
|
-
long: "--azure-subnet-name SUBNET_NAME",
|
88
|
-
description: "Optional. Specifies the subnet of virtual machine"
|
89
|
-
|
90
|
-
option :azure_vm_startup_timeout,
|
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
|
94
|
-
|
95
|
-
option :azure_vm_ready_timeout,
|
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
|
99
|
-
|
100
|
-
option :auth_timeout,
|
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
|
104
|
-
|
105
|
-
option :identity_file_passphrase,
|
106
|
-
long: "--identity-file-passphrase PASSWORD",
|
107
|
-
description: "SSH key passphrase. Optional, specify if passphrase for identity-file exists"
|
108
|
-
|
109
|
-
option :winrm_max_timeout,
|
110
|
-
long: "--winrm-max-timeout MINUTES",
|
111
|
-
description: "Set winrm maximum command timeout in minutes, useful for long bootstraps"
|
112
|
-
|
113
|
-
option :winrm_max_memory_per_shell,
|
114
|
-
long: "--winrm-max-memory-per-shell",
|
115
|
-
description: "Set winrm max memory per shell in MB"
|
116
|
-
|
117
|
-
option :azure_domain_name,
|
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'
|
120
|
-
|
121
|
-
option :azure_domain_ou_dn,
|
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"
|
124
|
-
|
125
|
-
option :azure_domain_user,
|
126
|
-
long: "--azure-domain-user DOMAIN_USER_NAME",
|
127
|
-
description: 'Optional. Specifies the username who has access to join the domain.
|
128
|
-
Supported format: username(if domain is already specified in --azure-domain-name option),
|
129
|
-
fully-qualified-DNS-domain\username, user@fully-qualified-DNS-domain'
|
130
|
-
|
131
|
-
option :azure_domain_passwd,
|
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] = config[: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
|
217
|
-
|
218
|
-
def plugin_finalize
|
219
|
-
if config[:connection_protocol] == "cloud-api" && config[: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 ####
|
227
|
-
|
228
|
-
def wait_until_virtual_machine_ready(retry_interval_in_seconds = 30)
|
229
|
-
vm_status = nil
|
230
|
-
begin
|
231
|
-
azure_vm_startup_timeout = config[:azure_vm_startup_timeout].to_i
|
232
|
-
azure_vm_ready_timeout = config[:azure_vm_ready_timeout].to_i
|
233
|
-
vm_status = wait_for_virtual_machine_state(:vm_status_provisioning, azure_vm_startup_timeout, retry_interval_in_seconds)
|
234
|
-
if vm_status != :vm_status_ready
|
235
|
-
begin
|
236
|
-
wait_for_virtual_machine_state(:vm_status_ready, azure_vm_ready_timeout, retry_interval_in_seconds)
|
237
|
-
rescue Chef::Exceptions::CommandTimeout => e
|
238
|
-
ui.warn("\n#{e.message}")
|
239
|
-
ui.warn("Ignoring failure to reach 'ready' with bootstrap.")
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
msg_server_summary(@server)
|
244
|
-
|
245
|
-
if config[:connection_protocol] == "cloud-api"
|
246
|
-
extension_status = wait_for_resource_extension_state(:wagent_provisioning, 5, retry_interval_in_seconds)
|
247
|
-
|
248
|
-
if extension_status != :extension_installing
|
249
|
-
extension_status = wait_for_resource_extension_state(:extension_installing, 5, retry_interval_in_seconds)
|
250
|
-
end
|
251
|
-
|
252
|
-
if extension_status != :extension_provisioning
|
253
|
-
extension_status = wait_for_resource_extension_state(:extension_provisioning, 10, retry_interval_in_seconds)
|
254
|
-
end
|
255
|
-
|
256
|
-
if extension_status != :extension_ready
|
257
|
-
wait_for_resource_extension_state(:extension_ready, 5, retry_interval_in_seconds)
|
258
|
-
end
|
259
|
-
end
|
260
|
-
rescue Exception => e
|
261
|
-
Chef::Log.error("#{e}")
|
262
|
-
raise "Verify connectivity to Azure and subscription resource limit compliance (e.g. maximum CPU core limits) and try again."
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def wait_for_virtual_machine_state(vm_status_goal, total_wait_time_in_minutes, retry_interval_in_seconds)
|
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" }
|
269
|
-
|
270
|
-
print ui.color("\nWaiting for virtual machine to reach status '#{vm_status_description[vm_status_goal]}'\n", :magenta)
|
271
|
-
|
272
|
-
total_wait_time_in_seconds = total_wait_time_in_minutes * 60
|
273
|
-
max_polling_attempts = total_wait_time_in_seconds / retry_interval_in_seconds
|
274
|
-
polling_attempts = 0
|
275
|
-
|
276
|
-
wait_start_time = Time.now
|
277
|
-
|
278
|
-
begin
|
279
|
-
vm_status = get_virtual_machine_status
|
280
|
-
vm_ready = vm_status_ordering[vm_status] >= vm_status_ordering[vm_status_goal]
|
281
|
-
print "."
|
282
|
-
sleep retry_interval_in_seconds unless vm_ready
|
283
|
-
polling_attempts += 1
|
284
|
-
end until vm_ready || polling_attempts >= max_polling_attempts
|
285
|
-
|
286
|
-
unless vm_ready
|
287
|
-
raise Chef::Exceptions::CommandTimeout, "Virtual machine state '#{vm_status_description[vm_status_goal]}' not reached after #{total_wait_time_in_minutes} minutes."
|
288
|
-
end
|
289
|
-
|
290
|
-
elapsed_time_in_minutes = ((Time.now - wait_start_time) / 60).round(2)
|
291
|
-
print ui.color("\nvm state '#{vm_status_description[vm_status_goal]}' reached after #{elapsed_time_in_minutes} minutes.\n", :cyan)
|
292
|
-
vm_status
|
293
|
-
end
|
294
|
-
|
295
|
-
def wait_for_resource_extension_state(extension_status_goal, total_wait_time_in_minutes, retry_interval_in_seconds)
|
296
|
-
extension_status_ordering = { extension_status_not_detected: 0, wagent_provisioning: 1, extension_installing: 2, extension_provisioning: 3, extension_ready: 4 }
|
297
|
-
|
298
|
-
status_description = { extension_status_not_detected: "any", wagent_provisioning: "wagent provisioning", extension_installing: "installing", extension_provisioning: "provisioning", extension_ready: "ready" }
|
299
|
-
|
300
|
-
print ui.color("\nWaiting for Resource Extension to reach status '#{status_description[extension_status_goal]}'\n", :magenta)
|
301
|
-
|
302
|
-
max_polling_attempts = (total_wait_time_in_minutes * 60) / retry_interval_in_seconds
|
303
|
-
polling_attempts = 0
|
304
|
-
|
305
|
-
wait_start_time = Time.now
|
306
|
-
|
307
|
-
begin
|
308
|
-
extension_status = get_extension_status
|
309
|
-
extension_ready = extension_status_ordering[extension_status[:status]] >= extension_status_ordering[extension_status_goal]
|
310
|
-
print "."
|
311
|
-
sleep retry_interval_in_seconds unless extension_ready
|
312
|
-
polling_attempts += 1
|
313
|
-
end until extension_ready || polling_attempts >= max_polling_attempts
|
314
|
-
|
315
|
-
unless extension_ready
|
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]}"
|
317
|
-
end
|
318
|
-
|
319
|
-
elapsed_time_in_minutes = ((Time.now - wait_start_time) / 60).round(2)
|
320
|
-
print ui.color("\nResource extension state '#{status_description[extension_status_goal]}' reached after #{elapsed_time_in_minutes} minutes.\n", :cyan)
|
321
|
-
|
322
|
-
extension_status[:status]
|
323
|
-
end
|
324
|
-
|
325
|
-
def get_virtual_machine_status
|
326
|
-
@server = service.get_role_server(config[:azure_dns_name], config[: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
|
336
|
-
else
|
337
|
-
:vm_status_not_detected
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
def get_extension_status
|
343
|
-
deployment_name = service.deployment_name(config[:azure_dns_name])
|
344
|
-
deployment = service.deployment("hostedservices/#{config[:azure_dns_name]}/deployments/#{deployment_name}")
|
345
|
-
extension_status = {}
|
346
|
-
|
347
|
-
if deployment.at_css("Deployment Name") != nil
|
348
|
-
role_list_xml = deployment.css("RoleInstanceList RoleInstance")
|
349
|
-
role_list_xml.each do |role|
|
350
|
-
if role.at_css("RoleName").text == config[:azure_vm_name]
|
351
|
-
lnx_waagent_fail_msg = "Failed to deserialize the status reported by the Guest Agent"
|
352
|
-
waagent_status_msg = role.at_css("GuestAgentStatus FormattedMessage Message").text
|
353
|
-
if role.at_css("GuestAgentStatus Status").text == "Ready"
|
354
|
-
extn_status = role.at_css("ResourceExtensionStatusList Status").text
|
355
|
-
Chef::Log.debug("Resource extension status is #{extn_status}")
|
356
|
-
if extn_status == "Installing"
|
357
|
-
extension_status[:status] = :extension_installing
|
358
|
-
extension_status[:message] = role.at_css("ResourceExtensionStatusList FormattedMessage Message").text
|
359
|
-
elsif extn_status == "NotReady"
|
360
|
-
extension_status[:status] = :extension_provisioning
|
361
|
-
extension_status[:message] = role.at_css("ResourceExtensionStatusList FormattedMessage Message").text
|
362
|
-
elsif extn_status == "Ready"
|
363
|
-
extension_status[:status] = :extension_ready
|
364
|
-
extension_status[:message] = role.at_css("ResourceExtensionStatusList FormattedMessage Message").text
|
365
|
-
else
|
366
|
-
extension_status[:status] = :extension_status_not_detected
|
367
|
-
end
|
368
|
-
# This fix is for linux waagent issue: api unable to deserialize the waagent status.
|
369
|
-
elsif (role.at_css("GuestAgentStatus Status").text == "NotReady") && (waagent_status_msg == lnx_waagent_fail_msg)
|
370
|
-
extension_status[:status] = :extension_ready
|
371
|
-
else
|
372
|
-
extension_status[:status] = :wagent_provisioning
|
373
|
-
extension_status[:message] = role.at_css("GuestAgentStatus Message").text
|
374
|
-
end
|
375
|
-
else
|
376
|
-
extension_status[:status] = :extension_status_not_detected
|
377
|
-
end
|
378
|
-
end
|
379
|
-
else
|
380
|
-
extension_status[:status] = :extension_status_not_detected
|
381
|
-
end
|
382
|
-
extension_status
|
383
|
-
end
|
384
|
-
|
385
|
-
def create_server_def
|
386
|
-
server_def = {
|
387
|
-
azure_storage_account: config[:azure_storage_account],
|
388
|
-
azure_api_host_name: config[:azure_api_host_name],
|
389
|
-
azure_dns_name: config[:azure_dns_name],
|
390
|
-
azure_vm_name: config[:azure_vm_name],
|
391
|
-
azure_service_location: config[:azure_service_location],
|
392
|
-
azure_os_disk_name: config[:azure_os_disk_name],
|
393
|
-
azure_source_image: config[:azure_source_image],
|
394
|
-
azure_vm_size: config[:azure_vm_size],
|
395
|
-
tcp_endpoints: config[:tcp_endpoints],
|
396
|
-
udp_endpoints: config[:udp_endpoints],
|
397
|
-
connection_protocol: config[:connection_protocol],
|
398
|
-
azure_connect_to_existing_dns: config[:azure_connect_to_existing_dns],
|
399
|
-
connection_user: config[:connection_user],
|
400
|
-
azure_availability_set: config[:azure_availability_set],
|
401
|
-
azure_affinity_group: config[:azure_affinity_group],
|
402
|
-
azure_network_name: config[:azure_network_name],
|
403
|
-
azure_subnet_name: config[:azure_subnet_name],
|
404
|
-
ssl_cert_fingerprint: config[:thumbprint],
|
405
|
-
cert_path: config[:cert_path],
|
406
|
-
cert_password: config[:cert_passphrase],
|
407
|
-
winrm_ssl: config[:winrm_ssl],
|
408
|
-
winrm_max_timeout: config[:winrm_max_timeout].to_i * 60 * 1000, # converting minutes to milliseconds
|
409
|
-
winrm_max_memory_per_shell: config[:winrm_max_memory_per_shell],
|
410
|
-
}
|
411
|
-
|
412
|
-
if config[:connection_protocol] == "cloud-api"
|
413
|
-
server_def[:chef_extension] = get_chef_extension_name
|
414
|
-
server_def[:chef_extension_publisher] = get_chef_extension_publisher
|
415
|
-
server_def[:chef_extension_version] = get_chef_extension_version
|
416
|
-
server_def[:chef_extension_public_param] = get_chef_extension_public_params
|
417
|
-
server_def[:chef_extension_private_param] = get_chef_extension_private_params
|
418
|
-
else
|
419
|
-
if is_image_windows?
|
420
|
-
# We can specify the AdminUsername after API version 2013-03-01. However, in this API version,
|
421
|
-
# the AdminUsername is a required parameter.
|
422
|
-
# Also, the user name cannot be Administrator, Admin, Admin1 etc, for enhanced security (provided by Azure)
|
423
|
-
if config[:connection_user].nil? || config[:connection_user].downcase =~ /admin*/
|
424
|
-
ui.error("Connection User is compulsory parameter and it cannot be named 'admin*'")
|
425
|
-
exit 1
|
426
|
-
# take cares of when user name contains domain
|
427
|
-
# azure add role api doesn't support '\\' in user name
|
428
|
-
elsif config[:connection_user].split('\\').length.eql?(2)
|
429
|
-
server_def[:connection_user] = config[:connection_user].split('\\')[1]
|
430
|
-
end
|
431
|
-
else
|
432
|
-
unless config[:connection_user]
|
433
|
-
ui.error("Connection User is compulsory parameter")
|
434
|
-
exit 1
|
435
|
-
end
|
436
|
-
unless config[:connection_password] || config[:ssh_identity_file]
|
437
|
-
ui.error("Specify either SSH Key or SSH Password")
|
438
|
-
exit 1
|
439
|
-
end
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
if is_image_windows?
|
444
|
-
server_def[:os_type] = "Windows"
|
445
|
-
server_def[:admin_password] = config[:connection_password]
|
446
|
-
server_def[:connection_protocol] = config[:connection_protocol] || "winrm"
|
447
|
-
else
|
448
|
-
server_def[:os_type] = "Linux"
|
449
|
-
server_def[:connection_protocol] = config[:connection_protocol].nil? || config[:connection_protocol] == "winrm" ? "ssh" : config[:connection_protocol]
|
450
|
-
server_def[:connection_user] = config[:connection_user]
|
451
|
-
server_def[:connection_password] = config[:connection_password]
|
452
|
-
server_def[:ssh_identity_file] = config[:ssh_identity_file]
|
453
|
-
server_def[:identity_file_passphrase] = config[:identity_file_passphrase]
|
454
|
-
end
|
455
|
-
|
456
|
-
azure_connect_to_existing_dns = config[:azure_connect_to_existing_dns]
|
457
|
-
if is_image_windows? && server_def[:connection_protocol] == "winrm"
|
458
|
-
port = config[:connection_port] || "5985"
|
459
|
-
port = config[:connection_port] || Random.rand(64000) + 1000 if azure_connect_to_existing_dns
|
460
|
-
elsif server_def[:connection_protocol] == "ssh"
|
461
|
-
port = config[:connection_port] || "22"
|
462
|
-
port = config[:connection_port] || Random.rand(64000) + 1000 if azure_connect_to_existing_dns
|
463
|
-
end
|
464
|
-
|
465
|
-
server_def[:port] = port
|
466
|
-
|
467
|
-
server_def[:is_vm_image] = service.vm_image?(config[:azure_source_image])
|
468
|
-
server_def[:azure_domain_name] = config[:azure_domain_name] if config[:azure_domain_name]
|
469
|
-
|
470
|
-
if config[:azure_domain_user]
|
471
|
-
# extract domain name since it should be part of username
|
472
|
-
case config[:azure_domain_user]
|
473
|
-
when /(\S+)\\(.+)/ # format - fully-qualified-DNS-domain\username
|
474
|
-
server_def[:azure_domain_name] = $1 if config[:azure_domain_name].nil?
|
475
|
-
server_def[:azure_user_domain_name] = $1
|
476
|
-
server_def[:azure_domain_user] = $2
|
477
|
-
when /(.+)@(\S+)/ # format - user@fully-qualified-DNS-domain
|
478
|
-
server_def[:azure_domain_name] = $2 if config[:azure_domain_name].nil?
|
479
|
-
server_def[:azure_user_domain_name] = $2
|
480
|
-
server_def[:azure_domain_user] = $1
|
481
|
-
else
|
482
|
-
if config[:azure_domain_name].nil?
|
483
|
-
ui.error('--azure-domain-name should be specified if --azure-domain-user is not in one of the following formats: fully-qualified-DNS-domain\username, user@fully-qualified-DNS-domain')
|
484
|
-
exit 1
|
485
|
-
end
|
486
|
-
server_def[:azure_domain_user] = config[:azure_domain_user]
|
487
|
-
end
|
488
|
-
end
|
489
|
-
server_def[:azure_domain_passwd] = config[:azure_domain_passwd]
|
490
|
-
server_def[:azure_domain_ou_dn] = config[:azure_domain_ou_dn]
|
491
|
-
|
492
|
-
server_def
|
493
|
-
end
|
494
|
-
|
495
|
-
private
|
496
|
-
|
497
|
-
def set_defaults
|
498
|
-
set_configs
|
499
|
-
end
|
500
|
-
|
501
|
-
def set_configs
|
502
|
-
unless config[:connection_user].nil?
|
503
|
-
config[:connection_user] = config[:connection_user]
|
504
|
-
end
|
505
|
-
|
506
|
-
unless config[:connection_password].nil?
|
507
|
-
config[:connection_password] = config[:connection_password]
|
508
|
-
end
|
509
|
-
|
510
|
-
config[:azure_dns_name] = get_dns_name(config[:azure_dns_name])
|
511
|
-
config[:azure_vm_name] = config[:azure_dns_name] unless config[:azure_vm_name]
|
512
|
-
config[:chef_node_name] = config[:azure_vm_name] unless config[:chef_node_name]
|
513
|
-
end
|
514
|
-
|
515
|
-
# This is related to Windows VM's specifically and computer name
|
516
|
-
# length limits for legacy computer accounts
|
517
|
-
MAX_VM_NAME_CHARACTERS = 15
|
518
|
-
|
519
|
-
# generate a random dns_name if azure_dns_name is empty
|
520
|
-
def get_dns_name(azure_dns_name, prefix = "az-")
|
521
|
-
return azure_dns_name unless azure_dns_name.nil?
|
522
|
-
|
523
|
-
if config[:azure_vm_name].nil?
|
524
|
-
(prefix + SecureRandom.hex((MAX_VM_NAME_CHARACTERS - prefix.length) / 2))
|
525
|
-
else
|
526
|
-
config[:azure_vm_name]
|
527
|
-
end
|
528
|
-
end
|
529
|
-
end
|
530
|
-
end
|
531
|
-
end
|