knife-azure 1.1.4 → 1.2.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 +15 -0
- data/README.md +37 -0
- data/lib/azure/ag.rb +97 -0
- data/lib/azure/connection.rb +25 -7
- data/lib/azure/deploy.rb +8 -4
- data/lib/azure/host.rb +7 -4
- data/lib/azure/rest.rb +32 -8
- data/lib/azure/role.rb +85 -55
- data/lib/azure/storageaccount.rb +4 -2
- data/lib/azure/utility.rb +12 -0
- data/lib/azure/vnet.rb +89 -0
- data/lib/chef/knife/azure_ag_create.rb +76 -0
- data/lib/chef/knife/azure_ag_list.rb +51 -0
- data/lib/chef/knife/azure_base.rb +9 -0
- data/lib/chef/knife/azure_server_create.rb +61 -31
- data/lib/chef/knife/azure_server_delete.rb +8 -1
- data/lib/chef/knife/{azure_server_describe.rb → azure_server_show.rb} +22 -14
- data/lib/chef/knife/azure_vnet_create.rb +77 -0
- data/lib/chef/knife/azure_vnet_list.rb +52 -0
- data/lib/knife-azure/version.rb +1 -1
- metadata +28 -43
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NmY2MDlmMjMwZTA5OWVlOGRmODI2MzJmYjBmOWJkNmEzMjU1NWMzZQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZGM5ZGRiOWNhYWYwZWE1MzEyYmQxNTk2OTZlNGQwM2QzMjA3OWU4NQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZTBmY2UxNTFlNTE0NDkwNWUzMTgzNDQ4YjBmNWI5OWUyMzAwNjVmYzRkZWRk
|
10
|
+
YjNiZTQ4OGRkZDQ4OThlMDc3ZWMzZDJhZTc1YjNlZmJhMWZjOTk5NzEyMmJj
|
11
|
+
NzhiZTUwYWE5Njg5YjQ2YjFhNWIyZWZjMWI1ZmIyMTUzMjczNzc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZjgzYTM4OGJiZTQ2MDVkN2FmY2E1YmEyZDk4ODA0M2ZkZGVmM2MzMzE3NTM5
|
14
|
+
YTQxMzQwYjc0MDdmYmQ5ZGZiZjc5NWNmMTQwMTMwYzFlYzQ0NTkzMDgyOTc1
|
15
|
+
NWZjMmU2YmM3Y2ViZGJkOWRiYWRlYmJiYTQ0MDM0NmE1YmI4MWM=
|
data/README.md
CHANGED
@@ -240,6 +240,43 @@ Outputs a list of all servers in the currently configured Azure account. PLEASE
|
|
240
240
|
|
241
241
|
knife azure server list
|
242
242
|
|
243
|
+
### Azure AG List Subcommand
|
244
|
+
Outputs a list of defined affinity groups in the azure subscription.
|
245
|
+
|
246
|
+
knife azure ag list
|
247
|
+
|
248
|
+
### Azure AG Create Subcommand
|
249
|
+
Creates a new affinity group in the specified service location.
|
250
|
+
|
251
|
+
knife azure ag create -a 'mynewag' -m 'West US' --azure-ag-desc 'Optional Description'
|
252
|
+
|
253
|
+
Knife options:
|
254
|
+
|
255
|
+
:azure_affinity_group Specifies new affinity group name.
|
256
|
+
:azure_service_location Specifies the geographic location.
|
257
|
+
:azure_ag_desc Optional. Description for new affinity group.
|
258
|
+
|
259
|
+
### Azure Vnet List Subcommand
|
260
|
+
Outputs a list of defined virtual networks in the azure subscription.
|
261
|
+
|
262
|
+
knife azure vnet list
|
263
|
+
|
264
|
+
### Azure Vnet Create Subcommand
|
265
|
+
Creates a new or modifies an existing virtual network. If an existing virtual network is named, the
|
266
|
+
affinity group and address space are replaced with the new values.
|
267
|
+
|
268
|
+
knife azure vnet create -n 'mynewvn' -a 'existingag' --azure_address_space '10.0.0.0/24'
|
269
|
+
|
270
|
+
Knife options:
|
271
|
+
|
272
|
+
:azure_network_name Specifies the name of the virtual network to create.
|
273
|
+
:azure_affinity_group Specifies the affinity group to associate with the vnet.
|
274
|
+
:azure_address_space Specifies the address space of the vnet using CIDR notation.
|
275
|
+
|
276
|
+
For CIDR notation, see here: http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
|
277
|
+
Address available are defined in RFC 1918: http://en.wikipedia.org/wiki/Private_network
|
278
|
+
|
279
|
+
|
243
280
|
## Alternative Management Certificate Specification
|
244
281
|
In addition to specifying the management certificate using the publishsettings
|
245
282
|
file, you can also specify it in PEM format. Follow these steps to generate the certificate in the PEM format:
|
data/lib/azure/ag.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Jeff Mendoza (jeffmendoza@live.com)
|
3
|
+
# Copyright:: Copyright (c) 2013 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
class Azure
|
20
|
+
class AGs
|
21
|
+
def initialize(connection)
|
22
|
+
@connection = connection
|
23
|
+
end
|
24
|
+
|
25
|
+
def load
|
26
|
+
@ags ||= begin
|
27
|
+
@ags = {}
|
28
|
+
response = @connection.query_azure('affinitygroups',
|
29
|
+
'get',
|
30
|
+
'',
|
31
|
+
'',
|
32
|
+
false)
|
33
|
+
response.css('AffinityGroup').each do |ag|
|
34
|
+
item = AG.new(@connection).parse(ag)
|
35
|
+
@ags[item.name] = item
|
36
|
+
end
|
37
|
+
@ags
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def all
|
42
|
+
load.values
|
43
|
+
end
|
44
|
+
|
45
|
+
def exists?(name)
|
46
|
+
load.key?(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def find(name)
|
50
|
+
load[name]
|
51
|
+
end
|
52
|
+
|
53
|
+
def create(params)
|
54
|
+
ag = AG.new(@connection)
|
55
|
+
ag.create(params)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Azure
|
61
|
+
class AG
|
62
|
+
attr_accessor :name, :label, :description, :location
|
63
|
+
|
64
|
+
def initialize(connection)
|
65
|
+
@connection = connection
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse(image)
|
69
|
+
@name = image.at_css('Name').content
|
70
|
+
@label = image.at_css('Label').content
|
71
|
+
@description = image.at_css('Description').content if
|
72
|
+
image.at_css('Description')
|
73
|
+
@location = image.at_css('Location').content if image.at_css('Location')
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def create(params)
|
78
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'utf-8') do |xml|
|
79
|
+
xml.CreateAffinityGroup(
|
80
|
+
xmlns: 'http://schemas.microsoft.com/windowsazure'
|
81
|
+
) do
|
82
|
+
xml.Name params[:azure_ag_name]
|
83
|
+
xml.Label Base64.strict_encode64(params[:azure_ag_name])
|
84
|
+
unless params[:azure_ag_desc].nil?
|
85
|
+
xml.Description params[:azure_ag_desc]
|
86
|
+
end
|
87
|
+
xml.Location params[:azure_location]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
@connection.query_azure('affinitygroups',
|
91
|
+
'post',
|
92
|
+
builder.to_xml,
|
93
|
+
'',
|
94
|
+
false)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/azure/connection.rb
CHANGED
@@ -24,11 +24,15 @@ require File.expand_path('../role', __FILE__)
|
|
24
24
|
require File.expand_path('../disk', __FILE__)
|
25
25
|
require File.expand_path('../image', __FILE__)
|
26
26
|
require File.expand_path('../certificate', __FILE__)
|
27
|
+
require File.expand_path('../ag', __FILE__)
|
28
|
+
require File.expand_path('../vnet', __FILE__)
|
27
29
|
|
28
30
|
class Azure
|
29
31
|
class Connection
|
30
32
|
include AzureAPI
|
31
|
-
|
33
|
+
include AzureUtility
|
34
|
+
attr_accessor :hosts, :rest, :images, :deploys, :roles,
|
35
|
+
:disks, :storageaccounts, :certificates, :ags, :vnets
|
32
36
|
def initialize(params={})
|
33
37
|
@rest = Rest.new(params)
|
34
38
|
@hosts = Hosts.new(self)
|
@@ -38,19 +42,32 @@ class Azure
|
|
38
42
|
@roles = Roles.new(self)
|
39
43
|
@disks = Disks.new(self)
|
40
44
|
@certificates = Certificates.new(self)
|
45
|
+
@ags = AGs.new(self)
|
46
|
+
@vnets = Vnets.new(self)
|
41
47
|
end
|
42
|
-
|
43
|
-
|
48
|
+
|
49
|
+
def query_azure(service_name,
|
50
|
+
verb = 'get',
|
51
|
+
body = '',
|
52
|
+
params = '',
|
53
|
+
wait = true,
|
54
|
+
services = true)
|
55
|
+
Chef::Log.info 'calling ' + verb + ' ' + service_name + (wait ? " synchronously" : " asynchronously")
|
44
56
|
Chef::Log.debug body unless body == ''
|
45
|
-
response = @rest.query_azure(service_name, verb, body, params)
|
57
|
+
response = @rest.query_azure(service_name, verb, body, params, services)
|
46
58
|
if response.code.to_i == 200
|
47
59
|
ret_val = Nokogiri::XML response.body
|
60
|
+
elsif !wait && response.code.to_i == 202
|
61
|
+
Chef::Log.debug 'Request accepted in asynchronous mode'
|
62
|
+
ret_val = Nokogiri::XML response.body
|
48
63
|
elsif response.code.to_i >= 201 && response.code.to_i <= 299
|
49
64
|
ret_val = wait_for_completion()
|
50
65
|
else
|
51
66
|
if response.body
|
52
67
|
ret_val = Nokogiri::XML response.body
|
53
|
-
Chef::Log.
|
68
|
+
Chef::Log.debug ret_val.to_xml
|
69
|
+
error_code, error_message = error_from_response_xml(ret_val)
|
70
|
+
Chef::Log.warn error_code + ' : ' + error_message if error_code.length > 0
|
54
71
|
else
|
55
72
|
Chef::Log.warn 'http error: ' + response.code
|
56
73
|
end
|
@@ -63,14 +80,15 @@ class Azure
|
|
63
80
|
while status == 'InProgress'
|
64
81
|
response = @rest.query_for_completion()
|
65
82
|
ret_val = Nokogiri::XML response.body
|
66
|
-
status = ret_val
|
83
|
+
status = xml_content(ret_val,'Status')
|
67
84
|
if status == 'InProgress'
|
68
85
|
print '.'
|
69
86
|
sleep(0.5)
|
70
87
|
elsif status == 'Succeeded'
|
71
88
|
Chef::Log.debug 'not InProgress : ' + ret_val.to_xml
|
72
89
|
else
|
73
|
-
|
90
|
+
error_code, error_message = error_from_response_xml(ret_val)
|
91
|
+
Chef::Log.warn status + error_code + ' : ' + error_message if error_code.length > 0
|
74
92
|
end
|
75
93
|
end
|
76
94
|
ret_val
|
data/lib/azure/deploy.rb
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
|
19
19
|
class Azure
|
20
20
|
class Deploys
|
21
|
+
include AzureUtility
|
21
22
|
def initialize(connection)
|
22
23
|
@connection=connection
|
23
24
|
end
|
@@ -65,8 +66,9 @@ class Azure
|
|
65
66
|
end
|
66
67
|
else
|
67
68
|
ret_val = @connection.hosts.create(params)
|
68
|
-
|
69
|
-
|
69
|
+
error_code, error_message = error_from_response_xml(ret_val)
|
70
|
+
if error_code.length > 0
|
71
|
+
Chef::Log.fatal 'Unable to create DNS:' + error_code + ' : ' + error_message
|
70
72
|
exit 1
|
71
73
|
end
|
72
74
|
end
|
@@ -88,8 +90,10 @@ class Azure
|
|
88
90
|
deployXML = deploy.setup(params)
|
89
91
|
ret_val = deploy.create(params, deployXML)
|
90
92
|
end
|
91
|
-
|
92
|
-
|
93
|
+
error_code, error_message = error_from_response_xml(ret_val)
|
94
|
+
if error_code.length > 0
|
95
|
+
Chef::Log.debug(ret_val.to_s)
|
96
|
+
raise Chef::Log.fatal 'Unable to create role:' + error_code + ' : ' + error_message
|
93
97
|
end
|
94
98
|
@connection.roles.find_in_hosted_service(params[:azure_vm_name], params[:azure_dns_name])
|
95
99
|
end
|
data/lib/azure/host.rb
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
|
19
19
|
class Azure
|
20
20
|
class Hosts
|
21
|
+
include AzureUtility
|
21
22
|
def initialize(connection)
|
22
23
|
@connection=connection
|
23
24
|
end
|
@@ -53,8 +54,9 @@ class Azure
|
|
53
54
|
# Look up on cloud and not local cache
|
54
55
|
def exists_on_cloud?(name)
|
55
56
|
ret_val = @connection.query_azure("hostedservices/#{name}")
|
56
|
-
|
57
|
-
|
57
|
+
error_code, error_message = error_from_response_xml(ret_val) if ret_val
|
58
|
+
if ret_val.nil? || error_code.length > 0
|
59
|
+
Chef::Log.warn('Unable to find hosted(cloud) service:' + error_code + ' : ' + error_message) if ret_val
|
58
60
|
false
|
59
61
|
else
|
60
62
|
true
|
@@ -70,8 +72,9 @@ class Azure
|
|
70
72
|
# Look up hosted service on cloud and not local cache
|
71
73
|
def fetch_from_cloud(name)
|
72
74
|
ret_val = @connection.query_azure("hostedservices/#{name}")
|
73
|
-
|
74
|
-
|
75
|
+
error_code, error_message = error_from_response_xml(ret_val) if ret_val
|
76
|
+
if ret_val.nil? || error_code.length > 0
|
77
|
+
Chef::Log.warn('Unable to find hosted(cloud) service:' + error_code + ' : ' + error_message) if ret_val
|
75
78
|
nil
|
76
79
|
else
|
77
80
|
Host.new(@connection).parse(ret_val)
|
data/lib/azure/rest.rb
CHANGED
@@ -28,9 +28,26 @@ module AzureAPI
|
|
28
28
|
@host_name = params[:azure_api_host_name]
|
29
29
|
@verify_ssl = params[:verify_ssl_cert]
|
30
30
|
end
|
31
|
-
|
32
|
-
|
31
|
+
|
32
|
+
def query_azure(service_name,
|
33
|
+
verb = 'get',
|
34
|
+
body = '',
|
35
|
+
params = '',
|
36
|
+
services = true)
|
37
|
+
svc_str = services ? '/services' : ''
|
38
|
+
request_url =
|
39
|
+
"https://#{@host_name}/#{@subscription_id}#{svc_str}/#{service_name}"
|
33
40
|
print '.'
|
41
|
+
response = http_query(request_url, verb, body, params)
|
42
|
+
if response.code.to_i == 307
|
43
|
+
Chef::Log.debug "Redirect to #{response['Location']}"
|
44
|
+
response = http_query(response['Location'], verb, body, params)
|
45
|
+
end
|
46
|
+
@last_request_id = response['x-ms-request-id']
|
47
|
+
response
|
48
|
+
end
|
49
|
+
|
50
|
+
def http_query(request_url, verb, body, params)
|
34
51
|
uri = URI.parse(request_url)
|
35
52
|
uri.query = params
|
36
53
|
http = http_setup(uri)
|
@@ -39,13 +56,17 @@ module AzureAPI
|
|
39
56
|
@last_request_id = response['x-ms-request-id']
|
40
57
|
response
|
41
58
|
end
|
59
|
+
|
42
60
|
def query_for_completion()
|
43
61
|
request_url = "https://#{@host_name}/#{@subscription_id}/operations/#{@last_request_id}"
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
62
|
+
response = http_query(request_url, 'get', '', '')
|
63
|
+
if response.code.to_i == 307
|
64
|
+
Chef::Log.debug "Redirect to #{response['Location']}"
|
65
|
+
response = http_query(response['Location'], 'get', '', '')
|
66
|
+
end
|
67
|
+
response
|
48
68
|
end
|
69
|
+
|
49
70
|
def http_setup(uri)
|
50
71
|
http = Net::HTTP.new(uri.host, uri.port)
|
51
72
|
store = OpenSSL::X509::Store.new
|
@@ -72,9 +93,12 @@ module AzureAPI
|
|
72
93
|
request = Net::HTTP::Post.new(uri.request_uri)
|
73
94
|
elsif verb == 'delete'
|
74
95
|
request = Net::HTTP::Delete.new(uri.request_uri)
|
96
|
+
elsif verb == 'put'
|
97
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
75
98
|
end
|
76
|
-
|
77
|
-
request["
|
99
|
+
text = verb == 'put'
|
100
|
+
request["x-ms-version"] = "2013-08-01"
|
101
|
+
request["content-type"] = text ? "text/plain" : "application/xml"
|
78
102
|
request["accept"] = "application/xml"
|
79
103
|
request["accept-charset"] = "utf-8"
|
80
104
|
request.body = body
|
data/lib/azure/role.rb
CHANGED
@@ -77,74 +77,95 @@ class Azure
|
|
77
77
|
def delete(name, params)
|
78
78
|
role = find(name)
|
79
79
|
if role != nil
|
80
|
-
if alone_on_hostedservice(role)
|
81
|
-
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
|
82
|
-
"/#{role.deployname}"
|
83
|
-
else
|
84
|
-
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
|
85
|
-
"/#{role.deployname}/roles/#{role.name}"
|
86
|
-
end
|
87
|
-
|
88
80
|
roleXML = nil
|
81
|
+
roleXML = @connection.query_azure("hostedservices/#{role.hostedservicename}", "get", "", "embed-detail=true")
|
82
|
+
osdisk = roleXML.css(roleXML, 'OSVirtualHardDisk')
|
83
|
+
disk_name = xml_content(osdisk, 'DiskName')
|
84
|
+
storage_account_name = xml_content(osdisk, 'MediaLink').gsub("http://", "").gsub(/.blob(.*)$/, "")
|
89
85
|
|
90
|
-
|
91
|
-
|
86
|
+
if !params[:preserve_azure_os_disk] && !params[:preserve_azure_vhd] && !params[:wait]
|
87
|
+
# default compmedia = true. So, it deletes role and associated resources
|
88
|
+
check_and_delete_role_and_resources(params, role)
|
89
|
+
else
|
90
|
+
# compmedia = false. So, it deletes only role and not associated resources
|
91
|
+
check_and_delete_role_and_resources(params, role, compmedia=false)
|
92
|
+
check_and_delete_disks(params, disk_name)
|
93
|
+
check_and_delete_service(params)
|
92
94
|
end
|
95
|
+
check_and_delete_storage(params, disk_name, storage_account_name)
|
96
|
+
end
|
97
|
+
end
|
93
98
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
unless params[:azure_dns_name].nil?
|
101
|
-
roles_using_same_service = find_roles_within_hostedservice(params[:azure_dns_name])
|
102
|
-
if roles_using_same_service.size <= 1
|
103
|
-
servicecall = "hostedservices/" + params[:azure_dns_name]
|
104
|
-
@connection.query_azure(servicecall, "delete")
|
105
|
-
end
|
106
|
-
end
|
99
|
+
def check_and_delete_role_and_resources(params, role, compmedia=true)
|
100
|
+
if alone_on_hostedservice(role)
|
101
|
+
if !params[:preserve_azure_dns_name] && compmedia
|
102
|
+
servicecall = "hostedservices/#{role.hostedservicename}"
|
103
|
+
else
|
104
|
+
servicecall = "hostedservices/#{role.hostedservicename}/deployments/#{role.deployname}"
|
107
105
|
end
|
106
|
+
else
|
107
|
+
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
|
108
|
+
"/#{role.deployname}/roles/#{role.name}"
|
109
|
+
end
|
110
|
+
if compmedia
|
111
|
+
@connection.query_azure(servicecall, "delete", "", "comp=media", wait=params[:wait])
|
112
|
+
else
|
113
|
+
@connection.query_azure(servicecall, "delete")
|
114
|
+
end
|
108
115
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
storage_account = @connection.query_azure(servicecall, "get")
|
114
|
-
|
115
|
-
# OS Disk can only be deleted if it is detached from the VM.
|
116
|
-
# So Iteratively check for disk detachment from the VM while waiting for 5 minutes ,
|
117
|
-
# exit otherwise after 12 attempts.
|
118
|
-
for attempt in 0..12
|
119
|
-
break if @connection.query_azure(servicecall, "get").search("AttachedTo").text == ""
|
120
|
-
if attempt == 12 then puts "The associated disk could not be deleted due to time out." else sleep 25 end
|
121
|
-
end
|
122
|
-
|
123
|
-
unless params[:preserve_azure_vhd]
|
124
|
-
@connection.query_azure(servicecall, 'delete', '', 'comp=media')
|
125
|
-
else
|
126
|
-
@connection.query_azure(servicecall, 'delete')
|
127
|
-
end
|
128
|
-
|
129
|
-
if params[:delete_azure_storage_account]
|
130
|
-
storage_account_name = xml_content(storage_account, "MediaLink")
|
131
|
-
storage_account_name = storage_account_name.gsub("http://", "").gsub(/.blob(.*)$/, "")
|
116
|
+
# delete role from local cache as well.
|
117
|
+
@connection.hosts.find(role.hostedservicename).delete_role(role)
|
118
|
+
@roles.delete(role) if @roles
|
119
|
+
end
|
132
120
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
121
|
+
def check_and_delete_disks(params, disk_name)
|
122
|
+
servicecall = "disks/#{disk_name}"
|
123
|
+
unless params[:preserve_azure_os_disk]
|
124
|
+
# OS Disk can only be deleted if it is detached from the VM.
|
125
|
+
# So Iteratively check for disk detachment from the VM while waiting for 5 minutes ,
|
126
|
+
# exit otherwise after 12 attempts.
|
127
|
+
for attempt in 0..12
|
128
|
+
break if @connection.query_azure(servicecall, "get").search("AttachedTo").text == ""
|
129
|
+
if attempt == 12 then puts "The associated disk could not be deleted due to time out." else sleep 25 end
|
130
|
+
end
|
131
|
+
unless params[:preserve_azure_vhd]
|
132
|
+
@connection.query_azure(servicecall, 'delete', '', 'comp=media', wait=params[:wait])
|
133
|
+
else
|
134
|
+
@connection.query_azure(servicecall, 'delete')
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
139
138
|
|
139
|
+
def check_and_delete_service(params)
|
140
|
+
unless params[:preserve_azure_dns_name]
|
141
|
+
unless params[:azure_dns_name].nil?
|
142
|
+
roles_using_same_service = find_roles_within_hostedservice(params[:azure_dns_name])
|
143
|
+
if roles_using_same_service.size <= 1
|
144
|
+
servicecall = "hostedservices/" + params[:azure_dns_name]
|
145
|
+
@connection.query_azure(servicecall, "delete")
|
140
146
|
end
|
141
|
-
|
142
147
|
end
|
148
|
+
end
|
149
|
+
end
|
143
150
|
|
144
|
-
|
151
|
+
def check_and_delete_storage(params, disk_name, storage_account_name)
|
152
|
+
if params[:delete_azure_storage_account]
|
153
|
+
# Iteratively check for disk deletion
|
154
|
+
for attempt in 0..12
|
155
|
+
break unless @connection.query_azure("disks").search("Name").text.include?(disk_name)
|
156
|
+
if attempt == 12 then puts "The associated disk could not be deleted due to time out." else sleep 25 end
|
157
|
+
end
|
158
|
+
begin
|
159
|
+
@connection.query_azure("storageservices/#{storage_account_name}", "delete")
|
160
|
+
rescue Exception => ex
|
161
|
+
ui.warn("#{ex.message}")
|
162
|
+
ui.warn("#{ex.backtrace.join("\n")}")
|
163
|
+
end
|
145
164
|
end
|
146
165
|
end
|
147
166
|
|
167
|
+
private :check_and_delete_role_and_resources, :check_and_delete_disks, :check_and_delete_service, :check_and_delete_storage
|
168
|
+
|
148
169
|
end
|
149
170
|
|
150
171
|
class Role
|
@@ -210,7 +231,7 @@ class Azure
|
|
210
231
|
xml.SSH {
|
211
232
|
xml.PublicKeys {
|
212
233
|
xml.PublicKey {
|
213
|
-
xml.Fingerprint params[:fingerprint]
|
234
|
+
xml.Fingerprint params[:fingerprint].to_s.upcase
|
214
235
|
xml.Path '/home/' + params[:ssh_user] + '/.ssh/authorized_keys'
|
215
236
|
}
|
216
237
|
}
|
@@ -228,6 +249,15 @@ class Azure
|
|
228
249
|
xml.ResetPasswordOnFirstLogon 'false'
|
229
250
|
xml.EnableAutomaticUpdates 'false'
|
230
251
|
xml.AdminUsername params[:winrm_user]
|
252
|
+
if params[:bootstrap_proto].downcase == 'winrm'
|
253
|
+
xml.WinRM {
|
254
|
+
xml.Listeners {
|
255
|
+
xml.Listener {
|
256
|
+
xml.Protocol 'Http'
|
257
|
+
}
|
258
|
+
}
|
259
|
+
}
|
260
|
+
end
|
231
261
|
}
|
232
262
|
end
|
233
263
|
|