knife-azure 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +201 -201
- data/README.md +37 -654
- data/lib/azure/resource_management/ARM_deployment_template.rb +87 -50
- data/lib/azure/resource_management/ARM_interface.rb +236 -516
- data/lib/azure/resource_management/vnet_config.rb +254 -0
- data/lib/azure/resource_management/windows_credentials.rb +109 -61
- data/lib/azure/service_management/ASM_interface.rb +17 -1
- data/lib/azure/service_management/certificate.rb +37 -13
- data/lib/azure/service_management/connection.rb +0 -0
- data/lib/azure/service_management/deploy.rb +0 -0
- data/lib/azure/service_management/disk.rb +0 -0
- data/lib/azure/service_management/host.rb +0 -0
- data/lib/azure/service_management/image.rb +0 -0
- data/lib/azure/service_management/rest.rb +0 -0
- data/lib/azure/service_management/role.rb +0 -0
- data/lib/azure/service_management/utility.rb +0 -0
- data/lib/chef/knife/azure_base.rb +100 -0
- data/lib/chef/knife/azure_image_list.rb +0 -0
- data/lib/chef/knife/azure_server_create.rb +0 -98
- data/lib/chef/knife/azure_server_delete.rb +0 -0
- data/lib/chef/knife/azure_server_list.rb +0 -0
- data/lib/chef/knife/azure_server_show.rb +0 -0
- data/lib/chef/knife/azurerm_base.rb +42 -9
- data/lib/chef/knife/azurerm_server_create.rb +31 -24
- data/lib/chef/knife/azurerm_server_delete.rb +1 -10
- data/lib/chef/knife/azurerm_server_list.rb +5 -1
- data/lib/chef/knife/azurerm_server_show.rb +5 -1
- data/lib/chef/knife/bootstrap/bootstrap_options.rb +12 -18
- data/lib/chef/knife/bootstrap/bootstrapper.rb +34 -15
- data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +21 -24
- data/lib/chef/knife/bootstrap_azure.rb +58 -0
- data/lib/chef/knife/bootstrap_azurerm.rb +40 -50
- data/lib/knife-azure/version.rb +1 -1
- metadata +27 -12
@@ -132,17 +132,24 @@ class Chef
|
|
132
132
|
|
133
133
|
option :azure_vnet_name,
|
134
134
|
:long => "--azure-vnet-name VNET_NAME",
|
135
|
-
:description => "Optional. Specifies the virtual network name
|
136
|
-
|
137
|
-
|
135
|
+
:description => "Optional. Specifies the virtual network name.
|
136
|
+
This may be the name of an existing vnet present under the given resource group
|
137
|
+
or this may be the name of a new vnet to be added in the given resource group.
|
138
|
+
If not specified then azure-vm-name will be taken as the default name for vnet name as well.
|
139
|
+
Along with this option azure-vnet-subnet-name option can also be specified or it can also be skipped."
|
138
140
|
|
139
141
|
option :azure_vnet_subnet_name,
|
140
142
|
:long => "--azure-vnet-subnet-name VNET_SUBNET_NAME",
|
141
|
-
:description => "Optional. Specifies the virtual network subnet name.
|
143
|
+
:description => "Optional. Specifies the virtual network subnet name.
|
144
|
+
Must be specified only with azure-vnet-name option.
|
145
|
+
This may be the name of an existing subnet present under the given virtual network
|
146
|
+
or this may be the name of a new subnet to be added in the given virtual network.
|
147
|
+
If not specified then azure-vm-name will be taken as the default name for subnet name as well.
|
148
|
+
Value as 'GatewaySubnet' cannot be used as the name for the --azure-vnet-subnet-name option."
|
142
149
|
|
143
|
-
option :
|
144
|
-
:long => "--
|
145
|
-
:description => "
|
150
|
+
option :ssh_public_key,
|
151
|
+
:long => "--ssh-public-key FILENAME",
|
152
|
+
:description => "It is the ssh-rsa public key path. Specify either ssh-password or ssh-public-key"
|
146
153
|
|
147
154
|
option :thumbprint,
|
148
155
|
:long => "--thumbprint THUMBPRINT",
|
@@ -156,6 +163,11 @@ class Chef
|
|
156
163
|
:long => "--cert-path PATH",
|
157
164
|
:description => "SSL Certificate Path"
|
158
165
|
|
166
|
+
option :tcp_endpoints,
|
167
|
+
:short => "-t PORT_LIST",
|
168
|
+
:long => "--tcp-endpoints PORT_LIST",
|
169
|
+
:description => "Comma-separated list of TCP ports to open e.g. '80,433'"
|
170
|
+
|
159
171
|
option :server_count,
|
160
172
|
:long => "--server-count COUNT",
|
161
173
|
:description => "Number of servers to create with same configuration.
|
@@ -188,16 +200,7 @@ class Chef
|
|
188
200
|
|
189
201
|
vm_details = service.create_server(create_server_def)
|
190
202
|
rescue => error
|
191
|
-
|
192
|
-
if error.response.body['error']['code'] == 'DeploymentFailed'
|
193
|
-
ui.error("#{error.body['error']['message']}")
|
194
|
-
else
|
195
|
-
ui.error(error.response.body)
|
196
|
-
end
|
197
|
-
else
|
198
|
-
ui.error("#{error.message}")
|
199
|
-
end
|
200
|
-
Chef::Log.debug("#{error.backtrace.join("\n")}")
|
203
|
+
service.common_arm_rescue_block(error)
|
201
204
|
exit
|
202
205
|
end
|
203
206
|
end
|
@@ -227,6 +230,10 @@ class Chef
|
|
227
230
|
:server_count => locate_config_value(:server_count)
|
228
231
|
}
|
229
232
|
|
233
|
+
if locate_config_value(:tcp_endpoints)
|
234
|
+
server_def[:tcp_endpoints] = locate_config_value(:tcp_endpoints)
|
235
|
+
end
|
236
|
+
|
230
237
|
server_def[:azure_storage_account] = locate_config_value(:azure_vm_name) if server_def[:azure_storage_account].nil?
|
231
238
|
server_def[:azure_storage_account] = server_def[:azure_storage_account].gsub(/[!@#$%^&*()_-]/,'')
|
232
239
|
|
@@ -234,7 +241,7 @@ class Chef
|
|
234
241
|
server_def[:azure_os_disk_name] = server_def[:azure_os_disk_name].gsub(/[!@#$%^&*()_-]/,'')
|
235
242
|
|
236
243
|
server_def[:azure_vnet_name] = locate_config_value(:azure_vm_name) if server_def[:azure_vnet_name].nil?
|
237
|
-
server_def[:azure_vnet_subnet_name] = locate_config_value(:azure_vm_name) if locate_config_value(:azure_vnet_subnet_name).nil?
|
244
|
+
server_def[:azure_vnet_subnet_name] = locate_config_value(:azure_vm_name) if locate_config_value(:azure_vnet_subnet_name).nil?
|
238
245
|
|
239
246
|
server_def[:chef_extension] = get_chef_extension_name
|
240
247
|
server_def[:chef_extension_publisher] = get_chef_extension_publisher
|
@@ -249,9 +256,9 @@ class Chef
|
|
249
256
|
server_def[:ssh_user] = locate_config_value(:ssh_user)
|
250
257
|
server_def[:ssh_password] = locate_config_value(:ssh_password)
|
251
258
|
server_def[:disablePasswordAuthentication] = "false"
|
252
|
-
if locate_config_value(:
|
259
|
+
if locate_config_value(:ssh_public_key)
|
253
260
|
server_def[:disablePasswordAuthentication] = "true"
|
254
|
-
server_def[:ssh_key] = File.read(locate_config_value(:
|
261
|
+
server_def[:ssh_key] = File.read(locate_config_value(:ssh_public_key))
|
255
262
|
end
|
256
263
|
end
|
257
264
|
|
@@ -285,14 +292,14 @@ class Chef
|
|
285
292
|
end
|
286
293
|
|
287
294
|
def validate_params!
|
288
|
-
if locate_config_value(:azure_vnet_name) && !locate_config_value(:azure_vnet_subnet_name)
|
289
|
-
raise ArgumentError, "When a --azure-vnet-name is specified, the --azure-vnet-subnet-name must also be specified."
|
290
|
-
end
|
291
|
-
|
292
295
|
if locate_config_value(:azure_vnet_subnet_name) && !locate_config_value(:azure_vnet_name)
|
293
296
|
raise ArgumentError, "When --azure-vnet-subnet-name is specified, the --azure-vnet-name must also be specified."
|
294
297
|
end
|
295
298
|
|
299
|
+
if locate_config_value(:azure_vnet_subnet_name) == 'GatewaySubnet'
|
300
|
+
raise ArgumentError, 'GatewaySubnet cannot be used as the name for --azure-vnet-subnet-name option. GatewaySubnet can only be used for virtual network gateways.'
|
301
|
+
end
|
302
|
+
|
296
303
|
if is_image_windows?
|
297
304
|
if locate_config_value(:winrm_user).nil? || locate_config_value(:winrm_password).nil?
|
298
305
|
raise ArgumentError, "Please provide --winrm-user and --winrm-password options for Windows option."
|
@@ -104,16 +104,7 @@ class Chef
|
|
104
104
|
ui.warn("Corresponding node and client for the #{vm_name} server were not deleted and remain registered with the Chef Server")
|
105
105
|
end
|
106
106
|
rescue => error
|
107
|
-
|
108
|
-
if error.body['error']['code'] == 'ResourceNotFound'
|
109
|
-
ui.error("#{error.body['error']['message']}")
|
110
|
-
else
|
111
|
-
ui.error(error.body)
|
112
|
-
end
|
113
|
-
else
|
114
|
-
ui.error("#{error.message}")
|
115
|
-
Chef::Log.debug("#{error.backtrace.join("\n")}")
|
116
|
-
end
|
107
|
+
service.common_arm_rescue_block(error)
|
117
108
|
end
|
118
109
|
end
|
119
110
|
end
|
@@ -11,7 +11,11 @@ class Chef
|
|
11
11
|
def run
|
12
12
|
$stdout.sync = true
|
13
13
|
validate_arm_keys!
|
14
|
-
|
14
|
+
begin
|
15
|
+
service.list_servers(locate_config_value(:azure_resource_group_name))
|
16
|
+
rescue => error
|
17
|
+
service.common_arm_rescue_block(error)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
@@ -29,7 +29,11 @@ class Chef
|
|
29
29
|
def run
|
30
30
|
$stdout.sync = true
|
31
31
|
validate_arm_keys!(:azure_resource_group_name)
|
32
|
-
|
32
|
+
begin
|
33
|
+
service.show_server(@name_args[0], locate_config_value(:azure_resource_group_name))
|
34
|
+
rescue => error
|
35
|
+
service.common_arm_rescue_block(error)
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
end
|
@@ -16,6 +16,12 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
|
+
#
|
20
|
+
# Bootstrap options listed here are in accordance with the options supported by
|
21
|
+
# Chef's bootstrap which bootstraps the target system through protocols like ssh
|
22
|
+
# or winrm. In addition it contains additional options which gives the users a
|
23
|
+
# choice to bootstrap the target system through cloud-api protocol.
|
24
|
+
#
|
19
25
|
|
20
26
|
require 'chef/knife/winrm_base'
|
21
27
|
require 'chef/knife/bootstrap_windows_base'
|
@@ -72,30 +78,18 @@ class Chef
|
|
72
78
|
:description => "Execute the bootstrap via sudo with password",
|
73
79
|
:boolean => false
|
74
80
|
|
75
|
-
option :auto_update_client,
|
76
|
-
:long => "--auto-update-client",
|
77
|
-
:boolean => true,
|
78
|
-
:default => false,
|
79
|
-
:description => "Set this flag to enable auto chef client update in azure chef extension. This flag should be used with cloud-api bootstrap protocol only"
|
80
|
-
|
81
|
-
option :delete_chef_extension_config,
|
82
|
-
:long => "--delete-chef-extension-config",
|
83
|
-
:boolean => true,
|
84
|
-
:default => false,
|
85
|
-
:description => "Determines whether Chef configuration files removed when Azure removes the Chef resource extension from the VM. This option is only valid for the 'cloud-api' bootstrap protocol. The default is false."
|
86
|
-
|
87
|
-
option :uninstall_chef_client,
|
88
|
-
:long => "--uninstall-chef-client",
|
89
|
-
:boolean => true,
|
90
|
-
:default => false,
|
91
|
-
:description => "Determines whether Chef Client will be un-installed from the VM or not. This option is only valid for the 'cloud-api' bootstrap protocol. The default value is false."
|
92
|
-
|
93
81
|
option :extended_logs,
|
94
82
|
:long => "--extended-logs",
|
95
83
|
:boolean => true,
|
96
84
|
:default => false,
|
97
85
|
:description => "Optional. Provide this option when --bootstrap-protocol is set to 'cloud-api'. It shows chef converge logs in detail."
|
98
86
|
|
87
|
+
option :chef_service_interval,
|
88
|
+
:long => "--chef-service-interval INTERVAL",
|
89
|
+
:description => "Optional. Provide this option when --bootstrap-protocol is set to 'cloud-api'.
|
90
|
+
It specifies the frequency (in minutes) at which the chef-service runs.
|
91
|
+
Pass 0 if you don't want the chef-service to be installed on the target machine."
|
92
|
+
|
99
93
|
end
|
100
94
|
end
|
101
95
|
end
|
@@ -217,8 +217,8 @@ class Chef
|
|
217
217
|
bootstrap.config[:host_key_verify] = config[:host_key_verify]
|
218
218
|
Chef::Config[:knife][:secret] = config[:encrypted_data_bag_secret] if config[:encrypted_data_bag_secret]
|
219
219
|
Chef::Config[:knife][:secret_file] = config[:encrypted_data_bag_secret_file] if config[:encrypted_data_bag_secret_file]
|
220
|
-
bootstrap.config[:secret] = locate_config_value(:
|
221
|
-
bootstrap.config[:secret_file] = locate_config_value(:
|
220
|
+
bootstrap.config[:secret] = locate_config_value(:encrypted_data_bag_secret)
|
221
|
+
bootstrap.config[:secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
|
222
222
|
bootstrap.config[:bootstrap_install_command] = locate_config_value(:bootstrap_install_command)
|
223
223
|
bootstrap.config[:bootstrap_wget_options] = locate_config_value(:bootstrap_wget_options)
|
224
224
|
bootstrap.config[:bootstrap_curl_options] = locate_config_value(:bootstrap_curl_options)
|
@@ -239,8 +239,16 @@ class Chef
|
|
239
239
|
Chef::Config[:knife][:azure_chef_extension_version]
|
240
240
|
else
|
241
241
|
chef_extension_name = chef_extension_name.nil? ? get_chef_extension_name : chef_extension_name
|
242
|
-
|
243
|
-
|
242
|
+
if @service.instance_of? Azure::ResourceManagement::ARMInterface
|
243
|
+
service.get_latest_chef_extension_version({
|
244
|
+
:azure_service_location => locate_config_value(:azure_service_location),
|
245
|
+
:chef_extension_publisher => get_chef_extension_publisher,
|
246
|
+
:chef_extension => chef_extension_name
|
247
|
+
})
|
248
|
+
elsif @service.instance_of? Azure::ServiceManagement::ASMInterface
|
249
|
+
extensions = service.get_extension(chef_extension_name, get_chef_extension_publisher)
|
250
|
+
extensions.css("Version").max.text.split(".").first + ".*"
|
251
|
+
end
|
244
252
|
end
|
245
253
|
end
|
246
254
|
|
@@ -273,24 +281,15 @@ class Chef
|
|
273
281
|
end
|
274
282
|
|
275
283
|
pub_config[:runlist] = locate_config_value(:run_list).empty? ? "" : locate_config_value(:run_list).join(",").to_json
|
276
|
-
pub_config[:autoUpdateClient] = locate_config_value(:auto_update_client) ? "true" : "false"
|
277
|
-
pub_config[:deleteChefConfig] = locate_config_value(:delete_chef_extension_config) ? "true" : "false"
|
278
|
-
pub_config[:uninstallChefClient] = locate_config_value(:uninstall_chef_client) ? "true" : "false"
|
279
284
|
pub_config[:custom_json_attr] = locate_config_value(:json_attributes) || {}
|
280
285
|
pub_config[:extendedLogs] = locate_config_value(:extended_logs) ? "true" : "false"
|
281
|
-
pub_config[:hints] = ohai_hints if @service.instance_of?
|
286
|
+
pub_config[:hints] = ohai_hints if @service.instance_of?(Azure::ResourceManagement::ARMInterface) && !locate_config_value(:ohai_hints).nil?
|
287
|
+
pub_config[:chef_service_interval] = locate_config_value(:chef_service_interval) if locate_config_value(:chef_service_interval)
|
282
288
|
|
283
289
|
# bootstrap attributes
|
284
290
|
pub_config[:bootstrap_options] = {}
|
285
291
|
pub_config[:bootstrap_options][:environment] = locate_config_value(:environment) if locate_config_value(:environment)
|
286
292
|
pub_config[:bootstrap_options][:chef_node_name] = locate_config_value(:chef_node_name) if locate_config_value(:chef_node_name)
|
287
|
-
|
288
|
-
if ( locate_config_value(:secret_file) || locate_config_value(:encrypted_data_bag_secret_file) ) && ( !locate_config_value(:secret) || !locate_config_value(:encrypted_data_bag_secret) )
|
289
|
-
pub_config[:bootstrap_options][:encrypted_data_bag_secret] = Chef::EncryptedDataBagItem.load_secret(config[:secret_file])
|
290
|
-
elsif locate_config_value(:encrypted_data_bag_secret) || locate_config_value(:secret)
|
291
|
-
pub_config[:bootstrap_options][:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret) || locate_config_value(:secret)
|
292
|
-
end
|
293
|
-
|
294
293
|
pub_config[:bootstrap_options][:chef_server_url] = Chef::Config[:chef_server_url] if Chef::Config[:chef_server_url]
|
295
294
|
pub_config[:bootstrap_options][:validation_client_name] = Chef::Config[:validation_client_name] if Chef::Config[:validation_client_name]
|
296
295
|
pub_config[:bootstrap_options][:node_verify_api_cert] = locate_config_value(:node_verify_api_cert) ? "true" : "false" if config.key?(:node_verify_api_cert)
|
@@ -301,6 +300,23 @@ class Chef
|
|
301
300
|
pub_config
|
302
301
|
end
|
303
302
|
|
303
|
+
def load_correct_secret
|
304
|
+
knife_secret_file = Chef::Config[:knife][:encrypted_data_bag_secret_file]
|
305
|
+
knife_secret = Chef::Config[:knife][:encrypted_data_bag_secret]
|
306
|
+
cli_secret_file = config[:encrypted_data_bag_secret_file]
|
307
|
+
cli_secret = config[:encrypted_data_bag_secret]
|
308
|
+
|
309
|
+
#The value set in knife.rb gets set in config object too
|
310
|
+
#That's why setting cli objects to nil if the values are specified in knife.rb
|
311
|
+
cli_secret_file = nil if cli_secret_file == knife_secret_file
|
312
|
+
cli_secret = nil if cli_secret == knife_secret
|
313
|
+
|
314
|
+
cli_secret_file = Chef::EncryptedDataBagItem.load_secret(cli_secret_file) if cli_secret_file != nil
|
315
|
+
knife_secret_file = Chef::EncryptedDataBagItem.load_secret(knife_secret_file) if knife_secret_file != nil
|
316
|
+
|
317
|
+
cli_secret_file || cli_secret || knife_secret_file || knife_secret
|
318
|
+
end
|
319
|
+
|
304
320
|
def get_chef_extension_private_params
|
305
321
|
pri_config = Hash.new
|
306
322
|
|
@@ -335,6 +351,9 @@ class Chef
|
|
335
351
|
end
|
336
352
|
end
|
337
353
|
|
354
|
+
# encrypted_data_bag_secret key for encrypting/decrypting the data bags
|
355
|
+
pri_config[:encrypted_data_bag_secret] = load_correct_secret
|
356
|
+
|
338
357
|
pri_config
|
339
358
|
end
|
340
359
|
end
|
@@ -16,6 +16,9 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
|
+
#
|
20
|
+
# Bootstrap options listed here are supported only for cloud-api protocol.
|
21
|
+
#
|
19
22
|
|
20
23
|
class Chef
|
21
24
|
class Knife
|
@@ -81,36 +84,30 @@ class Chef
|
|
81
84
|
:long => "--azure-extension-client-config CLIENT_PATH",
|
82
85
|
:description => "Optional. Path to a client.rb file for use by the bootstrapped node."
|
83
86
|
|
84
|
-
option :
|
85
|
-
:long => "--auto-update-client",
|
86
|
-
:boolean => true,
|
87
|
-
:default => false,
|
88
|
-
:description => "Set this flag to enable auto chef client update in azure chef extension."
|
89
|
-
|
90
|
-
option :delete_chef_extension_config,
|
91
|
-
:long => "--delete-chef-extension-config",
|
92
|
-
:boolean => true,
|
93
|
-
:default => false,
|
94
|
-
:description => "Determines whether Chef configuration files removed when Azure removes the Chef resource extension from the VM. The default is false."
|
95
|
-
|
96
|
-
option :uninstall_chef_client,
|
97
|
-
:long => "--uninstall-chef-client",
|
98
|
-
:boolean => true,
|
99
|
-
:default => false,
|
100
|
-
:description => "Determines whether Chef Client will be un-installed from the VM or not. The default value is false."
|
101
|
-
|
102
|
-
option :secret,
|
87
|
+
option :encrypted_data_bag_secret,
|
103
88
|
:short => "-s SECRET",
|
104
89
|
:long => "--secret ",
|
105
90
|
:description => "The secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret'"
|
106
91
|
|
107
|
-
option :
|
92
|
+
option :encrypted_data_bag_secret_file,
|
108
93
|
:long => "--secret-file SECRET_FILE",
|
109
94
|
:description => "A file containing the secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret_file'"
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
95
|
+
|
96
|
+
option :extended_logs,
|
97
|
+
:long => "--extended-logs",
|
98
|
+
:boolean => true,
|
99
|
+
:default => false,
|
100
|
+
:description => "Optional. It shows chef convergence logs in detail."
|
101
|
+
|
102
|
+
option :chef_service_interval,
|
103
|
+
:long => "--chef-service-interval INTERVAL",
|
104
|
+
:description => "Optional. It specifies the frequency (in minutes) at which the chef-service runs.
|
105
|
+
Pass 0 if you don't want the chef-service to be installed on the target machine."
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
114
111
|
end
|
115
112
|
end
|
116
113
|
|
@@ -42,6 +42,12 @@ class Chef
|
|
42
42
|
begin
|
43
43
|
if @name_args.length == 1
|
44
44
|
service.add_extension(@name_args[0], set_ext_params)
|
45
|
+
if locate_config_value(:extended_logs)
|
46
|
+
print "\n\nWaiting for the Chef Extension to become available/ready"
|
47
|
+
wait_until_extension_available(Time.now, 10)
|
48
|
+
print "\n\nWaiting for the first chef-client run"
|
49
|
+
fetch_chef_client_logs(Time.now, 35)
|
50
|
+
end
|
45
51
|
else
|
46
52
|
raise ArgumentError, 'Please specify the SERVER name which needs to be bootstrapped via the Chef Extension.' if @name_args.length == 0
|
47
53
|
raise ArgumentError, 'Please specify only one SERVER name which needs to be bootstrapped via the Chef Extension.' if @name_args.length > 1
|
@@ -61,6 +67,8 @@ class Chef
|
|
61
67
|
azure_dns_name: locate_config_value(:azure_dns_name)
|
62
68
|
})
|
63
69
|
|
70
|
+
## if azure_dns_name value not passed by user then set it using the hostedservicename attribute from the retrieved server's object ##
|
71
|
+
config[:azure_dns_name] = server.hostedservicename if locate_config_value(:azure_dns_name).nil? && (server.instance_of? Azure::Role)
|
64
72
|
if !server.instance_of? Azure::Role
|
65
73
|
if server.nil?
|
66
74
|
if !locate_config_value(:azure_dns_name).nil?
|
@@ -105,6 +113,56 @@ class Chef
|
|
105
113
|
|
106
114
|
ext_params
|
107
115
|
end
|
116
|
+
|
117
|
+
def wait_until_extension_available(extension_deploy_start_time, extension_availaibility_wait_timeout)
|
118
|
+
extension_availaibility_wait_time = ((Time.now - extension_deploy_start_time) / 60).round
|
119
|
+
if extension_availaibility_wait_time <= extension_availaibility_wait_timeout
|
120
|
+
## extension availaibility wait time has not exceeded the maximum threshold set for the wait timeout ##
|
121
|
+
my_role = nil
|
122
|
+
sleep_and_wait = false
|
123
|
+
deployment = fetch_deployment
|
124
|
+
if deployment.at_css('Deployment Name') != nil
|
125
|
+
role_list_xml = deployment.css('RoleInstanceList RoleInstance')
|
126
|
+
## list of roles found under the deployment ##
|
127
|
+
role_list_xml.each do |role|
|
128
|
+
## search in the roles list for the given role ##
|
129
|
+
if role.at_css("RoleName").text == @name_args[0]
|
130
|
+
my_role = role
|
131
|
+
break
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
if my_role && my_role.at_css("GuestAgentStatus Status").text == "Ready"
|
136
|
+
## given role found and also GuestAgent is ready ##
|
137
|
+
extension = fetch_extension(my_role)
|
138
|
+
## check if Chef Extension not found (which means it is not available/ready yet) then sleep_and_wait OR
|
139
|
+
## if found (which means it is available/ready now) then proceed further with chef-client run logs fetch process ##
|
140
|
+
if extension.nil?
|
141
|
+
sleep_and_wait = true
|
142
|
+
end
|
143
|
+
else
|
144
|
+
## given role not found or GuestAgent not ready yet ##
|
145
|
+
sleep_and_wait = true
|
146
|
+
end
|
147
|
+
else
|
148
|
+
## deployment could not be found ##
|
149
|
+
sleep_and_wait = true
|
150
|
+
end
|
151
|
+
|
152
|
+
## wait for some time and then re-fetch the status ##
|
153
|
+
if sleep_and_wait == true
|
154
|
+
print "#{ui.color('.', :bold)}"
|
155
|
+
sleep 30
|
156
|
+
wait_until_extension_available(
|
157
|
+
extension_deploy_start_time,
|
158
|
+
extension_availaibility_wait_timeout
|
159
|
+
)
|
160
|
+
end
|
161
|
+
else
|
162
|
+
## extension availaibility wait time exceeded maximum threshold set for the wait timeout ##
|
163
|
+
raise "\nUnable to fetch chef-client run logs as Chef Extension seems to be unavailable even after #{extension_availaibility_wait_timeout} minutes of its deployment.\n"
|
164
|
+
end
|
165
|
+
end
|
108
166
|
end
|
109
167
|
end
|
110
168
|
end
|
@@ -20,6 +20,8 @@
|
|
20
20
|
require 'chef/knife/azurerm_base'
|
21
21
|
require 'chef/knife/bootstrap/common_bootstrap_options'
|
22
22
|
require 'chef/knife/bootstrap/bootstrapper'
|
23
|
+
require 'azure/resource_management/ARM_interface'
|
24
|
+
require 'time'
|
23
25
|
|
24
26
|
class Chef
|
25
27
|
class Knife
|
@@ -34,7 +36,7 @@ class Chef
|
|
34
36
|
:short => "-m LOCATION",
|
35
37
|
:long => "--azure-service-location LOCATION",
|
36
38
|
: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.
|
37
|
-
Eg:
|
39
|
+
Eg: westus, eastus, eastasia, southeastasia, northeurope, westeurope",
|
38
40
|
:proc => Proc.new { |lo| Chef::Config[:knife][:azure_service_location] = lo }
|
39
41
|
|
40
42
|
def run
|
@@ -42,70 +44,58 @@ class Chef
|
|
42
44
|
validate_arm_keys!(:azure_resource_group_name, :azure_service_location)
|
43
45
|
|
44
46
|
begin
|
45
|
-
|
47
|
+
if @name_args.length == 1
|
46
48
|
ui.log("Creating VirtualMachineExtension....")
|
47
|
-
|
49
|
+
ext_params = set_ext_params
|
50
|
+
vm_extension = service.create_vm_extension(ext_params)
|
48
51
|
if vm_extension
|
52
|
+
if ext_params[:chef_extension_public_param][:extendedLogs] == 'true'
|
53
|
+
service.fetch_chef_client_logs(ext_params[:azure_resource_group_name], ext_params[:azure_vm_name], ext_params[:chef_extension], Time.now)
|
54
|
+
end
|
49
55
|
ui.log("VirtualMachineExtension creation successfull.")
|
50
56
|
ui.log("Virtual Machine Extension name is: #{vm_extension.name}")
|
51
57
|
ui.log("Virtual Machine Extension ID is: #{vm_extension.id}")
|
52
58
|
end
|
53
|
-
else
|
54
|
-
raise ArgumentError, 'Please specify the SERVER name which needs to be bootstrapped via the Chef Extension.' if @name_args.length == 0
|
55
|
-
raise ArgumentError, 'Please specify only one SERVER name which needs to be bootstrapped via the Chef Extension.' if @name_args.length > 1
|
56
|
-
end
|
57
|
-
rescue => error
|
58
|
-
if error.class == MsRestAzure::AzureOperationError && error.body
|
59
|
-
if error.body['error']['code'] == 'DeploymentFailed'
|
60
|
-
ui.error("#{error.body['error']['message']}")
|
61
|
-
else
|
62
|
-
ui.error(error.body)
|
63
|
-
end
|
64
59
|
else
|
65
|
-
|
66
|
-
Chef
|
60
|
+
raise ArgumentError, 'Please specify the SERVER name which needs to be bootstrapped via the Chef Extension.' if @name_args.length == 0
|
61
|
+
raise ArgumentError, 'Please specify only one SERVER name which needs to be bootstrapped via the Chef Extension.' if @name_args.length > 1
|
67
62
|
end
|
68
|
-
|
69
|
-
|
63
|
+
rescue => error
|
64
|
+
service.common_arm_rescue_block(error)
|
65
|
+
end
|
70
66
|
end
|
71
67
|
|
72
68
|
def set_ext_params
|
73
|
-
|
74
|
-
server = service.find_server(locate_config_value(:azure_resource_group_name), name_args[0])
|
69
|
+
server = service.find_server(locate_config_value(:azure_resource_group_name), name_args[0])
|
75
70
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
else
|
88
|
-
raise "Offer #{server.properties.storage_profile.image_reference.offer} is not supported in the extension."
|
89
|
-
end
|
71
|
+
if server
|
72
|
+
if service.extension_already_installed?(server)
|
73
|
+
raise "Virtual machine #{server.name} already has Chef extension installed on it."
|
74
|
+
else
|
75
|
+
ext_params = Hash.new
|
76
|
+
case server.properties.storage_profile.os_disk.os_type.downcase
|
77
|
+
when 'windows'
|
78
|
+
ext_params[:chef_extension] = 'ChefClient'
|
79
|
+
when 'linux'
|
80
|
+
if ['ubuntu', 'debian', 'rhel', 'centos'].any? { |platform| server.properties.storage_profile.image_reference.offer.downcase.include? platform }
|
81
|
+
ext_params[:chef_extension] = 'LinuxChefClient'
|
90
82
|
else
|
91
|
-
raise "
|
83
|
+
raise "Offer #{server.properties.storage_profile.image_reference.offer} is not supported in the extension."
|
92
84
|
end
|
93
|
-
|
94
|
-
|
95
|
-
ext_params[:azure_vm_name] = @name_args[0]
|
96
|
-
ext_params[:azure_service_location] = locate_config_value(:azure_service_location)
|
97
|
-
ext_params[:chef_extension_publisher] = get_chef_extension_publisher
|
98
|
-
ext_params[:chef_extension_version] = get_chef_extension_version(ext_params[:chef_extension])
|
99
|
-
ext_params[:chef_extension_public_param] = get_chef_extension_public_params
|
100
|
-
ext_params[:chef_extension_private_param] = get_chef_extension_private_params
|
85
|
+
else
|
86
|
+
raise "OS type #{server.properties.storage_profile.os_disk.os_type} is not supported."
|
101
87
|
end
|
102
|
-
|
103
|
-
|
88
|
+
|
89
|
+
ext_params[:azure_resource_group_name] = locate_config_value(:azure_resource_group_name)
|
90
|
+
ext_params[:azure_vm_name] = @name_args[0]
|
91
|
+
ext_params[:azure_service_location] = locate_config_value(:azure_service_location)
|
92
|
+
ext_params[:chef_extension_publisher] = get_chef_extension_publisher
|
93
|
+
ext_params[:chef_extension_version] = get_chef_extension_version(ext_params[:chef_extension])
|
94
|
+
ext_params[:chef_extension_public_param] = get_chef_extension_public_params
|
95
|
+
ext_params[:chef_extension_private_param] = get_chef_extension_private_params
|
104
96
|
end
|
105
|
-
|
106
|
-
|
107
|
-
Chef::Log.debug("#{error.backtrace.join("\n")}")
|
108
|
-
exit
|
97
|
+
else
|
98
|
+
raise "The given server '#{@name_args[0]}' does not exist under resource group '#{locate_config_value(:azure_resource_group_name)}'"
|
109
99
|
end
|
110
100
|
|
111
101
|
ext_params
|
@@ -113,4 +103,4 @@ class Chef
|
|
113
103
|
|
114
104
|
end
|
115
105
|
end
|
116
|
-
end
|
106
|
+
end
|