knife-azure 1.1.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|