chef-provisioning-azure 0.5.0 → 0.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.
@@ -1,62 +1,62 @@
1
- require 'chef/provisioning/machine_options'
2
- require 'chef/provisioning/azure_driver/constants'
1
+ require "chef/provisioning/machine_options"
2
+ require "chef/provisioning/azure_driver/constants"
3
3
 
4
4
  # Chef Provisioning Azure driver
5
5
  class Chef
6
- module Provisioning
7
- module AzureDriver
8
- # Represents available machine provisioning options for Azure
9
- # These are used to tell Azure how to construct a new VM
10
- class MachineOptions < Chef::Provisioning::MachineOptions
11
- # @return [String] Storage account name.
12
- attr_accessor :storage_account_name
6
+ module Provisioning
7
+ module AzureDriver
8
+ # Represents available machine provisioning options for Azure
9
+ # These are used to tell Azure how to construct a new VM
10
+ class MachineOptions < Chef::Provisioning::MachineOptions
11
+ # @return [String] Storage account name.
12
+ attr_accessor :storage_account_name
13
13
 
14
- # @return [String] WinRM transport mechanism ("http", or "https").
15
- # Defaults to "http".
16
- attr_accessor :winrm_transport
14
+ # @return [String] WinRM transport mechanism ("http", or "https").
15
+ # Defaults to "http".
16
+ attr_accessor :winrm_transport
17
17
 
18
- # @return [String] Cloud service name.
19
- attr_accessor :cloud_service_name
18
+ # @return [String] Cloud service name.
19
+ attr_accessor :cloud_service_name
20
20
 
21
- # @return [String] Deployment name.
22
- attr_accessor :deployment_name
21
+ # @return [String] Deployment name.
22
+ attr_accessor :deployment_name
23
23
 
24
- # @return [Array] Array of ports to enable.
25
- # Can be in +port+ or +src:dest+ format.
26
- attr_accessor :tcp_endpoints
24
+ # @return [Array] Array of ports to enable.
25
+ # Can be in +port+ or +src:dest+ format.
26
+ attr_accessor :tcp_endpoints
27
27
 
28
- # @return [Pathname] Path to the private key.
29
- attr_accessor :private_key_file
28
+ # @return [Pathname] Path to the private key.
29
+ attr_accessor :private_key_file
30
30
 
31
- # @return [Pathname] Path to the certificate file.
32
- attr_accessor :certificate_file
31
+ # @return [Pathname] Path to the certificate file.
32
+ attr_accessor :certificate_file
33
33
 
34
- # @return [Integer] The SSH port to listen on.
35
- # Defaults to 22
36
- attr_accessor :ssh_port
34
+ # @return [Integer] The SSH port to listen on.
35
+ # Defaults to 22
36
+ attr_accessor :ssh_port
37
37
 
38
- # @return [Chef::Provisioning::AzureDriver::Constants::MachineSize] The Azure machine size.
39
- attr_accessor :vm_size
38
+ # @return [Chef::Provisioning::AzureDriver::Constants::MachineSize] The Azure machine size.
39
+ attr_accessor :vm_size
40
40
 
41
- # @return [String] Name of the affinity group being used.
42
- attr_accessor :affinity_group_name
41
+ # @return [String] Name of the affinity group being used.
42
+ attr_accessor :affinity_group_name
43
43
 
44
- # @return [String] Virtual network name.
45
- attr_accessor :virtual_network_name
44
+ # @return [String] Virtual network name.
45
+ attr_accessor :virtual_network_name
46
46
 
47
- # @return [String] Subnet name.
48
- attr_accessor :subnet_name
47
+ # @return [String] Subnet name.
48
+ attr_accessor :subnet_name
49
49
 
50
- # @return [String] Availability set name.
51
- attr_accessor :availability_set_name
50
+ # @return [String] Availability set name.
51
+ attr_accessor :availability_set_name
52
52
 
53
- def initialize
54
- # Set defaults
55
- self.winrm_transport = 'http'
56
- self.ssh_port = 22
57
- end
53
+ def initialize
54
+ # Set defaults
55
+ self.winrm_transport = "http"
56
+ self.ssh_port = 22
57
+ end
58
58
 
59
+ end
60
+ end
59
61
  end
60
62
  end
61
- end
62
- end
@@ -1,4 +1,4 @@
1
- resources = %w(storage_account cloud_service sql_server)
1
+ resources = %w{storage_account cloud_service sql_server}
2
2
 
3
3
  resources.each do |r|
4
4
  Chef::Log.debug("Loading resource: #{r}")
@@ -1,222 +1,222 @@
1
- require 'inifile'
2
- require 'json'
3
- require 'nokogiri'
1
+ require "inifile"
2
+ require "json"
3
+ require "nokogiri"
4
4
 
5
5
  class Chef
6
- module Provisioning
7
- module AzureDriver
8
- module Subscriptions
9
-
10
- #
11
- # Get the subscription with the given subscription_id or subscription_name
12
- #
13
- # Returns `nil` if nothing found.
14
- #
15
- def self.get_subscription(config, subscription_id_or_name)
16
- subscription_count = 0
17
- subscription = all_subscriptions(config).select do |s|
18
- subscription_count += 1
19
- s[:subscription_id] == subscription_id_or_name ||
20
- s[:subscription_name] == subscription_id_or_name
21
- end.first
22
- if !subscription
23
- Chef::Log.info("Subscription #{subscription_id_or_name} not found out of #{subscription_count} subscriptions read.")
24
- end
25
- subscription
26
- end
27
-
28
- #
29
- # Get the default subscription for the given config.
30
- #
31
- # The default subscription is either the first .azureProfile subscription with isDefault: true
32
- #
33
- def self.default_subscription(config)
34
- first_subscription = nil
35
- all_subscriptions(config).each do |subscription|
36
- if subscription[:is_default]
37
- Chef::Log.info("Picked default subscription: #{subscription[:subscription_name]} (#{subscription[:subscription_id]}) from #{subscription[:source]}")
38
- return subscription
39
- end
40
-
41
- first_subscription ||= subscription;
42
- end
43
- if first_subscription
44
- Chef::Log.info("Picked first subscription found as default: #{first_subscription[:subscription_name]} (#{first_subscription[:subscription_id]}) from #{first_subscription[:source]}")
45
- else
46
- Chef::Log.info("No subscriptions found.")
47
- end
48
- first_subscription
49
- end
50
-
51
- #
52
- # We search for subscription in the order specified by Chef::Config.azure_subscriptions,
53
- # which includes:
54
- #
55
- # Key | Description
56
- # ------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------
57
- # `subscription_id` | The GUID of the subscription.
58
- # `subscription_name` | The name of the subscription.
59
- # `management_certificate` | The path to the actual credentials, a proc, or an IO object (optional; if this is not set, the keychain will be searched).
60
- # `management_endpoint` | The management endpoint URL (optional; if not set, the default Azure endpoint will be used).
61
- # `is_default` | If `true`, this should be considered the default subscription.
62
- # `publishsettings` | The path/glob to one or more `.publishsettings` formatted files, an IO object, or a hash with one or more { type: <path|io> } keys, where type=:pem, :pdx or :cert.
63
- # `azure_profile` | The path/glob to one or more `azureProfile.json` formatted files, an IO object, or a Hash representing the parsed data.
64
- # `allow_missing_file` | If `true`, provisioning will skip the publishsettings or azure_profile if it does not exist; otherwise it will raise an error on missing file. Defaults to `false`.
65
- #
66
- def self.all_subscriptions(config)
67
- Enumerator.new do |y|
68
- subscriptions = config[:azure_subscriptions]
69
- subscriptions ||= default_subscriptions(config)
70
- subscriptions = [ subscriptions ].flatten
71
-
72
- subscriptions.each do |subscription_spec|
73
- allow_missing_file = subscription_spec[:allow_missing_file]
74
- if subscription_spec[:subscription_id]
75
- subscription = {
76
- management_endpoint: default_management_endpoint(config),
77
- source: "Chef configuration"
78
- }
79
- y.yield subscription.merge(subscription_spec)
6
+ module Provisioning
7
+ module AzureDriver
8
+ module Subscriptions
9
+
10
+ #
11
+ # Get the subscription with the given subscription_id or subscription_name
12
+ #
13
+ # Returns `nil` if nothing found.
14
+ #
15
+ def self.get_subscription(config, subscription_id_or_name)
16
+ subscription_count = 0
17
+ subscription = all_subscriptions(config).select do |s|
18
+ subscription_count += 1
19
+ s[:subscription_id] == subscription_id_or_name ||
20
+ s[:subscription_name] == subscription_id_or_name
21
+ end.first
22
+ if !subscription
23
+ Chef::Log.info("Subscription #{subscription_id_or_name} not found out of #{subscription_count} subscriptions read.")
24
+ end
25
+ subscription
80
26
  end
81
- if subscription_spec[:publishsettings]
82
- load_publishsettings_subscriptions(config, subscription_spec[:publishsettings], allow_missing_file) do |subscription|
83
- y.yield subscription.merge(subscription_spec)
27
+
28
+ #
29
+ # Get the default subscription for the given config.
30
+ #
31
+ # The default subscription is either the first .azureProfile subscription with isDefault: true
32
+ #
33
+ def self.default_subscription(config)
34
+ first_subscription = nil
35
+ all_subscriptions(config).each do |subscription|
36
+ if subscription[:is_default]
37
+ Chef::Log.info("Picked default subscription: #{subscription[:subscription_name]} (#{subscription[:subscription_id]}) from #{subscription[:source]}")
38
+ return subscription
39
+ end
40
+
41
+ first_subscription ||= subscription;
42
+ end
43
+ if first_subscription
44
+ Chef::Log.info("Picked first subscription found as default: #{first_subscription[:subscription_name]} (#{first_subscription[:subscription_id]}) from #{first_subscription[:source]}")
45
+ else
46
+ Chef::Log.info("No subscriptions found.")
84
47
  end
48
+ first_subscription
85
49
  end
86
- if subscription_spec[:azure_profile]
87
- load_azure_profile_subscriptions(config, subscription_spec[:azure_profile], allow_missing_file) do |subscription|
88
- y.yield subscription.merge(subscription_spec)
50
+
51
+ #
52
+ # We search for subscription in the order specified by Chef::Config.azure_subscriptions,
53
+ # which includes:
54
+ #
55
+ # Key | Description
56
+ # ------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------
57
+ # `subscription_id` | The GUID of the subscription.
58
+ # `subscription_name` | The name of the subscription.
59
+ # `management_certificate` | The path to the actual credentials, a proc, or an IO object (optional; if this is not set, the keychain will be searched).
60
+ # `management_endpoint` | The management endpoint URL (optional; if not set, the default Azure endpoint will be used).
61
+ # `is_default` | If `true`, this should be considered the default subscription.
62
+ # `publishsettings` | The path/glob to one or more `.publishsettings` formatted files, an IO object, or a hash with one or more { type: <path|io> } keys, where type=:pem, :pdx or :cert.
63
+ # `azure_profile` | The path/glob to one or more `azureProfile.json` formatted files, an IO object, or a Hash representing the parsed data.
64
+ # `allow_missing_file` | If `true`, provisioning will skip the publishsettings or azure_profile if it does not exist; otherwise it will raise an error on missing file. Defaults to `false`.
65
+ #
66
+ def self.all_subscriptions(config)
67
+ Enumerator.new do |y|
68
+ subscriptions = config[:azure_subscriptions]
69
+ subscriptions ||= default_subscriptions(config)
70
+ subscriptions = [ subscriptions ].flatten
71
+
72
+ subscriptions.each do |subscription_spec|
73
+ allow_missing_file = subscription_spec[:allow_missing_file]
74
+ if subscription_spec[:subscription_id]
75
+ subscription = {
76
+ management_endpoint: default_management_endpoint(config),
77
+ source: "Chef configuration",
78
+ }
79
+ y.yield subscription.merge(subscription_spec)
80
+ end
81
+ if subscription_spec[:publishsettings]
82
+ load_publishsettings_subscriptions(config, subscription_spec[:publishsettings], allow_missing_file) do |subscription|
83
+ y.yield subscription.merge(subscription_spec)
84
+ end
85
+ end
86
+ if subscription_spec[:azure_profile]
87
+ load_azure_profile_subscriptions(config, subscription_spec[:azure_profile], allow_missing_file) do |subscription|
88
+ y.yield subscription.merge(subscription_spec)
89
+ end
90
+ end
91
+ end
89
92
  end
90
93
  end
91
- end
92
- end
93
- end
94
94
 
95
- def self.load_publishsettings_subscriptions(config, data, allow_missing_file, filename=nil, &block)
96
- case data
97
- when String
98
- found = false
99
- Dir.glob(data) do |filename|
100
- found = true
101
- Chef::Log.info("Reading publishsettings file #{filename}")
102
- File.open(filename) do |f|
103
- load_publishsettings_subscriptions(config, f, allow_missing_file, filename, &block)
95
+ def self.load_publishsettings_subscriptions(config, data, allow_missing_file, filename = nil, &block)
96
+ case data
97
+ when String
98
+ found = false
99
+ Dir.glob(data) do |filename|
100
+ found = true
101
+ Chef::Log.info("Reading publishsettings file #{filename}")
102
+ File.open(filename) do |f|
103
+ load_publishsettings_subscriptions(config, f, allow_missing_file, filename, &block)
104
+ end
105
+ end
106
+ if !found
107
+ if allow_missing_file
108
+ Chef::Log.info("Skipping missing publishsettings file #{data}.")
109
+ else
110
+ raise "Missing publishsettings file #{data}!"
111
+ end
112
+ end
113
+
114
+ when IO
115
+ xml = Nokogiri::XML(data)
116
+
117
+ # Parse publishsettings content
118
+ xml.xpath("//PublishData/PublishProfile/Subscription").each do |subscription|
119
+ Chef::Log.debug("- Read subscription #{subscription['Name']} (#{subscription['Id']})")
120
+ result = {
121
+ subscription_id: subscription["Id"],
122
+ subscription_name: subscription["Name"],
123
+ management_endpoint: subscription["ServiceManagementUrl"] || default_management_endpoint(config),
124
+ source: "publishsettings #{filename ? "file #{filename}" : " IO object"}",
125
+ }
126
+ result[:publishsettings] = filename if filename
127
+ if subscription["ManagementCertificate"]
128
+ result[:management_certificate] = {
129
+ type: :pdx,
130
+ data: subscription["ManagementCertificate"],
131
+ }
132
+ end
133
+ yield result
134
+ end
135
+ else
136
+ raise "Unexpected value #{data.inspect} for publishsettings!"
137
+ end
104
138
  end
105
- end
106
- if !found
107
- if allow_missing_file
108
- Chef::Log.info("Skipping missing publishsettings file #{data}.")
109
- else
110
- raise "Missing publishsettings file #{data}!"
139
+
140
+ def self.load_azure_profile_subscriptions(config, data, allow_missing_file, filename = nil, &block)
141
+ case data
142
+ when String
143
+ found = false
144
+ Dir.glob(data) do |filename|
145
+ found = true
146
+ Chef::Log.info("Reading azure profile file #{filename}")
147
+ File.open(filename) do |f|
148
+ load_azure_profile_subscriptions(config, f, allow_missing_file, filename, &block)
149
+ end
150
+ end
151
+ if !found
152
+ if allow_missing_file
153
+ Chef::Log.info("Skipping missing azure profile file #{data}.")
154
+ else
155
+ raise "Missing azure profile file #{data}!"
156
+ end
157
+ end
158
+
159
+ when IO
160
+ profile = JSON.parse(data.read, create_additions: false)
161
+ if profile["subscriptions"]
162
+ profile["subscriptions"].each do |subscription|
163
+ Chef::Log.debug("- Read#{subscription['isDefault'] ? " default" : ""} subscription #{subscription['name']} (#{subscription['id']})")
164
+
165
+ result = {
166
+ subscription_id: subscription["id"],
167
+ subscription_name: subscription["name"],
168
+ management_endpoint: subscription["managementEndpointUrl"] || default_management_endpoint(config),
169
+ source: "azure profile #{filename ? "file #{filename}" : " IO object"}",
170
+ }
171
+ subscription[:azure_profile] = filename
172
+ if subscription["isDefault"]
173
+ result[:is_default] = true
174
+ end
175
+ if subscription["managementCertificate"] && subscription["managementCertificate"]["key"]
176
+ # Concatenate the key and cert to one .pem so the SDK will be OK with it
177
+ result[:management_certificate] = {
178
+ type: :pem,
179
+ data: "#{subscription['managementCertificate']['key']}#{subscription['managementCertificate']['cert']}",
180
+ }
181
+ end
182
+ yield result
183
+ end
184
+ else
185
+ Chef::Log.warn("Azure profile #{filename ? "file #{filename}" : data} has no subscriptions")
186
+ end
187
+
188
+ else
189
+ raise "Unexpected value #{data.inspect} for azure_profile!"
190
+ end
111
191
  end
112
- end
113
192
 
114
- when IO
115
- xml = Nokogiri::XML(data)
116
-
117
- # Parse publishsettings content
118
- xml.xpath("//PublishData/PublishProfile/Subscription").each do |subscription|
119
- Chef::Log.debug("- Read subscription #{subscription['Name']} (#{subscription['Id']})")
120
- result = {
121
- subscription_id: subscription['Id'],
122
- subscription_name: subscription['Name'],
123
- management_endpoint: subscription['ServiceManagementUrl'] || default_management_endpoint(config),
124
- source: "publishsettings #{filename ? "file #{filename}" : " IO object"}"
125
- }
126
- result[:publishsettings] = filename if filename
127
- if subscription['ManagementCertificate']
128
- result[:management_certificate] = {
129
- type: :pdx,
130
- data: subscription['ManagementCertificate']
193
+ def self.default_subscriptions(config)
194
+ default_azure_profile = self.default_azure_profile(config)
195
+ azure_publish_settings_file = Chef::Config.knife[:azure_publish_settings_file] if Chef::Config.knife
196
+ Chef::Log.debug("No Chef::Config[:driver_options][:subscriptions] found, reading environment variables AZURE_SUBSCRIPTION_ID, AZURE_MANAGEMENT_CERTIFICATE, and AZURE_MANAGEMENT_ENDPOINT,#{azure_publish_settings_file ? " then #{azure_publish_settings_file}," : ""} and then reading #{default_azure_profile}")
197
+ result = []
198
+ result << {
199
+ subscription_id: ENV["AZURE_SUBSCRIPTION_ID"],
200
+ management_certificate: ENV["AZURE_MANAGEMENT_CERTIFICATE"],
201
+ management_endpoint: ENV["AZURE_MANAGEMENT_ENDPOINT"],
202
+ source: "environment variables",
203
+ }
204
+ result << { publishsettings: azure_publish_settings_file } if azure_publish_settings_file
205
+ result << {
206
+ azure_profile: default_azure_profile,
207
+ allow_missing_file: true,
131
208
  }
209
+ result
132
210
  end
133
- yield result
134
- end
135
- else
136
- raise "Unexpected value #{data.inspect} for publishsettings!"
137
- end
138
- end
139
211
 
140
- def self.load_azure_profile_subscriptions(config, data, allow_missing_file, filename=nil, &block)
141
- case data
142
- when String
143
- found = false
144
- Dir.glob(data) do |filename|
145
- found = true
146
- Chef::Log.info("Reading azure profile file #{filename}")
147
- File.open(filename) do |f|
148
- load_azure_profile_subscriptions(config, f, allow_missing_file, filename, &block)
212
+ def self.default_management_endpoint(config)
213
+ "https://management.core.windows.net"
149
214
  end
150
- end
151
- if !found
152
- if allow_missing_file
153
- Chef::Log.info("Skipping missing azure profile file #{data}.")
154
- else
155
- raise "Missing azure profile file #{data}!"
156
- end
157
- end
158
215
 
159
- when IO
160
- profile = JSON.parse(data.read, create_additions: false)
161
- if profile["subscriptions"]
162
- profile["subscriptions"].each do |subscription|
163
- Chef::Log.debug("- Read#{subscription['isDefault'] ? " default" : ""} subscription #{subscription['name']} (#{subscription['id']})")
164
-
165
- result = {
166
- subscription_id: subscription['id'],
167
- subscription_name: subscription['name'],
168
- management_endpoint: subscription['managementEndpointUrl'] || default_management_endpoint(config),
169
- source: "azure profile #{filename ? "file #{filename}" : " IO object"}"
170
- }
171
- subscription[:azure_profile] = filename
172
- if subscription['isDefault']
173
- result[:is_default] = true
174
- end
175
- if subscription['managementCertificate'] && subscription['managementCertificate']['key']
176
- # Concatenate the key and cert to one .pem so the SDK will be OK with it
177
- result[:management_certificate] = {
178
- type: :pem,
179
- data: "#{subscription['managementCertificate']['key']}#{subscription['managementCertificate']['cert']}",
180
- }
181
- end
182
- yield result
216
+ def self.default_azure_profile(config)
217
+ File.join(config[:home_dir] || File.expand_path("~"), ".azure", "azureProfile.json")
183
218
  end
184
- else
185
- Chef::Log.warn("Azure profile #{filename ? "file #{filename}" : data} has no subscriptions")
186
219
  end
187
-
188
- else
189
- raise "Unexpected value #{data.inspect} for azure_profile!"
190
220
  end
191
221
  end
192
-
193
- def self.default_subscriptions(config)
194
- default_azure_profile = self.default_azure_profile(config)
195
- azure_publish_settings_file = Chef::Config.knife[:azure_publish_settings_file] if Chef::Config.knife
196
- Chef::Log.debug("No Chef::Config[:driver_options][:subscriptions] found, reading environment variables AZURE_SUBSCRIPTION_ID, AZURE_MANAGEMENT_CERTIFICATE, and AZURE_MANAGEMENT_ENDPOINT,#{azure_publish_settings_file ? " then #{azure_publish_settings_file}," : ""} and then reading #{default_azure_profile}")
197
- result = []
198
- result << {
199
- subscription_id: ENV["AZURE_SUBSCRIPTION_ID"],
200
- management_certificate: ENV["AZURE_MANAGEMENT_CERTIFICATE"],
201
- management_endpoint: ENV["AZURE_MANAGEMENT_ENDPOINT"],
202
- source: "environment variables"
203
- }
204
- result << { publishsettings: azure_publish_settings_file } if azure_publish_settings_file
205
- result << {
206
- azure_profile: default_azure_profile,
207
- allow_missing_file: true
208
- }
209
- result
210
- end
211
-
212
- def self.default_management_endpoint(config)
213
- 'https://management.core.windows.net'
214
- end
215
-
216
- def self.default_azure_profile(config)
217
- File.join(config[:home_dir] || File.expand_path("~"), ".azure", "azureProfile.json")
218
- end
219
- end
220
- end
221
- end
222
222
  end