knife-azure 1.6.0.rc.0 → 1.6.0

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