knife-azure 1.8.7 → 1.9.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/lib/azure/azure_interface.rb +79 -81
- data/lib/azure/custom_errors.rb +34 -35
- data/lib/azure/helpers.rb +43 -44
- data/lib/azure/resource_management/ARM_deployment_template.rb +679 -678
- data/lib/azure/resource_management/ARM_interface.rb +513 -515
- data/lib/azure/resource_management/vnet_config.rb +43 -43
- data/lib/azure/resource_management/windows_credentials.rb +181 -184
- data/lib/azure/service_management/ASM_interface.rb +309 -317
- data/lib/azure/service_management/ag.rb +16 -16
- data/lib/azure/service_management/certificate.rb +30 -31
- data/lib/azure/service_management/connection.rb +31 -31
- data/lib/azure/service_management/deploy.rb +40 -38
- data/lib/azure/service_management/disk.rb +14 -10
- data/lib/azure/service_management/host.rb +28 -24
- data/lib/azure/service_management/image.rb +23 -22
- data/lib/azure/service_management/loadbalancer.rb +12 -12
- data/lib/azure/service_management/rest.rb +20 -19
- data/lib/azure/service_management/role.rb +274 -273
- data/lib/azure/service_management/storageaccount.rb +29 -25
- data/lib/azure/service_management/utility.rb +6 -7
- data/lib/azure/service_management/vnet.rb +44 -44
- data/lib/chef/knife/azure_ag_create.rb +18 -18
- data/lib/chef/knife/azure_ag_list.rb +3 -3
- data/lib/chef/knife/azure_base.rb +56 -56
- data/lib/chef/knife/azure_image_list.rb +8 -10
- data/lib/chef/knife/azure_internal-lb_create.rb +15 -15
- data/lib/chef/knife/azure_internal-lb_list.rb +3 -3
- data/lib/chef/knife/azure_server_create.rb +49 -50
- data/lib/chef/knife/azure_server_delete.rb +22 -24
- data/lib/chef/knife/azure_server_list.rb +4 -4
- data/lib/chef/knife/azure_server_show.rb +5 -5
- data/lib/chef/knife/azure_vnet_create.rb +17 -17
- data/lib/chef/knife/azure_vnet_list.rb +3 -3
- data/lib/chef/knife/azurerm_base.rb +58 -60
- data/lib/chef/knife/azurerm_server_create.rb +23 -22
- data/lib/chef/knife/azurerm_server_delete.rb +30 -34
- data/lib/chef/knife/azurerm_server_list.rb +42 -42
- data/lib/chef/knife/azurerm_server_show.rb +1 -1
- data/lib/chef/knife/bootstrap/bootstrap_options.rb +7 -8
- data/lib/chef/knife/bootstrap/bootstrapper.rb +65 -65
- data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +3 -4
- data/lib/chef/knife/bootstrap_azure.rb +13 -13
- data/lib/chef/knife/bootstrap_azurerm.rb +106 -106
- data/lib/knife-azure/version.rb +2 -2
- metadata +43 -76
- data/lib/azure/resource_management/ARM_base.rb +0 -29
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2010-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -19,33 +19,37 @@
|
|
19
19
|
module Azure
|
20
20
|
class Disks
|
21
21
|
def initialize(connection)
|
22
|
-
@connection=connection
|
22
|
+
@connection = connection
|
23
23
|
end
|
24
|
+
|
24
25
|
def all
|
25
26
|
disks = Array.new
|
26
|
-
response = @connection.query_azure(
|
27
|
-
founddisks = response.css(
|
27
|
+
response = @connection.query_azure("disks")
|
28
|
+
founddisks = response.css("Disk")
|
28
29
|
founddisks.each do |disk|
|
29
30
|
item = Disk.new(disk)
|
30
31
|
disks << item
|
31
32
|
end
|
32
33
|
disks
|
33
34
|
end
|
35
|
+
|
34
36
|
def find(name)
|
35
37
|
founddisk = nil
|
36
|
-
|
38
|
+
all.each do |disk|
|
37
39
|
next unless disk.name == name
|
38
40
|
founddisk = disk
|
39
41
|
end
|
40
42
|
founddisk
|
41
43
|
end
|
44
|
+
|
42
45
|
def exists(name)
|
43
|
-
find(name)
|
46
|
+
!find(name).nil?
|
44
47
|
end
|
48
|
+
|
45
49
|
def clear_unattached
|
46
|
-
|
50
|
+
all.each do |disk|
|
47
51
|
next unless disk.attached == false
|
48
|
-
@connection.query_azure(
|
52
|
+
@connection.query_azure("disks/" + disk.name, "delete")
|
49
53
|
end
|
50
54
|
end
|
51
55
|
end
|
@@ -55,8 +59,8 @@ module Azure
|
|
55
59
|
class Disk
|
56
60
|
attr_accessor :name, :attached
|
57
61
|
def initialize(disk)
|
58
|
-
@name = disk.at_css(
|
59
|
-
@attached = disk.at_css(
|
62
|
+
@name = disk.at_css("Name").content
|
63
|
+
@attached = !disk.at_css("AttachedTo").nil?
|
60
64
|
end
|
61
65
|
end
|
62
66
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2010-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -20,7 +20,7 @@ module Azure
|
|
20
20
|
class Hosts
|
21
21
|
include AzureUtility
|
22
22
|
def initialize(connection)
|
23
|
-
@connection=connection
|
23
|
+
@connection = connection
|
24
24
|
end
|
25
25
|
|
26
26
|
# force_load should be true when there is something in local cache and we want to reload
|
@@ -29,8 +29,8 @@ module Azure
|
|
29
29
|
if not @hosted_services || force_load
|
30
30
|
@hosted_services = begin
|
31
31
|
hosted_services = Hash.new
|
32
|
-
responseXML = @connection.query_azure(
|
33
|
-
servicesXML = responseXML.css(
|
32
|
+
responseXML = @connection.query_azure("hostedservices")
|
33
|
+
servicesXML = responseXML.css("HostedServices HostedService")
|
34
34
|
servicesXML.each do |serviceXML|
|
35
35
|
host = Host.new(@connection).parse(serviceXML)
|
36
36
|
hosted_services[host.name] = host
|
@@ -42,13 +42,13 @@ module Azure
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def all
|
45
|
-
|
45
|
+
load.values
|
46
46
|
end
|
47
47
|
|
48
48
|
# first look up local cache if we have already loaded list.
|
49
49
|
def exists?(name)
|
50
50
|
return @hosted_services.key?(name) if @hosted_services
|
51
|
-
|
51
|
+
exists_on_cloud?(name)
|
52
52
|
end
|
53
53
|
|
54
54
|
# Look up on cloud and not local cache
|
@@ -56,7 +56,7 @@ module Azure
|
|
56
56
|
ret_val = @connection.query_azure("hostedservices/#{name}")
|
57
57
|
error_code, error_message = error_from_response_xml(ret_val) if ret_val
|
58
58
|
if ret_val.nil? || error_code.length > 0
|
59
|
-
Chef::Log.debug(
|
59
|
+
Chef::Log.debug("Unable to find hosted(cloud) service:" + error_code + " : " + error_message) if ret_val
|
60
60
|
false
|
61
61
|
else
|
62
62
|
true
|
@@ -66,7 +66,7 @@ module Azure
|
|
66
66
|
# first look up local cache if we have already loaded list.
|
67
67
|
def find(name)
|
68
68
|
return @hosted_services[name] if @hosted_services && @hosted_services.key?(name)
|
69
|
-
|
69
|
+
fetch_from_cloud(name)
|
70
70
|
end
|
71
71
|
|
72
72
|
# Look up hosted service on cloud and not local cache
|
@@ -74,7 +74,7 @@ module Azure
|
|
74
74
|
ret_val = @connection.query_azure("hostedservices/#{name}")
|
75
75
|
error_code, error_message = error_from_response_xml(ret_val) if ret_val
|
76
76
|
if ret_val.nil? || error_code.length > 0
|
77
|
-
Chef::Log.warn(
|
77
|
+
Chef::Log.warn("Unable to find hosted(cloud) service:" + error_code + " : " + error_message) if ret_val
|
78
78
|
nil
|
79
79
|
else
|
80
80
|
Host.new(@connection).parse(ret_val)
|
@@ -85,10 +85,11 @@ module Azure
|
|
85
85
|
host = Host.new(@connection)
|
86
86
|
host.create(params)
|
87
87
|
end
|
88
|
+
|
88
89
|
def delete(name)
|
89
|
-
if
|
90
|
-
|
91
|
-
@connection.query_azure(servicecall, "delete")
|
90
|
+
if exists?(name)
|
91
|
+
servicecall = "hostedservices/" + name
|
92
|
+
@connection.query_azure(servicecall, "delete")
|
92
93
|
end
|
93
94
|
end
|
94
95
|
end
|
@@ -106,35 +107,38 @@ module Azure
|
|
106
107
|
@deploys_loaded = false
|
107
108
|
@deploys = Hash.new
|
108
109
|
end
|
110
|
+
|
109
111
|
def parse(serviceXML)
|
110
|
-
@name = xml_content(serviceXML,
|
111
|
-
@url = xml_content(serviceXML,
|
112
|
-
@label = xml_content(serviceXML,
|
113
|
-
@dateCreated = xml_content(serviceXML,
|
114
|
-
@description = xml_content(serviceXML,
|
115
|
-
@location = xml_content(serviceXML,
|
116
|
-
@dateModified = xml_content(serviceXML,
|
117
|
-
@status = xml_content(serviceXML,
|
112
|
+
@name = xml_content(serviceXML, "ServiceName")
|
113
|
+
@url = xml_content(serviceXML, "Url")
|
114
|
+
@label = xml_content(serviceXML, "HostedServiceProperties Label")
|
115
|
+
@dateCreated = xml_content(serviceXML, "HostedServiceProperties DateCreated")
|
116
|
+
@description = xml_content(serviceXML, "HostedServiceProperties Description")
|
117
|
+
@location = xml_content(serviceXML, "HostedServiceProperties Location")
|
118
|
+
@dateModified = xml_content(serviceXML, "HostedServiceProperties DateLastModified")
|
119
|
+
@status = xml_content(serviceXML, "HostedServiceProperties Status")
|
118
120
|
self
|
119
121
|
end
|
122
|
+
|
120
123
|
def create(params)
|
121
124
|
builder = Nokogiri::XML::Builder.new do |xml|
|
122
|
-
xml.CreateHostedService(
|
125
|
+
xml.CreateHostedService("xmlns" => "http://schemas.microsoft.com/windowsazure") do
|
123
126
|
xml.ServiceName params[:azure_dns_name]
|
124
127
|
xml.Label Base64.encode64(params[:azure_dns_name])
|
125
|
-
xml.Description
|
128
|
+
xml.Description "Explicitly created hosted service"
|
126
129
|
unless params[:azure_service_location].nil?
|
127
130
|
xml.Location params[:azure_service_location]
|
128
131
|
end
|
129
132
|
unless params[:azure_affinity_group].nil?
|
130
133
|
xml.AffinityGroup params[:azure_affinity_group]
|
131
134
|
end
|
132
|
-
|
135
|
+
end
|
133
136
|
end
|
134
137
|
@connection.query_azure("hostedservices", "post", builder.to_xml)
|
135
138
|
end
|
139
|
+
|
136
140
|
def details
|
137
|
-
response = @connection.query_azure(
|
141
|
+
response = @connection.query_azure("hostedservices/" + @name + "?embed-detail=true")
|
138
142
|
end
|
139
143
|
|
140
144
|
# Deployments within this hostedservice
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2010-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -19,29 +19,30 @@
|
|
19
19
|
module Azure
|
20
20
|
class Images
|
21
21
|
def initialize(connection)
|
22
|
-
@connection=connection
|
22
|
+
@connection = connection
|
23
23
|
end
|
24
|
+
|
24
25
|
def load
|
25
26
|
@images ||= begin
|
26
|
-
osimages =
|
27
|
-
vmimages =
|
27
|
+
osimages = get_images("OSImage") #get OSImages
|
28
|
+
vmimages = get_images("VMImage") #get VMImages
|
28
29
|
|
29
30
|
all_images = osimages.merge(vmimages)
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
34
|
def all
|
34
|
-
|
35
|
+
load.values
|
35
36
|
end
|
36
37
|
|
37
38
|
# img_type = OSImages or VMImage
|
38
39
|
def get_images(img_type)
|
39
40
|
images = Hash.new
|
40
41
|
|
41
|
-
if
|
42
|
-
response = @connection.query_azure(
|
43
|
-
elsif
|
44
|
-
response = @connection.query_azure(
|
42
|
+
if img_type == "OSImage"
|
43
|
+
response = @connection.query_azure("images")
|
44
|
+
elsif img_type == "VMImage"
|
45
|
+
response = @connection.query_azure("vmimages")
|
45
46
|
end
|
46
47
|
|
47
48
|
unless response.to_s.empty?
|
@@ -57,21 +58,21 @@ module Azure
|
|
57
58
|
end
|
58
59
|
|
59
60
|
def is_os_image(image_name)
|
60
|
-
os_images =
|
61
|
-
os_images.detect {|img| img.name == image_name} ? true : false
|
61
|
+
os_images = get_images("OSImage").values
|
62
|
+
os_images.detect { |img| img.name == image_name } ? true : false
|
62
63
|
end
|
63
64
|
|
64
65
|
def is_vm_image(image_name)
|
65
|
-
vm_images =
|
66
|
-
vm_images.detect {|img| img.name == image_name} ? true : false
|
66
|
+
vm_images = get_images("VMImage").values
|
67
|
+
vm_images.detect { |img| img.name == image_name } ? true : false
|
67
68
|
end
|
68
69
|
|
69
70
|
def exists?(name)
|
70
|
-
|
71
|
+
all.detect { |img| img.name == name } ? true : false
|
71
72
|
end
|
72
73
|
|
73
74
|
def find(name)
|
74
|
-
|
75
|
+
load[name]
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
@@ -81,13 +82,13 @@ module Azure
|
|
81
82
|
attr_accessor :category, :label
|
82
83
|
attr_accessor :name, :os, :eula, :description, :location
|
83
84
|
def initialize(image)
|
84
|
-
@category = image.at_css(
|
85
|
-
@label = image.at_css(
|
86
|
-
@name = image.at_css(
|
87
|
-
@os = image.at_css(
|
88
|
-
@location = image.at_css(
|
89
|
-
@eula = image.at_css(
|
90
|
-
@description = image.at_css(
|
85
|
+
@category = image.at_css("Category").content
|
86
|
+
@label = image.at_css("Label").content
|
87
|
+
@name = image.at_css("Name").content
|
88
|
+
@os = image.at_css("OS").content
|
89
|
+
@location = image.at_css("Location").content.gsub(";", ", ") if image.at_css("Location")
|
90
|
+
@eula = image.at_css("Eula").content if image.at_css("Eula")
|
91
|
+
@description = image.at_css("Description").content if image.at_css("Description")
|
91
92
|
end
|
92
93
|
end
|
93
94
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Aiman Alsari (aiman.alsari@gmail.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2013-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -48,27 +48,27 @@ module Azure
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def parse(lbXML, hostedservicename)
|
51
|
-
@name = xml_content(lbXML,
|
52
|
-
ip_configXML = lbXML.css(
|
53
|
-
@subnet = xml_content(ip_configXML,
|
54
|
-
@vip = xml_content(ip_configXML,
|
51
|
+
@name = xml_content(lbXML, "Name")
|
52
|
+
ip_configXML = lbXML.css("FrontendIpConfiguration")
|
53
|
+
@subnet = xml_content(ip_configXML, "SubnetName")
|
54
|
+
@vip = xml_content(ip_configXML, "StaticVirtualNetworkIPAddress")
|
55
55
|
@service = hostedservicename
|
56
56
|
self
|
57
57
|
end
|
58
58
|
|
59
59
|
def create(params)
|
60
60
|
if params[:azure_lb_static_vip] && !params[:azure_subnet_name]
|
61
|
-
Chef::Log.fatal
|
61
|
+
Chef::Log.fatal "Unable to create Loadbalancer, :azure_subnet_name needs to be set if :azure_lb_static_vip is set"
|
62
62
|
end
|
63
|
-
builder = Nokogiri::XML::Builder.new(encoding:
|
64
|
-
xml.LoadBalancer(xmlns:
|
63
|
+
builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
|
64
|
+
xml.LoadBalancer(xmlns: "http://schemas.microsoft.com/windowsazure") do
|
65
65
|
xml.Name params[:azure_load_balancer]
|
66
|
-
xml.FrontendIpConfiguration
|
67
|
-
xml.Type
|
66
|
+
xml.FrontendIpConfiguration do
|
67
|
+
xml.Type "Private"
|
68
68
|
xml.SubnetName params[:azure_subnet_name] if params[:azure_subnet_name]
|
69
69
|
xml.StaticVirtualNetworkIPAddress params[:azure_lb_static_vip] if params[:azure_lb_static_vip]
|
70
|
-
|
71
|
-
|
70
|
+
end
|
71
|
+
end
|
72
72
|
end
|
73
73
|
deploy_name = @connection.deploys.get_deploy_name_for_hostedservice(params[:azure_dns_name])
|
74
74
|
servicecall = "hostedservices/#{params[:azure_dns_name]}/deployments/#{deploy_name}/loadbalancers"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2010-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -30,22 +30,22 @@ module AzureAPI
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def query_azure(service_name,
|
33
|
-
verb =
|
34
|
-
body =
|
35
|
-
params =
|
33
|
+
verb = "get",
|
34
|
+
body = "",
|
35
|
+
params = "",
|
36
36
|
services = true,
|
37
37
|
content_type = nil)
|
38
|
-
svc_str = services ?
|
38
|
+
svc_str = services ? "/services" : ""
|
39
39
|
uri = URI.parse("#{@host_name}/#{@subscription_id}#{svc_str}/#{service_name}")
|
40
40
|
scheme = !uri.scheme ? "https://" : ""
|
41
41
|
request_url = "#{scheme}#{@host_name}/#{@subscription_id}#{svc_str}/#{service_name}"
|
42
|
-
print
|
42
|
+
print "."
|
43
43
|
response = http_query(request_url, verb, body, params, content_type)
|
44
44
|
if response.code.to_i == 307
|
45
45
|
Chef::Log.debug "Redirect to #{response['Location']}"
|
46
|
-
response = http_query(response[
|
46
|
+
response = http_query(response["Location"], verb, body, params, content_type)
|
47
47
|
end
|
48
|
-
@last_request_id = response[
|
48
|
+
@last_request_id = response["x-ms-request-id"]
|
49
49
|
response
|
50
50
|
end
|
51
51
|
|
@@ -55,18 +55,18 @@ module AzureAPI
|
|
55
55
|
http = http_setup(uri)
|
56
56
|
request = request_setup(uri, verb, body, content_type)
|
57
57
|
response = http.request(request)
|
58
|
-
@last_request_id = response[
|
58
|
+
@last_request_id = response["x-ms-request-id"]
|
59
59
|
response
|
60
60
|
end
|
61
61
|
|
62
|
-
def query_for_completion
|
62
|
+
def query_for_completion
|
63
63
|
uri = URI.parse("#{@host_name}/#{@subscription_id}/operations/#{@last_request_id}")
|
64
64
|
scheme = !uri.scheme ? "https://" : ""
|
65
65
|
request_url = "#{scheme}#{@host_name}/#{@subscription_id}/operations/#{@last_request_id}"
|
66
|
-
response = http_query(request_url,
|
66
|
+
response = http_query(request_url, "get", "", "")
|
67
67
|
if response.code.to_i == 307
|
68
68
|
Chef::Log.debug "Redirect to #{response['Location']}"
|
69
|
-
response = http_query(response[
|
69
|
+
response = http_query(response["Location"], "get", "", "")
|
70
70
|
end
|
71
71
|
response
|
72
72
|
end
|
@@ -87,20 +87,21 @@ module AzureAPI
|
|
87
87
|
rescue OpenSSL::X509::CertificateError => err
|
88
88
|
raise "Invalid Azure Certificate pem file. Error: #{err}"
|
89
89
|
end
|
90
|
-
|
90
|
+
http.key = OpenSSL::PKey::RSA.new(@pem_file)
|
91
91
|
http
|
92
92
|
end
|
93
|
+
|
93
94
|
def request_setup(uri, verb, body, content_type)
|
94
|
-
if verb ==
|
95
|
+
if verb == "get"
|
95
96
|
request = Net::HTTP::Get.new(uri.request_uri)
|
96
|
-
elsif verb ==
|
97
|
+
elsif verb == "post"
|
97
98
|
request = Net::HTTP::Post.new(uri.request_uri)
|
98
|
-
elsif verb ==
|
99
|
+
elsif verb == "delete"
|
99
100
|
request = Net::HTTP::Delete.new(uri.request_uri)
|
100
|
-
elsif verb ==
|
101
|
+
elsif verb == "put"
|
101
102
|
request = Net::HTTP::Put.new(uri.request_uri)
|
102
103
|
end
|
103
|
-
text = verb ==
|
104
|
+
text = verb == "put" && content_type.nil?
|
104
105
|
request["x-ms-version"] = "2014-05-01"
|
105
106
|
request["content-type"] = text ? "text/plain" : "application/xml"
|
106
107
|
request["accept"] = "application/xml"
|
@@ -117,7 +118,7 @@ module AzureAPI
|
|
117
118
|
puts "=== response.inspect ==="
|
118
119
|
puts response.inspect
|
119
120
|
puts "=== all of the headers ==="
|
120
|
-
puts response.each_header { |h, j| puts h.inspect +
|
121
|
+
puts response.each_header { |h, j| puts h.inspect + " : " + j.inspect }
|
121
122
|
end
|
122
123
|
end
|
123
124
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2010-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -15,8 +15,8 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
-
require
|
19
|
-
require
|
18
|
+
require "securerandom"
|
19
|
+
require "azure/service_management/utility"
|
20
20
|
|
21
21
|
module Azure
|
22
22
|
class Roles
|
@@ -26,6 +26,7 @@ module Azure
|
|
26
26
|
@connection = connection
|
27
27
|
@roles = nil
|
28
28
|
end
|
29
|
+
|
29
30
|
# do not use this unless you want a list of all roles(vms) in your subscription
|
30
31
|
def all
|
31
32
|
@roles = Array.new
|
@@ -48,16 +49,16 @@ module Azure
|
|
48
49
|
host.find_role(role_name)
|
49
50
|
end
|
50
51
|
|
51
|
-
def find(role_name, params= nil)
|
52
|
+
def find(role_name, params = nil)
|
52
53
|
if params && params[:azure_dns_name]
|
53
54
|
return find_in_hosted_service(role_name, params[:azure_dns_name])
|
54
55
|
end
|
55
56
|
|
56
|
-
all if @roles
|
57
|
+
all if @roles.nil?
|
57
58
|
|
58
59
|
# TODO - optimize this lookup
|
59
60
|
@roles.each do |role|
|
60
|
-
if
|
61
|
+
if role.name == role_name
|
61
62
|
return role
|
62
63
|
end
|
63
64
|
end
|
@@ -69,7 +70,7 @@ module Azure
|
|
69
70
|
if roles && roles.length > 1
|
70
71
|
return false
|
71
72
|
end
|
72
|
-
|
73
|
+
true
|
73
74
|
end
|
74
75
|
|
75
76
|
def exists?(name)
|
@@ -78,19 +79,19 @@ module Azure
|
|
78
79
|
|
79
80
|
def delete(params)
|
80
81
|
role = find(params[:name])
|
81
|
-
if role
|
82
|
+
if !role.nil?
|
82
83
|
roleXML = nil
|
83
84
|
roleXML = @connection.query_azure("hostedservices/#{role.hostedservicename}", "get", "", "embed-detail=true")
|
84
|
-
osdisk = roleXML.css(roleXML,
|
85
|
-
disk_name = xml_content(osdisk,
|
86
|
-
storage_account_name = xml_content(osdisk,
|
85
|
+
osdisk = roleXML.css(roleXML, "OSVirtualHardDisk")
|
86
|
+
disk_name = xml_content(osdisk, "DiskName")
|
87
|
+
storage_account_name = xml_content(osdisk, "MediaLink").gsub("http://", "").gsub(/.blob(.*)$/, "")
|
87
88
|
|
88
89
|
if !params[:preserve_azure_os_disk] && !params[:preserve_azure_vhd] && !params[:wait]
|
89
90
|
# default compmedia = true. So, it deletes role and associated resources
|
90
91
|
check_and_delete_role_and_resources(params, role)
|
91
92
|
else
|
92
93
|
# compmedia = false. So, it deletes only role and not associated resources
|
93
|
-
check_and_delete_role_and_resources(params, role, compmedia=false)
|
94
|
+
check_and_delete_role_and_resources(params, role, compmedia = false)
|
94
95
|
check_and_delete_disks(params, disk_name)
|
95
96
|
check_and_delete_service(params)
|
96
97
|
end
|
@@ -98,7 +99,7 @@ module Azure
|
|
98
99
|
end
|
99
100
|
end
|
100
101
|
|
101
|
-
def check_and_delete_role_and_resources(params, role, compmedia=true)
|
102
|
+
def check_and_delete_role_and_resources(params, role, compmedia = true)
|
102
103
|
if alone_on_hostedservice(role)
|
103
104
|
if !params[:preserve_azure_dns_name] && compmedia
|
104
105
|
servicecall = "hostedservices/#{role.hostedservicename}"
|
@@ -107,10 +108,10 @@ module Azure
|
|
107
108
|
end
|
108
109
|
else
|
109
110
|
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
|
110
|
-
|
111
|
+
"/#{role.deployname}/roles/#{role.name}"
|
111
112
|
end
|
112
113
|
if compmedia
|
113
|
-
@connection.query_azure(servicecall, "delete", "", "comp=media", wait=params[:wait])
|
114
|
+
@connection.query_azure(servicecall, "delete", "", "comp=media", wait = params[:wait])
|
114
115
|
else
|
115
116
|
@connection.query_azure(servicecall, "delete")
|
116
117
|
end
|
@@ -127,13 +128,13 @@ module Azure
|
|
127
128
|
# So Iteratively check for disk detachment from the VM while waiting for 5 minutes ,
|
128
129
|
# exit otherwise after 12 attempts.
|
129
130
|
for attempt in 0..12
|
130
|
-
|
131
|
-
|
131
|
+
break if @connection.query_azure(servicecall, "get").search("AttachedTo").text == ""
|
132
|
+
attempt == 12 ? (puts "The associated disk could not be deleted due to time out.") : (sleep 25)
|
132
133
|
end
|
133
134
|
unless params[:preserve_azure_vhd]
|
134
|
-
@connection.query_azure(servicecall,
|
135
|
+
@connection.query_azure(servicecall, "delete", "", "comp=media", wait = params[:wait])
|
135
136
|
else
|
136
|
-
@connection.query_azure(servicecall,
|
137
|
+
@connection.query_azure(servicecall, "delete")
|
137
138
|
end
|
138
139
|
end
|
139
140
|
end
|
@@ -151,11 +152,11 @@ module Azure
|
|
151
152
|
end
|
152
153
|
|
153
154
|
def check_and_delete_storage(params, disk_name, storage_account_name)
|
154
|
-
|
155
|
-
|
155
|
+
if params[:delete_azure_storage_account]
|
156
|
+
# Iteratively check for disk deletion
|
156
157
|
for attempt in 0..12
|
157
|
-
|
158
|
-
|
158
|
+
break unless @connection.query_azure("disks").search("Name").text.include?(disk_name)
|
159
|
+
attempt == 12 ? (puts "The associated disk could not be deleted due to time out.") : (sleep 25)
|
159
160
|
end
|
160
161
|
begin
|
161
162
|
@connection.query_azure("storageservices/#{storage_account_name}", "delete")
|
@@ -163,7 +164,7 @@ module Azure
|
|
163
164
|
ui.warn("#{ex.message}")
|
164
165
|
ui.warn("#{ex.backtrace.join("\n")}")
|
165
166
|
end
|
166
|
-
|
167
|
+
end
|
167
168
|
end
|
168
169
|
|
169
170
|
def update(name, params)
|
@@ -184,55 +185,55 @@ module Azure
|
|
184
185
|
attr_accessor :hostname, :tcpports, :udpports
|
185
186
|
attr_accessor :role_xml, :os_type, :os_version
|
186
187
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
188
|
+
TCP_ENDPOINTS_MAPPING = { "3389" => "Remote Desktop",
|
189
|
+
"5986" => "PowerShell",
|
190
|
+
"22" => "SSH",
|
191
|
+
"21" => "FTP",
|
192
|
+
"25" => "SMTP",
|
193
|
+
"53" => "DNS",
|
194
|
+
"80" => "HTTP",
|
195
|
+
"110" => "POP3",
|
196
|
+
"143" => "IMAP",
|
197
|
+
"389" => "LDAP",
|
198
|
+
"443" => "HTTPs",
|
199
|
+
"587" => "SMTPS",
|
200
|
+
"995" => "POP3S",
|
201
|
+
"993" => "IMAPS",
|
202
|
+
"1433" => "MSSQL",
|
203
|
+
"3306" => "MySQL"
|
204
|
+
}
|
204
205
|
|
205
206
|
def initialize(connection)
|
206
207
|
@connection = connection
|
207
208
|
end
|
208
209
|
|
209
210
|
def parse(roleXML, hostedservicename, deployname)
|
210
|
-
@name = xml_content(roleXML,
|
211
|
-
@status = xml_content(roleXML,
|
212
|
-
@size = xml_content(roleXML,
|
213
|
-
@ipaddress = xml_content(roleXML,
|
214
|
-
@hostname = xml_content(roleXML,
|
211
|
+
@name = xml_content(roleXML, "RoleName")
|
212
|
+
@status = xml_content(roleXML, "InstanceStatus")
|
213
|
+
@size = xml_content(roleXML, "InstanceSize")
|
214
|
+
@ipaddress = xml_content(roleXML, "IpAddress")
|
215
|
+
@hostname = xml_content(roleXML, "HostName")
|
215
216
|
@hostedservicename = hostedservicename
|
216
217
|
@deployname = deployname
|
217
218
|
@thumbprint = fetch_thumbprint
|
218
219
|
@tcpports = Array.new
|
219
220
|
@udpports = Array.new
|
220
221
|
|
221
|
-
endpoints = roleXML.css(
|
222
|
-
@publicipaddress = xml_content(endpoints[0],
|
222
|
+
endpoints = roleXML.css("InstanceEndpoint")
|
223
|
+
@publicipaddress = xml_content(endpoints[0], "Vip") if !endpoints.empty?
|
223
224
|
endpoints.each do |endpoint|
|
224
|
-
if xml_content(endpoint,
|
225
|
-
@sshport = xml_content(endpoint,
|
226
|
-
elsif xml_content(endpoint,
|
227
|
-
@winrmport = xml_content(endpoint,
|
225
|
+
if xml_content(endpoint, "Name").casecmp("ssh").zero?
|
226
|
+
@sshport = xml_content(endpoint, "PublicPort")
|
227
|
+
elsif xml_content(endpoint, "Name").casecmp("winrm").zero?
|
228
|
+
@winrmport = xml_content(endpoint, "PublicPort")
|
228
229
|
else
|
229
230
|
hash = Hash.new
|
230
|
-
hash[
|
231
|
-
hash[
|
232
|
-
hash[
|
233
|
-
hash[
|
231
|
+
hash["Name"] = xml_content(endpoint, "Name")
|
232
|
+
hash["Vip"] = xml_content(endpoint, "Vip")
|
233
|
+
hash["PublicPort"] = xml_content(endpoint, "PublicPort")
|
234
|
+
hash["LocalPort"] = xml_content(endpoint, "LocalPort")
|
234
235
|
|
235
|
-
if xml_content(endpoint,
|
236
|
+
if xml_content(endpoint, "Protocol") == "tcp"
|
236
237
|
@tcpports << hash
|
237
238
|
else # == 'udp'
|
238
239
|
@udpports << hash
|
@@ -243,31 +244,31 @@ module Azure
|
|
243
244
|
|
244
245
|
def parse_role_list_xml(roleListXML)
|
245
246
|
@role_xml = roleListXML
|
246
|
-
os_disk_xml = roleListXML.css(
|
247
|
-
@os_type = xml_content(os_disk_xml,
|
248
|
-
@os_version = xml_content(os_disk_xml,
|
247
|
+
os_disk_xml = roleListXML.css("OSVirtualHardDisk")
|
248
|
+
@os_type = xml_content(os_disk_xml, "OS")
|
249
|
+
@os_version = xml_content(os_disk_xml, "SourceImageName")
|
249
250
|
end
|
250
251
|
|
251
252
|
# Expects endpoint_param_string to be in the form {localport}:{publicport}:{lb_set_name}:{lb_probe_path}
|
252
253
|
# Only localport is mandatory.
|
253
254
|
def parse_endpoint_from_params(protocol, azure_vm_name, endpoint_param_string)
|
254
|
-
fields = endpoint_param_string.split(
|
255
|
+
fields = endpoint_param_string.split(":").map(&:strip)
|
255
256
|
hash = {}
|
256
|
-
hash[
|
257
|
-
hash[
|
258
|
-
hash[
|
259
|
-
hash[
|
260
|
-
hash[
|
261
|
-
if TCP_ENDPOINTS_MAPPING.include?(hash[
|
262
|
-
hash[
|
257
|
+
hash["LocalPort"] = fields[0]
|
258
|
+
hash["Port"] = fields[1] || fields[0]
|
259
|
+
hash["LoadBalancerName"] = fields[2] if fields[2] != "EXTERNAL" # TODO: hackity hack.. Shouldn't use magic words.
|
260
|
+
hash["LoadBalancedEndpointSetName"] = fields[3]
|
261
|
+
hash["Protocol"] = protocol
|
262
|
+
if TCP_ENDPOINTS_MAPPING.include?(hash["Port"]) && protocol == "TCP"
|
263
|
+
hash["Name"] = TCP_ENDPOINTS_MAPPING[hash["Port"]]
|
263
264
|
else
|
264
|
-
hash[
|
265
|
+
hash["Name"] = "#{protocol}Endpoint_chef_#{fields[0]}"
|
265
266
|
end
|
266
267
|
if fields[2]
|
267
|
-
hash[
|
268
|
-
hash[
|
269
|
-
hash[
|
270
|
-
hash[
|
268
|
+
hash["LoadBalancerProbe"] = {}
|
269
|
+
hash["LoadBalancerProbe"]["Path"] = fields[4]
|
270
|
+
hash["LoadBalancerProbe"]["Port"] = fields[0]
|
271
|
+
hash["LoadBalancerProbe"]["Protocol"] = fields[4] ? "HTTP" : protocol
|
271
272
|
end
|
272
273
|
hash
|
273
274
|
end
|
@@ -283,252 +284,252 @@ module Azure
|
|
283
284
|
|
284
285
|
if existing_endpoints
|
285
286
|
existing_endpoints.each do |eep|
|
286
|
-
ep = eep if eep[
|
287
|
+
ep = eep if eep["LoadBalancedEndpointSetName"] && ep["LoadBalancedEndpointSetName"] && ( eep["LoadBalancedEndpointSetName"] == ep["LoadBalancedEndpointSetName"] )
|
287
288
|
end
|
288
289
|
end
|
289
290
|
|
290
|
-
if ep[
|
291
|
+
if ep["Port"] == params[:port] && ep["Protocol"].casecmp("tcp").zero?
|
291
292
|
puts("Skipping tcp-endpoints: #{ep['LocalPort']} because this port is already in use by ssh/winrm endpoint in current VM.")
|
292
293
|
next
|
293
294
|
end
|
294
295
|
|
295
|
-
xml.InputEndpoint
|
296
|
-
xml.LoadBalancedEndpointSetName ep[
|
297
|
-
xml.LocalPort ep[
|
298
|
-
xml.Name ep[
|
299
|
-
xml.Port ep[
|
300
|
-
if ep[
|
301
|
-
xml.LoadBalancerProbe
|
302
|
-
xml.Path ep[
|
303
|
-
xml.Port ep[
|
304
|
-
xml.Protocol ep[
|
305
|
-
xml.IntervalInSeconds ep[
|
306
|
-
xml.TimeoutInSeconds ep[
|
307
|
-
|
296
|
+
xml.InputEndpoint do
|
297
|
+
xml.LoadBalancedEndpointSetName ep["LoadBalancedEndpointSetName"] if ep["LoadBalancedEndpointSetName"]
|
298
|
+
xml.LocalPort ep["LocalPort"]
|
299
|
+
xml.Name ep["Name"]
|
300
|
+
xml.Port ep["Port"]
|
301
|
+
if ep["LoadBalancerProbe"]
|
302
|
+
xml.LoadBalancerProbe do
|
303
|
+
xml.Path ep["LoadBalancerProbe"]["Path"] if ep["LoadBalancerProbe"]["Path"]
|
304
|
+
xml.Port ep["LoadBalancerProbe"]["Port"]
|
305
|
+
xml.Protocol ep["LoadBalancerProbe"]["Protocol"]
|
306
|
+
xml.IntervalInSeconds ep["LoadBalancerProbe"]["IntervalInSeconds"] if ep["LoadBalancerProbe"]["IntervalInSeconds"]
|
307
|
+
xml.TimeoutInSeconds ep["LoadBalancerProbe"]["TimeoutInSeconds"] if ep["LoadBalancerProbe"]["TimeoutInSeconds"]
|
308
|
+
end
|
308
309
|
end
|
309
|
-
xml.Protocol ep[
|
310
|
-
xml.EnableDirectServerReturn ep[
|
311
|
-
xml.LoadBalancerName ep[
|
312
|
-
xml.IdleTimeoutInMinutes ep[
|
313
|
-
|
310
|
+
xml.Protocol ep["Protocol"]
|
311
|
+
xml.EnableDirectServerReturn ep["EnableDirectServerReturn"] if ep["EnableDirectServerReturn"]
|
312
|
+
xml.LoadBalancerName ep["LoadBalancerName"] if ep["LoadBalancerName"]
|
313
|
+
xml.IdleTimeoutInMinutes ep["IdleTimeoutInMinutes"] if ep["IdleTimeoutInMinutes"]
|
314
|
+
end
|
314
315
|
end
|
315
316
|
end
|
316
317
|
|
317
318
|
def fetch_thumbprint
|
318
319
|
query_result = connection.query_azure("hostedservices/#{@hostedservicename}/deployments/#{@hostedservicename}/roles/#{@name}")
|
319
|
-
query_result.at_css("DefaultWinRmCertificateThumbprint").nil? ?
|
320
|
+
query_result.at_css("DefaultWinRmCertificateThumbprint").nil? ? "" : query_result.at_css("DefaultWinRmCertificateThumbprint").text
|
320
321
|
end
|
321
322
|
|
322
323
|
def setup(params)
|
323
324
|
azure_user_domain_name = params[:azure_user_domain_name] || params[:azure_domain_name]
|
324
325
|
builder = Nokogiri::XML::Builder.new do |xml|
|
325
326
|
xml.PersistentVMRole(
|
326
|
-
|
327
|
-
|
328
|
-
)
|
329
|
-
xml.RoleName {xml.text params[:azure_vm_name]}
|
330
|
-
xml.OsVersion(
|
331
|
-
xml.RoleType
|
332
|
-
|
333
|
-
xml.ConfigurationSets
|
334
|
-
if params[:os_type] ==
|
335
|
-
xml.ConfigurationSet(
|
336
|
-
xml.ConfigurationSetType
|
327
|
+
"xmlns" => "http://schemas.microsoft.com/windowsazure",
|
328
|
+
"xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance"
|
329
|
+
) do
|
330
|
+
xml.RoleName { xml.text params[:azure_vm_name] }
|
331
|
+
xml.OsVersion("i:nil" => "true")
|
332
|
+
xml.RoleType "PersistentVMRole"
|
333
|
+
|
334
|
+
xml.ConfigurationSets do
|
335
|
+
if params[:os_type] == "Linux"
|
336
|
+
xml.ConfigurationSet("i:type" => "LinuxProvisioningConfigurationSet") do
|
337
|
+
xml.ConfigurationSetType "LinuxProvisioningConfiguration"
|
337
338
|
xml.HostName params[:azure_vm_name]
|
338
339
|
xml.UserName params[:ssh_user]
|
339
340
|
unless params[:identity_file].nil?
|
340
|
-
xml.DisableSshPasswordAuthentication
|
341
|
-
xml.SSH
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
341
|
+
xml.DisableSshPasswordAuthentication "true"
|
342
|
+
xml.SSH do
|
343
|
+
xml.PublicKeys do
|
344
|
+
xml.PublicKey do
|
345
|
+
xml.Fingerprint params[:fingerprint].to_s.upcase
|
346
|
+
xml.Path "/home/" + params[:ssh_user] + "/.ssh/authorized_keys"
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
349
350
|
else
|
350
351
|
xml.UserPassword params[:ssh_password]
|
351
|
-
xml.DisableSshPasswordAuthentication
|
352
|
+
xml.DisableSshPasswordAuthentication "false"
|
352
353
|
end
|
353
|
-
|
354
|
-
elsif params[:os_type] ==
|
355
|
-
xml.ConfigurationSet(
|
356
|
-
xml.ConfigurationSetType
|
354
|
+
end
|
355
|
+
elsif params[:os_type] == "Windows"
|
356
|
+
xml.ConfigurationSet("i:type" => "WindowsProvisioningConfigurationSet") do
|
357
|
+
xml.ConfigurationSetType "WindowsProvisioningConfiguration"
|
357
358
|
xml.ComputerName params[:azure_vm_name]
|
358
359
|
xml.AdminPassword params[:admin_password]
|
359
|
-
xml.ResetPasswordOnFirstLogon
|
360
|
-
xml.EnableAutomaticUpdates
|
360
|
+
xml.ResetPasswordOnFirstLogon "false"
|
361
|
+
xml.EnableAutomaticUpdates "false"
|
361
362
|
if params[:azure_domain_name]
|
362
|
-
xml.DomainJoin
|
363
|
-
xml.Credentials
|
363
|
+
xml.DomainJoin do
|
364
|
+
xml.Credentials do
|
364
365
|
xml.Domain azure_user_domain_name
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
366
|
+
xml.Username params[:azure_domain_user]
|
367
|
+
xml.Password params[:azure_domain_passwd]
|
368
|
+
end
|
369
|
+
xml.JoinDomain params[:azure_domain_name]
|
370
|
+
xml.MachineObjectOU params[:azure_domain_ou_dn] if params[:azure_domain_ou_dn]
|
371
|
+
end
|
371
372
|
end
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
}
|
373
|
+
if params[:bootstrap_proto].casecmp("winrm").zero?
|
374
|
+
if params[:ssl_cert_fingerprint]
|
375
|
+
xml.StoredCertificateSettings do
|
376
|
+
xml.CertificateSetting do
|
377
|
+
xml.StoreLocation "LocalMachine"
|
378
|
+
xml.StoreName "My"
|
379
|
+
xml.Thumbprint params[:ssl_cert_fingerprint]
|
380
|
+
end
|
381
381
|
end
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
382
|
+
end
|
383
|
+
xml.WinRM do
|
384
|
+
xml.Listeners do
|
385
|
+
if params[:winrm_transport] == "ssl" || params[:ssl_cert_fingerprint]
|
386
|
+
xml.Listener do
|
386
387
|
xml.CertificateThumbprint params[:ssl_cert_fingerprint] if params[:ssl_cert_fingerprint]
|
387
|
-
xml.Protocol
|
388
|
-
}
|
389
|
-
else
|
390
|
-
xml.Listener {
|
391
|
-
xml.Protocol 'Http'
|
392
|
-
}
|
388
|
+
xml.Protocol "Https"
|
393
389
|
end
|
394
|
-
|
395
|
-
|
390
|
+
else
|
391
|
+
xml.Listener do
|
392
|
+
xml.Protocol "Http"
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
396
|
end
|
397
|
+
end
|
397
398
|
xml.AdminUsername params[:winrm_user]
|
398
|
-
if params[:bootstrap_proto].
|
399
|
-
xml.AdditionalUnattendContent
|
400
|
-
xml.Passes
|
401
|
-
xml.UnattendPass
|
402
|
-
xml.PassName
|
403
|
-
xml.Components
|
404
|
-
xml.UnattendComponent
|
405
|
-
xml.ComponentName
|
406
|
-
xml.ComponentSettings
|
407
|
-
xml.ComponentSetting
|
408
|
-
xml.SettingName
|
399
|
+
if params[:bootstrap_proto].casecmp("winrm").zero? && (params[:winrm_max_timeout] || params[:winrm_max_memoryPerShell])
|
400
|
+
xml.AdditionalUnattendContent do
|
401
|
+
xml.Passes do
|
402
|
+
xml.UnattendPass do
|
403
|
+
xml.PassName "oobeSystem"
|
404
|
+
xml.Components do
|
405
|
+
xml.UnattendComponent do
|
406
|
+
xml.ComponentName "Microsoft-Windows-Shell-Setup"
|
407
|
+
xml.ComponentSettings do
|
408
|
+
xml.ComponentSetting do
|
409
|
+
xml.SettingName "AutoLogon"
|
409
410
|
xml.Content Base64.encode64(
|
410
411
|
Nokogiri::XML::Builder.new do |auto_logon_xml|
|
411
|
-
auto_logon_xml.AutoLogon
|
412
|
+
auto_logon_xml.AutoLogon do
|
412
413
|
auto_logon_xml.Username params[:winrm_user]
|
413
|
-
auto_logon_xml.Password
|
414
|
+
auto_logon_xml.Password do
|
414
415
|
auto_logon_xml.Value params[:admin_password]
|
415
416
|
auto_logon_xml.PlainText true
|
416
|
-
|
417
|
+
end
|
417
418
|
auto_logon_xml.LogonCount 1
|
418
419
|
auto_logon_xml.Enabled true
|
419
|
-
|
420
|
+
end
|
420
421
|
end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
|
421
422
|
).strip
|
422
|
-
|
423
|
-
xml.ComponentSetting
|
424
|
-
xml.SettingName
|
423
|
+
end
|
424
|
+
xml.ComponentSetting do
|
425
|
+
xml.SettingName "FirstLogonCommands"
|
425
426
|
xml.Content Base64.encode64(
|
426
427
|
Nokogiri::XML::Builder.new do |first_logon_xml|
|
427
|
-
first_logon_xml.FirstLogonCommands
|
428
|
+
first_logon_xml.FirstLogonCommands do
|
428
429
|
if params[:winrm_max_timeout]
|
429
|
-
first_logon_xml.SynchronousCommand(
|
430
|
+
first_logon_xml.SynchronousCommand("wcm:action" => "add") do
|
430
431
|
first_logon_xml.Order 1
|
431
432
|
first_logon_xml.CommandLine "cmd.exe /c winrm set winrm/config @{MaxTimeoutms=\"#{params[:winrm_max_timeout]}\"}"
|
432
433
|
first_logon_xml.Description "Bump WinRM max timeout to #{params[:winrm_max_timeout]} milliseconds"
|
433
|
-
|
434
|
+
end
|
434
435
|
end
|
435
436
|
|
436
437
|
if params[:winrm_max_memoryPerShell]
|
437
|
-
first_logon_xml.SynchronousCommand(
|
438
|
+
first_logon_xml.SynchronousCommand("wcm:action" => "add") do
|
438
439
|
first_logon_xml.Order 2
|
439
440
|
first_logon_xml.CommandLine "cmd.exe /c winrm set winrm/config/winrs @{MaxMemoryPerShellMB=\"#{params[:winrm_max_memoryPerShell]}\"}"
|
440
441
|
first_logon_xml.Description "Bump WinRM max memory per shell to #{params[:winrm_max_memoryPerShell]} MB"
|
441
|
-
|
442
|
+
end
|
442
443
|
end
|
443
|
-
|
444
|
+
end
|
444
445
|
end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
|
445
446
|
).strip
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
453
454
|
end
|
454
|
-
|
455
|
+
end
|
455
456
|
end
|
456
457
|
|
457
|
-
xml.ConfigurationSet(
|
458
|
-
xml.ConfigurationSetType
|
459
|
-
xml.InputEndpoints
|
458
|
+
xml.ConfigurationSet("i:type" => "NetworkConfigurationSet") do
|
459
|
+
xml.ConfigurationSetType "NetworkConfiguration"
|
460
|
+
xml.InputEndpoints do
|
460
461
|
|
461
462
|
#1. bootstrap_proto = 'winrm' for windows => Set winrm port
|
462
463
|
#2. bootstrap_proto = 'ssh' for windows and linux => Set ssh port
|
463
464
|
#3. bootstrap_proto = 'cloud-api' for windows and linux => Set no port
|
464
|
-
if params[:os_type] ==
|
465
|
-
xml.InputEndpoint
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
465
|
+
if (params[:os_type] == "Windows") && (params[:bootstrap_proto].casecmp("winrm").zero?)
|
466
|
+
xml.InputEndpoint do
|
467
|
+
if params[:winrm_transport] == "ssl"
|
468
|
+
xml.LocalPort "5986"
|
469
|
+
else
|
470
|
+
xml.LocalPort "5985"
|
471
|
+
end
|
472
|
+
xml.Name "WinRM"
|
473
|
+
xml.Port params[:port]
|
474
|
+
xml.Protocol "TCP"
|
475
|
+
end
|
476
|
+
elsif params[:bootstrap_proto].casecmp("ssh").zero?
|
477
|
+
xml.InputEndpoint do
|
478
|
+
xml.LocalPort "22"
|
479
|
+
xml.Name "SSH"
|
480
|
+
xml.Port params[:port]
|
481
|
+
xml.Protocol "TCP"
|
470
482
|
end
|
471
|
-
xml.Name 'WinRM'
|
472
|
-
xml.Port params[:port]
|
473
|
-
xml.Protocol 'TCP'
|
474
|
-
}
|
475
|
-
elsif(params[:bootstrap_proto].downcase == 'ssh')
|
476
|
-
xml.InputEndpoint {
|
477
|
-
xml.LocalPort '22'
|
478
|
-
xml.Name 'SSH'
|
479
|
-
xml.Port params[:port]
|
480
|
-
xml.Protocol 'TCP'
|
481
|
-
}
|
482
483
|
end
|
483
484
|
all_endpoints = Array.new
|
484
485
|
|
485
486
|
if params[:tcp_endpoints]
|
486
|
-
params[:tcp_endpoints].split(
|
487
|
-
all_endpoints << parse_endpoint_from_params(
|
487
|
+
params[:tcp_endpoints].split(",").map(&:strip).each do |endpoint|
|
488
|
+
all_endpoints << parse_endpoint_from_params("TCP", params[:azure_vm_name], endpoint)
|
488
489
|
end
|
489
490
|
end
|
490
491
|
if params[:udp_endpoints]
|
491
|
-
params[:udp_endpoints].split(
|
492
|
-
all_endpoints << parse_endpoint_from_params(
|
492
|
+
params[:udp_endpoints].split(",").map(&:strip).each do |endpoint|
|
493
|
+
all_endpoints << parse_endpoint_from_params("UDP", params[:azure_vm_name], endpoint)
|
493
494
|
end
|
494
495
|
end
|
495
496
|
add_endpoints_to_xml(xml, all_endpoints, params) if all_endpoints.any?
|
496
|
-
|
497
|
+
end
|
497
498
|
if params[:azure_subnet_name]
|
498
|
-
xml.SubnetNames
|
499
|
+
xml.SubnetNames do
|
499
500
|
xml.SubnetName params[:azure_subnet_name]
|
500
|
-
|
501
|
+
end
|
501
502
|
end
|
502
|
-
|
503
|
-
|
503
|
+
end
|
504
|
+
end
|
504
505
|
|
505
506
|
# Azure resource extension support
|
506
|
-
if params[:bootstrap_proto] ==
|
507
|
-
xml.ResourceExtensionReferences
|
508
|
-
xml.ResourceExtensionReference
|
507
|
+
if params[:bootstrap_proto] == "cloud-api"
|
508
|
+
xml.ResourceExtensionReferences do
|
509
|
+
xml.ResourceExtensionReference do
|
509
510
|
xml.ReferenceName params[:chef_extension]
|
510
511
|
xml.Publisher params[:chef_extension_publisher]
|
511
512
|
xml.Name params[:chef_extension]
|
512
513
|
xml.Version params[:chef_extension_version]
|
513
|
-
xml.ResourceExtensionParameterValues
|
514
|
+
xml.ResourceExtensionParameterValues do
|
514
515
|
if params[:chef_extension_public_param]
|
515
|
-
xml.ResourceExtensionParameterValue
|
516
|
+
xml.ResourceExtensionParameterValue do
|
516
517
|
xml.Key "PublicParams"
|
517
518
|
xml.Value Base64.encode64(params[:chef_extension_public_param].to_json)
|
518
519
|
xml.Type "Public"
|
519
|
-
|
520
|
+
end
|
520
521
|
end
|
521
522
|
if params[:chef_extension_private_param]
|
522
|
-
xml.ResourceExtensionParameterValue
|
523
|
+
xml.ResourceExtensionParameterValue do
|
523
524
|
xml.Key "PrivateParams"
|
524
525
|
xml.Value Base64.encode64(params[:chef_extension_private_param].to_json)
|
525
526
|
xml.Type "Private"
|
526
|
-
|
527
|
+
end
|
527
528
|
end
|
528
|
-
|
529
|
+
end
|
529
530
|
xml.State "Enable"
|
530
|
-
|
531
|
-
|
531
|
+
end
|
532
|
+
end
|
532
533
|
end
|
533
534
|
|
534
535
|
if params[:azure_availability_set]
|
@@ -540,26 +541,26 @@ module Azure
|
|
540
541
|
xml.Label Base64.encode64(params[:azure_vm_name]).strip
|
541
542
|
|
542
543
|
#OSVirtualHardDisk not required in case azure_source_image is a VMImage
|
543
|
-
unless
|
544
|
-
xml.OSVirtualHardDisk
|
544
|
+
unless params[:is_vm_image]
|
545
|
+
xml.OSVirtualHardDisk do
|
545
546
|
disk_name = params[:azure_os_disk_name] || "disk_" + SecureRandom.uuid
|
546
547
|
xml.DiskName disk_name
|
547
|
-
domain_suffix = params[:azure_api_host_name] ? params[:azure_api_host_name].scan(/core.*/)[0] :
|
548
|
-
xml.MediaLink
|
548
|
+
domain_suffix = params[:azure_api_host_name] ? params[:azure_api_host_name].scan(/core.*/)[0] : ""
|
549
|
+
xml.MediaLink "http://" + params[:azure_storage_account] + ".blob." + domain_suffix + "/vhds/" + disk_name + ".vhd"
|
549
550
|
xml.SourceImageName params[:azure_source_image]
|
550
|
-
|
551
|
+
end
|
551
552
|
end
|
552
553
|
|
553
554
|
xml.RoleSize params[:azure_vm_size]
|
554
|
-
xml.ProvisionGuestAgent true if params[:bootstrap_proto] ==
|
555
|
-
|
555
|
+
xml.ProvisionGuestAgent true if params[:bootstrap_proto] == "cloud-api"
|
556
|
+
end
|
556
557
|
end
|
557
558
|
builder.doc
|
558
559
|
end
|
559
560
|
|
560
561
|
def create(params, roleXML)
|
561
562
|
servicecall = "hostedservices/#{params[:azure_dns_name]}/deployments" +
|
562
|
-
|
563
|
+
"/#{params['deploy_name']}/roles"
|
563
564
|
@connection.query_azure(servicecall, "post", roleXML.to_xml)
|
564
565
|
end
|
565
566
|
|
@@ -576,31 +577,31 @@ module Azure
|
|
576
577
|
## using the required values of the updated role_xml
|
577
578
|
builder = Nokogiri::XML::Builder.new do |xml|
|
578
579
|
xml.PersistentVMRole(
|
579
|
-
|
580
|
-
|
581
|
-
)
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
580
|
+
"xmlns" => "http://schemas.microsoft.com/windowsazure",
|
581
|
+
"xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance"
|
582
|
+
) do
|
583
|
+
xml.ConfigurationSets role_xml.at_css("ConfigurationSets").children if !role_xml.at_css("ConfigurationSets").nil?
|
584
|
+
xml.ResourceExtensionReferences role_xml.at_css("ResourceExtensionReferences").children if !role_xml.at_css("ResourceExtensionReferences").nil?
|
585
|
+
xml.AvailabilitySetName role_xml.at_css("AvailabilitySetName").children if !role_xml.at_css("AvailabilitySetName").nil?
|
586
|
+
xml.DataVirtualHardDisks role_xml.at_css("DataVirtualHardDisks").children if !role_xml.at_css("DataVirtualHardDisks").nil?
|
587
|
+
xml.OSVirtualHardDisk role_xml.at_css("OSVirtualHardDisk").children if !role_xml.at_css("OSVirtualHardDisk").nil?
|
588
|
+
xml.RoleSize role_xml.at_css("RoleSize").children if !role_xml.at_css("RoleSize").nil?
|
589
|
+
xml.ProvisionGuestAgent role_xml.at_css("ProvisionGuestAgent").children if !role_xml.at_css("ProvisionGuestAgent").nil?
|
590
|
+
end
|
590
591
|
end
|
591
592
|
|
592
|
-
builder.doc.to_xml.gsub("<\;","<").gsub(">\;",">")
|
593
|
+
builder.doc.to_xml.gsub("<\;", "<").gsub(">\;", ">")
|
593
594
|
end
|
594
595
|
|
595
596
|
def update_role_xml_for_extension(roleXML, params)
|
596
597
|
## check if 'ResourceExtensionReferences' node already exist in the XML,
|
597
598
|
## if no add it, else retrieve the object of the existing node
|
598
|
-
add_resource_extension_references = roleXML.at_css(
|
599
|
+
add_resource_extension_references = roleXML.at_css("ResourceExtensionReferences").nil?
|
599
600
|
|
600
601
|
if add_resource_extension_references
|
601
|
-
resource_extension_references = Nokogiri::XML::Node.new(
|
602
|
+
resource_extension_references = Nokogiri::XML::Node.new("ResourceExtensionReferences", roleXML)
|
602
603
|
else
|
603
|
-
resource_extension_references = roleXML.css(
|
604
|
+
resource_extension_references = roleXML.css("ResourceExtensionReferences")
|
604
605
|
end
|
605
606
|
|
606
607
|
## check if Azure Chef Extension is already installed on the given server,
|
@@ -608,8 +609,8 @@ module Azure
|
|
608
609
|
## already installed
|
609
610
|
ext = nil
|
610
611
|
if !add_resource_extension_references
|
611
|
-
if !resource_extension_references.at_css(
|
612
|
-
resource_extension_references.css(
|
612
|
+
if !resource_extension_references.at_css("ReferenceName").nil?
|
613
|
+
resource_extension_references.css("ReferenceName").each { |node| ext = node if node.content == params[:chef_extension] }
|
613
614
|
end
|
614
615
|
end
|
615
616
|
|
@@ -617,56 +618,56 @@ module Azure
|
|
617
618
|
|
618
619
|
## create Azure Chef Extension config and add it in the role_xml
|
619
620
|
if add_resource_extension_reference
|
620
|
-
resource_extension_reference = Nokogiri::XML::Node.new(
|
621
|
+
resource_extension_reference = Nokogiri::XML::Node.new("ResourceExtensionReference", roleXML)
|
621
622
|
|
622
|
-
reference_name = Nokogiri::XML::Node.new(
|
623
|
+
reference_name = Nokogiri::XML::Node.new("ReferenceName", roleXML)
|
623
624
|
reference_name.content = params[:chef_extension]
|
624
625
|
resource_extension_reference.add_child(reference_name)
|
625
626
|
|
626
|
-
publisher = Nokogiri::XML::Node.new(
|
627
|
+
publisher = Nokogiri::XML::Node.new("Publisher", roleXML)
|
627
628
|
publisher.content = params[:chef_extension_publisher]
|
628
629
|
resource_extension_reference.add_child(publisher)
|
629
630
|
|
630
|
-
name = Nokogiri::XML::Node.new(
|
631
|
+
name = Nokogiri::XML::Node.new("Name", roleXML)
|
631
632
|
name.content = params[:chef_extension]
|
632
633
|
resource_extension_reference.add_child(name)
|
633
634
|
|
634
|
-
version = Nokogiri::XML::Node.new(
|
635
|
+
version = Nokogiri::XML::Node.new("Version", roleXML)
|
635
636
|
version.content = params[:chef_extension_version]
|
636
637
|
resource_extension_reference.add_child(version)
|
637
638
|
|
638
|
-
resource_extension_parameter_values = Nokogiri::XML::Node.new(
|
639
|
+
resource_extension_parameter_values = Nokogiri::XML::Node.new("ResourceExtensionParameterValues", roleXML)
|
639
640
|
if params[:chef_extension_public_param]
|
640
|
-
resource_extension_parameter_value = Nokogiri::XML::Node.new(
|
641
|
+
resource_extension_parameter_value = Nokogiri::XML::Node.new("ResourceExtensionParameterValue", roleXML)
|
641
642
|
|
642
|
-
key = Nokogiri::XML::Node.new(
|
643
|
-
key.content =
|
643
|
+
key = Nokogiri::XML::Node.new("Key", roleXML)
|
644
|
+
key.content = "PublicParams"
|
644
645
|
resource_extension_parameter_value.add_child(key)
|
645
646
|
|
646
|
-
value = Nokogiri::XML::Node.new(
|
647
|
+
value = Nokogiri::XML::Node.new("Value", roleXML)
|
647
648
|
value.content = Base64.encode64(params[:chef_extension_public_param].to_json)
|
648
649
|
resource_extension_parameter_value.add_child(value)
|
649
650
|
|
650
|
-
type = Nokogiri::XML::Node.new(
|
651
|
-
type.content =
|
651
|
+
type = Nokogiri::XML::Node.new("Type", roleXML)
|
652
|
+
type.content = "Public"
|
652
653
|
resource_extension_parameter_value.add_child(type)
|
653
654
|
|
654
655
|
resource_extension_parameter_values.add_child(resource_extension_parameter_value)
|
655
656
|
end
|
656
657
|
|
657
658
|
if params[:chef_extension_private_param]
|
658
|
-
resource_extension_parameter_value = Nokogiri::XML::Node.new(
|
659
|
+
resource_extension_parameter_value = Nokogiri::XML::Node.new("ResourceExtensionParameterValue", roleXML)
|
659
660
|
|
660
|
-
key = Nokogiri::XML::Node.new(
|
661
|
-
key.content =
|
661
|
+
key = Nokogiri::XML::Node.new("Key", roleXML)
|
662
|
+
key.content = "PrivateParams"
|
662
663
|
resource_extension_parameter_value.add_child(key)
|
663
664
|
|
664
|
-
value = Nokogiri::XML::Node.new(
|
665
|
+
value = Nokogiri::XML::Node.new("Value", roleXML)
|
665
666
|
value.content = Base64.encode64(params[:chef_extension_private_param].to_json)
|
666
667
|
resource_extension_parameter_value.add_child(value)
|
667
668
|
|
668
|
-
type = Nokogiri::XML::Node.new(
|
669
|
-
type.content =
|
669
|
+
type = Nokogiri::XML::Node.new("Type", roleXML)
|
670
|
+
type.content = "Private"
|
670
671
|
resource_extension_parameter_value.add_child(type)
|
671
672
|
|
672
673
|
resource_extension_parameter_values.add_child(resource_extension_parameter_value)
|
@@ -674,8 +675,8 @@ module Azure
|
|
674
675
|
|
675
676
|
resource_extension_reference.add_child(resource_extension_parameter_values)
|
676
677
|
|
677
|
-
state = Nokogiri::XML::Node.new(
|
678
|
-
state.content =
|
678
|
+
state = Nokogiri::XML::Node.new("State", roleXML)
|
679
|
+
state.content = "enable"
|
679
680
|
resource_extension_reference.add_child(state)
|
680
681
|
|
681
682
|
if add_resource_extension_references
|
@@ -686,13 +687,13 @@ module Azure
|
|
686
687
|
|
687
688
|
roleXML.add_child(resource_extension_references) if add_resource_extension_references
|
688
689
|
|
689
|
-
add_provision_guest_agent = roleXML.at_css(
|
690
|
+
add_provision_guest_agent = roleXML.at_css("ProvisionGuestAgent").nil?
|
690
691
|
|
691
692
|
if add_provision_guest_agent
|
692
|
-
provision_guest_agent = Nokogiri::XML::Node.new(
|
693
|
+
provision_guest_agent = Nokogiri::XML::Node.new("ProvisionGuestAgent", roleXML)
|
693
694
|
provision_guest_agent.content = true
|
694
695
|
else
|
695
|
-
provision_guest_agent = roleXML.css(
|
696
|
+
provision_guest_agent = roleXML.css("ProvisionGuestAgent")
|
696
697
|
provision_guest_agent.first.content = true
|
697
698
|
end
|
698
699
|
|
@@ -707,12 +708,12 @@ module Azure
|
|
707
708
|
def update(name, params, roleXML)
|
708
709
|
puts "Updating server role..."
|
709
710
|
servicecall = "hostedservices/#{params[:azure_dns_name]}" +
|
710
|
-
|
711
|
-
ret_val = @connection.query_azure(servicecall,
|
711
|
+
"/deployments/#{params[:deploy_name]}/roles/#{name}"
|
712
|
+
ret_val = @connection.query_azure(servicecall, "put", roleXML, "", true, true, "application/xml")
|
712
713
|
error_code, error_message = error_from_response_xml(ret_val)
|
713
714
|
if error_code.length > 0
|
714
715
|
Chef::Log.debug(ret_val.to_s)
|
715
|
-
raise
|
716
|
+
raise "Unable to update role:" + error_code + " : " + error_message
|
716
717
|
end
|
717
718
|
end
|
718
719
|
end
|