knife-azure 3.0.6 → 4.0.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/azure/custom_errors.rb +1 -1
  3. data/lib/azure/resource_management/ARM_deployment_template.rb +5 -5
  4. data/lib/azure/resource_management/ARM_interface.rb +4 -6
  5. data/lib/azure/resource_management/windows_credentials.rb +2 -2
  6. data/lib/chef/knife/azurerm_server_create.rb +1 -1
  7. data/lib/chef/knife/bootstrap/bootstrapper.rb +5 -10
  8. data/lib/chef/knife/helpers/azurerm_base.rb +4 -4
  9. data/lib/knife-azure/version.rb +1 -1
  10. metadata +30 -43
  11. data/lib/azure/service_management/ASM_interface.rb +0 -310
  12. data/lib/azure/service_management/ag.rb +0 -99
  13. data/lib/azure/service_management/certificate.rb +0 -235
  14. data/lib/azure/service_management/connection.rb +0 -102
  15. data/lib/azure/service_management/deploy.rb +0 -221
  16. data/lib/azure/service_management/disk.rb +0 -68
  17. data/lib/azure/service_management/host.rb +0 -184
  18. data/lib/azure/service_management/image.rb +0 -94
  19. data/lib/azure/service_management/loadbalancer.rb +0 -78
  20. data/lib/azure/service_management/rest.rb +0 -126
  21. data/lib/azure/service_management/role.rb +0 -717
  22. data/lib/azure/service_management/storageaccount.rb +0 -127
  23. data/lib/azure/service_management/utility.rb +0 -40
  24. data/lib/azure/service_management/vnet.rb +0 -134
  25. data/lib/chef/knife/azure_ag_create.rb +0 -73
  26. data/lib/chef/knife/azure_ag_list.rb +0 -35
  27. data/lib/chef/knife/azure_image_list.rb +0 -56
  28. data/lib/chef/knife/azure_internal-lb_create.rb +0 -74
  29. data/lib/chef/knife/azure_internal-lb_list.rb +0 -35
  30. data/lib/chef/knife/azure_server_create.rb +0 -531
  31. data/lib/chef/knife/azure_server_delete.rb +0 -136
  32. data/lib/chef/knife/azure_server_list.rb +0 -38
  33. data/lib/chef/knife/azure_server_show.rb +0 -41
  34. data/lib/chef/knife/azure_vnet_create.rb +0 -74
  35. data/lib/chef/knife/azure_vnet_list.rb +0 -35
  36. data/lib/chef/knife/bootstrap_azure.rb +0 -191
  37. data/lib/chef/knife/helpers/azure_base.rb +0 -392
@@ -1,99 +0,0 @@
1
- #
2
- # Author:: Jeff Mendoza (jeffmendoza@live.com)
3
- # Copyright:: Copyright (c) Chef Software 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
- module 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
- true,
33
- false)
34
- response.css("AffinityGroup").each do |ag|
35
- item = AG.new(@connection).parse(ag)
36
- @ags[item.name] = item
37
- end
38
- @ags
39
- end
40
- end
41
-
42
- def all
43
- load.values
44
- end
45
-
46
- def exists?(name)
47
- load.key?(name)
48
- end
49
-
50
- def find(name)
51
- load[name]
52
- end
53
-
54
- def create(params)
55
- ag = AG.new(@connection)
56
- ag.create(params)
57
- end
58
- end
59
- end
60
-
61
- module Azure
62
- class AG
63
- attr_accessor :name, :label, :description, :location
64
-
65
- def initialize(connection)
66
- @connection = connection
67
- end
68
-
69
- def parse(image)
70
- @name = image.at_css("Name").content
71
- @label = image.at_css("Label").content
72
- @description = image.at_css("Description").content if
73
- image.at_css("Description")
74
- @location = image.at_css("Location").content if image.at_css("Location")
75
- self
76
- end
77
-
78
- def create(params)
79
- builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
80
- xml.CreateAffinityGroup(
81
- xmlns: "http://schemas.microsoft.com/windowsazure"
82
- ) do
83
- xml.Name params[:azure_ag_name]
84
- xml.Label Base64.strict_encode64(params[:azure_ag_name])
85
- unless params[:azure_ag_desc].nil?
86
- xml.Description params[:azure_ag_desc]
87
- end
88
- xml.Location params[:azure_location]
89
- end
90
- end
91
- @connection.query_azure("affinitygroups",
92
- "post",
93
- builder.to_xml,
94
- "",
95
- true,
96
- false)
97
- end
98
- end
99
- end
@@ -1,235 +0,0 @@
1
- #
2
- # Author:: Mukta Aphale (mukta.aphale@clogeny.com)
3
- # Copyright:: Copyright (c) Chef Software 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
- module Azure
20
- class Certificates
21
- def initialize(connection)
22
- @connection = connection
23
- end
24
-
25
- def create(params)
26
- certificate = Certificate.new(@connection)
27
- certificate.create(params)
28
- end
29
-
30
- def add(certificate_data, certificate_password, certificate_format, dns_name)
31
- certificate = Certificate.new(@connection)
32
- certificate.add_certificate certificate_data, certificate_password, certificate_format, dns_name
33
- end
34
-
35
- def create_ssl_certificate(azure_dns_name)
36
- cert_params = { output_file: "winrm", key_length: 2048, cert_validity: 24,
37
- azure_dns_name: azure_dns_name }
38
- certificate = Certificate.new(@connection)
39
- thumbprint = certificate.create_ssl_certificate(cert_params)
40
- end
41
-
42
- def get_certificate(dns_name, fingerprint)
43
- certificate = Certificate.new(@connection)
44
- certificate.get_certificate(dns_name, fingerprint)
45
- end
46
- end
47
- end
48
-
49
- module Azure
50
- class Certificate
51
- attr_accessor :connection
52
- attr_accessor :cert_data, :fingerprint, :certificate_version
53
- def initialize(connection)
54
- @connection = connection
55
- @certificate_version = 2 # cf. RFC 5280 - to make it a "v3" certificate
56
- end
57
-
58
- def create(params)
59
- # If RSA private key has been specified, then generate an x 509 certificate from the
60
- # public part of the key
61
- @cert_data = generate_public_key_certificate_data({ ssh_key: params[:ssh_identity_file],
62
- ssh_key_passphrase: params[:identity_file_passphrase] })
63
- add_certificate @cert_data, "knifeazure", "pfx", params[:azure_dns_name]
64
-
65
- # Return the fingerprint to be used while adding role
66
- @fingerprint
67
- end
68
-
69
- def generate_public_key_certificate_data(params)
70
- # Generate OpenSSL RSA key from the mentioned ssh key path (and passphrase)
71
- key = OpenSSL::PKey::RSA.new(File.read(params[:ssh_key]), params[:ssh_key_passphrase])
72
- # Generate X 509 certificate
73
- ca = OpenSSL::X509::Certificate.new
74
- ca.version = @certificate_version
75
- ca.serial = Random.rand(65534) + 1 # 2 digit byte range random number for better security aspect
76
- ca.subject = OpenSSL::X509::Name.parse "/DC=org/DC=knife-plugin/CN=Opscode CA"
77
- ca.issuer = ca.subject # root CA's are "self-signed"
78
- ca.public_key = key.public_key # Assign the ssh-key's public part to the certificate
79
- ca.not_before = Time.now
80
- ca.not_after = ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity
81
- ef = OpenSSL::X509::ExtensionFactory.new
82
- ef.subject_certificate = ca
83
- ef.issuer_certificate = ca
84
- ca.add_extension(ef.create_extension("basicConstraints", "CA:TRUE", true))
85
- ca.add_extension(ef.create_extension("keyUsage", "keyCertSign, cRLSign", true))
86
- ca.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false))
87
- ca.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false))
88
- ca.sign(key, OpenSSL::Digest.new("SHA256"))
89
- # Generate the SHA1 fingerprint of the der format of the X 509 certificate
90
- @fingerprint = OpenSSL::Digest::SHA1.new(ca.to_der)
91
- # Create the pfx format of the certificate
92
- pfx = OpenSSL::PKCS12.create("knifeazure", "knife-azure-pfx", key, ca)
93
- # Encode the pfx format - upload this certificate
94
- Base64.strict_encode64(pfx.to_der)
95
- end
96
-
97
- def add_certificate(certificate_data, certificate_password, certificate_format, dns_name)
98
- # Generate XML to call the API
99
- # Add certificate to the hosted service
100
- builder = Nokogiri::XML::Builder.new do |xml|
101
- xml.CertificateFile("xmlns" => "http://schemas.microsoft.com/windowsazure") do
102
- xml.Data certificate_data
103
- xml.CertificateFormat certificate_format
104
- xml.Password certificate_password
105
- end
106
- end
107
- # Windows Azure API call
108
- @connection.query_azure("hostedservices/#{dns_name}/certificates", "post", builder.to_xml)
109
-
110
- # Check if certificate is available else raise error
111
- for attempt in 0..4
112
- Chef::Log.info "Waiting to get certificate ..."
113
- res = get_certificate(dns_name, @fingerprint)
114
- break unless res.empty?
115
- if attempt == 4
116
- raise "The certificate with thumbprint #{fingerprint} was not found."
117
- else
118
- sleep 5
119
- end
120
- end
121
- end
122
-
123
- def get_certificate(dns_name, fingerprint)
124
- @connection.query_azure("hostedservices/#{dns_name}/certificates/sha1-#{fingerprint}", "get").search("Certificate")
125
- end
126
-
127
- ######## SSL certificate generation for knife-azure ssl bootstrap ######
128
- def create_ssl_certificate(cert_params)
129
- file_path = cert_params[:output_file].sub(/\.(\w+)$/, "")
130
- path = prompt_for_file_path
131
- file_path = File.join(path, file_path) unless path.empty?
132
- cert_params[:domain] = prompt_for_domain
133
-
134
- rsa_key = generate_keypair cert_params[:key_length]
135
- cert = generate_certificate(rsa_key, cert_params)
136
- write_certificate_to_file cert, file_path, rsa_key, cert_params
137
- puts "*" * 70
138
- puts "Generated Certificates:"
139
- puts "- #{file_path}.pfx - PKCS12 format keypair. Contains both the public and private keys, usually used on the server."
140
- puts "- #{file_path}.b64 - Base64 encoded PKCS12 keypair. Contains both the public and private keys, for upload to the Azure REST API."
141
- puts "- #{file_path}.pem - Base64 encoded public certificate only. Required by the client to connect to the server."
142
- puts "Certificate Thumbprint: #{@thumbprint.to_s.upcase}"
143
- puts "*" * 70
144
-
145
- config[:ca_trust_file] = file_path + ".pem" if config[:ca_trust_file].nil?
146
- cert_data = File.read (file_path + ".b64")
147
- add_certificate cert_data, @winrm_cert_passphrase, "pfx", cert_params[:azure_dns_name]
148
- @thumbprint
149
- end
150
-
151
- def generate_keypair(key_length)
152
- OpenSSL::PKey::RSA.new(key_length.to_i)
153
- end
154
-
155
- def prompt_for_passphrase
156
- passphrase = ""
157
- begin
158
- print "Passphrases do not match. Try again.\n" unless passphrase.empty?
159
- print "Enter certificate passphrase (empty for no passphrase):"
160
- passphrase = STDIN.gets
161
- return passphrase.strip if passphrase == "\n"
162
-
163
- print "Enter same passphrase again:"
164
- confirm_passphrase = STDIN.gets
165
- end until passphrase == confirm_passphrase
166
- passphrase.strip
167
- end
168
-
169
- def prompt_for_file_path
170
- file_path = ""
171
- counter = 0
172
- begin
173
- print "Invalid location! \n" unless file_path.empty?
174
- print 'Enter the file path for certificates e.g. C:\Windows (empty for current location):'
175
- file_path = STDIN.gets
176
- stripped_file_path = file_path.strip
177
- return stripped_file_path if file_path == "\n"
178
-
179
- counter += 1
180
- exit(1) if counter == 3
181
- end until File.directory?(stripped_file_path)
182
- stripped_file_path
183
- end
184
-
185
- def prompt_for_domain
186
- counter = 0
187
- begin
188
- print "Enter the domain (mandatory):"
189
- domain = STDIN.gets
190
- domain = domain.strip
191
- counter += 1
192
- exit(1) if counter == 3
193
- end until !domain.empty?
194
- domain
195
- end
196
-
197
- def generate_certificate(rsa_key, cert_params)
198
- @hostname = "*"
199
- if cert_params[:domain]
200
- @hostname = "*." + cert_params[:domain]
201
- end
202
-
203
- # Create a self-signed X509 certificate from the rsa_key (unencrypted)
204
- cert = OpenSSL::X509::Certificate.new
205
- cert.version = 2
206
- cert.serial = Random.rand(65534) + 1 # 2 digit byte range random number for better security aspect
207
-
208
- cert.subject = OpenSSL::X509::Name.parse "/CN=#{@hostname}"
209
- cert.issuer = cert.subject
210
- cert.public_key = rsa_key.public_key
211
- cert.not_before = Time.now
212
- cert.not_after = cert.not_before + 2 * 365 * cert_params[:cert_validity].to_i * 60 * 60 # 2 years validity
213
- ef = OpenSSL::X509::ExtensionFactory.new
214
- ef.subject_certificate = cert
215
- ef.issuer_certificate = cert
216
- cert.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false))
217
- cert.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false))
218
- cert.add_extension(ef.create_extension("extendedKeyUsage", "1.3.6.1.5.5.7.3.1", false))
219
- cert.sign(rsa_key, OpenSSL::Digest.new("SHA1"))
220
- @thumbprint = OpenSSL::Digest::SHA1.new(cert.to_der)
221
- cert
222
- end
223
-
224
- def write_certificate_to_file(cert, file_path, rsa_key, cert_params)
225
- File.open(file_path + ".pem", "wb") { |f| f.print cert.to_pem }
226
- @winrm_cert_passphrase = prompt_for_passphrase unless @winrm_cert_passphrase
227
- pfx = OpenSSL::PKCS12.create("#{cert_params[:winrm_cert_passphrase]}", "winrmcert", rsa_key, cert)
228
- File.open(file_path + ".pfx", "wb") { |f| f.print pfx.to_der }
229
- File.open(file_path + ".b64", "wb") { |f| f.print Base64.strict_encode64(pfx.to_der) }
230
- end
231
-
232
- ########## SSL certificate generation ends ###########
233
-
234
- end
235
- end
@@ -1,102 +0,0 @@
1
- #
2
- # Author:: Barry Davis (barryd@jetstreamsoftware.com)
3
- # Copyright:: Copyright (c) Chef Software 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
- require_relative "image"
20
- require_relative "role"
21
- require_relative "deploy"
22
- require_relative "host"
23
- require_relative "loadbalancer"
24
- require_relative "vnet"
25
- require_relative "utility"
26
- require_relative "ag"
27
- require_relative "storageaccount"
28
- require_relative "certificate"
29
- require_relative "disk"
30
-
31
- module Azure
32
- class ServiceManagement
33
- class Connection
34
- include AzureUtility
35
- attr_accessor :hosts, :rest, :images, :deploys, :roles,
36
- :disks, :storageaccounts, :certificates, :ags, :vnets, :lbs
37
- def initialize(rest)
38
- @images = Images.new(self)
39
- @roles = Roles.new(self)
40
- @deploys = Deploys.new(self)
41
- @hosts = Hosts.new(self)
42
- @rest = rest
43
- @lbs = Loadbalancer.new(self)
44
- @vnets = Vnets.new(self)
45
- @ags = AGs.new(self)
46
- @storageaccounts = StorageAccounts.new(self)
47
- @certificates = Certificates.new(self)
48
- @disks = Disks.new(self)
49
- end
50
-
51
- def query_azure(service_name,
52
- verb = "get",
53
- body = "",
54
- params = "",
55
- wait = true,
56
- services = true,
57
- content_type = nil)
58
- Chef::Log.info "calling " + verb + " " + service_name + (wait ? " synchronously" : " asynchronously")
59
- Chef::Log.debug body unless body == ""
60
- response = @rest.query_azure(service_name, verb, body, params, services, content_type)
61
- if response.code.to_i == 200
62
- ret_val = Nokogiri::XML response.body
63
- elsif !wait && response.code.to_i == 202
64
- Chef::Log.debug "Request accepted in asynchronous mode"
65
- ret_val = Nokogiri::XML response.body
66
- elsif response.code.to_i >= 201 && response.code.to_i <= 299
67
- ret_val = wait_for_completion
68
- else
69
- if response.body
70
- ret_val = Nokogiri::XML response.body
71
- Chef::Log.debug ret_val.to_xml
72
- error_code, error_message = error_from_response_xml(ret_val)
73
- Chef::Log.debug error_code + " : " + error_message if error_code.length > 0
74
- else
75
- Chef::Log.warn "http error: " + response.code
76
- end
77
- end
78
- ret_val
79
- end
80
-
81
- def wait_for_completion
82
- status = "InProgress"
83
- Chef::Log.info "Waiting while status returns InProgress"
84
- while status == "InProgress"
85
- response = @rest.query_for_completion
86
- ret_val = Nokogiri::XML response.body
87
- status = xml_content(ret_val, "Status")
88
- if status == "InProgress"
89
- print "."
90
- sleep(0.5)
91
- elsif status == "Succeeded"
92
- Chef::Log.debug "not InProgress : " + ret_val.to_xml
93
- else
94
- error_code, error_message = error_from_response_xml(ret_val)
95
- Chef::Log.debug status + error_code + " : " + error_message if error_code.length > 0
96
- end
97
- end
98
- ret_val
99
- end
100
- end
101
- end
102
- end
@@ -1,221 +0,0 @@
1
- #
2
- # Author:: Barry Davis (barryd@jetstreamsoftware.com)
3
- # Copyright:: Copyright (c) Chef Software 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
- module Azure
20
- class Deploys
21
- include AzureUtility
22
- def initialize(connection)
23
- @connection = connection
24
- end
25
-
26
- # force_load should be true when there is something in local cache and we want to reload
27
- # first call is always load.
28
- def load(force_load = false)
29
- unless @deploys || force_load
30
- @deploys = begin
31
- deploys = []
32
- hosts = @connection.hosts.all
33
- hosts.each do |host|
34
- deploy = Deploy.new(@connection)
35
- deploy.retrieve(host.name)
36
- if deploy.name
37
- host.add_deploy(deploy)
38
- deploys << deploy
39
- end
40
- end
41
- deploys
42
- end
43
- end
44
- @deploys
45
- end
46
-
47
- def all
48
- load
49
- end
50
-
51
- # TODO - Current knife-azure plug-in seems to have assumption that single hostedservice
52
- # will always have one deployment (production). see Deploy#retrieve below
53
- def get_deploy_name_for_hostedservice(hostedservicename)
54
- host = @connection.hosts.find(hostedservicename)
55
- if host && host.deploys.length > 0
56
- host.deploys[0].name
57
- else
58
- nil
59
- end
60
- end
61
-
62
- def create(params)
63
- if params[:azure_connect_to_existing_dns]
64
- unless @connection.hosts.exists?(params[:azure_dns_name])
65
- Chef::Log.fatal "The specified Azure DNS Name does not exist."
66
- exit 1
67
- end
68
- else
69
- ret_val = @connection.hosts.create(params)
70
- error_code, error_message = error_from_response_xml(ret_val)
71
- if error_code.length > 0
72
- Chef::Log.fatal "Unable to create DNS:" + error_code + " : " + error_message
73
- exit 1
74
- end
75
- end
76
- unless @connection.storageaccounts.exists?(params[:azure_storage_account])
77
- @connection.storageaccounts.create(params)
78
- end
79
- if params[:ssh_identity_file]
80
- params[:fingerprint] = @connection.certificates.create(params)
81
- end
82
- if params[:cert_path]
83
- cert_data = File.read (params[:cert_path])
84
- @connection.certificates.add cert_data, params[:cert_password], "pfx", params[:azure_dns_name]
85
- elsif params[:winrm_ssl]
86
- # TODO: generate certificates for ssl listener
87
- end
88
-
89
- params["deploy_name"] = get_deploy_name_for_hostedservice(params[:azure_dns_name])
90
-
91
- if !params["deploy_name"].nil?
92
- role = Role.new(@connection)
93
- roleXML = role.setup(params)
94
- ret_val = role.create(params, roleXML)
95
- else
96
- params["deploy_name"] = params[:azure_dns_name]
97
- deploy = Deploy.new(@connection)
98
- deployXML = deploy.setup(params)
99
- ret_val = deploy.create(params, deployXML)
100
- end
101
- error_code, error_message = error_from_response_xml(ret_val)
102
- if error_code.length > 0
103
- Chef::Log.debug(ret_val.to_s)
104
- raise Chef::Log.fatal "Unable to create role:" + error_code + " : " + error_message
105
- end
106
- @connection.roles.find_in_hosted_service(params[:azure_vm_name], params[:azure_dns_name])
107
- end
108
-
109
- def delete(rolename); end
110
-
111
- def queryDeploy(hostedservicename)
112
- deploy = Deploy.new(@connection)
113
- deploy.retrieve(hostedservicename)
114
- deploy
115
- end
116
- end
117
-
118
- class Deploy
119
- include AzureUtility
120
- attr_accessor :connection, :name, :status, :url, :hostedservicename, :input_endpoints, :loadbalancers
121
-
122
- def initialize(connection)
123
- @connection = connection
124
- end
125
-
126
- def retrieve(hostedservicename)
127
- @hostedservicename = hostedservicename
128
- deployXML = @connection.query_azure("hostedservices/#{hostedservicename}/deploymentslots/Production")
129
- if deployXML.at_css("Deployment Name") != nil
130
- @name = xml_content(deployXML, "Deployment Name")
131
- @status = xml_content(deployXML, "Deployment Status")
132
- @url = xml_content(deployXML, "Deployment Url")
133
- @roles = {}
134
- rolesXML = deployXML.css("Deployment RoleInstanceList RoleInstance")
135
- rolesListXML = deployXML.css("Deployment RoleList Role")
136
- rolesXML.zip(rolesListXML).each do |roleXML, roleListXML|
137
- role = Role.new(@connection)
138
- role.parse(roleXML, hostedservicename, @name)
139
- if role.publicipaddress.to_s.empty?
140
- role.publicipaddress = xml_content(deployXML, "VirtualIPs VirtualIP Address")
141
- end
142
- role.parse_role_list_xml(roleListXML)
143
- @roles[role.name] = role
144
- end
145
- @input_endpoints = []
146
- endpointsXML = deployXML.css("InputEndpoint")
147
- endpointsXML.each do |endpointXML|
148
- @input_endpoints << parse_endpoint(endpointXML)
149
- end
150
- @loadbalancers = {}
151
- lbsXML = deployXML.css("Deployment LoadBalancers LoadBalancer")
152
- lbsXML.each do |lbXML|
153
- loadbalancer = Loadbalancer.new(@connection)
154
- loadbalancer.parse(lbXML, hostedservicename)
155
- @loadbalancers[loadbalancer.name] = loadbalancer
156
- end
157
- end
158
- end
159
-
160
- def setup(params)
161
- role = Role.new(@connection)
162
- roleXML = role.setup(params)
163
- builder = Nokogiri::XML::Builder.new do |xml|
164
- xml.Deployment(
165
- "xmlns" => "http://schemas.microsoft.com/windowsazure",
166
- "xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance"
167
- ) do
168
- xml.Name params["deploy_name"]
169
- xml.DeploymentSlot "Production"
170
- xml.Label Base64.encode64(params["deploy_name"]).strip
171
- xml.RoleList { xml.Role("i:type" => "PersistentVMRole") }
172
- if params[:azure_network_name]
173
- xml.VirtualNetworkName params[:azure_network_name]
174
- end
175
- end
176
- end
177
- builder.doc.at_css("Role") << roleXML.at_css("PersistentVMRole").children.to_s
178
- builder.doc
179
- end
180
-
181
- def create(params, deployXML)
182
- servicecall = "hostedservices/#{params[:azure_dns_name]}/deployments"
183
- @connection.query_azure(servicecall, "post", deployXML.to_xml)
184
- end
185
-
186
- # This parses endpoints from a RoleList-Role-InputEndpoint, NOT a RoleInstanceList-RoleInstance-InstanceEndpoint
187
- # Refactor: make this an object rather than a hash..?
188
- def parse_endpoint(inputendpoint_xml)
189
- hash = {}
190
- %w{LoadBalancedEndpointSetName LocalPort Name Port Protocol EnableDirectServerReturn LoadBalancerName IdleTimeoutInMinutes}.each do |key|
191
- hash[key] = xml_content(inputendpoint_xml, key, nil)
192
- end
193
- # Protocol could be in there twice... If we have two, pick the second one as the first is for the probe.
194
- if inputendpoint_xml.css("Protocol").count > 1
195
- hash["Protocol"] = inputendpoint_xml.css("Protocol")[1].content
196
- end
197
- probe = inputendpoint_xml.css("LoadBalancerProbe")
198
- if probe
199
- hash["LoadBalancerProbe"] = {}
200
- %w{Path Port Protocol IntervalInSeconds TimeoutInSeconds}.each do |key|
201
- hash["LoadBalancerProbe"][key] = xml_content(probe, key, nil)
202
- end
203
- end
204
- hash
205
- end
206
-
207
- def roles
208
- @roles.values if @roles
209
- end
210
-
211
- # just delete from local cache
212
- def delete_role_if_present(role)
213
- @roles.delete(role.name) if @roles
214
- end
215
-
216
- def find_role(name)
217
- @roles[name] if @roles
218
- end
219
-
220
- end
221
- end