knife-azure 1.6.0.rc.0 → 1.6.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +304 -8
  3. data/lib/azure/azure_interface.rb +81 -0
  4. data/lib/azure/custom_errors.rb +35 -0
  5. data/lib/azure/helpers.rb +44 -0
  6. data/lib/azure/resource_management/ARM_base.rb +29 -0
  7. data/lib/azure/resource_management/ARM_deployment_template.rb +561 -0
  8. data/lib/azure/resource_management/ARM_interface.rb +795 -0
  9. data/lib/azure/resource_management/windows_credentials.rb +136 -0
  10. data/lib/azure/service_management/ASM_interface.rb +301 -0
  11. data/lib/azure/{ag.rb → service_management/ag.rb} +2 -2
  12. data/lib/azure/{certificate.rb → service_management/certificate.rb} +2 -2
  13. data/lib/azure/service_management/connection.rb +102 -0
  14. data/lib/azure/{deploy.rb → service_management/deploy.rb} +8 -2
  15. data/lib/azure/{disk.rb → service_management/disk.rb} +2 -2
  16. data/lib/azure/{host.rb → service_management/host.rb} +2 -2
  17. data/lib/azure/{image.rb → service_management/image.rb} +2 -2
  18. data/lib/azure/{loadbalancer.rb → service_management/loadbalancer.rb} +4 -18
  19. data/lib/azure/{rest.rb → service_management/rest.rb} +15 -10
  20. data/lib/azure/{role.rb → service_management/role.rb} +174 -6
  21. data/lib/azure/{storageaccount.rb → service_management/storageaccount.rb} +2 -2
  22. data/lib/azure/{utility.rb → service_management/utility.rb} +0 -0
  23. data/lib/azure/{vnet.rb → service_management/vnet.rb} +2 -2
  24. data/lib/chef/knife/azure_ag_create.rb +3 -6
  25. data/lib/chef/knife/azure_ag_list.rb +2 -16
  26. data/lib/chef/knife/azure_base.rb +89 -22
  27. data/lib/chef/knife/azure_image_list.rb +3 -7
  28. data/lib/chef/knife/azure_internal-lb_create.rb +2 -5
  29. data/lib/chef/knife/azure_internal-lb_list.rb +2 -16
  30. data/lib/chef/knife/azure_server_create.rb +122 -501
  31. data/lib/chef/knife/azure_server_delete.rb +15 -38
  32. data/lib/chef/knife/azure_server_list.rb +2 -27
  33. data/lib/chef/knife/azure_server_show.rb +4 -60
  34. data/lib/chef/knife/azure_vnet_create.rb +2 -7
  35. data/lib/chef/knife/azure_vnet_list.rb +2 -17
  36. data/lib/chef/knife/azurerm_base.rb +228 -0
  37. data/lib/chef/knife/azurerm_server_create.rb +393 -0
  38. data/lib/chef/knife/azurerm_server_delete.rb +121 -0
  39. data/lib/chef/knife/azurerm_server_list.rb +18 -0
  40. data/lib/chef/knife/azurerm_server_show.rb +37 -0
  41. data/lib/chef/knife/bootstrap/bootstrap_options.rb +105 -0
  42. data/lib/chef/knife/bootstrap/bootstrapper.rb +343 -0
  43. data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +116 -0
  44. data/lib/chef/knife/bootstrap_azure.rb +110 -0
  45. data/lib/chef/knife/bootstrap_azurerm.rb +116 -0
  46. data/lib/knife-azure/version.rb +1 -2
  47. metadata +132 -16
  48. data/lib/azure/connection.rb +0 -99
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
19
+ module Azure
20
20
  class Certificates
21
21
  def initialize(connection)
22
22
  @connection=connection
@@ -39,7 +39,7 @@ class Azure
39
39
  end
40
40
  end
41
41
 
42
- class Azure
42
+ module Azure
43
43
  class Certificate
44
44
  attr_accessor :connection
45
45
  attr_accessor :cert_data, :fingerprint, :certificate_version
@@ -0,0 +1,102 @@
1
+ #
2
+ # Author:: Barry Davis (barryd@jetstreamsoftware.com)
3
+ # Copyright:: Copyright (c) 2010-2011 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
+ require 'azure/service_management/image'
20
+ require 'azure/service_management/role'
21
+ require 'azure/service_management/deploy'
22
+ require 'azure/service_management/host'
23
+ require 'azure/service_management/loadbalancer'
24
+ require 'azure/service_management/vnet'
25
+ require 'azure/service_management/utility'
26
+ require 'azure/service_management/ag'
27
+ require 'azure/service_management/storageaccount'
28
+ require 'azure/service_management/certificate'
29
+ require 'azure/service_management/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
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
19
+ module Azure
20
20
  class Deploys
21
21
  include AzureUtility
22
22
  def initialize(connection)
@@ -104,6 +104,7 @@ class Azure
104
104
  end
105
105
  @connection.roles.find_in_hosted_service(params[:azure_vm_name], params[:azure_dns_name])
106
106
  end
107
+
107
108
  def delete(rolename)
108
109
  end
109
110
 
@@ -130,9 +131,14 @@ class Azure
130
131
  @url = xml_content(deployXML, 'Deployment Url')
131
132
  @roles = Hash.new
132
133
  rolesXML = deployXML.css('Deployment RoleInstanceList RoleInstance')
133
- rolesXML.each do |roleXML|
134
+ rolesListXML = deployXML.css('Deployment RoleList Role')
135
+ rolesXML.zip(rolesListXML).each do |roleXML,roleListXML|
134
136
  role = Role.new(@connection)
135
137
  role.parse(roleXML, hostedservicename, @name)
138
+ if role.publicipaddress.to_s.empty?
139
+ role.publicipaddress = xml_content(deployXML, 'VirtualIPs VirtualIP Address')
140
+ end
141
+ role.parse_role_list_xml(roleListXML)
136
142
  @roles[role.name] = role
137
143
  end
138
144
  @input_endpoints = Array.new
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
19
+ module Azure
20
20
  class Disks
21
21
  def initialize(connection)
22
22
  @connection=connection
@@ -51,7 +51,7 @@ class Azure
51
51
  end
52
52
  end
53
53
 
54
- class Azure
54
+ module Azure
55
55
  class Disk
56
56
  attr_accessor :name, :attached
57
57
  def initialize(disk)
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
19
+ module Azure
20
20
  class Hosts
21
21
  include AzureUtility
22
22
  def initialize(connection)
@@ -94,7 +94,7 @@ class Azure
94
94
  end
95
95
  end
96
96
 
97
- class Azure
97
+ module Azure
98
98
  class Host
99
99
  include AzureUtility
100
100
  attr_accessor :connection, :name, :url, :label
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
19
+ module Azure
20
20
  class Images
21
21
  def initialize(connection)
22
22
  @connection=connection
@@ -76,7 +76,7 @@ class Azure
76
76
  end
77
77
  end
78
78
 
79
- class Azure
79
+ module Azure
80
80
  class Image
81
81
  attr_accessor :category, :label
82
82
  attr_accessor :name, :os, :eula, :description, :location
@@ -16,8 +16,10 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- class Azure
20
- class Loadbalancers
19
+ module Azure
20
+ class Loadbalancer
21
+ include AzureUtility
22
+ attr_accessor :name, :service, :subnet, :vip
21
23
 
22
24
  def initialize(connection)
23
25
  @connection = connection
@@ -45,22 +47,6 @@ class Azure
45
47
  load[name]
46
48
  end
47
49
 
48
- def create(params)
49
- lb = Loadbalancer.new(@connection)
50
- lb.create(params)
51
- end
52
- end
53
- end
54
-
55
- class Azure
56
- class Loadbalancer
57
- include AzureUtility
58
- attr_accessor :name, :service, :subnet, :vip
59
-
60
- def initialize(connection)
61
- @connection = connection
62
- end
63
-
64
50
  def parse(lbXML, hostedservicename)
65
51
  @name = xml_content(lbXML, 'Name')
66
52
  ip_configXML = lbXML.css('FrontendIpConfiguration')
@@ -33,32 +33,36 @@ module AzureAPI
33
33
  verb = 'get',
34
34
  body = '',
35
35
  params = '',
36
- services = true)
36
+ services = true,
37
+ content_type = nil)
37
38
  svc_str = services ? '/services' : ''
38
- request_url =
39
- "https://#{@host_name}/#{@subscription_id}#{svc_str}/#{service_name}"
39
+ uri = URI.parse("#{@host_name}/#{@subscription_id}#{svc_str}/#{service_name}")
40
+ scheme = !uri.scheme ? "https://" : ""
41
+ request_url = "#{scheme}#{@host_name}/#{@subscription_id}#{svc_str}/#{service_name}"
40
42
  print '.'
41
- response = http_query(request_url, verb, body, params)
43
+ response = http_query(request_url, verb, body, params, content_type)
42
44
  if response.code.to_i == 307
43
45
  Chef::Log.debug "Redirect to #{response['Location']}"
44
- response = http_query(response['Location'], verb, body, params)
46
+ response = http_query(response['Location'], verb, body, params, content_type)
45
47
  end
46
48
  @last_request_id = response['x-ms-request-id']
47
49
  response
48
50
  end
49
51
 
50
- def http_query(request_url, verb, body, params)
52
+ def http_query(request_url, verb, body, params, content_type = nil)
51
53
  uri = URI.parse(request_url)
52
54
  uri.query = params
53
55
  http = http_setup(uri)
54
- request = request_setup(uri, verb, body)
56
+ request = request_setup(uri, verb, body, content_type)
55
57
  response = http.request(request)
56
58
  @last_request_id = response['x-ms-request-id']
57
59
  response
58
60
  end
59
61
 
60
62
  def query_for_completion()
61
- request_url = "https://#{@host_name}/#{@subscription_id}/operations/#{@last_request_id}"
63
+ uri = URI.parse("#{@host_name}/#{@subscription_id}/operations/#{@last_request_id}")
64
+ scheme = !uri.scheme ? "https://" : ""
65
+ request_url = "#{scheme}#{@host_name}/#{@subscription_id}/operations/#{@last_request_id}"
62
66
  response = http_query(request_url, 'get', '', '')
63
67
  if response.code.to_i == 307
64
68
  Chef::Log.debug "Redirect to #{response['Location']}"
@@ -86,7 +90,7 @@ module AzureAPI
86
90
  http.key = OpenSSL::PKey::RSA.new(@pem_file)
87
91
  http
88
92
  end
89
- def request_setup(uri, verb, body)
93
+ def request_setup(uri, verb, body, content_type)
90
94
  if verb == 'get'
91
95
  request = Net::HTTP::Get.new(uri.request_uri)
92
96
  elsif verb == 'post'
@@ -96,7 +100,7 @@ module AzureAPI
96
100
  elsif verb == 'put'
97
101
  request = Net::HTTP::Put.new(uri.request_uri)
98
102
  end
99
- text = verb == 'put'
103
+ text = verb == 'put' && content_type.nil?
100
104
  request["x-ms-version"] = "2014-05-01"
101
105
  request["content-type"] = text ? "text/plain" : "application/xml"
102
106
  request["accept"] = "application/xml"
@@ -104,6 +108,7 @@ module AzureAPI
104
108
  request.body = body
105
109
  request
106
110
  end
111
+
107
112
  def showResponse(response)
108
113
  puts "=== response body ==="
109
114
  puts response.body
@@ -16,8 +16,9 @@
16
16
  # limitations under the License.
17
17
  #
18
18
  require 'securerandom'
19
+ require 'azure/service_management/utility'
19
20
 
20
- class Azure
21
+ module Azure
21
22
  class Roles
22
23
  include AzureUtility
23
24
  attr_accessor :connection, :roles
@@ -75,8 +76,8 @@ class Azure
75
76
  find(name) != nil
76
77
  end
77
78
 
78
- def delete(name, params)
79
- role = find(name)
79
+ def delete(params)
80
+ role = find(params[:name])
80
81
  if role != nil
81
82
  roleXML = nil
82
83
  roleXML = @connection.query_azure("hostedservices/#{role.hostedservicename}", "get", "", "embed-detail=true")
@@ -165,6 +166,12 @@ class Azure
165
166
  end
166
167
  end
167
168
 
169
+ def update(name, params)
170
+ role = Role.new(@connection)
171
+ roleExtensionXml = role.setup_extension(params)
172
+ role.update(name, params, roleExtensionXml)
173
+ end
174
+
168
175
  private :check_and_delete_role_and_resources, :check_and_delete_disks, :check_and_delete_service, :check_and_delete_storage
169
176
 
170
177
  end
@@ -175,6 +182,7 @@ class Azure
175
182
  attr_accessor :sshport, :hostedservicename, :deployname, :thumbprint
176
183
  attr_accessor :winrmport
177
184
  attr_accessor :hostname, :tcpports, :udpports
185
+ attr_accessor :role_xml, :os_type, :os_version
178
186
 
179
187
  TCP_ENDPOINTS_MAPPING = { '3389' => 'Remote Desktop',
180
188
  '5986' => 'PowerShell',
@@ -233,6 +241,13 @@ class Azure
233
241
  end
234
242
  end
235
243
 
244
+ def parse_role_list_xml(roleListXML)
245
+ @role_xml = roleListXML
246
+ os_disk_xml = roleListXML.css('OSVirtualHardDisk')
247
+ @os_type = xml_content(os_disk_xml, 'OS')
248
+ @os_version = xml_content(os_disk_xml, 'SourceImageName')
249
+ end
250
+
236
251
  # Expects endpoint_param_string to be in the form {localport}:{publicport}:{lb_set_name}:{lb_probe_path}
237
252
  # Only localport is mandatory.
238
253
  def parse_endpoint_from_params(protocol, azure_vm_name, endpoint_param_string)
@@ -499,14 +514,14 @@ class Azure
499
514
  if params[:chef_extension_public_param]
500
515
  xml.ResourceExtensionParameterValue {
501
516
  xml.Key "PublicParams"
502
- xml.Value params[:chef_extension_public_param]
517
+ xml.Value Base64.encode64(params[:chef_extension_public_param].to_json)
503
518
  xml.Type "Public"
504
519
  }
505
520
  end
506
521
  if params[:chef_extension_private_param]
507
522
  xml.ResourceExtensionParameterValue {
508
523
  xml.Key "PrivateParams"
509
- xml.Value params[:chef_extension_private_param]
524
+ xml.Value Base64.encode64(params[:chef_extension_private_param].to_json)
510
525
  xml.Type "Private"
511
526
  }
512
527
  end
@@ -529,7 +544,7 @@ class Azure
529
544
  xml.OSVirtualHardDisk {
530
545
  disk_name = params[:azure_os_disk_name] || "disk_" + SecureRandom.uuid
531
546
  xml.DiskName disk_name
532
- domain_suffix = params[:azure_api_host_name].scan(/core.*/)[0]
547
+ domain_suffix = params[:azure_api_host_name] ? params[:azure_api_host_name].scan(/core.*/)[0] : ''
533
548
  xml.MediaLink 'http://' + params[:azure_storage_account] + '.blob.' + domain_suffix + '/vhds/' + disk_name + '.vhd'
534
549
  xml.SourceImageName params[:azure_source_image]
535
550
  }
@@ -547,5 +562,158 @@ class Azure
547
562
  "/#{params['deploy_name']}/roles"
548
563
  @connection.query_azure(servicecall, "post", roleXML.to_xml)
549
564
  end
565
+
566
+ def setup_extension(params)
567
+ ## add Chef Extension config in role_xml retrieved from the server
568
+ puts "Adding Chef Extension config in server role..."
569
+ role_xml = update_role_xml_for_extension(params[:role_xml], params)
570
+
571
+ ## role_xml can't be used for update as it has additional tags like
572
+ ## role_name, osversion etc. which update API does not support, also the
573
+ ## xml is the child of parent node 'Deployment' in XML, so instead of
574
+ ## modifying the role_xml to fit for our requirements, we create
575
+ ## new XML (with Chef Extension config and other pre-existing VM config)
576
+ ## using the required values of the updated role_xml
577
+ builder = Nokogiri::XML::Builder.new do |xml|
578
+ xml.PersistentVMRole(
579
+ 'xmlns' => 'http://schemas.microsoft.com/windowsazure',
580
+ 'xmlns:i' => 'http://www.w3.org/2001/XMLSchema-instance'
581
+ ) {
582
+ xml.ConfigurationSets role_xml.at_css('ConfigurationSets').children if !role_xml.at_css('ConfigurationSets').nil?
583
+ xml.ResourceExtensionReferences role_xml.at_css('ResourceExtensionReferences').children if !role_xml.at_css('ResourceExtensionReferences').nil?
584
+ xml.AvailabilitySetName role_xml.at_css('AvailabilitySetName').children if !role_xml.at_css('AvailabilitySetName').nil?
585
+ xml.DataVirtualHardDisks role_xml.at_css('DataVirtualHardDisks').children if !role_xml.at_css('DataVirtualHardDisks').nil?
586
+ xml.OSVirtualHardDisk role_xml.at_css('OSVirtualHardDisk').children if !role_xml.at_css('OSVirtualHardDisk').nil?
587
+ xml.RoleSize role_xml.at_css('RoleSize').children if !role_xml.at_css('RoleSize').nil?
588
+ xml.ProvisionGuestAgent role_xml.at_css('ProvisionGuestAgent').children if !role_xml.at_css('ProvisionGuestAgent').nil?
589
+ }
590
+ end
591
+
592
+ builder.doc.to_xml.gsub("&lt\;","<").gsub("&gt\;",">")
593
+ end
594
+
595
+ def update_role_xml_for_extension(roleXML, params)
596
+ ## check if 'ResourceExtensionReferences' node already exist in the XML,
597
+ ## if no add it, else retrieve the object of the existing node
598
+ add_resource_extension_references = roleXML.at_css('ResourceExtensionReferences').nil?
599
+
600
+ if add_resource_extension_references
601
+ resource_extension_references = Nokogiri::XML::Node.new('ResourceExtensionReferences', roleXML)
602
+ else
603
+ resource_extension_references = roleXML.css('ResourceExtensionReferences')
604
+ end
605
+
606
+ ## check if Azure Chef Extension is already installed on the given server,
607
+ ## if no than install it, else raise error saying that the extension is
608
+ ## already installed
609
+ ext = nil
610
+ if !add_resource_extension_references
611
+ if !resource_extension_references.at_css('ReferenceName').nil?
612
+ resource_extension_references.css('ReferenceName').each { |node| ext = node if node.content == params[:chef_extension] }
613
+ end
614
+ end
615
+
616
+ add_resource_extension_reference = ext.nil?
617
+
618
+ ## create Azure Chef Extension config and add it in the role_xml
619
+ if add_resource_extension_reference
620
+ resource_extension_reference = Nokogiri::XML::Node.new('ResourceExtensionReference', roleXML)
621
+
622
+ reference_name = Nokogiri::XML::Node.new('ReferenceName', roleXML)
623
+ reference_name.content = params[:chef_extension]
624
+ resource_extension_reference.add_child(reference_name)
625
+
626
+ publisher = Nokogiri::XML::Node.new('Publisher', roleXML)
627
+ publisher.content = params[:chef_extension_publisher]
628
+ resource_extension_reference.add_child(publisher)
629
+
630
+ name = Nokogiri::XML::Node.new('Name', roleXML)
631
+ name.content = params[:chef_extension]
632
+ resource_extension_reference.add_child(name)
633
+
634
+ version = Nokogiri::XML::Node.new('Version', roleXML)
635
+ version.content = params[:chef_extension_version]
636
+ resource_extension_reference.add_child(version)
637
+
638
+ resource_extension_parameter_values = Nokogiri::XML::Node.new('ResourceExtensionParameterValues', roleXML)
639
+ if params[:chef_extension_public_param]
640
+ resource_extension_parameter_value = Nokogiri::XML::Node.new('ResourceExtensionParameterValue', roleXML)
641
+
642
+ key = Nokogiri::XML::Node.new('Key', roleXML)
643
+ key.content = 'PublicParams'
644
+ resource_extension_parameter_value.add_child(key)
645
+
646
+ value = Nokogiri::XML::Node.new('Value', roleXML)
647
+ value.content = Base64.encode64(params[:chef_extension_public_param].to_json)
648
+ resource_extension_parameter_value.add_child(value)
649
+
650
+ type = Nokogiri::XML::Node.new('Type', roleXML)
651
+ type.content = 'Public'
652
+ resource_extension_parameter_value.add_child(type)
653
+
654
+ resource_extension_parameter_values.add_child(resource_extension_parameter_value)
655
+ end
656
+
657
+ if params[:chef_extension_private_param]
658
+ resource_extension_parameter_value = Nokogiri::XML::Node.new('ResourceExtensionParameterValue', roleXML)
659
+
660
+ key = Nokogiri::XML::Node.new('Key', roleXML)
661
+ key.content = 'PrivateParams'
662
+ resource_extension_parameter_value.add_child(key)
663
+
664
+ value = Nokogiri::XML::Node.new('Value', roleXML)
665
+ value.content = Base64.encode64(params[:chef_extension_private_param].to_json)
666
+ resource_extension_parameter_value.add_child(value)
667
+
668
+ type = Nokogiri::XML::Node.new('Type', roleXML)
669
+ type.content = 'Private'
670
+ resource_extension_parameter_value.add_child(type)
671
+
672
+ resource_extension_parameter_values.add_child(resource_extension_parameter_value)
673
+ end
674
+
675
+ resource_extension_reference.add_child(resource_extension_parameter_values)
676
+
677
+ state = Nokogiri::XML::Node.new('State', roleXML)
678
+ state.content = 'enable'
679
+ resource_extension_reference.add_child(state)
680
+
681
+ if add_resource_extension_references
682
+ resource_extension_references.add_child(resource_extension_reference)
683
+ else
684
+ resource_extension_references.last.add_child(resource_extension_reference)
685
+ end
686
+
687
+ roleXML.add_child(resource_extension_references) if add_resource_extension_references
688
+
689
+ add_provision_guest_agent = roleXML.at_css('ProvisionGuestAgent').nil?
690
+
691
+ if add_provision_guest_agent
692
+ provision_guest_agent = Nokogiri::XML::Node.new('ProvisionGuestAgent', roleXML)
693
+ provision_guest_agent.content = true
694
+ else
695
+ provision_guest_agent = roleXML.css('ProvisionGuestAgent')
696
+ provision_guest_agent.first.content = true
697
+ end
698
+
699
+ roleXML.add_child(provision_guest_agent) if add_provision_guest_agent
700
+ else ## raise error as Chef Extension is already installed on the server
701
+ raise "Chef Extension is already installed on the server #{params[:azure_vm_name]}."
702
+ end
703
+
704
+ roleXML
705
+ end
706
+
707
+ def update(name, params, roleXML)
708
+ puts "Updating server role..."
709
+ servicecall = "hostedservices/#{params[:azure_dns_name]}" +
710
+ "/deployments/#{params[:deploy_name]}/roles/#{name}"
711
+ ret_val = @connection.query_azure(servicecall, 'put', roleXML, '', true, true, 'application/xml')
712
+ error_code, error_message = error_from_response_xml(ret_val)
713
+ if error_code.length > 0
714
+ Chef::Log.debug(ret_val.to_s)
715
+ raise 'Unable to update role:' + error_code + ' : ' + error_message
716
+ end
717
+ end
550
718
  end
551
719
  end