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.
- checksums.yaml +4 -4
- data/README.md +304 -8
- data/lib/azure/azure_interface.rb +81 -0
- data/lib/azure/custom_errors.rb +35 -0
- data/lib/azure/helpers.rb +44 -0
- data/lib/azure/resource_management/ARM_base.rb +29 -0
- data/lib/azure/resource_management/ARM_deployment_template.rb +561 -0
- data/lib/azure/resource_management/ARM_interface.rb +795 -0
- data/lib/azure/resource_management/windows_credentials.rb +136 -0
- data/lib/azure/service_management/ASM_interface.rb +301 -0
- data/lib/azure/{ag.rb → service_management/ag.rb} +2 -2
- data/lib/azure/{certificate.rb → service_management/certificate.rb} +2 -2
- data/lib/azure/service_management/connection.rb +102 -0
- data/lib/azure/{deploy.rb → service_management/deploy.rb} +8 -2
- data/lib/azure/{disk.rb → service_management/disk.rb} +2 -2
- data/lib/azure/{host.rb → service_management/host.rb} +2 -2
- data/lib/azure/{image.rb → service_management/image.rb} +2 -2
- data/lib/azure/{loadbalancer.rb → service_management/loadbalancer.rb} +4 -18
- data/lib/azure/{rest.rb → service_management/rest.rb} +15 -10
- data/lib/azure/{role.rb → service_management/role.rb} +174 -6
- data/lib/azure/{storageaccount.rb → service_management/storageaccount.rb} +2 -2
- data/lib/azure/{utility.rb → service_management/utility.rb} +0 -0
- data/lib/azure/{vnet.rb → service_management/vnet.rb} +2 -2
- data/lib/chef/knife/azure_ag_create.rb +3 -6
- data/lib/chef/knife/azure_ag_list.rb +2 -16
- data/lib/chef/knife/azure_base.rb +89 -22
- data/lib/chef/knife/azure_image_list.rb +3 -7
- data/lib/chef/knife/azure_internal-lb_create.rb +2 -5
- data/lib/chef/knife/azure_internal-lb_list.rb +2 -16
- data/lib/chef/knife/azure_server_create.rb +122 -501
- data/lib/chef/knife/azure_server_delete.rb +15 -38
- data/lib/chef/knife/azure_server_list.rb +2 -27
- data/lib/chef/knife/azure_server_show.rb +4 -60
- data/lib/chef/knife/azure_vnet_create.rb +2 -7
- data/lib/chef/knife/azure_vnet_list.rb +2 -17
- data/lib/chef/knife/azurerm_base.rb +228 -0
- data/lib/chef/knife/azurerm_server_create.rb +393 -0
- data/lib/chef/knife/azurerm_server_delete.rb +121 -0
- data/lib/chef/knife/azurerm_server_list.rb +18 -0
- data/lib/chef/knife/azurerm_server_show.rb +37 -0
- data/lib/chef/knife/bootstrap/bootstrap_options.rb +105 -0
- data/lib/chef/knife/bootstrap/bootstrapper.rb +343 -0
- data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +116 -0
- data/lib/chef/knife/bootstrap_azure.rb +110 -0
- data/lib/chef/knife/bootstrap_azurerm.rb +116 -0
- data/lib/knife-azure/version.rb +1 -2
- metadata +132 -16
- data/lib/azure/connection.rb +0 -99
@@ -0,0 +1,795 @@
|
|
1
|
+
# License:: Apache License, Version 2.0
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'azure/azure_interface'
|
17
|
+
require 'azure/resource_management/ARM_base'
|
18
|
+
require 'azure/resource_management/ARM_deployment_template'
|
19
|
+
require 'azure_mgmt_resources'
|
20
|
+
require 'azure_mgmt_compute'
|
21
|
+
require 'azure_mgmt_storage'
|
22
|
+
require 'azure_mgmt_network'
|
23
|
+
|
24
|
+
module Azure
|
25
|
+
class ResourceManagement
|
26
|
+
class ARMInterface < AzureInterface
|
27
|
+
include Azure::ARM::ARMBase
|
28
|
+
include Azure::ARM::ARMDeploymentTemplate
|
29
|
+
|
30
|
+
include Azure::ARM::Resources
|
31
|
+
include Azure::ARM::Resources::Models
|
32
|
+
|
33
|
+
include Azure::ARM::Compute
|
34
|
+
include Azure::ARM::Compute::Models
|
35
|
+
|
36
|
+
include Azure::ARM::Storage
|
37
|
+
include Azure::ARM::Storage::Models
|
38
|
+
|
39
|
+
include Azure::ARM::Network
|
40
|
+
include Azure::ARM::Network::Models
|
41
|
+
|
42
|
+
attr_accessor :connection
|
43
|
+
|
44
|
+
def initialize(params = {})
|
45
|
+
if params[:azure_client_secret]
|
46
|
+
token_provider = MsRestAzure::ApplicationTokenProvider.new(params[:azure_tenant_id], params[:azure_client_id], params[:azure_client_secret])
|
47
|
+
else
|
48
|
+
token_provider = MsRest::StringTokenProvider.new(params[:token],params[:tokentype])
|
49
|
+
end
|
50
|
+
@credentials = MsRest::TokenCredentials.new(token_provider)
|
51
|
+
@azure_subscription_id = params[:azure_subscription_id]
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
def resource_management_client
|
56
|
+
@resource_management_client ||= begin
|
57
|
+
resource_management_client = ResourceManagementClient.new(@credentials)
|
58
|
+
resource_management_client.subscription_id = @azure_subscription_id
|
59
|
+
resource_management_client
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def compute_management_client
|
64
|
+
@compute_management_client ||= begin
|
65
|
+
compute_management_client = ComputeManagementClient.new(@credentials)
|
66
|
+
compute_management_client.subscription_id = @azure_subscription_id
|
67
|
+
compute_management_client
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def storage_management_client
|
72
|
+
@storage_management_client ||= begin
|
73
|
+
storage_management_client = StorageManagementClient.new(@credentials)
|
74
|
+
storage_management_client.subscription_id = @azure_subscription_id
|
75
|
+
storage_management_client
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def network_resource_client
|
80
|
+
@network_resource_client ||= begin
|
81
|
+
network_resource_client = NetworkManagementClient.new(@credentials)
|
82
|
+
network_resource_client.subscription_id = @azure_subscription_id
|
83
|
+
network_resource_client
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def list_images
|
88
|
+
end
|
89
|
+
|
90
|
+
def list_servers(resource_group_name = nil)
|
91
|
+
begin
|
92
|
+
if resource_group_name.nil?
|
93
|
+
promise = compute_management_client.virtual_machines.list_all
|
94
|
+
else
|
95
|
+
promise = compute_management_client.virtual_machines.list(resource_group_name)
|
96
|
+
end
|
97
|
+
|
98
|
+
result = promise.value!
|
99
|
+
servers = result.body.value
|
100
|
+
|
101
|
+
cols = ['VM Name', 'Resource Group Name', 'Location', 'Provisioning State', 'OS Type']
|
102
|
+
rows = []
|
103
|
+
|
104
|
+
servers.each do |server|
|
105
|
+
rows << server.name.to_s
|
106
|
+
rows << server.id.split('/')[4].downcase
|
107
|
+
rows << server.location.to_s
|
108
|
+
rows << begin
|
109
|
+
state = server.properties.provisioning_state.to_s.downcase
|
110
|
+
case state
|
111
|
+
when 'failed'
|
112
|
+
ui.color(state, :red)
|
113
|
+
when 'succeeded'
|
114
|
+
ui.color(state, :green)
|
115
|
+
else
|
116
|
+
ui.color(state, :yellow)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
rows << server.properties.storage_profile.os_disk.os_type.to_s
|
120
|
+
end
|
121
|
+
display_list(ui, cols, rows)
|
122
|
+
rescue => error
|
123
|
+
if error.class == MsRestAzure::AzureOperationError && error.body
|
124
|
+
if error.body['error']['code']
|
125
|
+
ui.error("#{error.body['error']['message']}")
|
126
|
+
else
|
127
|
+
ui.error(error.body)
|
128
|
+
end
|
129
|
+
else
|
130
|
+
ui.error("#{error.message}")
|
131
|
+
Chef::Log.debug("#{error.backtrace.join("\n")}")
|
132
|
+
end
|
133
|
+
exit
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def delete_server(resource_group_name, vm_name)
|
138
|
+
promise = compute_management_client.virtual_machines.get(resource_group_name, vm_name)
|
139
|
+
if promise.value! && promise.value!.body.name == vm_name
|
140
|
+
puts "\n\n"
|
141
|
+
msg_pair(ui, 'VM Name', promise.value!.body.name)
|
142
|
+
msg_pair(ui, 'VM Size', promise.value!.body.properties.hardware_profile.vm_size)
|
143
|
+
msg_pair(ui, 'VM OS', promise.value!.body.properties.storage_profile.os_disk.os_type)
|
144
|
+
puts "\n"
|
145
|
+
|
146
|
+
begin
|
147
|
+
ui.confirm('Do you really want to delete this server')
|
148
|
+
rescue SystemExit # Need to handle this as confirming with N/n raises SystemExit exception
|
149
|
+
server = nil # Cleanup is implicitly performed in other cloud plugins
|
150
|
+
exit!
|
151
|
+
end
|
152
|
+
|
153
|
+
ui.info 'Deleting ..'
|
154
|
+
|
155
|
+
begin
|
156
|
+
print '.'
|
157
|
+
promise = compute_management_client.virtual_machines.delete(resource_group_name, vm_name)
|
158
|
+
end until promise.value!.body.nil?
|
159
|
+
|
160
|
+
puts "\n"
|
161
|
+
ui.warn "Deleted server #{vm_name}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def show_server(name, resource_group)
|
166
|
+
begin
|
167
|
+
server = find_server(resource_group, name)
|
168
|
+
if server
|
169
|
+
network_interface_name = server.properties.network_profile.network_interfaces[0].id.split('/')[-1]
|
170
|
+
network_interface_data = network_resource_client.network_interfaces.get(resource_group, network_interface_name).value!.body
|
171
|
+
public_ip_id_data = network_interface_data.properties.ip_configurations[0].properties.public_ipaddress
|
172
|
+
unless public_ip_id_data.nil?
|
173
|
+
public_ip_name = public_ip_id_data.id.split('/')[-1]
|
174
|
+
public_ip_data = network_resource_client.public_ipaddresses.get(resource_group, public_ip_name).value!.body
|
175
|
+
else
|
176
|
+
public_ip_data = nil
|
177
|
+
end
|
178
|
+
|
179
|
+
details = Array.new
|
180
|
+
details << ui.color('Server Name', :bold, :cyan)
|
181
|
+
details << server.name
|
182
|
+
|
183
|
+
details << ui.color('Size', :bold, :cyan)
|
184
|
+
details << server.properties.hardware_profile.vm_size
|
185
|
+
|
186
|
+
details << ui.color('Provisioning State', :bold, :cyan)
|
187
|
+
details << server.properties.provisioning_state
|
188
|
+
|
189
|
+
details << ui.color('Location', :bold, :cyan)
|
190
|
+
details << server.location
|
191
|
+
|
192
|
+
details << ui.color('Publisher', :bold, :cyan)
|
193
|
+
details << server.properties.storage_profile.image_reference.publisher
|
194
|
+
|
195
|
+
details << ui.color('Offer', :bold, :cyan)
|
196
|
+
details << server.properties.storage_profile.image_reference.offer
|
197
|
+
|
198
|
+
details << ui.color('Sku', :bold, :cyan)
|
199
|
+
details << server.properties.storage_profile.image_reference.sku
|
200
|
+
|
201
|
+
details << ui.color('Version', :bold, :cyan)
|
202
|
+
details << server.properties.storage_profile.image_reference.version
|
203
|
+
|
204
|
+
details << ui.color('OS Type', :bold, :cyan)
|
205
|
+
details << server.properties.storage_profile.os_disk.os_type
|
206
|
+
|
207
|
+
details << ui.color('Public IP address', :bold, :cyan)
|
208
|
+
unless public_ip_data.nil?
|
209
|
+
details << public_ip_data.properties.ip_address
|
210
|
+
else
|
211
|
+
details << ' -- '
|
212
|
+
end
|
213
|
+
|
214
|
+
details << ui.color('FQDN', :bold, :cyan)
|
215
|
+
unless public_ip_data.nil? or public_ip_data.properties.dns_settings.nil?
|
216
|
+
details << public_ip_data.properties.dns_settings.fqdn
|
217
|
+
else
|
218
|
+
details << ' -- '
|
219
|
+
end
|
220
|
+
|
221
|
+
puts ui.list(details, :columns_across, 2)
|
222
|
+
end
|
223
|
+
rescue => error
|
224
|
+
puts "#{error.body["error"]["message"]}"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def find_server(resource_group, name)
|
229
|
+
begin
|
230
|
+
promise = compute_management_client.virtual_machines.get(resource_group, name)
|
231
|
+
result = promise.value!
|
232
|
+
|
233
|
+
unless result.nil?
|
234
|
+
server = result.body
|
235
|
+
else
|
236
|
+
ui.error("There is no server with name #{name} or resource_group #{resource_group}. Please provide correct details.")
|
237
|
+
end
|
238
|
+
rescue => error
|
239
|
+
ui.error("#{error.body["error"]["message"]}")
|
240
|
+
end
|
241
|
+
server
|
242
|
+
end
|
243
|
+
|
244
|
+
def virtual_machine_exist?(resource_group_name, vm_name)
|
245
|
+
!compute_management_client.virtual_machines.get(resource_group_name, vm_name).value.nil?
|
246
|
+
end
|
247
|
+
|
248
|
+
def resource_group_exist?(resource_group_name)
|
249
|
+
resource_management_client.resource_groups.check_existence(resource_group_name).value!.body
|
250
|
+
end
|
251
|
+
|
252
|
+
def platform(image_reference)
|
253
|
+
@platform ||= begin
|
254
|
+
if image_reference =~ /WindowsServer.*/
|
255
|
+
platform = 'Windows'
|
256
|
+
else
|
257
|
+
platform = 'Linux'
|
258
|
+
end
|
259
|
+
platform
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def create_server(params = {})
|
264
|
+
platform(params[:azure_image_reference_offer])
|
265
|
+
# resource group creation
|
266
|
+
if resource_group_exist?(params[:azure_resource_group_name])
|
267
|
+
ui.log("INFO:Resource Group #{params[:azure_resource_group_name]} already exist. Skipping its creation.")
|
268
|
+
ui.log("INFO:Adding new VM #{params[:azure_vm_name]} to this resource group.")
|
269
|
+
else
|
270
|
+
ui.log("Creating ResourceGroup....\n\n")
|
271
|
+
resource_group = create_resource_group(params)
|
272
|
+
Chef::Log.info("ResourceGroup creation successfull.")
|
273
|
+
Chef::Log.info("Resource Group name is: #{resource_group.name}")
|
274
|
+
Chef::Log.info("Resource Group ID is: #{resource_group.id}")
|
275
|
+
end
|
276
|
+
|
277
|
+
# virtual machine creation
|
278
|
+
if virtual_machine_exist?(params[:azure_resource_group_name], params[:azure_vm_name])
|
279
|
+
ui.log("INFO:Virtual Machine #{params[:azure_vm_name]} already exist under the Resource Group #{params[:azure_resource_group_name]}. Exiting for now.")
|
280
|
+
else
|
281
|
+
params[:chef_extension_version] = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
|
282
|
+
params[:vm_size] = get_vm_size(params[:azure_vm_size])
|
283
|
+
ui.log("Creating Virtual Machine....")
|
284
|
+
deployment = create_virtual_machine_using_template(params)
|
285
|
+
ui.log("Virtual Machine creation successfull.") unless deployment.nil?
|
286
|
+
|
287
|
+
unless deployment.nil?
|
288
|
+
ui.log("Deployment name is: #{deployment.name}")
|
289
|
+
ui.log("Deployment ID is: #{deployment.id}")
|
290
|
+
deployment.properties.dependencies.each do |deploy|
|
291
|
+
if deploy.resource_type == "Microsoft.Compute/virtualMachines"
|
292
|
+
ui.log("VM Details ...")
|
293
|
+
ui.log("-------------------------------")
|
294
|
+
ui.log("Virtual Machine name is: #{deploy.resource_name}")
|
295
|
+
ui.log("Virtual Machine ID is: #{deploy.id}")
|
296
|
+
show_server(deploy.resource_name, params[:azure_resource_group_name])
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def vm_details(virtual_machine, vm_extension, params)
|
304
|
+
vm_details = OpenStruct.new
|
305
|
+
vm_details.publicipaddress = vm_public_ip(params)
|
306
|
+
|
307
|
+
if @platform == 'Windows'
|
308
|
+
vm_details.rdpport = vm_default_port(params)
|
309
|
+
else
|
310
|
+
vm_details.sshport = vm_default_port(params)
|
311
|
+
end
|
312
|
+
|
313
|
+
vm_details.id = virtual_machine.id
|
314
|
+
vm_details.name = virtual_machine.name
|
315
|
+
vm_details.locationname = params[:azure_service_location].gsub(/[ ]/,'').downcase
|
316
|
+
vm_details.ostype = virtual_machine.properties.storage_profile.os_disk.os_type
|
317
|
+
vm_details.provisioningstate = virtual_machine.properties.provisioning_state
|
318
|
+
vm_details.resources = OpenStruct.new
|
319
|
+
vm_details.resources.id = vm_extension.id
|
320
|
+
vm_details.resources.name = vm_extension.name
|
321
|
+
vm_details.resources.publisher = vm_extension.properties.publisher
|
322
|
+
vm_details.resources.type = vm_extension.properties.type
|
323
|
+
vm_details.resources.type_handler_version = vm_extension.properties.type_handler_version
|
324
|
+
vm_details.resources.provisioning_state = vm_extension.properties.provisioning_state
|
325
|
+
|
326
|
+
vm_details
|
327
|
+
end
|
328
|
+
|
329
|
+
def vm_public_ip(params = {})
|
330
|
+
network_resource_client.public_ipaddresses.get(
|
331
|
+
params[:azure_resource_group_name],
|
332
|
+
params[:azure_vm_name]
|
333
|
+
).value!.body.properties.ip_address
|
334
|
+
end
|
335
|
+
|
336
|
+
def vm_default_port(params = {})
|
337
|
+
network_resource_client.network_security_groups.get(
|
338
|
+
params[:azure_resource_group_name],
|
339
|
+
params[:azure_vm_name]
|
340
|
+
).value!.body.properties.security_rules[0].properties.destination_port_range
|
341
|
+
end
|
342
|
+
|
343
|
+
def create_resource_group(params = {})
|
344
|
+
resource_group = ResourceGroup.new()
|
345
|
+
resource_group.name = params[:azure_resource_group_name]
|
346
|
+
resource_group.location = params[:azure_service_location]
|
347
|
+
|
348
|
+
begin
|
349
|
+
resource_group = resource_management_client.resource_groups.create_or_update(resource_group.name, resource_group).value!.body
|
350
|
+
rescue Exception => e
|
351
|
+
Chef::Log.error("Failed to create the Resource Group -- exception being rescued: #{e.to_s}")
|
352
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
353
|
+
Chef::Log.debug("#{backtrace_message}")
|
354
|
+
end
|
355
|
+
|
356
|
+
resource_group
|
357
|
+
end
|
358
|
+
|
359
|
+
def create_virtual_machine_using_template(params)
|
360
|
+
template = create_deployment_template(params)
|
361
|
+
parameters = create_deployment_parameters(params, @platform)
|
362
|
+
|
363
|
+
deploy_prop = DeploymentProperties.new
|
364
|
+
deploy_prop.template = template
|
365
|
+
deploy_prop.parameters = parameters
|
366
|
+
deploy_prop.mode = 'Incremental'
|
367
|
+
|
368
|
+
deploy_params = Deployment.new
|
369
|
+
deploy_params.properties = deploy_prop
|
370
|
+
|
371
|
+
deployment = resource_management_client.deployments.create_or_update(params[:azure_resource_group_name], "#{params[:azure_vm_name]}_deploy", deploy_params).value!.body
|
372
|
+
deployment
|
373
|
+
end
|
374
|
+
|
375
|
+
def create_virtual_machine(params)
|
376
|
+
os_profile = OSProfile.new
|
377
|
+
os_profile.computer_name = params[:azure_vm_name]
|
378
|
+
os_profile.secrets = []
|
379
|
+
|
380
|
+
if @platform == 'Windows'
|
381
|
+
windows_config = WindowsConfiguration.new
|
382
|
+
windows_config.provision_vmagent = true
|
383
|
+
windows_config.enable_automatic_updates = true
|
384
|
+
|
385
|
+
os_profile.admin_username = params[:winrm_user]
|
386
|
+
os_profile.admin_password = params[:admin_password]
|
387
|
+
os_profile.windows_configuration = windows_config
|
388
|
+
else
|
389
|
+
linux_config = LinuxConfiguration.new
|
390
|
+
linux_config.disable_password_authentication = false
|
391
|
+
|
392
|
+
os_profile.admin_username = params[:ssh_user]
|
393
|
+
os_profile.admin_password = params[:ssh_password]
|
394
|
+
os_profile.linux_configuration = linux_config
|
395
|
+
end
|
396
|
+
|
397
|
+
hardware_profile = HardwareProfile.new
|
398
|
+
hardware_profile.vm_size = get_vm_size(params[:azure_vm_size])
|
399
|
+
|
400
|
+
vm_props = VirtualMachineProperties.new
|
401
|
+
vm_props.os_profile = os_profile
|
402
|
+
vm_props.hardware_profile = hardware_profile
|
403
|
+
vm_props.storage_profile = create_storage_profile(params)
|
404
|
+
vm_props.network_profile = create_network_profile(params)
|
405
|
+
|
406
|
+
vm_params = VirtualMachine.new
|
407
|
+
vm_params.name = params[:azure_vm_name]
|
408
|
+
vm_params.type = 'Microsoft.Compute/virtualMachines'
|
409
|
+
vm_params.properties = vm_props
|
410
|
+
vm_params.location = params[:azure_service_location]
|
411
|
+
|
412
|
+
begin
|
413
|
+
virtual_machine = compute_management_client.virtual_machines.create_or_update(params[:azure_resource_group_name], vm_params.name, vm_params).value!.body
|
414
|
+
rescue Exception => e
|
415
|
+
ui.log("Failed to create the virtual machine, use verbose mode for more details")
|
416
|
+
Chef::Log.error("Failed to create the Virtual Machine -- exception being rescued: #{e.to_s}")
|
417
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
418
|
+
Chef::Log.debug("#{backtrace_message}")
|
419
|
+
end
|
420
|
+
|
421
|
+
virtual_machine
|
422
|
+
end
|
423
|
+
|
424
|
+
def create_storage_profile(params)
|
425
|
+
ui.log("Creating Storage Account.... \n\n ")
|
426
|
+
storage_account = create_storage_account(
|
427
|
+
params[:azure_storage_account],
|
428
|
+
params[:azure_service_location],
|
429
|
+
params[:azure_storage_account_type],
|
430
|
+
params[:azure_resource_group_name]
|
431
|
+
)
|
432
|
+
|
433
|
+
virtual_hard_disk = get_vhd(
|
434
|
+
params[:azure_storage_account],
|
435
|
+
params[:azure_os_disk_name]
|
436
|
+
)
|
437
|
+
|
438
|
+
ui.log("StorageAccount creation successfull.")
|
439
|
+
storage_profile = StorageProfile.new
|
440
|
+
storage_profile.image_reference = get_image_reference(
|
441
|
+
params[:azure_image_reference_publisher],
|
442
|
+
params[:azure_image_reference_offer],
|
443
|
+
params[:azure_image_reference_sku],
|
444
|
+
params[:azure_image_reference_version]
|
445
|
+
)
|
446
|
+
storage_profile.os_disk = get_os_disk(
|
447
|
+
virtual_hard_disk,
|
448
|
+
params[:azure_os_disk_name],
|
449
|
+
params[:azure_os_disk_caching],
|
450
|
+
params[:azure_os_disk_create_option]
|
451
|
+
)
|
452
|
+
|
453
|
+
storage_profile
|
454
|
+
end
|
455
|
+
|
456
|
+
def create_storage_account(storage_account_name, location, storage_account_type, resource_group_name)
|
457
|
+
storage_props = Azure::ARM::Storage::Models::StorageAccountPropertiesCreateParameters.new
|
458
|
+
storage_props.account_type = storage_account_type
|
459
|
+
|
460
|
+
storage_params = Azure::ARM::Storage::Models::StorageAccountCreateParameters.new
|
461
|
+
storage_params.location = location
|
462
|
+
storage_params.properties = storage_props
|
463
|
+
|
464
|
+
storage = storage_management_client.storage_accounts.create(resource_group_name, storage_account_name, storage_params).value!.body
|
465
|
+
storage
|
466
|
+
end
|
467
|
+
|
468
|
+
def get_vhd(storage_account_name, os_disk_name)
|
469
|
+
virtual_hard_disk = VirtualHardDisk.new
|
470
|
+
virtual_hard_disk.uri = "http://#{storage_account_name}.blob.core.windows.net/vhds/#{os_disk_name}.vhd"
|
471
|
+
virtual_hard_disk
|
472
|
+
end
|
473
|
+
|
474
|
+
def get_image_reference(publisher, offer, sku, version)
|
475
|
+
image_reference = ImageReference.new
|
476
|
+
image_reference.publisher = publisher
|
477
|
+
image_reference.offer = offer
|
478
|
+
image_reference.sku = sku
|
479
|
+
image_reference.version = version
|
480
|
+
image_reference
|
481
|
+
end
|
482
|
+
|
483
|
+
def get_os_disk(virtual_hard_disk, os_disk_name, os_disk_caching, os_disk_create_option)
|
484
|
+
os_disk = OSDisk.new
|
485
|
+
os_disk.name = os_disk_name
|
486
|
+
os_disk.vhd = virtual_hard_disk
|
487
|
+
os_disk.caching = os_disk_caching
|
488
|
+
os_disk.create_option = os_disk_create_option
|
489
|
+
os_disk
|
490
|
+
end
|
491
|
+
|
492
|
+
def vnet_exist?(resource_group_name, vnet_name)
|
493
|
+
begin
|
494
|
+
network_resource_client.virtual_networks.get(resource_group_name, vnet_name).value!.body
|
495
|
+
rescue
|
496
|
+
return false
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
def subnet_exist?(resource_group_name, vnet_name, subnet_name)
|
501
|
+
begin
|
502
|
+
network_resource_client.subnets.get(resource_group_name, vnet_name, subnet_name).value!.body
|
503
|
+
rescue
|
504
|
+
return false
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
def create_network_profile(params)
|
509
|
+
if vnet_exist?(params[:azure_resource_group_name], params[:azure_vnet_name])
|
510
|
+
vnet = network_resource_client.virtual_networks.get(params[:azure_resource_group_name], params[:azure_vnet_name]).value!.body
|
511
|
+
Chef::Log.info("Found existing vnet #{vnet.name}...")
|
512
|
+
else
|
513
|
+
ui.log("Creating VirtualNetwork....\n\n")
|
514
|
+
vnet = create_virtual_network(
|
515
|
+
params[:azure_resource_group_name],
|
516
|
+
params[:azure_vnet_name],
|
517
|
+
params[:azure_service_location]
|
518
|
+
)
|
519
|
+
Chef::Log.info("VirtualNetwork creation successfull.")
|
520
|
+
end
|
521
|
+
|
522
|
+
Chef::Log.info("Virtual Network name is: #{vnet.name}")
|
523
|
+
|
524
|
+
Chef::Log.info("Virtual Network ID is: #{vnet.id}")
|
525
|
+
|
526
|
+
if subnet_exist?(params[:azure_resource_group_name], vnet.name, params[:azure_vnet_subnet_name])
|
527
|
+
sbn = network_resource_client.subnets.get(params[:azure_resource_group_name], vnet.name, params[:azure_vnet_subnet_name]).value!.body
|
528
|
+
|
529
|
+
Chef::Log.info("Found subnet #{sbn.name} under virtual network #{vnet.name} ...")
|
530
|
+
|
531
|
+
else
|
532
|
+
ui.log("Creating Subnet....\n\n")
|
533
|
+
sbn = create_subnet(
|
534
|
+
params[:azure_resource_group_name],
|
535
|
+
params[:azure_vnet_subnet_name],
|
536
|
+
vnet
|
537
|
+
)
|
538
|
+
Chef::Log.info("Subnet creation successfull.")
|
539
|
+
end
|
540
|
+
|
541
|
+
Chef::Log.info("Subnet name is: #{sbn.name}")
|
542
|
+
Chef::Log.info("Subnet ID is: #{sbn.id}")
|
543
|
+
|
544
|
+
ui.log("Creating NetworkInterface....\n\n")
|
545
|
+
nic = create_network_interface(
|
546
|
+
params[:azure_resource_group_name],
|
547
|
+
params[:azure_vm_name],
|
548
|
+
params[:azure_service_location],
|
549
|
+
sbn
|
550
|
+
)
|
551
|
+
Chef::Log.info("NetworkInterface creation successfull.")
|
552
|
+
Chef::Log.info("Network Interface name is: #{nic.name}")
|
553
|
+
Chef::Log.info("Network Interface ID is: #{nic.id}")
|
554
|
+
|
555
|
+
network_profile = NetworkProfile.new
|
556
|
+
network_profile.network_interfaces = [nic]
|
557
|
+
network_profile
|
558
|
+
end
|
559
|
+
|
560
|
+
def create_virtual_network(resource_group_name, virtual_network_name, service_location)
|
561
|
+
address_space = AddressSpace.new
|
562
|
+
address_space.address_prefixes = ['10.0.0.0/16']
|
563
|
+
|
564
|
+
vnet_props = VirtualNetworkPropertiesFormat.new
|
565
|
+
vnet_props.address_space = address_space
|
566
|
+
|
567
|
+
vnet_params = VirtualNetwork.new
|
568
|
+
vnet_params.name = virtual_network_name
|
569
|
+
vnet_params.location = service_location
|
570
|
+
vnet_params.properties = vnet_props
|
571
|
+
|
572
|
+
begin
|
573
|
+
vnet = network_resource_client.virtual_networks.create_or_update(resource_group_name, vnet_params.name, vnet_params).value!.body
|
574
|
+
rescue Exception => e
|
575
|
+
Chef::Log.error("Failed to create the Virtual Network -- exception being rescued: #{e.to_s}")
|
576
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
577
|
+
Chef::Log.debug("#{backtrace_message}")
|
578
|
+
end
|
579
|
+
vnet
|
580
|
+
end
|
581
|
+
|
582
|
+
def create_subnet(resource_group_name, subnet_name, virtual_network)
|
583
|
+
sbn_prop = SubnetPropertiesFormat.new
|
584
|
+
sbn_prop.address_prefix = '10.0.1.0/24'
|
585
|
+
|
586
|
+
sbn_params = Subnet.new
|
587
|
+
sbn_params.name = subnet_name
|
588
|
+
sbn_params.properties = sbn_prop
|
589
|
+
|
590
|
+
begin
|
591
|
+
sbn = network_resource_client.subnets.create_or_update(resource_group_name, virtual_network.name, sbn_params.name, sbn_params).value!.body
|
592
|
+
rescue Exception => e
|
593
|
+
Chef::Log.error("Failed to create the Subnet -- exception being rescued: #{e.to_s}")
|
594
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
595
|
+
Chef::Log.debug("#{backtrace_message}")
|
596
|
+
end
|
597
|
+
sbn
|
598
|
+
end
|
599
|
+
|
600
|
+
def create_network_interface(resource_group_name, vm_name, service_location, subnet)
|
601
|
+
network_ip_configuration_properties = NetworkInterfaceIPConfigurationPropertiesFormat.new
|
602
|
+
network_ip_configuration_properties.private_ipallocation_method = 'Dynamic'
|
603
|
+
|
604
|
+
network_ip_configuration_properties.public_ipaddress = create_public_ip_config(
|
605
|
+
resource_group_name,
|
606
|
+
vm_name,
|
607
|
+
service_location
|
608
|
+
)
|
609
|
+
|
610
|
+
network_ip_configuration_properties.subnet = subnet
|
611
|
+
|
612
|
+
network_interface_ip_configuration = NetworkInterfaceIPConfiguration.new
|
613
|
+
network_interface_ip_configuration.properties = network_ip_configuration_properties
|
614
|
+
network_interface_ip_configuration.name = vm_name
|
615
|
+
|
616
|
+
network_interface_props_format = NetworkInterfacePropertiesFormat.new
|
617
|
+
network_interface_props_format.ip_configurations = [network_interface_ip_configuration]
|
618
|
+
network_interface_props_format.network_security_group = create_network_security_group(
|
619
|
+
resource_group_name,
|
620
|
+
vm_name,
|
621
|
+
service_location
|
622
|
+
)
|
623
|
+
|
624
|
+
network_interface = NetworkInterface.new
|
625
|
+
network_interface.location = service_location
|
626
|
+
network_interface.name = vm_name
|
627
|
+
network_interface.properties = network_interface_props_format
|
628
|
+
|
629
|
+
begin
|
630
|
+
nic = network_resource_client.network_interfaces.create_or_update(resource_group_name, network_interface.name, network_interface).value!.body
|
631
|
+
rescue Exception => e
|
632
|
+
Chef::Log.error("Failed to create the Network Interface -- exception being rescued: #{e.to_s}")
|
633
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
634
|
+
Chef::Log.debug("#{backtrace_message}")
|
635
|
+
end
|
636
|
+
|
637
|
+
nic
|
638
|
+
end
|
639
|
+
|
640
|
+
def create_public_ip_config(resource_group_name, vm_name, service_location)
|
641
|
+
public_ip_props = PublicIPAddressPropertiesFormat.new
|
642
|
+
public_ip_props.public_ipallocation_method = 'Dynamic'
|
643
|
+
|
644
|
+
public_ip = PublicIPAddress.new
|
645
|
+
public_ip.name = vm_name
|
646
|
+
public_ip.location = service_location
|
647
|
+
public_ip.properties = public_ip_props
|
648
|
+
|
649
|
+
begin
|
650
|
+
public_ip_address = network_resource_client.public_ipaddresses.create_or_update(
|
651
|
+
resource_group_name,
|
652
|
+
public_ip.name,
|
653
|
+
public_ip
|
654
|
+
).value!.body
|
655
|
+
rescue Exception => e
|
656
|
+
Chef::Log.error("Failed to create the Public IP Address -- exception being rescued: #{e.to_s}")
|
657
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
658
|
+
Chef::Log.debug("#{backtrace_message}")
|
659
|
+
end
|
660
|
+
|
661
|
+
public_ip_address
|
662
|
+
end
|
663
|
+
|
664
|
+
def create_network_security_group(resource_group_name, vm_name, service_location)
|
665
|
+
network_security_group_prop_format = NetworkSecurityGroupPropertiesFormat.new
|
666
|
+
network_security_group = NetworkSecurityGroup.new
|
667
|
+
network_security_group.name = vm_name
|
668
|
+
network_security_group.location = service_location
|
669
|
+
network_security_group.properties = network_security_group_prop_format
|
670
|
+
|
671
|
+
begin
|
672
|
+
nsg = network_resource_client.network_security_groups.create_or_update(
|
673
|
+
resource_group_name,
|
674
|
+
network_security_group.name,
|
675
|
+
network_security_group
|
676
|
+
).value!.body
|
677
|
+
rescue Exception => e
|
678
|
+
Chef::Log.error("Failed to create the Network Security Group -- exception being rescued: #{e.to_s}")
|
679
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
680
|
+
Chef::Log.debug("#{backtrace_message}")
|
681
|
+
end
|
682
|
+
|
683
|
+
security_rules = []
|
684
|
+
if @platform == 'Windows'
|
685
|
+
security_rules << add_security_rule('3389', "RDP", 1000, resource_group_name, vm_name, network_security_group)
|
686
|
+
else
|
687
|
+
security_rules << add_security_rule("22", "SSH", 1000, resource_group_name, vm_name, network_security_group)
|
688
|
+
end
|
689
|
+
network_security_group_prop_format.default_security_rules = security_rules
|
690
|
+
|
691
|
+
nsg
|
692
|
+
end
|
693
|
+
|
694
|
+
def add_security_rule(port, description, priority, resource_group_name, vm_name, network_security_group)
|
695
|
+
security_rule_props = SecurityRulePropertiesFormat.new
|
696
|
+
security_rule_props.description = description
|
697
|
+
security_rule_props.destination_port_range = port
|
698
|
+
security_rule_props.protocol = "Tcp"
|
699
|
+
security_rule_props.source_port_range = "*"
|
700
|
+
security_rule_props.source_address_prefix = "*"
|
701
|
+
security_rule_props.destination_address_prefix = "*"
|
702
|
+
security_rule_props.access = "Allow"
|
703
|
+
security_rule_props.priority = priority
|
704
|
+
security_rule_props.direction = "Inbound"
|
705
|
+
|
706
|
+
security_rule = SecurityRule.new
|
707
|
+
security_rule.name = vm_name
|
708
|
+
security_rule.properties = security_rule_props
|
709
|
+
|
710
|
+
begin
|
711
|
+
security_rule = network_resource_client.security_rules.create_or_update(
|
712
|
+
resource_group_name,
|
713
|
+
network_security_group.name,
|
714
|
+
security_rule.name,
|
715
|
+
security_rule
|
716
|
+
).value!.body
|
717
|
+
rescue Exception => e
|
718
|
+
Chef::Log.error("Failed to create the Security Rule -- exception being rescued: #{e.to_s}")
|
719
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
720
|
+
Chef::Log.debug("#{backtrace_message}")
|
721
|
+
end
|
722
|
+
|
723
|
+
security_rule
|
724
|
+
end
|
725
|
+
|
726
|
+
def create_vm_extension(params)
|
727
|
+
vm_ext_props = VirtualMachineExtensionProperties.new
|
728
|
+
vm_ext_props.publisher = params[:chef_extension_publisher]
|
729
|
+
vm_ext_props.type = params[:chef_extension]
|
730
|
+
vm_ext_props.type_handler_version = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
|
731
|
+
vm_ext_props.auto_upgrade_minor_version = false
|
732
|
+
vm_ext_props.settings = params[:chef_extension_public_param]
|
733
|
+
vm_ext_props.protected_settings = params[:chef_extension_private_param]
|
734
|
+
|
735
|
+
vm_ext = VirtualMachineExtension.new
|
736
|
+
vm_ext.name = params[:chef_extension]
|
737
|
+
vm_ext.location = params[:azure_service_location]
|
738
|
+
vm_ext.properties = vm_ext_props
|
739
|
+
|
740
|
+
begin
|
741
|
+
vm_extension = compute_management_client.virtual_machine_extensions.create_or_update(
|
742
|
+
params[:azure_resource_group_name],
|
743
|
+
params[:azure_vm_name],
|
744
|
+
vm_ext.name,
|
745
|
+
vm_ext
|
746
|
+
).value!.body
|
747
|
+
rescue Exception => e
|
748
|
+
Chef::Log.error("Failed to create the Virtual Machine Extension -- exception being rescued.")
|
749
|
+
|
750
|
+
if e.class == MsRestAzure::AzureOperationError && e.body
|
751
|
+
if e.body['error']['code'] == 'DeploymentFailed'
|
752
|
+
ui.error("#{error.body['error']['message']}")
|
753
|
+
else
|
754
|
+
ui.error(e.body)
|
755
|
+
end
|
756
|
+
else
|
757
|
+
ui.error("#{error.message}")
|
758
|
+
Chef::Log.debug("#{error.backtrace.join("\n")}")
|
759
|
+
end
|
760
|
+
|
761
|
+
backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
762
|
+
Chef::Log.debug("#{backtrace_message}")
|
763
|
+
end
|
764
|
+
|
765
|
+
vm_extension
|
766
|
+
end
|
767
|
+
|
768
|
+
def extension_already_installed?(server)
|
769
|
+
server.resources.each do |extension|
|
770
|
+
return true if (extension.properties.type == "ChefClient" || extension.properties.type == "LinuxChefClient")
|
771
|
+
end if server.resources
|
772
|
+
false
|
773
|
+
end
|
774
|
+
|
775
|
+
def get_latest_chef_extension_version(params)
|
776
|
+
ext_version = compute_management_client.virtual_machine_extension_images.list_versions(
|
777
|
+
params[:azure_service_location],
|
778
|
+
params[:chef_extension_publisher],
|
779
|
+
params[:chef_extension]).value!.body.last.name
|
780
|
+
ext_version_split_values = ext_version.split(".")
|
781
|
+
ext_version = ext_version_split_values[0] + "." + ext_version_split_values[1]
|
782
|
+
ext_version
|
783
|
+
end
|
784
|
+
|
785
|
+
def delete_resource_group(resource_group_name)
|
786
|
+
ui.info 'Resource group deletion takes some time. Please wait ...'
|
787
|
+
begin
|
788
|
+
print '.'
|
789
|
+
promise = resource_management_client.resource_groups.delete(resource_group_name)
|
790
|
+
end until promise.value!.body.nil?
|
791
|
+
puts "\n"
|
792
|
+
end
|
793
|
+
end
|
794
|
+
end
|
795
|
+
end
|