knife-azure 1.0.2 → 1.1.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.
- data/README.md +275 -0
- data/lib/azure/certificate.rb +87 -0
- data/lib/azure/connection.rb +3 -1
- data/lib/azure/deploy.rb +72 -28
- data/lib/azure/host.rb +97 -18
- data/lib/azure/image.rb +21 -15
- data/lib/azure/rest.rb +9 -18
- data/lib/azure/role.rb +165 -48
- data/lib/azure/storageaccount.rb +39 -18
- data/lib/chef/knife/azure_base.rb +69 -9
- data/lib/chef/knife/azure_image_list.rb +14 -13
- data/lib/chef/knife/azure_server_create.rb +271 -108
- data/lib/chef/knife/azure_server_delete.rb +55 -13
- data/lib/chef/knife/azure_server_list.rb +9 -16
- data/lib/knife-azure/version.rb +1 -1
- metadata +119 -207
- data/README.rdoc +0 -252
data/lib/azure/host.rb
CHANGED
@@ -21,30 +21,69 @@ class Azure
|
|
21
21
|
def initialize(connection)
|
22
22
|
@connection=connection
|
23
23
|
end
|
24
|
+
|
25
|
+
# force_load should be true when there is something in local cache and we want to reload
|
26
|
+
# first call is always load.
|
27
|
+
def load(force_load = false)
|
28
|
+
if not @hosted_services || force_load
|
29
|
+
@hosted_services = begin
|
30
|
+
hosted_services = Hash.new
|
31
|
+
responseXML = @connection.query_azure('hostedservices')
|
32
|
+
servicesXML = responseXML.css('HostedServices HostedService')
|
33
|
+
servicesXML.each do |serviceXML|
|
34
|
+
host = Host.new(@connection).parse(serviceXML)
|
35
|
+
hosted_services[host.name] = host
|
36
|
+
end
|
37
|
+
hosted_services
|
38
|
+
end
|
39
|
+
end
|
40
|
+
@hosted_services
|
41
|
+
end
|
42
|
+
|
24
43
|
def all
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
44
|
+
self.load.values
|
45
|
+
end
|
46
|
+
|
47
|
+
# first look up local cache if we have already loaded list.
|
48
|
+
def exists?(name)
|
49
|
+
return @hosted_services.key?(name) if @hosted_services
|
50
|
+
self.exists_on_cloud?(name)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Look up on cloud and not local cache
|
54
|
+
def exists_on_cloud?(name)
|
55
|
+
ret_val = @connection.query_azure("hostedservices/#{name}")
|
56
|
+
if ret_val.nil? || ret_val.css('Error Code').length > 0
|
57
|
+
Chef::Log.warn 'Unable to find hosted(cloud) service:' + ret_val.at_css('Error Code').content + ' : ' + ret_val.at_css('Error Message').content if ret_val
|
58
|
+
false
|
59
|
+
else
|
60
|
+
true
|
31
61
|
end
|
32
|
-
hosted_services
|
33
62
|
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
63
|
+
|
64
|
+
# first look up local cache if we have already loaded list.
|
65
|
+
def find(name)
|
66
|
+
return @hosted_services[name] if @hosted_services && @hosted_services.key?(name)
|
67
|
+
self.fetch_from_cloud(name)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Look up hosted service on cloud and not local cache
|
71
|
+
def fetch_from_cloud(name)
|
72
|
+
ret_val = @connection.query_azure("hostedservices/#{name}")
|
73
|
+
if ret_val.nil? || ret_val.css('Error Code').length > 0
|
74
|
+
Chef::Log.warn 'Unable to find hosted(cloud) service:' + ret_val.at_css('Error Code').content + ' : ' + ret_val.at_css('Error Message').content if ret_val
|
75
|
+
nil
|
76
|
+
else
|
77
|
+
Host.new(@connection).parse(ret_val)
|
39
78
|
end
|
40
|
-
hostExists
|
41
79
|
end
|
80
|
+
|
42
81
|
def create(params)
|
43
82
|
host = Host.new(@connection)
|
44
83
|
host.create(params)
|
45
84
|
end
|
46
85
|
def delete(name)
|
47
|
-
if self.exists
|
86
|
+
if self.exists?(name)
|
48
87
|
servicecall = "hostedservices/" + name
|
49
88
|
@connection.query_azure(servicecall, "delete")
|
50
89
|
end
|
@@ -58,8 +97,11 @@ class Azure
|
|
58
97
|
attr_accessor :connection, :name, :url, :label
|
59
98
|
attr_accessor :dateCreated, :description, :location
|
60
99
|
attr_accessor :dateModified, :status
|
100
|
+
|
61
101
|
def initialize(connection)
|
62
102
|
@connection = connection
|
103
|
+
@deploys_loaded = false
|
104
|
+
@deploys = Hash.new
|
63
105
|
end
|
64
106
|
def parse(serviceXML)
|
65
107
|
@name = xml_content(serviceXML, 'ServiceName')
|
@@ -75,10 +117,10 @@ class Azure
|
|
75
117
|
def create(params)
|
76
118
|
builder = Nokogiri::XML::Builder.new do |xml|
|
77
119
|
xml.CreateHostedService('xmlns'=>'http://schemas.microsoft.com/windowsazure') {
|
78
|
-
xml.ServiceName params[:
|
79
|
-
xml.Label Base64.encode64(params[:
|
80
|
-
xml.Description
|
81
|
-
xml.Location params[:
|
120
|
+
xml.ServiceName params[:azure_dns_name]
|
121
|
+
xml.Label Base64.encode64(params[:azure_dns_name])
|
122
|
+
xml.Description 'Explicitly created hosted service'
|
123
|
+
xml.Location params[:azure_service_location] || 'West US'
|
82
124
|
}
|
83
125
|
end
|
84
126
|
@connection.query_azure("hostedservices", "post", builder.to_xml)
|
@@ -86,5 +128,42 @@ class Azure
|
|
86
128
|
def details
|
87
129
|
response = @connection.query_azure('hostedservices/' + @name + '?embed-detail=true')
|
88
130
|
end
|
131
|
+
|
132
|
+
# Deployments within this hostedservice
|
133
|
+
def add_deploy(deploy)
|
134
|
+
@deploys[deploy.name] = deploy
|
135
|
+
end
|
136
|
+
|
137
|
+
def delete_role(role)
|
138
|
+
deploys.each { |d| d.delete_role_if_present(role) }
|
139
|
+
end
|
140
|
+
|
141
|
+
def deploys
|
142
|
+
# check if we have deploys loaded, else load.
|
143
|
+
if (@deploys.length == 0) && !@deploys_loaded
|
144
|
+
deploy = Deploy.new(@connection)
|
145
|
+
deploy.retrieve(@name)
|
146
|
+
@deploys[deploy.name] = deploy
|
147
|
+
@deploys_loaded = true
|
148
|
+
end
|
149
|
+
@deploys.values
|
150
|
+
end
|
151
|
+
|
152
|
+
def roles
|
153
|
+
roles = []
|
154
|
+
deploys.each do |deploy|
|
155
|
+
roles.concat(deploy.roles) if deploy.roles
|
156
|
+
end
|
157
|
+
roles
|
158
|
+
end
|
159
|
+
|
160
|
+
def find_role(role_name, deploy_name = nil)
|
161
|
+
return @deploys[deploy_name].find_role(role_name) if deploy_name && deploys
|
162
|
+
# else lookup all deploys within hostedservice
|
163
|
+
deploys.each do |deploy|
|
164
|
+
role = deploy.find_role(role_name)
|
165
|
+
return role if role
|
166
|
+
end
|
167
|
+
end
|
89
168
|
end
|
90
169
|
end
|
data/lib/azure/image.rb
CHANGED
@@ -21,23 +21,29 @@ class Azure
|
|
21
21
|
def initialize(connection)
|
22
22
|
@connection=connection
|
23
23
|
end
|
24
|
-
def
|
25
|
-
images
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
def load
|
25
|
+
@images ||= begin
|
26
|
+
images = Hash.new
|
27
|
+
response = @connection.query_azure('images')
|
28
|
+
osimages = response.css('OSImage')
|
29
|
+
osimages.each do |image|
|
30
|
+
item = Image.new(image)
|
31
|
+
images[item.name] = item
|
32
|
+
end
|
33
|
+
images
|
31
34
|
end
|
32
|
-
images
|
33
35
|
end
|
34
|
-
|
35
|
-
|
36
|
-
self.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
|
37
|
+
def all
|
38
|
+
self.load.values
|
39
|
+
end
|
40
|
+
|
41
|
+
def exists?(name)
|
42
|
+
self.all.key?(name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def find(name)
|
46
|
+
self.load[name]
|
41
47
|
end
|
42
48
|
end
|
43
49
|
end
|
data/lib/azure/rest.rb
CHANGED
@@ -24,23 +24,10 @@ module AzureAPI
|
|
24
24
|
class Rest
|
25
25
|
def initialize(params)
|
26
26
|
@subscription_id = params[:azure_subscription_id]
|
27
|
-
@pem_file =
|
28
|
-
@host_name = params[:
|
27
|
+
@pem_file = params[:azure_mgmt_cert]
|
28
|
+
@host_name = params[:azure_api_host_name]
|
29
29
|
@verify_ssl = params[:verify_ssl_cert]
|
30
30
|
end
|
31
|
-
def find_pem(name)
|
32
|
-
config_dir = Chef::Knife.chef_config_dir
|
33
|
-
if File.exist? name
|
34
|
-
pem_file = name
|
35
|
-
elsif config_dir && File.exist?(File.join(config_dir, name))
|
36
|
-
pem_file = File.join(config_dir, name)
|
37
|
-
elsif File.exist?(File.join(ENV['HOME'], '.chef', name))
|
38
|
-
pem_file = File.join(ENV['HOME'], '.chef', name)
|
39
|
-
else
|
40
|
-
raise 'Unable to find certificate pem file - ' + name
|
41
|
-
end
|
42
|
-
pem_file
|
43
|
-
end
|
44
31
|
def query_azure(service_name, verb = 'get', body = '')
|
45
32
|
request_url = "https://#{@host_name}/#{@subscription_id}/services/#{service_name}"
|
46
33
|
print '.'
|
@@ -69,8 +56,12 @@ module AzureAPI
|
|
69
56
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
70
57
|
end
|
71
58
|
http.use_ssl = true
|
72
|
-
|
73
|
-
|
59
|
+
begin
|
60
|
+
http.cert = OpenSSL::X509::Certificate.new(@pem_file)
|
61
|
+
rescue OpenSSL::X509::CertificateError => err
|
62
|
+
raise "Invalid Azure Certificate pem file. Error: #{err}"
|
63
|
+
end
|
64
|
+
http.key = OpenSSL::PKey::RSA.new(@pem_file)
|
74
65
|
http
|
75
66
|
end
|
76
67
|
def request_setup(uri, verb, body)
|
@@ -95,7 +86,7 @@ module AzureAPI
|
|
95
86
|
puts response.code
|
96
87
|
puts "=== response.inspect ==="
|
97
88
|
puts response.inspect
|
98
|
-
puts "=== all of the headers ==="
|
89
|
+
puts "=== all of the headers ==="
|
99
90
|
puts response.each_header { |h, j| puts h.inspect + ' : ' + j.inspect}
|
100
91
|
end
|
101
92
|
end
|
data/lib/azure/role.rb
CHANGED
@@ -15,14 +15,16 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
-
|
18
|
+
require 'securerandom'
|
19
19
|
class Azure
|
20
20
|
class Roles
|
21
|
+
include AzureUtility
|
21
22
|
attr_accessor :connection, :roles
|
22
23
|
def initialize(connection)
|
23
24
|
@connection = connection
|
24
25
|
@roles = nil
|
25
26
|
end
|
27
|
+
# do not use this unless you want a list of all roles(vms) in your subscription
|
26
28
|
def all
|
27
29
|
@roles = Array.new
|
28
30
|
@connection.deploys.all.each do |deploy|
|
@@ -32,51 +34,121 @@ class Azure
|
|
32
34
|
end
|
33
35
|
@roles
|
34
36
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
|
38
|
+
def find_roles_within_hostedservice(hostedservicename)
|
39
|
+
host = @connection.hosts.find(hostedservicename)
|
40
|
+
(host) ? host.roles : nil # nil says invalid hosted service
|
41
|
+
end
|
42
|
+
|
43
|
+
def find_in_hosted_service(role_name, hostedservicename)
|
44
|
+
host = @connection.hosts.find(hostedservicename)
|
45
|
+
return nil if host.nil?
|
46
|
+
host.find_role(role_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def find(role_name, params= nil)
|
50
|
+
if params && params[:azure_dns_name]
|
51
|
+
return find_in_hosted_service(role_name, params[:azure_dns_name])
|
38
52
|
end
|
53
|
+
|
54
|
+
all if @roles == nil
|
55
|
+
|
56
|
+
# TODO - optimize this lookup
|
39
57
|
@roles.each do |role|
|
40
|
-
if(role.name ==
|
41
|
-
return role
|
58
|
+
if(role.name == role_name)
|
59
|
+
return role
|
42
60
|
end
|
43
61
|
end
|
44
|
-
nil
|
62
|
+
nil
|
45
63
|
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
role.hostedservicename == found_role.hostedservicename)
|
52
|
-
return false;
|
53
|
-
end
|
64
|
+
|
65
|
+
def alone_on_hostedservice(found_role)
|
66
|
+
roles = find_roles_within_hostedservice(found_role.hostedservicename)
|
67
|
+
if roles && roles.length > 1
|
68
|
+
return false
|
54
69
|
end
|
55
|
-
true
|
70
|
+
return true
|
56
71
|
end
|
57
|
-
|
72
|
+
|
73
|
+
def exists?(name)
|
58
74
|
find(name) != nil
|
59
75
|
end
|
60
|
-
|
76
|
+
|
77
|
+
def delete(name, params)
|
61
78
|
role = find(name)
|
62
79
|
if role != nil
|
63
|
-
if
|
80
|
+
if alone_on_hostedservice(role)
|
64
81
|
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
|
65
82
|
"/#{role.deployname}"
|
66
83
|
else
|
67
84
|
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
|
68
85
|
"/#{role.deployname}/roles/#{role.name}"
|
69
86
|
end
|
70
|
-
|
87
|
+
|
88
|
+
roleXML = nil
|
89
|
+
|
90
|
+
unless params[:preserve_azure_os_disk]
|
91
|
+
roleXML = @connection.query_azure(servicecall, "get")
|
92
|
+
end
|
93
|
+
|
94
|
+
@connection.query_azure(servicecall, "delete")
|
95
|
+
# delete role from local cache as well.
|
96
|
+
@connection.hosts.find(role.hostedservicename).delete_role(role)
|
97
|
+
@roles.delete(role) if @roles
|
98
|
+
|
99
|
+
unless params[:preserve_azure_dns_name]
|
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
|
107
|
+
end
|
108
|
+
|
109
|
+
unless params[:preserve_azure_os_disk]
|
110
|
+
osdisk = roleXML.css(roleXML, 'OSVirtualHardDisk')
|
111
|
+
disk_name = xml_content(osdisk, 'DiskName')
|
112
|
+
servicecall = "disks/#{disk_name}"
|
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
|
+
@connection.query_azure(servicecall, "delete")
|
123
|
+
|
124
|
+
if params[:delete_azure_storage_account]
|
125
|
+
storage_account_name = xml_content(storage_account, "MediaLink")
|
126
|
+
storage_account_name = storage_account_name.gsub("http://", "").gsub(/.blob(.*)$/, "")
|
127
|
+
|
128
|
+
begin
|
129
|
+
@connection.query_azure("storageservices/#{storage_account_name}", "delete")
|
130
|
+
rescue Exception => ex
|
131
|
+
ui.warn("#{ex.message}")
|
132
|
+
ui.warn("#{ex.backtrace.join("\n")}")
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
71
140
|
end
|
72
|
-
#@connection.disks.clear_unattached
|
73
141
|
end
|
142
|
+
|
74
143
|
end
|
144
|
+
|
75
145
|
class Role
|
76
146
|
include AzureUtility
|
77
|
-
attr_accessor :connection, :name, :status, :size, :ipaddress
|
78
|
-
attr_accessor :sshport, :
|
147
|
+
attr_accessor :connection, :name, :status, :size, :ipaddress, :publicipaddress
|
148
|
+
attr_accessor :sshport, :hostedservicename, :deployname
|
149
|
+
attr_accessor :winrmport
|
79
150
|
attr_accessor :hostname, :tcpports, :udpports
|
151
|
+
|
80
152
|
def initialize(connection)
|
81
153
|
@connection = connection
|
82
154
|
end
|
@@ -90,11 +162,14 @@ class Azure
|
|
90
162
|
@deployname = deployname
|
91
163
|
@tcpports = Array.new
|
92
164
|
@udpports = Array.new
|
165
|
+
|
93
166
|
endpoints = roleXML.css('InstanceEndpoint')
|
167
|
+
@publicipaddress = xml_content(endpoints[0], 'Vip') if !endpoints.empty?
|
94
168
|
endpoints.each do |endpoint|
|
95
169
|
if xml_content(endpoint, 'Name').downcase == 'ssh'
|
96
170
|
@sshport = xml_content(endpoint, 'PublicPort')
|
97
|
-
|
171
|
+
elsif xml_content(endpoint, 'Name').downcase == 'winrm'
|
172
|
+
@winrmport = xml_content(endpoint, 'PublicPort')
|
98
173
|
else
|
99
174
|
hash = Hash.new
|
100
175
|
hash['Name'] = xml_content(endpoint, 'Name')
|
@@ -115,34 +190,72 @@ class Azure
|
|
115
190
|
'xmlns'=>'http://schemas.microsoft.com/windowsazure',
|
116
191
|
'xmlns:i'=>'http://www.w3.org/2001/XMLSchema-instance'
|
117
192
|
) {
|
118
|
-
xml.RoleName {xml.text params[:
|
193
|
+
xml.RoleName {xml.text params[:azure_vm_name]}
|
119
194
|
xml.OsVersion('i:nil' => 'true')
|
120
195
|
xml.RoleType 'PersistentVMRole'
|
121
196
|
xml.ConfigurationSets {
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
197
|
+
if params[:os_type] == 'Linux'
|
198
|
+
|
199
|
+
xml.ConfigurationSet('i:type' => 'LinuxProvisioningConfigurationSet') {
|
200
|
+
xml.ConfigurationSetType 'LinuxProvisioningConfiguration'
|
201
|
+
xml.HostName params[:azure_vm_name]
|
202
|
+
xml.UserName params[:ssh_user]
|
203
|
+
unless params[:identity_file].nil?
|
204
|
+
xml.DisableSshPasswordAuthentication 'true'
|
205
|
+
xml.SSH {
|
206
|
+
xml.PublicKeys {
|
207
|
+
xml.PublicKey {
|
208
|
+
xml.Fingerprint params[:fingerprint]
|
209
|
+
xml.Path '/home/' + params[:ssh_user] + '/.ssh/authorized_keys'
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
else
|
214
|
+
xml.UserPassword params[:ssh_password]
|
215
|
+
xml.DisableSshPasswordAuthentication 'false'
|
216
|
+
end
|
217
|
+
}
|
218
|
+
elsif params[:os_type] == 'Windows'
|
219
|
+
xml.ConfigurationSet('i:type' => 'WindowsProvisioningConfigurationSet') {
|
220
|
+
xml.ConfigurationSetType 'WindowsProvisioningConfiguration'
|
221
|
+
xml.ComputerName params[:azure_vm_name]
|
222
|
+
xml.AdminPassword params[:admin_password]
|
223
|
+
xml.ResetPasswordOnFirstLogon 'false'
|
224
|
+
xml.EnableAutomaticUpdates 'false'
|
225
|
+
|
226
|
+
}
|
227
|
+
end
|
228
|
+
|
129
229
|
xml.ConfigurationSet('i:type' => 'NetworkConfigurationSet') {
|
130
230
|
xml.ConfigurationSetType 'NetworkConfiguration'
|
131
231
|
xml.InputEndpoints {
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
232
|
+
if params[:bootstrap_proto].downcase == 'ssh'
|
233
|
+
xml.InputEndpoint {
|
234
|
+
xml.LocalPort '22'
|
235
|
+
xml.Name 'SSH'
|
236
|
+
xml.Port params[:port]
|
237
|
+
xml.Protocol 'TCP'
|
238
|
+
}
|
239
|
+
elsif params[:bootstrap_proto].downcase == 'winrm' and params[:os_type] == 'Windows'
|
240
|
+
xml.InputEndpoint {
|
241
|
+
xml.LocalPort '5985'
|
242
|
+
xml.Name 'WinRM'
|
243
|
+
xml.Port params[:port]
|
244
|
+
xml.Protocol 'TCP'
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
137
248
|
if params[:tcp_endpoints]
|
138
249
|
params[:tcp_endpoints].split(',').each do |endpoint|
|
139
250
|
ports = endpoint.split(':')
|
140
251
|
xml.InputEndpoint {
|
141
252
|
xml.LocalPort ports[0]
|
142
|
-
xml.Name 'tcpport_' + ports[0] + '_' + params[:
|
253
|
+
xml.Name 'tcpport_' + ports[0] + '_' + params[:azure_vm_name]
|
143
254
|
if ports.length > 1
|
144
255
|
xml.Port ports[1]
|
145
|
-
|
256
|
+
else
|
257
|
+
xml.Port ports[0]
|
258
|
+
end
|
146
259
|
xml.Protocol 'TCP'
|
147
260
|
}
|
148
261
|
end
|
@@ -152,10 +265,12 @@ class Azure
|
|
152
265
|
ports = endpoint.split(':')
|
153
266
|
xml.InputEndpoint {
|
154
267
|
xml.LocalPort ports[0]
|
155
|
-
xml.Name 'udpport_' + ports[0] + '_' + params[:
|
268
|
+
xml.Name 'udpport_' + ports[0] + '_' + params[:azure_vm_name]
|
156
269
|
if ports.length > 1
|
157
270
|
xml.Port ports[1]
|
158
|
-
|
271
|
+
else
|
272
|
+
xml.Port ports[0]
|
273
|
+
end
|
159
274
|
xml.Protocol 'UDP'
|
160
275
|
}
|
161
276
|
end
|
@@ -163,20 +278,22 @@ class Azure
|
|
163
278
|
}
|
164
279
|
}
|
165
280
|
}
|
166
|
-
xml.Label Base64.encode64(params[:
|
281
|
+
xml.Label Base64.encode64(params[:azure_vm_name]).strip
|
167
282
|
xml.OSVirtualHardDisk {
|
168
|
-
|
169
|
-
xml.
|
283
|
+
disk_name = params[:azure_os_disk_name] || "disk_" + SecureRandom.uuid
|
284
|
+
xml.DiskName disk_name
|
285
|
+
xml.MediaLink 'http://' + params[:azure_storage_account] + '.blob.core.windows.net/vhds/' + disk_name + '.vhd'
|
286
|
+
xml.SourceImageName params[:azure_source_image]
|
170
287
|
}
|
171
|
-
xml.RoleSize params[:
|
288
|
+
xml.RoleSize params[:azure_vm_size]
|
172
289
|
}
|
173
|
-
end
|
290
|
+
end
|
174
291
|
builder.doc
|
175
292
|
end
|
176
293
|
def create(params, roleXML)
|
177
|
-
servicecall = "hostedservices/#{params[:
|
294
|
+
servicecall = "hostedservices/#{params[:azure_dns_name]}/deployments" +
|
178
295
|
"/#{params['deploy_name']}/roles"
|
179
|
-
@connection.query_azure(servicecall, "post", roleXML.to_xml)
|
296
|
+
@connection.query_azure(servicecall, "post", roleXML.to_xml)
|
180
297
|
end
|
181
298
|
end
|
182
299
|
end
|