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.
- checksums.yaml +4 -4
- data/README.md +304 -8
- data/lib/azure/azure_interface.rb +81 -0
- data/lib/azure/custom_errors.rb +35 -0
- data/lib/azure/helpers.rb +44 -0
- data/lib/azure/resource_management/ARM_base.rb +29 -0
- data/lib/azure/resource_management/ARM_deployment_template.rb +561 -0
- data/lib/azure/resource_management/ARM_interface.rb +795 -0
- data/lib/azure/resource_management/windows_credentials.rb +136 -0
- data/lib/azure/service_management/ASM_interface.rb +301 -0
- data/lib/azure/{ag.rb → service_management/ag.rb} +2 -2
- data/lib/azure/{certificate.rb → service_management/certificate.rb} +2 -2
- data/lib/azure/service_management/connection.rb +102 -0
- data/lib/azure/{deploy.rb → service_management/deploy.rb} +8 -2
- data/lib/azure/{disk.rb → service_management/disk.rb} +2 -2
- data/lib/azure/{host.rb → service_management/host.rb} +2 -2
- data/lib/azure/{image.rb → service_management/image.rb} +2 -2
- data/lib/azure/{loadbalancer.rb → service_management/loadbalancer.rb} +4 -18
- data/lib/azure/{rest.rb → service_management/rest.rb} +15 -10
- data/lib/azure/{role.rb → service_management/role.rb} +174 -6
- data/lib/azure/{storageaccount.rb → service_management/storageaccount.rb} +2 -2
- data/lib/azure/{utility.rb → service_management/utility.rb} +0 -0
- data/lib/azure/{vnet.rb → service_management/vnet.rb} +2 -2
- data/lib/chef/knife/azure_ag_create.rb +3 -6
- data/lib/chef/knife/azure_ag_list.rb +2 -16
- data/lib/chef/knife/azure_base.rb +89 -22
- data/lib/chef/knife/azure_image_list.rb +3 -7
- data/lib/chef/knife/azure_internal-lb_create.rb +2 -5
- data/lib/chef/knife/azure_internal-lb_list.rb +2 -16
- data/lib/chef/knife/azure_server_create.rb +122 -501
- data/lib/chef/knife/azure_server_delete.rb +15 -38
- data/lib/chef/knife/azure_server_list.rb +2 -27
- data/lib/chef/knife/azure_server_show.rb +4 -60
- data/lib/chef/knife/azure_vnet_create.rb +2 -7
- data/lib/chef/knife/azure_vnet_list.rb +2 -17
- data/lib/chef/knife/azurerm_base.rb +228 -0
- data/lib/chef/knife/azurerm_server_create.rb +393 -0
- data/lib/chef/knife/azurerm_server_delete.rb +121 -0
- data/lib/chef/knife/azurerm_server_list.rb +18 -0
- data/lib/chef/knife/azurerm_server_show.rb +37 -0
- data/lib/chef/knife/bootstrap/bootstrap_options.rb +105 -0
- data/lib/chef/knife/bootstrap/bootstrapper.rb +343 -0
- data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +116 -0
- data/lib/chef/knife/bootstrap_azure.rb +110 -0
- data/lib/chef/knife/bootstrap_azurerm.rb +116 -0
- data/lib/knife-azure/version.rb +1 -2
- metadata +132 -16
- data/lib/azure/connection.rb +0 -99
@@ -16,7 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
|
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
|
-
|
85
|
+
module Azure
|
86
86
|
class StorageAccount
|
87
87
|
include AzureUtility
|
88
88
|
attr_accessor :name, :location
|
File without changes
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
|
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
|
-
|
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
|
-
|
50
|
-
:
|
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 =
|
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
|
-
|
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
|
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 =
|
71
|
-
target_image = images.
|
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
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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 =
|
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
|
-
|
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::
|
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 =
|
496
|
-
deployment =
|
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
|
542
|
-
|
543
|
-
|
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
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
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
|
569
|
-
|
570
|
-
|
571
|
-
if
|
572
|
-
Chef
|
573
|
-
|
574
|
-
|
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
|
-
|
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
|
-
|
491
|
+
validate_asm_keys!(:azure_source_image)
|
601
492
|
|
602
|
-
|
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
|
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
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
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
|
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 !(
|
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] =
|
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
|
-
|
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
|