knife-azure 1.6.0.rc.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|