knife-azure 1.6.0.rc.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +304 -8
  3. data/lib/azure/azure_interface.rb +81 -0
  4. data/lib/azure/custom_errors.rb +35 -0
  5. data/lib/azure/helpers.rb +44 -0
  6. data/lib/azure/resource_management/ARM_base.rb +29 -0
  7. data/lib/azure/resource_management/ARM_deployment_template.rb +561 -0
  8. data/lib/azure/resource_management/ARM_interface.rb +795 -0
  9. data/lib/azure/resource_management/windows_credentials.rb +136 -0
  10. data/lib/azure/service_management/ASM_interface.rb +301 -0
  11. data/lib/azure/{ag.rb → service_management/ag.rb} +2 -2
  12. data/lib/azure/{certificate.rb → service_management/certificate.rb} +2 -2
  13. data/lib/azure/service_management/connection.rb +102 -0
  14. data/lib/azure/{deploy.rb → service_management/deploy.rb} +8 -2
  15. data/lib/azure/{disk.rb → service_management/disk.rb} +2 -2
  16. data/lib/azure/{host.rb → service_management/host.rb} +2 -2
  17. data/lib/azure/{image.rb → service_management/image.rb} +2 -2
  18. data/lib/azure/{loadbalancer.rb → service_management/loadbalancer.rb} +4 -18
  19. data/lib/azure/{rest.rb → service_management/rest.rb} +15 -10
  20. data/lib/azure/{role.rb → service_management/role.rb} +174 -6
  21. data/lib/azure/{storageaccount.rb → service_management/storageaccount.rb} +2 -2
  22. data/lib/azure/{utility.rb → service_management/utility.rb} +0 -0
  23. data/lib/azure/{vnet.rb → service_management/vnet.rb} +2 -2
  24. data/lib/chef/knife/azure_ag_create.rb +3 -6
  25. data/lib/chef/knife/azure_ag_list.rb +2 -16
  26. data/lib/chef/knife/azure_base.rb +89 -22
  27. data/lib/chef/knife/azure_image_list.rb +3 -7
  28. data/lib/chef/knife/azure_internal-lb_create.rb +2 -5
  29. data/lib/chef/knife/azure_internal-lb_list.rb +2 -16
  30. data/lib/chef/knife/azure_server_create.rb +122 -501
  31. data/lib/chef/knife/azure_server_delete.rb +15 -38
  32. data/lib/chef/knife/azure_server_list.rb +2 -27
  33. data/lib/chef/knife/azure_server_show.rb +4 -60
  34. data/lib/chef/knife/azure_vnet_create.rb +2 -7
  35. data/lib/chef/knife/azure_vnet_list.rb +2 -17
  36. data/lib/chef/knife/azurerm_base.rb +228 -0
  37. data/lib/chef/knife/azurerm_server_create.rb +393 -0
  38. data/lib/chef/knife/azurerm_server_delete.rb +121 -0
  39. data/lib/chef/knife/azurerm_server_list.rb +18 -0
  40. data/lib/chef/knife/azurerm_server_show.rb +37 -0
  41. data/lib/chef/knife/bootstrap/bootstrap_options.rb +105 -0
  42. data/lib/chef/knife/bootstrap/bootstrapper.rb +343 -0
  43. data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +116 -0
  44. data/lib/chef/knife/bootstrap_azure.rb +110 -0
  45. data/lib/chef/knife/bootstrap_azurerm.rb +116 -0
  46. data/lib/knife-azure/version.rb +1 -2
  47. metadata +132 -16
  48. data/lib/azure/connection.rb +0 -99
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
19
+ module Azure
20
20
  class StorageAccounts
21
21
  include AzureUtility
22
22
  def initialize(connection)
@@ -82,7 +82,7 @@ class Azure
82
82
  end
83
83
  end
84
84
 
85
- class Azure
85
+ module Azure
86
86
  class StorageAccount
87
87
  include AzureUtility
88
88
  attr_accessor :name, :location
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
19
+ module Azure
20
20
  class Vnets
21
21
  def initialize(connection)
22
22
  @connection = connection
@@ -53,7 +53,7 @@ class Azure
53
53
  end
54
54
  end
55
55
 
56
- class Azure
56
+ module Azure
57
57
  class Vnet
58
58
  attr_accessor :name, :affinity_group, :state
59
59
 
@@ -46,11 +46,8 @@ class Chef
46
46
  $stdout.sync = true
47
47
 
48
48
  Chef::Log.info('validating...')
49
- validate!([:azure_subscription_id,
50
- :azure_mgmt_cert,
51
- :azure_api_host_name,
52
- :azure_affinity_group,
53
- :azure_service_location])
49
+ validate_asm_keys!(:azure_affinity_group,
50
+ :azure_service_location)
54
51
 
55
52
  params = {
56
53
  azure_ag_name: locate_config_value(:azure_affinity_group),
@@ -58,7 +55,7 @@ class Chef
58
55
  azure_location: locate_config_value(:azure_service_location),
59
56
  }
60
57
 
61
- rsp = connection.ags.create(params)
58
+ rsp = service.create_affinity_group(params)
62
59
  print "\n"
63
60
  if rsp.at_css('Status').nil?
64
61
  if rsp.at_css('Code').nil? || rsp.at_css('Message').nil?
@@ -27,24 +27,10 @@ class Chef
27
27
 
28
28
  banner 'knife azure ag list (options)'
29
29
 
30
- def hl
31
- @highline ||= HighLine.new
32
- end
33
-
34
30
  def run
35
31
  $stdout.sync = true
36
-
37
- validate!
38
-
39
- cols = %w{Name Location Description}
40
-
41
- the_list = cols.map { |col| ui.color(col, :bold) }
42
- connection.ags.all.each do |ag|
43
- cols.each { |attr| the_list << ag.send(attr.downcase).to_s }
44
- end
45
-
46
- puts "\n"
47
- puts hl.list(the_list, :uneven_columns_across, cols.size)
32
+ validate_asm_keys!
33
+ service.list_affinity_groups
48
34
  end
49
35
  end
50
36
  end
@@ -18,7 +18,7 @@
18
18
  #
19
19
 
20
20
  require 'chef/knife'
21
- require File.expand_path('../../../azure/connection', __FILE__)
21
+ require 'azure/service_management/ASM_interface'
22
22
 
23
23
  class Chef
24
24
  class Knife
@@ -67,8 +67,8 @@ class Chef
67
67
  end
68
68
 
69
69
  def is_image_windows?
70
- images = connection.images
71
- target_image = images.all.select { |i| i.name == locate_config_value(:azure_source_image) }
70
+ images = service.list_images
71
+ target_image = images.select { |i| i.name == locate_config_value(:azure_source_image) }
72
72
  unless target_image[0].nil?
73
73
  return target_image[0].os == 'Windows'
74
74
  else
@@ -76,15 +76,18 @@ class Chef
76
76
  exit 1
77
77
  end
78
78
  end
79
- def connection
80
- @connection ||= begin
81
- connection = Azure::Connection.new(
82
- :azure_subscription_id => locate_config_value(:azure_subscription_id),
83
- :azure_mgmt_cert => locate_config_value(:azure_mgmt_cert),
84
- :azure_api_host_name => locate_config_value(:azure_api_host_name),
85
- :verify_ssl_cert => locate_config_value(:verify_ssl_cert)
86
- )
87
- end
79
+
80
+ def service
81
+ @service ||= begin
82
+ service = Azure::ServiceManagement::ASMInterface.new(
83
+ :azure_subscription_id => locate_config_value(:azure_subscription_id),
84
+ :azure_mgmt_cert => locate_config_value(:azure_mgmt_cert),
85
+ :azure_api_host_name => locate_config_value(:azure_api_host_name),
86
+ :verify_ssl_cert => locate_config_value(:verify_ssl_cert)
87
+ )
88
+ end
89
+ @service.ui = ui
90
+ @service
88
91
  end
89
92
 
90
93
  def locate_config_value(key)
@@ -116,18 +119,20 @@ class Chef
116
119
  puts "\n"
117
120
  end
118
121
 
119
- def validate!(keys=[:azure_subscription_id, :azure_mgmt_cert, :azure_api_host_name])
122
+ def pretty_key(key)
123
+ key.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
124
+ end
125
+
126
+ # validate command pre-requisites (cli options)
127
+ def validate_params!
128
+ end
129
+
130
+ # validates keys
131
+ def validate!(keys)
120
132
  errors = []
121
- if(locate_config_value(:azure_mgmt_cert) != nil)
122
- config[:azure_mgmt_cert] = File.read find_file(locate_config_value(:azure_mgmt_cert))
123
- end
124
- if(locate_config_value(:azure_publish_settings_file) != nil)
125
- parse_publish_settings_file(locate_config_value(:azure_publish_settings_file))
126
- end
127
133
  keys.each do |k|
128
- pretty_key = k.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
129
134
  if locate_config_value(k).nil?
130
- errors << "You did not provide a valid '#{pretty_key}' value. Please set knife[:#{k}] in your knife.rb or pass as an option."
135
+ errors << "You did not provide a valid '#{pretty_key(k)}' value. Please set knife[:#{k}] in your knife.rb or pass as an option."
131
136
  end
132
137
  end
133
138
  if errors.each{|e| ui.error(e)}.any?
@@ -135,6 +140,26 @@ class Chef
135
140
  end
136
141
  end
137
142
 
143
+ # validate ASM mandatory keys
144
+ def validate_asm_keys!(*keys)
145
+ mandatory_keys = [:azure_subscription_id, :azure_mgmt_cert, :azure_api_host_name]
146
+ keys.concat(mandatory_keys)
147
+
148
+ if(locate_config_value(:azure_mgmt_cert) != nil)
149
+ config[:azure_mgmt_cert] = File.read find_file(locate_config_value(:azure_mgmt_cert))
150
+ end
151
+
152
+ if(locate_config_value(:azure_publish_settings_file) != nil)
153
+ parse_publish_settings_file(locate_config_value(:azure_publish_settings_file))
154
+ elsif locate_config_value(:azure_subscription_id).nil? && locate_config_value(:azure_mgmt_cert).nil? && locate_config_value(:azure_api_host_name).nil?
155
+ azureprofile_file = get_azure_profile_file_path
156
+ if File.exist?(File.expand_path(azureprofile_file))
157
+ errors = parse_azure_profile(azureprofile_file, errors)
158
+ end
159
+ end
160
+ validate!(keys)
161
+ end
162
+
138
163
  def parse_publish_settings_file(filename)
139
164
  require 'nokogiri'
140
165
  require 'base64'
@@ -162,6 +187,49 @@ class Chef
162
187
  end
163
188
  end
164
189
 
190
+ def get_azure_profile_file_path
191
+ '~/.azure/azureProfile.json'
192
+ end
193
+
194
+ def parse_azure_profile(filename, errors)
195
+ require 'openssl'
196
+ require 'uri'
197
+ azure_profile = File.read(File.expand_path(filename))
198
+ azure_profile = JSON.parse(azure_profile)
199
+ default_subscription = get_default_subscription(azure_profile)
200
+ if default_subscription.has_key?('id') && default_subscription.has_key?('managementCertificate') && default_subscription.has_key?('managementEndpointUrl')
201
+
202
+ Chef::Config[:knife][:azure_subscription_id] = default_subscription['id']
203
+ mgmt_key = OpenSSL::PKey::RSA.new(default_subscription['managementCertificate']['key']).to_pem
204
+ mgmt_cert = OpenSSL::X509::Certificate.new(default_subscription['managementCertificate']['cert']).to_pem
205
+ Chef::Config[:knife][:azure_mgmt_cert] = mgmt_key + mgmt_cert
206
+ Chef::Config[:knife][:azure_api_host_name] = URI(default_subscription['managementEndpointUrl']).host
207
+ else
208
+ errors << "Check if values set for 'id', 'managementCertificate', 'managementEndpointUrl' in -> #{filename} for 'defaultSubscription'. \n OR "
209
+ end
210
+ errors
211
+ end
212
+
213
+ def get_default_subscription(azure_profile)
214
+ first_subscription_as_default = nil
215
+ azure_profile['subscriptions'].each do |subscription|
216
+ if subscription['isDefault']
217
+ Chef::Log.info("Default subscription \'#{subscription['name']}\'' selected.")
218
+ return subscription
219
+ end
220
+
221
+ first_subscription_as_default ||= subscription
222
+ end
223
+
224
+ if first_subscription_as_default
225
+ Chef::Log.info("First subscription \'#{subscription['name']}\' selected as default.")
226
+ else
227
+ Chef::Log.info('No subscriptions found.')
228
+ exit 1
229
+ end
230
+ first_subscription_as_default
231
+ end
232
+
165
233
  def find_file(name)
166
234
  config_dir = Chef::Knife.chef_config_dir
167
235
  if File.exist? name
@@ -176,7 +244,6 @@ class Chef
176
244
  end
177
245
  file
178
246
  end
179
-
180
247
  end
181
248
  end
182
249
  end
@@ -18,7 +18,6 @@
18
18
  # limitations under the License.
19
19
  #
20
20
 
21
- require 'highline'
22
21
  require File.expand_path('../azure_base', __FILE__)
23
22
 
24
23
  class Chef
@@ -35,18 +34,15 @@ class Chef
35
34
  :boolean => true,
36
35
  :description => "Show all the fields of the images"
37
36
 
38
- def h
39
- @highline ||= HighLine.new
40
- end
41
37
 
42
38
  def run
43
39
  $stdout.sync = true
44
40
 
45
- validate!
41
+ validate_asm_keys!
42
+ items = service.list_images
46
43
 
47
44
  image_labels = !locate_config_value(:show_all_fields) ? ['Name', 'OS', 'Location'] : ['Name', 'Category', 'Label', 'OS', 'Location']
48
45
  image_list = image_labels.map {|label| ui.color(label, :bold)}
49
- items = connection.images.all
50
46
 
51
47
  image_items = image_labels.map {|item| item.downcase }
52
48
  items.each do |image|
@@ -54,7 +50,7 @@ class Chef
54
50
  end
55
51
 
56
52
  puts "\n"
57
- puts h.list(image_list, :uneven_columns_across, !locate_config_value(:show_all_fields) ? 3 : 5)
53
+ puts ui.list(image_list, :uneven_columns_across, !locate_config_value(:show_all_fields) ? 3 : 5)
58
54
 
59
55
  end
60
56
  end
@@ -47,10 +47,7 @@ class Chef
47
47
  $stdout.sync = true
48
48
 
49
49
  Chef::Log.info('validating...')
50
- validate!([:azure_subscription_id,
51
- :azure_mgmt_cert,
52
- :azure_api_host_name,
53
- :azure_load_balancer])
50
+ validate_asm_keys!(:azure_load_balancer)
54
51
 
55
52
  params = {
56
53
  azure_load_balancer: locate_config_value(:azure_load_balancer),
@@ -59,7 +56,7 @@ class Chef
59
56
  azure_dns_name: locate_config_value(:azure_dns_name)
60
57
  }
61
58
 
62
- rsp = connection.lbs.create(params)
59
+ rsp = service.create_internal_lb(params)
63
60
  print "\n"
64
61
  if rsp.at_css('Status').nil?
65
62
  if rsp.at_css('Code').nil? || rsp.at_css('Message').nil?
@@ -27,24 +27,10 @@ class Chef
27
27
 
28
28
  banner 'knife azure internal lb list (options)'
29
29
 
30
- def hl
31
- @highline ||= HighLine.new
32
- end
33
-
34
30
  def run
35
31
  $stdout.sync = true
36
-
37
- validate!
38
-
39
- cols = %w{Name Service Subnet VIP}
40
-
41
- the_list = cols.map { |col| ui.color(col, :bold) }
42
- connection.lbs.all.each do |lb|
43
- cols.each { |attr| the_list << lb.send(attr.downcase).to_s }
44
- end
45
-
46
- puts "\n"
47
- puts hl.list(the_list, :uneven_columns_across, cols.size)
32
+ validate_asm_keys!
33
+ service.list_internal_lb
48
34
  end
49
35
  end
50
36
  end
@@ -20,8 +20,9 @@
20
20
 
21
21
  require 'chef/knife/azure_base'
22
22
  require 'chef/knife/winrm_base'
23
- require 'chef/knife/bootstrap_windows_base'
24
23
  require 'securerandom'
24
+ require 'chef/knife/bootstrap/bootstrap_options'
25
+ require 'chef/knife/bootstrap/bootstrapper'
25
26
 
26
27
  class Chef
27
28
  class Knife
@@ -29,7 +30,8 @@ class Chef
29
30
 
30
31
  include Knife::AzureBase
31
32
  include Knife::WinrmBase
32
- include Knife::BootstrapWindowsBase
33
+ include Knife::Bootstrap::BootstrapOptions
34
+ include Knife::Bootstrap::Bootstrapper
33
35
 
34
36
  deps do
35
37
  require 'readline'
@@ -40,32 +42,16 @@ class Chef
40
42
  Chef::Knife::Bootstrap.load_deps
41
43
  end
42
44
 
43
- def load_winrm_deps
44
- require 'winrm'
45
- require 'chef/knife/winrm'
46
- require 'chef/knife/bootstrap_windows_winrm'
47
- end
48
-
49
45
  banner "knife azure server create (options)"
50
46
 
51
47
  attr_accessor :initial_sleep_delay
52
48
 
53
- option :forward_agent,
54
- :short => "-A",
55
- :long => "--forward-agent",
56
- :description => "Enable SSH agent forwarding",
57
- :boolean => true
58
49
 
59
50
  option :bootstrap_protocol,
60
51
  :long => "--bootstrap-protocol protocol",
61
52
  :description => "Protocol to bootstrap windows servers. options: 'winrm' or 'ssh' or 'cloud-api'.",
62
53
  :default => "winrm"
63
54
 
64
- option :chef_node_name,
65
- :short => "-N NAME",
66
- :long => "--node-name NAME",
67
- :description => "The Chef node name for your new node"
68
-
69
55
  option :ssh_user,
70
56
  :short => "-x USERNAME",
71
57
  :long => "--ssh-user USERNAME",
@@ -81,49 +67,6 @@ class Chef
81
67
  :long => "--ssh-port PORT",
82
68
  :description => "The ssh port. Default is 22. If --azure-connect-to-existing-dns set then default SSH port is random"
83
69
 
84
- option :prerelease,
85
- :long => "--prerelease",
86
- :description => "Install the pre-release chef gems"
87
-
88
- option :bootstrap_version,
89
- :long => "--bootstrap-version VERSION",
90
- :description => "The version of Chef to install",
91
- :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
92
-
93
- option :distro,
94
- :short => "-d DISTRO",
95
- :long => "--distro DISTRO",
96
- :description => "Bootstrap a distro using a template. [DEPRECATED] Use --bootstrap-template option instead.",
97
- :proc => Proc.new { |v|
98
- Chef::Log.warn("[DEPRECATED] -d / --distro option is deprecated. Use --bootstrap-template option instead.")
99
- v
100
- }
101
-
102
- option :template_file,
103
- :long => "--template-file TEMPLATE",
104
- :description => "Full path to location of template to use. [DEPRECATED] Use -t / --bootstrap-template option instead.",
105
- :proc => Proc.new { |v|
106
- Chef::Log.warn("[DEPRECATED] --template-file option is deprecated. Use -t / --bootstrap-template option instead.")
107
- v
108
- }
109
-
110
- option :bootstrap_template,
111
- :long => "--bootstrap-template TEMPLATE",
112
- :description => "Bootstrap Chef using a built-in or custom template. Set to the full path of an erb template or use one of the built-in templates."
113
-
114
- option :run_list,
115
- :short => "-r RUN_LIST",
116
- :long => "--run-list RUN_LIST",
117
- :description => "Comma separated list of roles/recipes to apply",
118
- :proc => lambda { |o| o.split(/[\s,]+/) },
119
- :default => []
120
-
121
- option :host_key_verify,
122
- :long => "--[no-]host-key-verify",
123
- :description => "Verify host key, enabled by default.",
124
- :boolean => true,
125
- :default => true
126
-
127
70
  option :node_ssl_verify_mode,
128
71
  :long => "--node-ssl-verify-mode [peer|none]",
129
72
  :description => "Whether or not to verify the SSL cert for all HTTPS requests.",
@@ -139,60 +82,6 @@ class Chef
139
82
  :description => "Verify the SSL cert for HTTPS requests to the Chef server API.",
140
83
  :boolean => true
141
84
 
142
- option :bootstrap_proxy,
143
- :long => "--bootstrap-proxy PROXY_URL",
144
- :description => "The proxy server for the node being bootstrapped",
145
- :proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
146
-
147
- option :bootstrap_no_proxy,
148
- :long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]",
149
- :description => "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode",
150
- :proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np }
151
-
152
- option :bootstrap_url,
153
- :long => "--bootstrap-url URL",
154
- :description => "URL to a custom installation script",
155
- :proc => Proc.new { |u| Chef::Config[:knife][:bootstrap_url] = u }
156
-
157
- option :bootstrap_install_command,
158
- :long => "--bootstrap-install-command COMMANDS",
159
- :description => "Custom command to install chef-client",
160
- :proc => Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic }
161
-
162
- option :bootstrap_wget_options,
163
- :long => "--bootstrap-wget-options OPTIONS",
164
- :description => "Add options to wget when installing chef-client",
165
- :proc => Proc.new { |wo| Chef::Config[:knife][:bootstrap_wget_options] = wo }
166
-
167
- option :bootstrap_curl_options,
168
- :long => "--bootstrap-curl-options OPTIONS",
169
- :description => "Add options to curl when install chef-client",
170
- :proc => Proc.new { |co| Chef::Config[:knife][:bootstrap_curl_options] = co }
171
-
172
- option :bootstrap_vault_file,
173
- :long => '--bootstrap-vault-file VAULT_FILE',
174
- :description => 'A JSON file with a list of vault(s) and item(s) to be updated'
175
-
176
- option :bootstrap_vault_json,
177
- :long => '--bootstrap-vault-json VAULT_JSON',
178
- :description => 'A JSON string with the vault(s) and item(s) to be updated'
179
-
180
- option :bootstrap_vault_item,
181
- :long => '--bootstrap-vault-item VAULT_ITEM',
182
- :description => 'A single vault and item to update as "vault:item"',
183
- :proc => Proc.new { |i|
184
- (vault, item) = i.split(/:/)
185
- Chef::Config[:knife][:bootstrap_vault_item] ||= {}
186
- Chef::Config[:knife][:bootstrap_vault_item][vault] ||= []
187
- Chef::Config[:knife][:bootstrap_vault_item][vault].push(item)
188
- Chef::Config[:knife][:bootstrap_vault_item]
189
- }
190
-
191
- option :use_sudo_password,
192
- :long => "--use-sudo-password",
193
- :description => "Execute the bootstrap via sudo with password",
194
- :boolean => false
195
-
196
85
  option :azure_storage_account,
197
86
  :short => "-a NAME",
198
87
  :long => "--azure-storage-account NAME",
@@ -211,7 +100,8 @@ class Chef
211
100
  :short => "-m LOCATION",
212
101
  :long => "--azure-service-location LOCATION",
213
102
  :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.
214
- Eg: West US, East US, East Asia, Southeast Asia, North Europe, West Europe"
103
+ Eg: West US, East US, East Asia, Southeast Asia, North Europe, West Europe",
104
+ :proc => Proc.new { |lo| Chef::Config[:knife][:azure_service_location] = lo }
215
105
 
216
106
  option :azure_affinity_group,
217
107
  :short => "-a GROUP",
@@ -242,7 +132,8 @@ class Chef
242
132
  :short => "-z SIZE",
243
133
  :long => "--azure-vm-size SIZE",
244
134
  :description => "Optional. Size of virtual machine (ExtraSmall, Small, Medium, Large, ExtraLarge)",
245
- :default => 'Small'
135
+ :default => 'Small',
136
+ :proc => Proc.new { |si| Chef::Config[:knife][:azure_vm_size] = si }
246
137
 
247
138
  option :azure_availability_set,
248
139
  :long => "--azure-availability-set NAME",
@@ -297,21 +188,6 @@ class Chef
297
188
  :long => "--identity-file-passphrase PASSWORD",
298
189
  :description => "SSH key passphrase. Optional, specify if passphrase for identity-file exists"
299
190
 
300
- option :hint,
301
- :long => "--hint HINT_NAME[=HINT_FILE]",
302
- :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.",
303
- :proc => Proc.new { |h|
304
- Chef::Config[:knife][:hints] ||= {}
305
- name, path = h.split("=")
306
- Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new
307
- }
308
-
309
- option :json_attributes,
310
- :short => "-j JSON",
311
- :long => "--json-attributes JSON",
312
- :description => "A JSON string to be added to the first run of chef-client",
313
- :proc => lambda { |o| JSON.parse(o) }
314
-
315
191
  option :thumbprint,
316
192
  :long => "--thumbprint THUMBPRINT",
317
193
  :description => "The thumprint of the ssl certificate"
@@ -324,12 +200,6 @@ class Chef
324
200
  :long => "--cert-path PATH",
325
201
  :description => "SSL Certificate Path"
326
202
 
327
- option :auto_update_client,
328
- :long => "--auto-update-client",
329
- :boolean => true,
330
- :default => false,
331
- :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"
332
-
333
203
  option :winrm_max_timeout,
334
204
  :long => "--winrm-max-timeout MINUTES",
335
205
  :description => "Set winrm maximum command timeout in minutes, useful for long bootstraps"
@@ -338,12 +208,6 @@ class Chef
338
208
  :long => "--winrm-max-memory-per-shell",
339
209
  :description => "Set winrm max memory per shell in MB"
340
210
 
341
- option :delete_chef_extension_config,
342
- :long => "--delete-chef-extension-config",
343
- :boolean => true,
344
- :default => false,
345
- :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."
346
-
347
211
  option :azure_domain_name,
348
212
  :long => "--azure-domain-name DOMAIN_NAME",
349
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"
@@ -366,20 +230,9 @@ class Chef
366
230
  :long => "--azure-extension-client-config CLIENT_PATH",
367
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`."
368
232
 
369
- def strip_non_ascii(string)
370
- string.gsub(/[^0-9a-z ]/i, '')
371
- end
372
-
373
- def random_string(len=10)
374
- (0...len).map{65.+(rand(25)).chr}.join
375
- end
376
-
377
233
  def wait_until_virtual_machine_ready(retry_interval_in_seconds = 30)
378
-
379
234
  vm_status = nil
380
235
 
381
- puts
382
-
383
236
  begin
384
237
  azure_vm_startup_timeout = locate_config_value(:azure_vm_startup_timeout).to_i
385
238
  azure_vm_ready_timeout = locate_config_value(:azure_vm_ready_timeout).to_i
@@ -393,7 +246,7 @@ class Chef
393
246
  end
394
247
  end
395
248
 
396
- msg_server_summary(get_role_server())
249
+ msg_server_summary(service.get_role_server(locate_config_value(:azure_dns_name), locate_config_value(:azure_vm_name)))
397
250
 
398
251
  if locate_config_value(:bootstrap_protocol) == "cloud-api"
399
252
  extension_status = wait_for_resource_extension_state(:wagent_provisioning, 5, retry_interval_in_seconds)
@@ -477,7 +330,7 @@ class Chef
477
330
  end
478
331
 
479
332
  def get_virtual_machine_status()
480
- role = get_role_server()
333
+ role = service.get_role_server(locate_config_value(:azure_dns_name), locate_config_value(:azure_vm_name))
481
334
  unless role.nil?
482
335
  Chef::Log.debug("Role status is #{role.status.to_s}")
483
336
  if "ReadyRole".eql? role.status.to_s
@@ -492,8 +345,8 @@ class Chef
492
345
  end
493
346
 
494
347
  def get_extension_status()
495
- deployment_name = connection.deploys.get_deploy_name_for_hostedservice(locate_config_value(:azure_dns_name))
496
- deployment = connection.query_azure("hostedservices/#{locate_config_value(:azure_dns_name)}/deployments/#{deployment_name}")
348
+ deployment_name = service.deployment_name(locate_config_value(:azure_dns_name))
349
+ deployment = service.deployment("hostedservices/#{locate_config_value(:azure_dns_name)}/deployments/#{deployment_name}")
497
350
  extension_status = Hash.new
498
351
 
499
352
  if deployment.at_css('Deployment Name') != nil
@@ -538,279 +391,130 @@ class Chef
538
391
  return extension_status
539
392
  end
540
393
 
541
- def get_role_server
542
- deploy = connection.deploys.queryDeploy(locate_config_value(:azure_dns_name))
543
- deploy.find_role(locate_config_value(:azure_vm_name))
394
+ def fetch_role
395
+ deployment_name = service.deployment_name(locate_config_value(:azure_dns_name))
396
+ deployment = service.deployment("hostedservices/#{locate_config_value(:azure_dns_name)}/deployments/#{deployment_name}")
397
+
398
+ if deployment.at_css('Deployment Name') != nil
399
+ role_list_xml = deployment.css('RoleInstanceList RoleInstance')
400
+ role_list_xml.each do |role|
401
+ if role.at_css("RoleName").text == locate_config_value(:azure_vm_name)
402
+ return role
403
+ end
404
+ end
405
+ end
406
+ return nil
407
+ end
408
+
409
+ def fetch_extension(role)
410
+ ext_list_xml = role.css("ResourceExtensionStatusList ResourceExtensionStatus")
411
+ ext_list_xml.each do |ext|
412
+ if ext.at_css("HandlerName").text == "Chef.Bootstrap.WindowsAzure.LinuxChefClient" || ext.at_css("HandlerName").text == "Chef.Bootstrap.WindowsAzure.ChefClient"
413
+ return ext
414
+ end
415
+ end
416
+ return nil
544
417
  end
545
418
 
546
- def tcp_test_winrm(ip_addr, port)
547
- hostname = ip_addr
548
- socket = TCPSocket.new(hostname, port)
549
- return true
550
- rescue SocketError
551
- sleep 2
552
- false
553
- rescue Errno::ETIMEDOUT
554
- false
555
- rescue Errno::EPERM
556
- false
557
- rescue Errno::ECONNREFUSED
558
- sleep 2
559
- false
560
- rescue Errno::EHOSTUNREACH
561
- sleep 2
562
- false
563
- rescue Errno::ENETUNREACH
564
- sleep 2
565
- false
419
+ def fetch_substatus(extension)
420
+ return nil if extension.at_css("ExtensionSettingStatus SubStatusList SubStatus").nil?
421
+ substatus_list_xml = extension.css("ExtensionSettingStatus SubStatusList SubStatus")
422
+ substatus_list_xml.each do |substatus|
423
+ if substatus.at_css("Name").text == "Chef Client run logs"
424
+ return substatus
425
+ end
426
+ end
427
+ return nil
566
428
  end
567
429
 
568
- def tcp_test_ssh(fqdn, sshport)
569
- tcp_socket = TCPSocket.new(fqdn, sshport)
570
- readable = IO.select([tcp_socket], nil, nil, 5)
571
- if readable
572
- Chef::Log.debug("sshd accepting connections on #{fqdn}, banner is #{tcp_socket.gets}")
573
- yield
574
- true
430
+ def fetch_chef_client_logs(fetch_process_start_time, fetch_process_wait_timeout)
431
+ ## fetch server details ##
432
+ role = fetch_role
433
+ if role != nil
434
+ ## fetch Chef Extension details deployed on the server ##
435
+ ext = fetch_extension(role)
436
+ if ext != nil
437
+ ## fetch substatus field which contains the chef-client run logs ##
438
+ substatus = fetch_substatus(ext)
439
+ if substatus != nil
440
+ ## chef-client run logs becomes available ##
441
+ name = substatus.at_css("Name").text
442
+ status = substatus.at_css("Status").text
443
+ message = substatus.at_css("Message").text
444
+
445
+ ## printing the logs ##
446
+ puts "\n\n******** Please find the chef-client run details below ********\n\n"
447
+ print "----> chef-client run status: "
448
+ case status
449
+ when "Success"
450
+ ## chef-client run succeeded ##
451
+ color = :green
452
+ when "Error"
453
+ ## chef-client run failed ##
454
+ color = :red
455
+ when "Transitioning"
456
+ ## chef-client run did not complete within maximum timeout of 30 minutes ##
457
+ ## fetch whatever logs available under the chef-client.log file ##
458
+ color = :yellow
459
+ end
460
+ puts "#{ui.color(status, color, :bold)}"
461
+ puts "----> chef-client run logs: "
462
+ puts "\n#{message}\n" ## message field of substatus contains the chef-client run logs ##
463
+ else
464
+ ## unavailability of the substatus field indicates that chef-client run is not completed yet on the server ##
465
+ fetch_process_wait_time = ((Time.now - fetch_process_start_time) / 60).round
466
+ if fetch_process_wait_time <= fetch_process_wait_timeout ## wait for maximum 30 minutes until chef-client run logs becomes available ##
467
+ print "#{ui.color('.', :bold)}"
468
+ sleep 30
469
+ fetch_chef_client_logs(fetch_process_start_time, fetch_process_wait_timeout)
470
+ else
471
+ ## wait time exceeded 30 minutes timeout ##
472
+ ui.error "\nchef-client run logs could not be fetched since fetch process exceeded wait timeout of #{fetch_process_wait_timeout} minutes.\n"
473
+ end
474
+ end
475
+ else
476
+ ## Chef Extension could not be found ##
477
+ ui.error("Unable to find Chef extension under role #{locate_config_value(:azure_vm_name)}.")
478
+ end
575
479
  else
576
- false
480
+ ## server could not be found ##
481
+ ui.error("chef-client run logs could not be fetched since role #{locate_config_value(:azure_vm_name)} could not be found.")
577
482
  end
578
- rescue SocketError
579
- sleep 2
580
- false
581
- rescue Errno::ETIMEDOUT
582
- false
583
- rescue Errno::EPERM
584
- false
585
- rescue Errno::ECONNREFUSED
586
- sleep 2
587
- false
588
- rescue Errno::EHOSTUNREACH
589
- sleep 2
590
- false
591
- ensure
592
- tcp_socket && tcp_socket.close
593
483
  end
594
484
 
595
485
  def run
596
486
  $stdout.sync = true
487
+
597
488
  storage = nil
598
489
 
599
490
  Chef::Log.info("validating...")
600
- validate!
491
+ validate_asm_keys!(:azure_source_image)
601
492
 
602
- if (locate_config_value(:auto_update_client) || locate_config_value(:delete_chef_extension_config)) && (locate_config_value(:bootstrap_protocol) != 'cloud-api')
603
- ui.error("--auto-update-client option works with --bootstrap-protocol cloud-api") if locate_config_value(:auto_update_client)
604
- ui.error("--delete-chef-extension-config option works with --bootstrap-protocol cloud-api") if locate_config_value(:delete_chef_extension_config)
605
- exit 1
606
- end
493
+ validate_params!
607
494
 
608
- ssh_override_winrm if %w(ssh cloud-api).include?(locate_config_value(:bootstrap_protocol)) and !is_image_windows?
495
+ ssh_override_winrm if !is_image_windows?
609
496
 
610
497
  Chef::Log.info("creating...")
611
498
 
612
499
  config[:azure_dns_name] = get_dns_name(locate_config_value(:azure_dns_name))
500
+
613
501
  if not locate_config_value(:azure_vm_name)
614
502
  config[:azure_vm_name] = locate_config_value(:azure_dns_name)
615
503
  end
616
504
 
617
- remove_hosted_service_on_failure = locate_config_value(:azure_dns_name)
618
- if connection.hosts.exists?(locate_config_value(:azure_dns_name))
619
- remove_hosted_service_on_failure = nil
620
- end
621
-
622
- #If Storage Account is not specified, check if the geographic location has one to re-use
623
- if not locate_config_value(:azure_storage_account)
624
- storage_accts = connection.storageaccounts.all
625
- storage = storage_accts.find { |storage_acct| storage_acct.location.to_s == locate_config_value(:azure_service_location) }
626
- if not storage
627
- config[:azure_storage_account] = [strip_non_ascii(locate_config_value(:azure_vm_name)), random_string].join.downcase
628
- remove_storage_service_on_failure = config[:azure_storage_account]
629
- else
630
- remove_storage_service_on_failure = nil
631
- config[:azure_storage_account] = storage.name.to_s
632
- end
633
- else
634
- if connection.storageaccounts.exists?(locate_config_value(:azure_storage_account))
635
- remove_storage_service_on_failure = nil
636
- else
637
- remove_storage_service_on_failure = locate_config_value(:azure_storage_account)
638
- end
505
+ service.create_server(create_server_def)
506
+ wait_until_virtual_machine_ready()
507
+ if locate_config_value(:bootstrap_protocol) == 'cloud-api' && locate_config_value(:extended_logs)
508
+ print "\n\nWaiting for the first chef-client run"
509
+ fetch_chef_client_logs(Time.now, 30)
639
510
  end
640
-
641
- begin
642
- connection.deploys.create(create_server_def)
643
- wait_until_virtual_machine_ready()
644
- server = get_role_server()
645
- rescue Exception => e
646
- Chef::Log.error("Failed to create the server -- exception being rescued: #{e.to_s}")
647
- backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
648
- Chef::Log.debug("#{backtrace_message}")
649
- cleanup_and_exit(remove_hosted_service_on_failure, remove_storage_service_on_failure)
650
- end
651
-
511
+ server = service.get_role_server(locate_config_value(:azure_dns_name), locate_config_value(:azure_vm_name))
652
512
  msg_server_summary(server)
653
513
 
654
514
  bootstrap_exec(server) unless locate_config_value(:bootstrap_protocol) == 'cloud-api'
655
515
  end
656
516
 
657
- def default_bootstrap_template
658
- is_image_windows? ? 'windows-chef-client-msi' : 'chef-full'
659
- end
660
-
661
- def bootstrap_exec(server)
662
- fqdn = server.publicipaddress
663
-
664
- if is_image_windows?
665
- if locate_config_value(:bootstrap_protocol) == 'ssh'
666
- port = server.sshport
667
- print "#{ui.color("Waiting for sshd on #{fqdn}:#{port}", :magenta)}"
668
-
669
- print(".") until tcp_test_ssh(fqdn,port) {
670
- sleep @initial_sleep_delay ||= 10
671
- puts("done")
672
- }
673
-
674
- elsif locate_config_value(:bootstrap_protocol) == 'winrm'
675
- port = server.winrmport
676
-
677
- print "#{ui.color("Waiting for winrm on #{fqdn}:#{port}", :magenta)}"
678
-
679
- print(".") until tcp_test_winrm(fqdn,port) {
680
- sleep @initial_sleep_delay ||= 10
681
- puts("done")
682
- }
683
- end
684
-
685
- puts("\n")
686
- bootstrap_for_windows_node(server,fqdn, port).run
687
- else
688
- unless server && server.publicipaddress && server.sshport
689
- Chef::Log.fatal("server not created")
690
- exit 1
691
- end
692
-
693
- port = server.sshport
694
-
695
- print ui.color("Waiting for sshd on #{fqdn}:#{port}", :magenta)
696
-
697
- print(".") until tcp_test_ssh(fqdn,port) {
698
- sleep @initial_sleep_delay ||= 10
699
- puts("done")
700
- }
701
-
702
- puts("\n")
703
- bootstrap_for_node(server,fqdn,port).run
704
- end
705
-
706
- msg_server_summary(server)
707
- end
708
-
709
- def load_cloud_attributes_in_hints(server)
710
- # Modify global configuration state to ensure hint gets set by knife-bootstrap
711
- # Query azure and load necessary attributes.
712
- cloud_attributes = {}
713
- cloud_attributes["public_ip"] = server.publicipaddress
714
- cloud_attributes["vm_name"] = server.name
715
- cloud_attributes["public_fqdn"] = server.hostedservicename.to_s + ".cloudapp.net"
716
- cloud_attributes["public_ssh_port"] = server.sshport if server.sshport
717
- cloud_attributes["public_winrm_port"] = server.winrmport if server.winrmport
718
-
719
- Chef::Config[:knife][:hints] ||= {}
720
- Chef::Config[:knife][:hints]["azure"] ||= cloud_attributes
721
-
722
- end
723
-
724
- def bootstrap_common_params(bootstrap, server)
725
-
726
- bootstrap.config[:run_list] = config[:run_list]
727
- bootstrap.config[:prerelease] = config[:prerelease]
728
- bootstrap.config[:first_boot_attributes] = locate_config_value(:json_attributes) || {}
729
- bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
730
- bootstrap.config[:distro] = locate_config_value(:distro) || default_bootstrap_template
731
- # setting bootstrap_template value to template_file for backward
732
- bootstrap.config[:template_file] = locate_config_value(:template_file) || locate_config_value(:bootstrap_template)
733
- bootstrap.config[:node_ssl_verify_mode] = locate_config_value(:node_ssl_verify_mode)
734
- bootstrap.config[:node_verify_api_cert] = locate_config_value(:node_verify_api_cert)
735
- bootstrap.config[:bootstrap_no_proxy] = locate_config_value(:bootstrap_no_proxy)
736
- bootstrap.config[:bootstrap_url] = locate_config_value(:bootstrap_url)
737
- bootstrap.config[:bootstrap_vault_file] = locate_config_value(:bootstrap_vault_file)
738
- bootstrap.config[:bootstrap_vault_json] = locate_config_value(:bootstrap_vault_json)
739
- bootstrap.config[:bootstrap_vault_item] = locate_config_value(:bootstrap_vault_item)
740
-
741
- load_cloud_attributes_in_hints(server)
742
- bootstrap
743
- end
744
-
745
- def bootstrap_for_windows_node(server, fqdn, port)
746
- if locate_config_value(:bootstrap_protocol) == 'winrm'
747
-
748
- load_winrm_deps
749
- if not Chef::Platform.windows?
750
- require 'gssapi'
751
- end
752
-
753
- bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
754
-
755
- bootstrap.config[:winrm_user] = locate_config_value(:winrm_user) || 'Administrator'
756
- bootstrap.config[:winrm_password] = locate_config_value(:winrm_password)
757
- bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
758
- bootstrap.config[:winrm_authentication_protocol] = locate_config_value(:winrm_authentication_protocol)
759
- bootstrap.config[:winrm_port] = port
760
- bootstrap.config[:auth_timeout] = locate_config_value(:auth_timeout)
761
- # Todo: we should skip cert generate in case when winrm_ssl_verify_mode=verify_none
762
- bootstrap.config[:winrm_ssl_verify_mode] = locate_config_value(:winrm_ssl_verify_mode)
763
- elsif locate_config_value(:bootstrap_protocol) == 'ssh'
764
- bootstrap = Chef::Knife::BootstrapWindowsSsh.new
765
- bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
766
- bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
767
- bootstrap.config[:forward_agent] = locate_config_value(:forward_agent)
768
- bootstrap.config[:ssh_port] = port
769
- bootstrap.config[:identity_file] = locate_config_value(:identity_file)
770
- bootstrap.config[:host_key_verify] = locate_config_value(:host_key_verify)
771
- else
772
- ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
773
- exit 1
774
- end
775
- bootstrap.name_args = [fqdn]
776
- bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.name
777
- bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret)
778
- bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
779
- bootstrap.config[:msi_url] = locate_config_value(:msi_url)
780
- bootstrap.config[:install_as_service] = locate_config_value(:install_as_service)
781
- bootstrap_common_params(bootstrap, server)
782
- end
783
-
784
- def bootstrap_for_node(server,fqdn,port)
785
- bootstrap = Chef::Knife::Bootstrap.new
786
- bootstrap.name_args = [fqdn]
787
- bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
788
- bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
789
- bootstrap.config[:ssh_port] = port
790
- bootstrap.config[:identity_file] = locate_config_value(:identity_file)
791
- bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.name
792
- bootstrap.config[:use_sudo] = true unless locate_config_value(:ssh_user) == 'root'
793
- bootstrap.config[:use_sudo_password] = true if bootstrap.config[:use_sudo]
794
- bootstrap.config[:environment] = locate_config_value(:environment)
795
- # may be needed for vpc_mode
796
- bootstrap.config[:host_key_verify] = config[:host_key_verify]
797
- bootstrap.config[:secret] = locate_config_value(:secret)
798
- bootstrap.config[:secret_file] = locate_config_value(:secret_file)
799
- bootstrap.config[:bootstrap_install_command] = locate_config_value(:bootstrap_install_command)
800
- bootstrap.config[:bootstrap_wget_options] = locate_config_value(:bootstrap_wget_options)
801
- bootstrap.config[:bootstrap_curl_options] = locate_config_value(:bootstrap_curl_options)
802
- bootstrap_common_params(bootstrap, server)
803
- end
804
-
805
- def validate!
806
- super([
807
- :azure_subscription_id,
808
- :azure_mgmt_cert,
809
- :azure_api_host_name,
810
- :azure_source_image,
811
- :azure_vm_size,
812
- ])
813
-
517
+ def validate_params!
814
518
  if locate_config_value(:winrm_password) and (locate_config_value(:winrm_password).length <= 6 and locate_config_value(:winrm_password).length >= 72)
815
519
  ui.error("The supplied password must be 6-72 characters long and meet password complexity requirements")
816
520
  exit 1
@@ -839,7 +543,7 @@ class Chef
839
543
  exit 1
840
544
  end
841
545
 
842
- if !(connection.images.exists?(locate_config_value(:azure_source_image)))
546
+ if !(service.valid_image?(locate_config_value(:azure_source_image)))
843
547
  ui.error("Image provided is invalid")
844
548
  exit 1
845
549
  end
@@ -856,6 +560,18 @@ class Chef
856
560
  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.")
857
561
  exit 1
858
562
  end
563
+
564
+ if (locate_config_value(:auto_update_client) || locate_config_value(:delete_chef_extension_config) || locate_config_value(:uninstall_chef_client)) && (locate_config_value(:bootstrap_protocol) != 'cloud-api')
565
+ ui.error("--auto-update-client option works with --bootstrap-protocol cloud-api") if locate_config_value(:auto_update_client)
566
+ ui.error("--delete-chef-extension-config option works with --bootstrap-protocol cloud-api") if locate_config_value(:delete_chef_extension_config)
567
+ ui.error("--uninstall-chef-client option works with --bootstrap-protocol cloud-api") if locate_config_value(:uninstall_chef_client)
568
+ exit 1
569
+ end
570
+
571
+ if locate_config_value(:extended_logs) && locate_config_value(:bootstrap_protocol) != 'cloud-api'
572
+ ui.error("--extended-logs option works with --bootstrap-protocol cloud-api")
573
+ exit 1
574
+ end
859
575
  end
860
576
 
861
577
  def create_server_def
@@ -945,7 +661,7 @@ class Chef
945
661
 
946
662
  server_def[:port] = port
947
663
 
948
- server_def[:is_vm_image] = connection.images.is_vm_image(locate_config_value(:azure_source_image))
664
+ server_def[:is_vm_image] = service.vm_image?(locate_config_value(:azure_source_image))
949
665
  server_def[:azure_domain_name] = locate_config_value(:azure_domain_name) if locate_config_value(:azure_domain_name)
950
666
 
951
667
  if locate_config_value(:azure_domain_user)
@@ -969,103 +685,8 @@ class Chef
969
685
  end
970
686
  server_def[:azure_domain_passwd] = locate_config_value(:azure_domain_passwd)
971
687
  server_def[:azure_domain_ou_dn] = locate_config_value(:azure_domain_ou_dn)
972
- server_def
973
- end
974
-
975
- def get_chef_extension_name
976
- extension_name = is_image_windows? ? "ChefClient" : "LinuxChefClient"
977
- end
978
-
979
- def get_chef_extension_publisher
980
- publisher = "Chef.Bootstrap.WindowsAzure"
981
- end
982
-
983
- # get latest version
984
- def get_chef_extension_version
985
- if locate_config_value(:azure_chef_extension_version)
986
- Chef::Config[:knife][:azure_chef_extension_version]
987
- else
988
- extensions = @connection.query_azure("resourceextensions/#{get_chef_extension_publisher}/#{get_chef_extension_name}")
989
- extensions.css("Version").max.text.split(".").first + ".*"
990
- end
991
- end
992
-
993
- def get_chef_extension_public_params
994
- pub_config = Hash.new
995
- if(locate_config_value(:azure_extension_client_config))
996
- pub_config[:client_rb] = File.read(locate_config_value(:azure_extension_client_config))
997
- else
998
- pub_config[:client_rb] = "chef_server_url \t #{Chef::Config[:chef_server_url].to_json}\nvalidation_client_name\t#{Chef::Config[:validation_client_name].to_json}"
999
- end
1000
-
1001
- pub_config[:runlist] = locate_config_value(:run_list).empty? ? "" : locate_config_value(:run_list).join(",").to_json
1002
- pub_config[:autoUpdateClient] = locate_config_value(:auto_update_client) ? "true" : "false"
1003
- pub_config[:deleteChefConfig] = locate_config_value(:delete_chef_extension_config) ? "true" : "false"
1004
- pub_config[:custom_json_attr] = locate_config_value(:json_attributes) || {}
1005
-
1006
- # bootstrap attributes
1007
- pub_config[:bootstrap_options] = {}
1008
- pub_config[:bootstrap_options][:environment] = locate_config_value(:environment) if locate_config_value(:environment)
1009
- pub_config[:bootstrap_options][:chef_node_name] = config[:chef_node_name] if config[:chef_node_name]
1010
- pub_config[:bootstrap_options][:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret) if locate_config_value(:encrypted_data_bag_secret)
1011
- pub_config[:bootstrap_options][:chef_server_url] = Chef::Config[:chef_server_url] if Chef::Config[:chef_server_url]
1012
- pub_config[:bootstrap_options][:validation_client_name] = Chef::Config[:validation_client_name] if Chef::Config[:validation_client_name]
1013
- pub_config[:bootstrap_options][:node_verify_api_cert] = locate_config_value(:node_verify_api_cert) ? "true" : "false" if config.key?(:node_verify_api_cert)
1014
- pub_config[:bootstrap_options][:bootstrap_version] = locate_config_value(:bootstrap_version) if locate_config_value(:bootstrap_version)
1015
- pub_config[:bootstrap_options][:node_ssl_verify_mode] = locate_config_value(:node_ssl_verify_mode) if locate_config_value(:node_ssl_verify_mode)
1016
- pub_config[:bootstrap_options][:bootstrap_proxy] = locate_config_value(:bootstrap_proxy) if locate_config_value(:bootstrap_proxy)
1017
- Base64.encode64(pub_config.to_json)
1018
- end
1019
-
1020
- def get_chef_extension_private_params
1021
- pri_config = Hash.new
1022
688
 
1023
- # validator less bootstrap support for bootstrap protocol cloud-api
1024
- if (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
1025
-
1026
- if Chef::VERSION.split('.').first.to_i == 11
1027
- ui.error('Unable to find validation key. Please verify your configuration file for validation_key config value.')
1028
- exit 1
1029
- end
1030
-
1031
- client_builder = Chef::Knife::Bootstrap::ClientBuilder.new(
1032
- chef_config: Chef::Config,
1033
- knife_config: config,
1034
- ui: ui,
1035
- )
1036
-
1037
- client_builder.run
1038
- key_path = client_builder.client_path
1039
- pri_config[:client_pem] = File.read(key_path)
1040
- else
1041
- pri_config[:validation_key] = File.read(Chef::Config[:validation_key])
1042
- end
1043
-
1044
- # SSL cert bootstrap support
1045
- if locate_config_value(:cert_path)
1046
- if File.exist?(File.expand_path(locate_config_value(:cert_path)))
1047
- pri_config[:chef_server_crt] = File.read(locate_config_value(:cert_path))
1048
- else
1049
- ui.error('Specified SSL certificate does not exist.')
1050
- exit 1
1051
- end
1052
- end
1053
- Base64.encode64(pri_config.to_json)
1054
- end
1055
-
1056
- def cleanup_and_exit(remove_hosted_service_on_failure, remove_storage_service_on_failure)
1057
- ui.warn("Cleaning up resources...")
1058
-
1059
- if remove_hosted_service_on_failure
1060
- ret_val = connection.hosts.delete(remove_hosted_service_on_failure)
1061
- ret_val.content.empty? ? ui.warn("Deleted created DNS: #{remove_hosted_service_on_failure}.") : ui.warn("Deletion failed for created DNS:#{remove_hosted_service_on_failure}. " + ret_val.text)
1062
- end
1063
-
1064
- if remove_storage_service_on_failure
1065
- ret_val = connection.storageaccounts.delete(remove_storage_service_on_failure)
1066
- ret_val.content.empty? ? ui.warn("Deleted created Storage Account: #{remove_storage_service_on_failure}.") : ui.warn("Deletion failed for created Storage Account: #{remove_storage_service_on_failure}. " + ret_val.text)
1067
- end
1068
- exit 1
689
+ server_def
1069
690
  end
1070
691
 
1071
692
  private