knife-azure 1.8.0 → 1.8.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,8 +23,6 @@ class Chef
23
23
  class AzureAgList < Knife
24
24
  include Knife::AzureBase
25
25
 
26
- deps { require 'highline' }
27
-
28
26
  banner 'knife azure ag list (options)'
29
27
 
30
28
  def run
@@ -124,7 +124,77 @@ class Chef
124
124
  end
125
125
 
126
126
  # validate command pre-requisites (cli options)
127
+ # (locate_config_value(:winrm_password).length <= 6 && locate_config_value(:winrm_password).length >= 72)
127
128
  def validate_params!
129
+ if locate_config_value(:winrm_password) && !locate_config_value(:winrm_password).strip.size.between?(6, 72)
130
+ ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
131
+ exit 1
132
+ end
133
+
134
+ if locate_config_value(:ssh_password) && !locate_config_value(:ssh_password).empty? && !locate_config_value(:ssh_password).strip.size.between?(6, 72)
135
+ ui.error("The supplied ssh password must be 6-72 characters long and meet password complexity requirements")
136
+ exit 1
137
+ end
138
+
139
+ if locate_config_value(:azure_connect_to_existing_dns) && locate_config_value(:azure_vm_name).nil?
140
+ ui.error("Specify the VM name using --azure-vm-name option, since you are connecting to existing dns")
141
+ exit 1
142
+ end
143
+
144
+ if locate_config_value(:azure_service_location) && locate_config_value(:azure_affinity_group)
145
+ ui.error("Cannot specify both --azure-service-location and --azure-affinity-group, use one or the other.")
146
+ exit 1
147
+ elsif locate_config_value(:azure_service_location).nil? && locate_config_value(:azure_affinity_group).nil?
148
+ ui.error("Must specify either --azure-service-location or --azure-affinity-group.")
149
+ exit 1
150
+ end
151
+
152
+ if locate_config_value(:winrm_authentication_protocol) && ! %w{basic negotiate kerberos}.include?(locate_config_value(:winrm_authentication_protocol).downcase)
153
+ ui.error("Invalid value for --winrm-authentication-protocol option. Use valid protocol values i.e [basic, negotiate, kerberos]")
154
+ exit 1
155
+ end
156
+
157
+ if !(service.valid_image?(locate_config_value(:azure_source_image)))
158
+ ui.error("Image '#{locate_config_value(:azure_source_image)}' is invalid")
159
+ exit 1
160
+ end
161
+
162
+ # Validate join domain requirements.
163
+ if locate_config_value(:azure_domain_name) || locate_config_value(:azure_domain_user)
164
+ if locate_config_value(:azure_domain_user).nil? || locate_config_value(:azure_domain_passwd).nil?
165
+ ui.error("Must specify both --azure-domain-user and --azure-domain-passwd.")
166
+ exit 1
167
+ end
168
+ end
169
+
170
+ if locate_config_value(:winrm_transport) == "ssl" && locate_config_value(:thumbprint).nil? && ( locate_config_value(:winrm_ssl_verify_mode).nil? || locate_config_value(:winrm_ssl_verify_mode) == :verify_peer )
171
+ ui.error("The SSL transport was specified without the --thumbprint option. Specify a thumbprint, or alternatively set the --winrm-ssl-verify-mode option to 'verify_none' to skip verification.")
172
+ exit 1
173
+ end
174
+
175
+ if locate_config_value(:extended_logs) && locate_config_value(:bootstrap_protocol) != 'cloud-api'
176
+ ui.error("--extended-logs option only works with --bootstrap-protocol cloud-api")
177
+ exit 1
178
+ end
179
+
180
+ if locate_config_value(:bootstrap_protocol) == 'cloud-api' && locate_config_value(:azure_vm_name).nil? && locate_config_value(:azure_dns_name).nil?
181
+ ui.error("Specifying the DNS name using --azure-dns-name or VM name using --azure-vm-name option is required with --bootstrap-protocol cloud-api")
182
+ exit 1
183
+ end
184
+
185
+ if locate_config_value(:daemon)
186
+ unless is_image_windows?
187
+ raise ArgumentError, "The daemon option is only supported for Windows nodes."
188
+ end
189
+
190
+ unless locate_config_value(:bootstrap_protocol) == 'cloud-api'
191
+ raise ArgumentError, "The --daemon option requires the use of --bootstrap-protocol cloud-api"
192
+ end
193
+
194
+ unless %w{none service task}.include?(locate_config_value(:daemon).downcase)
195
+ raise ArgumentError, "Invalid value for --daemon option. Valid values are 'none', 'service' and 'task'."
196
+ end
197
+ end
128
198
  end
129
199
 
130
200
  # validates keys
File without changes
@@ -23,8 +23,6 @@ class Chef
23
23
  class AzureInternalLbList < Knife
24
24
  include Knife::AzureBase
25
25
 
26
- deps { require 'highline' }
27
-
28
26
  banner 'knife azure internal lb list (options)'
29
27
 
30
28
  def run
@@ -232,7 +232,6 @@ class Chef
232
232
 
233
233
  def wait_until_virtual_machine_ready(retry_interval_in_seconds = 30)
234
234
  vm_status = nil
235
-
236
235
  begin
237
236
  azure_vm_startup_timeout = locate_config_value(:azure_vm_startup_timeout).to_i
238
237
  azure_vm_ready_timeout = locate_config_value(:azure_vm_ready_timeout).to_i
@@ -355,12 +354,9 @@ class Chef
355
354
  if role.at_css("RoleName").text == locate_config_value(:azure_vm_name)
356
355
  lnx_waagent_fail_msg = "Failed to deserialize the status reported by the Guest Agent"
357
356
  waagent_status_msg = role.at_css("GuestAgentStatus FormattedMessage Message").text
358
-
359
357
  if role.at_css("GuestAgentStatus Status").text == "Ready"
360
358
  extn_status = role.at_css("ResourceExtensionStatusList Status").text
361
-
362
359
  Chef::Log.debug("Resource extension status is #{extn_status}")
363
-
364
360
  if extn_status == "Installing"
365
361
  extension_status[:status] = :extension_installing
366
362
  extension_status[:message] = role.at_css("ResourceExtensionStatusList FormattedMessage Message").text
@@ -387,30 +383,20 @@ class Chef
387
383
  else
388
384
  extension_status[:status] = :extension_status_not_detected
389
385
  end
390
-
391
386
  return extension_status
392
387
  end
393
388
 
394
389
  def run
395
390
  $stdout.sync = true
396
-
397
391
  storage = nil
398
-
399
392
  Chef::Log.info("validating...")
400
393
  validate_asm_keys!(:azure_source_image)
401
-
402
394
  validate_params!
403
-
404
395
  ssh_override_winrm if !is_image_windows?
405
-
406
396
  Chef::Log.info("creating...")
407
-
408
397
  config[:azure_dns_name] = get_dns_name(locate_config_value(:azure_dns_name))
409
-
410
- if not locate_config_value(:azure_vm_name)
411
- config[:azure_vm_name] = locate_config_value(:azure_dns_name)
412
- end
413
-
398
+ config[:azure_vm_name] = locate_config_value(:azure_dns_name) unless locate_config_value(:azure_vm_name)
399
+ config[:chef_node_name] = locate_config_value(:azure_vm_name) unless locate_config_value(:chef_node_name)
414
400
  service.create_server(create_server_def)
415
401
  wait_until_virtual_machine_ready()
416
402
  if locate_config_value(:bootstrap_protocol) == 'cloud-api' && locate_config_value(:extended_logs)
@@ -423,73 +409,6 @@ class Chef
423
409
  bootstrap_exec(server) unless locate_config_value(:bootstrap_protocol) == 'cloud-api'
424
410
  end
425
411
 
426
- def validate_params!
427
- if locate_config_value(:winrm_password) && (locate_config_value(:winrm_password).length <= 6 && locate_config_value(:winrm_password).length >= 72)
428
- ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
429
- exit 1
430
- end
431
-
432
- if locate_config_value(:ssh_password) && (locate_config_value(:ssh_password).length <= 6 && locate_config_value(:ssh_password).length >= 72)
433
- ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
434
- exit 1
435
- end
436
-
437
- if locate_config_value(:azure_connect_to_existing_dns) && locate_config_value(:azure_vm_name).nil?
438
- ui.error("Specify the VM name using --azure-vm-name option, since you are connecting to existing dns")
439
- exit 1
440
- end
441
-
442
- if locate_config_value(:azure_service_location) && locate_config_value(:azure_affinity_group)
443
- ui.error("Cannot specify both --azure-service-location and --azure-affinity-group, use one or the other.")
444
- exit 1
445
- elsif locate_config_value(:azure_service_location).nil? && locate_config_value(:azure_affinity_group).nil?
446
- ui.error("Must specify either --azure-service-location or --azure-affinity-group.")
447
- exit 1
448
- end
449
-
450
- if locate_config_value(:winrm_authentication_protocol) && ! %w{basic negotiate kerberos}.include?(locate_config_value(:winrm_authentication_protocol))
451
- ui.error("Invalid value for --winrm-authentication-protocol option. Use valid protocol values i.e [basic, negotiate, kerberos]")
452
- exit 1
453
- end
454
-
455
- if !(service.valid_image?(locate_config_value(:azure_source_image)))
456
- ui.error("Image provided is invalid")
457
- exit 1
458
- end
459
-
460
- # Validate join domain requirements.
461
- if locate_config_value(:azure_domain_name) || locate_config_value(:azure_domain_user)
462
- if locate_config_value(:azure_domain_user).nil? || locate_config_value(:azure_domain_passwd).nil?
463
- ui.error("Must specify both --azure-domain-user and --azure-domain-passwd.")
464
- exit 1
465
- end
466
- end
467
-
468
- if locate_config_value(:winrm_transport) == "ssl" && locate_config_value(:thumbprint).nil? && ( locate_config_value(:winrm_ssl_verify_mode).nil? || locate_config_value(:winrm_ssl_verify_mode) == :verify_peer )
469
- ui.error("The SSL transport was specified without the --thumbprint option. Specify a thumbprint, or alternatively set the --winrm-ssl-verify-mode option to 'verify_none' to skip verification.")
470
- exit 1
471
- end
472
-
473
- if locate_config_value(:extended_logs) && locate_config_value(:bootstrap_protocol) != 'cloud-api'
474
- ui.error("--extended-logs option works with --bootstrap-protocol cloud-api")
475
- exit 1
476
- end
477
-
478
- if locate_config_value(:daemon)
479
- unless is_image_windows?
480
- raise ArgumentError, "The daemon option is only support for Windows nodes."
481
- end
482
-
483
- unless locate_config_value(:bootstrap_protocol) == 'cloud-api'
484
- raise ArgumentError, "--daemon option works with --bootstrap-protocol cloud-api"
485
- end
486
-
487
- unless %w{none service task}.include?(locate_config_value(:daemon))
488
- raise ArgumentError, "Invalid value for --daemon option. Use valid daemon values i.e 'none', 'service' and 'task'."
489
- end
490
- end
491
- end
492
-
493
412
  def create_server_def
494
413
  server_def = {
495
414
  :azure_storage_account => locate_config_value(:azure_storage_account),
File without changes
File without changes
File without changes
@@ -23,8 +23,6 @@ class Chef
23
23
  class AzureVnetList < Knife
24
24
  include Knife::AzureBase
25
25
 
26
- deps { require 'highline' }
27
-
28
26
  banner 'knife azure vnet list (options)'
29
27
 
30
28
  def run
@@ -1,7 +1,7 @@
1
1
 
2
2
  # Author:: Aliasgar Batterywala (aliasgar.batterywala@clogeny.com)
3
3
  #
4
- # Copyright:: Copyright (c) 2016 Opscode, Inc.
4
+ # Copyright:: Copyright 2009-2018, Chef Software Inc.
5
5
  # License:: Apache License, Version 2.0
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,7 +40,6 @@ class Chef
40
40
 
41
41
  def self.included(includer)
42
42
  includer.class_eval do
43
-
44
43
  deps do
45
44
  require 'readline'
46
45
  require 'chef/json_compat'
@@ -50,7 +49,6 @@ class Chef
50
49
  :short => "-r RESOURCE_GROUP_NAME",
51
50
  :long => "--azure-resource-group-name RESOURCE_GROUP_NAME",
52
51
  :description => "The Resource Group name."
53
-
54
52
  end
55
53
  end
56
54
 
@@ -71,13 +69,13 @@ class Chef
71
69
 
72
70
  # validates ARM mandatory keys
73
71
  def validate_arm_keys!(*keys)
74
- parse_publish_settings_file(locate_config_value(:azure_publish_settings_file)) if(locate_config_value(:azure_publish_settings_file) != nil)
72
+ parse_publish_settings_file(locate_config_value(:azure_publish_settings_file)) unless locate_config_value(:azure_publish_settings_file).nil?
75
73
  keys.push(:azure_subscription_id)
76
74
 
77
- if(locate_config_value(:azure_tenant_id).nil? || locate_config_value(:azure_client_id).nil? || locate_config_value(:azure_client_secret).nil?)
75
+ if azure_cred?
78
76
  validate_azure_login
79
77
  else
80
- keys.concat([:azure_tenant_id, :azure_client_id, :azure_client_secret])
78
+ keys.concat([:azure_tenant_id, :azure_client_id, :azure_client_secret])
81
79
  end
82
80
 
83
81
  errors = []
@@ -92,7 +90,7 @@ class Chef
92
90
  end
93
91
 
94
92
  def authentication_details
95
- if(locate_config_value(:azure_tenant_id) && locate_config_value(:azure_client_id) && locate_config_value(:azure_client_secret))
93
+ if is_azure_cred?
96
94
  return {:azure_tenant_id => locate_config_value(:azure_tenant_id), :azure_client_id => locate_config_value(:azure_client_id), :azure_client_secret => locate_config_value(:azure_client_secret)}
97
95
  elsif Chef::Platform.windows?
98
96
  token_details = token_details_for_windows()
@@ -103,16 +101,13 @@ class Chef
103
101
  token_details
104
102
  end
105
103
 
106
- def current_xplat_cli_version
107
- shell_out!("azure -v", { returns: [0] }).stdout
108
- end
109
-
110
- def is_old_xplat?
111
- Gem::Version.new(current_xplat_cli_version) < Gem::Version.new(XPLAT_VERSION_WITH_WCM_DEPRECATED)
112
- end
113
-
114
- def is_WCM_env_var_set?
115
- ENV['AZURE_USE_SECURE_TOKEN_STORAGE'].nil? ? false : true
104
+ def get_azure_cli_version
105
+ if @azure_version != ""
106
+ get_version = shell_out!("azure -v || az -v | grep azure-cli", { returns: [0] }).stdout
107
+ @azure_version = get_version.gsub(/[^0-9.]/, '')
108
+ end
109
+ @azure_prefix = @azure_version.to_i < 2 ? "azure" : "az"
110
+ @azure_version
116
111
  end
117
112
 
118
113
  def token_details_for_windows
@@ -141,56 +136,49 @@ class Chef
141
136
  return false
142
137
  elsif time_difference <= 600 # 600sec = 10min
143
138
  # This is required otherwise a long running command may fail inbetween if the token gets expired.
144
- raise "Token will expire within 10 minutes. Please run 'azure login' command"
139
+ raise "Token will expire within 10 minutes. Please run '#{@azure_prefix} login' command"
145
140
  else
146
141
  return true
147
142
  end
148
143
  end
149
144
 
150
145
  def refresh_token
146
+ azure_authentication
147
+ token_details = Chef::Platform.windows? ? token_details_for_windows() : token_details_for_linux()
148
+ end
149
+
150
+ def azure_authentication
151
151
  begin
152
152
  ui.log("Authenticating...")
153
- Mixlib::ShellOut.new("azure vm show 'knifetest@resourcegroup' testvm", :timeout => 30).run_command
153
+ Mixlib::ShellOut.new("#{@azure_prefix} vm show 'knifetest@resourcegroup' testvm", :timeout => 30).run_command
154
154
  rescue Mixlib::ShellOut::CommandTimeout
155
155
  rescue Exception
156
- raise "Token has expired. Please run 'azure login' command"
156
+ raise_azure_status
157
157
  end
158
- if Chef::Platform.windows?
159
- token_details = token_details_for_windows()
160
- else
161
- token_details = token_details_for_linux()
162
- end
163
- token_details
164
158
  end
165
159
 
166
160
  def check_token_validity(token_details)
167
- if !is_token_valid?(token_details)
168
- token_details = refresh_token()
169
- if !is_token_valid?(token_details)
170
- raise "Token has expired. Please run 'azure login' command"
161
+ unless is_token_valid?(token_details)
162
+ token_details = refresh_token
163
+ unless is_token_valid?(token_details)
164
+ raise_azure_status
171
165
  end
172
166
  end
173
167
  token_details
174
168
  end
175
169
 
176
170
  def validate_azure_login
177
- err_string = "Please run XPLAT's 'azure login' command OR specify azure_tenant_id, azure_subscription_id, azure_client_id, azure_client_secret in your knife.rb"
178
-
179
- ## Older versions of the Azure CLI on Windows stored credentials in a unique way
180
- ## in Windows Credentails Manager (WCM).
181
- ## Newer versions use the same pattern across platforms where credentials gets
182
- ## stored in ~/.azure/accessTokens.json file.
183
171
  if Chef::Platform.windows? && (is_old_xplat? || is_WCM_env_var_set?)
184
172
  # cmdkey command is used for accessing windows credential manager
185
173
  xplat_creds_cmd = Mixlib::ShellOut.new("cmdkey /list | findstr AzureXplatCli")
186
174
  result = xplat_creds_cmd.run_command
187
175
  if result.stdout.nil? || result.stdout.empty?
188
- raise err_string
176
+ raise login_message
189
177
  end
190
178
  else
191
179
  home_dir = File.expand_path('~')
192
180
  if !File.exists?(home_dir + "/.azure/accessTokens.json") || File.size?(home_dir + '/.azure/accessTokens.json') <= 2
193
- raise err_string
181
+ raise login_message
194
182
  end
195
183
  end
196
184
  end
@@ -238,20 +226,6 @@ class Chef
238
226
  file
239
227
  end
240
228
 
241
- def pretty_key(key)
242
- key.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
243
- end
244
-
245
- def is_image_windows?
246
- locate_config_value(:azure_image_reference_offer) =~ /WindowsServer.*/
247
- end
248
-
249
- def msg_pair(label, value, color=:cyan)
250
- if value && !value.to_s.empty?
251
- puts "#{ui.color(label, color)}: #{value}"
252
- end
253
- end
254
-
255
229
  def msg_server_summary(server)
256
230
  puts "\n\n"
257
231
  if server.provisioningstate == 'Succeeded'
@@ -335,6 +309,51 @@ class Chef
335
309
  config[:ohai_hints] = format_ohai_hints(locate_config_value(:ohai_hints))
336
310
  validate_ohai_hints if ! locate_config_value(:ohai_hints).casecmp('default').zero?
337
311
  end
312
+
313
+ private
314
+
315
+ def msg_pair(label, value, color=:cyan)
316
+ if value && !value.to_s.empty?
317
+ puts "#{ui.color(label, color)}: #{value}"
318
+ end
319
+ end
320
+
321
+ def pretty_key(key)
322
+ key.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
323
+ end
324
+
325
+ def is_image_windows?
326
+ locate_config_value(:azure_image_reference_offer) =~ /WindowsServer.*/
327
+ end
328
+
329
+ def is_azure_cred?
330
+ locate_config_value(:azure_tenant_id) && locate_config_value(:azure_client_id) && locate_config_value(:azure_client_secret)
331
+ end
332
+
333
+ def azure_cred?
334
+ locate_config_value(:azure_tenant_id).nil? || locate_config_value(:azure_client_id).nil? || locate_config_value(:azure_client_secret).nil?
335
+ end
336
+
337
+ def is_old_xplat?
338
+ return true unless @azure_version
339
+ Gem::Version.new(@azure_version) < Gem::Version.new(XPLAT_VERSION_WITH_WCM_DEPRECATED)
340
+ end
341
+
342
+ def is_WCM_env_var_set?
343
+ ENV['AZURE_USE_SECURE_TOKEN_STORAGE'].nil? ? false : true
344
+ end
345
+
346
+ def raise_azure_status
347
+ raise "Token has expired. Please run '#{@azure_prefix} login' command"
348
+ end
349
+
350
+ def login_message
351
+ ## Older versions of the Azure CLI on Windows stored credentials in a unique way
352
+ ## in Windows Credentails Manager (WCM).
353
+ ## Newer versions use the same pattern across platforms where credentials gets
354
+ ## stored in ~/.azure/accessTokens.json file.
355
+ "Please run XPLAT's '#{@azure_prefix} login' command OR specify azure_tenant_id, azure_subscription_id, azure_client_id, azure_client_secret in your knife.rb"
356
+ end
338
357
  end
339
358
  end
340
359
  end