kitchen-azurerm 1.3.0 → 1.4.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.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/lib/kitchen/driver/azure_credentials.rb +30 -5
- data/lib/kitchen/driver/azurerm.rb +97 -31
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51b127c1a7e5d1c197dde573ce77d5e9900fe2297d12e5d8cbcd4d6d1e328ccc
|
4
|
+
data.tar.gz: d59c1a55f910f415a271a4818a8879a16e06dff3192d3d3a64d5ce1c32313e6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e21e9a0cce3a113f9d6fd9206a9272282eb1d54c637e2c9f5b629a42ccbf144889355d18db7127a7693e088d8056005139cdf142e3232ed70870c72b23db3f0
|
7
|
+
data.tar.gz: '0690d8abddf2c745c7631e463e7479299a0e1e8a83af57caca797e8555a840bc0559c383d7d703b35c7bb7ec4c65b7556a15e95cf2b4582c153f8e45d0dd97e9'
|
data/README.md
CHANGED
@@ -670,11 +670,11 @@ info: vm image list command OK
|
|
670
670
|
|
671
671
|
* The ```azure_resource_group_prefix``` and ```azure_resource_group_suffix``` can be used to further disambiguate Azure resource group names created by the driver.
|
672
672
|
|
673
|
-
* The ```explicit_resource_group_name``` and ```destroy_explicit_resource_group``` (default: "true") parameters can be used in scenarios where you are provided a pre-created Resource Group. Example usage: ```explicit_resource_group_name: kitchen-<%= ENV["USERNAME"]
|
673
|
+
* The ```explicit_resource_group_name``` and ```destroy_explicit_resource_group``` (default: "true") parameters can be used in scenarios where you are provided a pre-created Resource Group. Example usage: ```explicit_resource_group_name: kitchen-<%= ENV["USERNAME"] %>```. The ```destroy_explicit_resource_group``` option can now be used after using the ```destroy_resource_group_contents``` option creates an empty resource group to destroy the resource group previously created.
|
674
674
|
|
675
|
-
* The ```destroy_resource_group_contents``` (default: "false") parameter can be used when you want to destroy the resources within a resource group without destroying the resource group itself. For example, the following configuration options used in combination would use an existing resource group (or create one if it doesn't exist) and will destroy the contents of the resource group in the ```kitchen destroy``` phase.
|
675
|
+
* The ```destroy_resource_group_contents``` (default: "false") parameter can be used when you want to destroy the resources within a resource group without destroying the resource group itself. For example, the following configuration options used in combination would use an existing resource group (or create one if it doesn't exist) and will destroy the contents of the resource group in the ```kitchen destroy``` phase. If you wish to destroy the empty resource group created after you empty the resource group with this flag you can now set the ```destroy_explicit_resource_group``` to "true" to destroy the empty resource group.
|
676
676
|
|
677
|
-
* The ```destroy_explicit_resource_group_tags``` (default: "true") parameter can be used when you want to remove tags associated with an explicit resource group. The default setting is set to
|
677
|
+
* The ```destroy_explicit_resource_group_tags``` (default: "true") parameter can be used when you want to remove tags associated with an explicit resource group. The default setting is set to "true" to remain consistent with previous behavior. This should be used in combination with an ```explicit_resource_group_name``` and will be honored during the ```kitchen destroy``` phase.
|
678
678
|
|
679
679
|
```yaml
|
680
680
|
---
|
@@ -688,6 +688,8 @@ driver:
|
|
688
688
|
|
689
689
|
* The ```secret_url```, ```vault_name```, and ```vault_resource_group``` parameters can be used to deploy VM with specified key vault certificate.
|
690
690
|
|
691
|
+
* The ```use_fqdn_hostname``` (default: "false") parameter can be used to determine how kitchen communicates with the Virtual Machine. When true, Kitchen will use the FQDN that is assigned to the Virtual Machine. When false, kitchen will use the public IP address of the machine. This may overcome issues with Corporate firewalls or VPNs blocking Public IP addresses.
|
692
|
+
|
691
693
|
## Enabling alternative WinRM configurations
|
692
694
|
|
693
695
|
* By default on Windows machines, a PowerShell script runs that enables WinRM over the SSL transport, for Basic, Negotiate and CredSSP connections. To supply your own PowerShell script (e.g. to enable HTTP), use the `winrm_powershell_script` parameter. Windows 2008 R2 example:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "inifile"
|
2
2
|
require "kitchen/logging"
|
3
|
+
autoload :MsRest, "ms_rest"
|
3
4
|
|
4
5
|
module Kitchen
|
5
6
|
module Driver
|
@@ -60,7 +61,7 @@ module Kitchen
|
|
60
61
|
if File.file?(config_path)
|
61
62
|
IniFile.load(config_path)
|
62
63
|
else
|
63
|
-
warn "#{config_path} was not found or not accessible.
|
64
|
+
warn "#{config_path} was not found or not accessible."
|
64
65
|
{}
|
65
66
|
end
|
66
67
|
end
|
@@ -71,7 +72,7 @@ module Kitchen
|
|
71
72
|
end
|
72
73
|
|
73
74
|
def tenant_id!
|
74
|
-
tenant_id ||
|
75
|
+
tenant_id || warn("(#{config_path}) does not contain tenant_id neither is the AZURE_TENANT_ID environment variable set.")
|
75
76
|
end
|
76
77
|
|
77
78
|
def tenant_id
|
@@ -86,13 +87,37 @@ module Kitchen
|
|
86
87
|
ENV["AZURE_CLIENT_SECRET"] || credentials_property("client_secret")
|
87
88
|
end
|
88
89
|
|
90
|
+
# Retrieve a token based upon the preferred authentication method.
|
91
|
+
#
|
92
|
+
# @return [::MsRest::TokenProvider] A new token provider object.
|
89
93
|
def token_provider
|
90
|
-
|
94
|
+
# Login with a credentials file or setting the environment variables
|
95
|
+
#
|
96
|
+
# Typically used with a service principal.
|
97
|
+
#
|
98
|
+
# SPN with client_id, client_secret and tenant_id
|
99
|
+
if client_id && client_secret && tenant_id
|
91
100
|
::MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret, ad_settings)
|
92
|
-
|
101
|
+
# Login with a Managed Service Identity.
|
102
|
+
#
|
103
|
+
# Typically used with a Managed Service Identity when you have a particular object registered in a tenant.
|
104
|
+
#
|
105
|
+
# MSI with client_id and tenant_id (aka User Assigned Identity).
|
106
|
+
elsif client_id && tenant_id
|
93
107
|
::MsRestAzure::MSITokenProvider.new(50342, ad_settings, { client_id: client_id })
|
94
|
-
|
108
|
+
# Default approach to inheriting existing object permissions (application or device this code is running on).
|
109
|
+
#
|
110
|
+
# Typically used when you want to inherit the permissions of the system you're running on that are in a tenant.
|
111
|
+
#
|
112
|
+
# MSI with just tenant_id (aka System Assigned Identity).
|
113
|
+
elsif tenant_id
|
95
114
|
::MsRestAzure::MSITokenProvider.new(50342, ad_settings)
|
115
|
+
# Login using the Azure CLI
|
116
|
+
#
|
117
|
+
# Typically used when you want to rely upon `az login` as your preferred authentication method.
|
118
|
+
else
|
119
|
+
warn("Using tenant id set through `az login`.")
|
120
|
+
::MsRestAzure::AzureCliTokenProvider.new(ad_settings)
|
96
121
|
end
|
97
122
|
end
|
98
123
|
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require "kitchen"
|
2
|
+
|
3
|
+
autoload :MsRestAzure, "ms_rest_azure"
|
2
4
|
require_relative "azure_credentials"
|
3
5
|
require "securerandom" unless defined?(SecureRandom)
|
4
6
|
module Azure
|
@@ -17,7 +19,9 @@ module Kitchen
|
|
17
19
|
module Driver
|
18
20
|
#
|
19
21
|
# Azurerm
|
22
|
+
# Create a new resource group object and set the location and tags attributes then return it.
|
20
23
|
#
|
24
|
+
# @return [::Azure::Resources::Profiles::Latest::Mgmt::Models::ResourceGroup] A new resource group object.
|
21
25
|
class Azurerm < Kitchen::Driver::Base
|
22
26
|
attr_accessor :resource_management_client
|
23
27
|
attr_accessor :network_management_client
|
@@ -208,6 +212,10 @@ module Kitchen
|
|
208
212
|
5
|
209
213
|
end
|
210
214
|
|
215
|
+
default_config(:use_fqdn_hostname) do |_config|
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
211
219
|
def create(state)
|
212
220
|
state = validate_state(state)
|
213
221
|
deployment_parameters = {
|
@@ -216,7 +224,7 @@ module Kitchen
|
|
216
224
|
storageAccountType: config[:storage_account_type],
|
217
225
|
bootDiagnosticsEnabled: config[:boot_diagnostics_enabled],
|
218
226
|
newStorageAccountName: "storage#{state[:uuid]}",
|
219
|
-
adminUsername:
|
227
|
+
adminUsername: config[:username],
|
220
228
|
dnsNameForPublicIP: "kitchen-#{state[:uuid]}",
|
221
229
|
vmName: state[:vm_name],
|
222
230
|
systemAssignedIdentity: config[:system_assigned_identity],
|
@@ -227,7 +235,7 @@ module Kitchen
|
|
227
235
|
}
|
228
236
|
|
229
237
|
if instance.transport[:ssh_key].nil?
|
230
|
-
deployment_parameters[
|
238
|
+
deployment_parameters[:adminPassword] = config[:password]
|
231
239
|
end
|
232
240
|
|
233
241
|
if config[:subscription_id].to_s == ""
|
@@ -303,6 +311,9 @@ module Kitchen
|
|
303
311
|
info "Creating deployment: #{deployment_name}"
|
304
312
|
create_deployment_async(state[:azure_resource_group_name], deployment_name, deployment(deployment_parameters)).value!
|
305
313
|
follow_deployment_until_end_state(state[:azure_resource_group_name], deployment_name)
|
314
|
+
state[:username] = deployment_parameters[:adminUsername] unless existing_state_value?(state, :username)
|
315
|
+
state[:password] = deployment_parameters[:adminPassword] unless existing_state_value?(state, :password) && instance.transport[:ssh_key].nil?
|
316
|
+
|
306
317
|
if File.file?(config[:post_deployment_template])
|
307
318
|
post_deployment_name = "post-deploy-#{state[:uuid]}"
|
308
319
|
info "Creating deployment: #{post_deployment_name}"
|
@@ -328,6 +339,10 @@ module Kitchen
|
|
328
339
|
result = get_public_ip(state[:azure_resource_group_name], "publicip")
|
329
340
|
info "IP Address is: #{result.ip_address} [#{result.dns_settings.fqdn}]"
|
330
341
|
state[:hostname] = result.ip_address
|
342
|
+
if config[:use_fqdn_hostname]
|
343
|
+
info "Using FQDN to communicate instead of IP"
|
344
|
+
state[:hostname] = result.dns_settings.fqdn
|
345
|
+
end
|
331
346
|
else
|
332
347
|
# Retrieve the internal IP from the resource group:
|
333
348
|
result = get_network_interface(state[:azure_resource_group_name], vmnic.to_s)
|
@@ -336,15 +351,24 @@ module Kitchen
|
|
336
351
|
end
|
337
352
|
end
|
338
353
|
|
354
|
+
# Return a True of False if the state is already stored for a particular property.
|
355
|
+
#
|
356
|
+
# @param [Hash] Hash of existing state values.
|
357
|
+
# @param [String] A property to check
|
358
|
+
# @return [Boolean]
|
339
359
|
def existing_state_value?(state, property)
|
340
360
|
state.key?(property) && !state[property].nil?
|
341
361
|
end
|
342
362
|
|
363
|
+
# Leverage existing state values or bring state into existence from a configuration file.
|
364
|
+
#
|
365
|
+
# @param [Hash] Existing Hash of state values.
|
366
|
+
# @return [Hash] Updated Hash of state values.
|
343
367
|
def validate_state(state = {})
|
344
368
|
state[:uuid] = SecureRandom.hex(8) unless existing_state_value?(state, :uuid)
|
345
369
|
state[:server_id] = "vm#{state[:uuid]}" unless existing_state_value?(state, :server_id)
|
346
370
|
state[:azure_resource_group_name] = azure_resource_group_name unless existing_state_value?(state, :azure_resource_group_name)
|
347
|
-
%i{subscription_id
|
371
|
+
%i{subscription_id vm_name azure_environment use_managed_disks}.each do |config_element|
|
348
372
|
state[config_element] = config[config_element] unless existing_state_value?(state, config_element)
|
349
373
|
end
|
350
374
|
state.delete(:password) unless instance.transport[:ssh_key].nil?
|
@@ -525,11 +549,38 @@ module Kitchen
|
|
525
549
|
end
|
526
550
|
|
527
551
|
def destroy(state)
|
528
|
-
|
552
|
+
# TODO: We have some not so fun state issues we need to clean up
|
553
|
+
state[:azure_environment] = config[:azure_environment] unless state[:azure_environment]
|
554
|
+
state[:subscription_id] = config[:subscription_id] unless state[:subscription_id]
|
529
555
|
|
556
|
+
# Setup our authentication components for the SDK
|
530
557
|
options = Kitchen::Driver::AzureCredentials.new(subscription_id: state[:subscription_id],
|
531
|
-
|
558
|
+
environment: state[:azure_environment]).azure_options
|
532
559
|
@resource_management_client = ::Azure::Resources::Profiles::Latest::Mgmt::Client.new(options)
|
560
|
+
|
561
|
+
# If we don't have any instances, let's check to see if the user wants to delete a resource group and if so let's delete!
|
562
|
+
if state[:server_id].nil? && state[:azure_resource_group_name].nil? && !config[:explicit_resource_group_name].nil? && config[:destroy_explicit_resource_group]
|
563
|
+
if resource_group_exists?(config[:explicit_resource_group_name])
|
564
|
+
info "This instance doesn't exist but you asked to delete the resource group."
|
565
|
+
begin
|
566
|
+
info "Destroying Resource Group: #{config[:explicit_resource_group_name]}"
|
567
|
+
delete_resource_group_async(config[:explicit_resource_group_name])
|
568
|
+
info "Destroy operation accepted and will continue in the background."
|
569
|
+
return
|
570
|
+
rescue ::MsRestAzure::AzureOperationError => operation_error
|
571
|
+
error operation_error.body
|
572
|
+
raise operation_error
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
# Our working environment
|
578
|
+
info "Azure environment: #{state[:azure_environment]}"
|
579
|
+
|
580
|
+
# Skip if we don't have any instances
|
581
|
+
return if state[:server_id].nil?
|
582
|
+
|
583
|
+
# Destroy resource group contents
|
533
584
|
if config[:destroy_resource_group_contents] == true
|
534
585
|
info "Destroying individual resources within the Resource Group."
|
535
586
|
empty_deployment_name = "empty-deploy-#{state[:uuid]}"
|
@@ -538,32 +589,20 @@ module Kitchen
|
|
538
589
|
create_deployment_async(state[:azure_resource_group_name], empty_deployment_name, empty_deployment).value!
|
539
590
|
follow_deployment_until_end_state(state[:azure_resource_group_name], empty_deployment_name)
|
540
591
|
|
541
|
-
#
|
542
|
-
|
543
|
-
|
544
|
-
#
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
rescue ::MsRestAzure::AzureOperationError => operation_error
|
549
|
-
error operation_error.body
|
550
|
-
raise operation_error
|
551
|
-
end
|
552
|
-
end
|
553
|
-
|
554
|
-
# Corner case where we want to use kitchen to remove the tags
|
555
|
-
if config[:destroy_explicit_resource_group_tags] == true
|
556
|
-
warn 'The "destroy_explicit_resource_group_tags" setting value is set to "true". The tags on the resource group will be removed.'
|
557
|
-
# NOTE: We are using the internal wrapper function create_resource_group() which wraps the API
|
558
|
-
# method of create_or_update().
|
592
|
+
# NOTE: We are using the internal wrapper function create_resource_group() which wraps the API
|
593
|
+
# method of create_or_update()
|
594
|
+
begin
|
595
|
+
# Maintain tags on the resource group
|
596
|
+
create_resource_group(state[:azure_resource_group_name], get_resource_group) unless config[:destroy_explicit_resource_group_tags] == true
|
597
|
+
warn 'The "destroy_explicit_resource_group_tags" setting value is set to "false". The tags on the resource group will NOT be removed.' unless config[:destroy_explicit_resource_group_tags] == true
|
598
|
+
# Corner case where we want to use kitchen to remove the tags
|
559
599
|
resource_group = get_resource_group
|
560
600
|
resource_group.tags = {}
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
end
|
601
|
+
create_resource_group(state[:azure_resource_group_name], resource_group) unless config[:destroy_explicit_resource_group_tags] == false
|
602
|
+
warn 'The "destroy_explicit_resource_group_tags" setting value is set to "true". The tags on the resource group will be removed.' unless config[:destroy_explicit_resource_group_tags] == false
|
603
|
+
rescue ::MsRestAzure::AzureOperationError => operation_error
|
604
|
+
error operation_error.body
|
605
|
+
raise operation_error
|
567
606
|
end
|
568
607
|
|
569
608
|
rescue ::MsRestAzure::AzureOperationError => operation_error
|
@@ -571,20 +610,27 @@ module Kitchen
|
|
571
610
|
raise operation_error
|
572
611
|
end
|
573
612
|
end
|
613
|
+
|
614
|
+
# Do not remove the explicitly named resource group
|
574
615
|
if config[:destroy_explicit_resource_group] == false && !config[:explicit_resource_group_name].nil?
|
575
616
|
warn 'The "destroy_explicit_resource_group" setting value is set to "false". The resource group will not be deleted.'
|
576
617
|
warn 'Remember to manually destroy resources, or set "destroy_resource_group_contents: true" to save costs!' unless config[:destroy_resource_group_contents] == true
|
577
|
-
return
|
618
|
+
return state
|
578
619
|
end
|
579
|
-
|
620
|
+
|
621
|
+
# Destroy the world
|
580
622
|
begin
|
581
623
|
info "Destroying Resource Group: #{state[:azure_resource_group_name]}"
|
582
624
|
delete_resource_group_async(state[:azure_resource_group_name])
|
583
625
|
info "Destroy operation accepted and will continue in the background."
|
626
|
+
# Remove resource group name from driver state
|
627
|
+
state.delete(:azure_resource_group_name)
|
584
628
|
rescue ::MsRestAzure::AzureOperationError => operation_error
|
585
629
|
error operation_error.body
|
586
630
|
raise operation_error
|
587
631
|
end
|
632
|
+
|
633
|
+
# Clear state of components
|
588
634
|
state.delete(:server_id)
|
589
635
|
state.delete(:hostname)
|
590
636
|
state.delete(:username)
|
@@ -748,6 +794,26 @@ module Kitchen
|
|
748
794
|
resource_group
|
749
795
|
end
|
750
796
|
|
797
|
+
# Checks whether a resource group exists.
|
798
|
+
#
|
799
|
+
# @param resource_group_name [String] The name of the resource group to check.
|
800
|
+
# The name is case insensitive.
|
801
|
+
#
|
802
|
+
# @return [Boolean] operation results.
|
803
|
+
#
|
804
|
+
def resource_group_exists?(resource_group_name)
|
805
|
+
retries = config[:azure_api_retries]
|
806
|
+
begin
|
807
|
+
resource_management_client.resource_groups.check_existence(resource_group_name)
|
808
|
+
rescue Faraday::TimeoutError, Faraday::ClientError => exception
|
809
|
+
send_exception_message(exception, "while checking if resource group '#{resource_group_name}' exists. #{retries} retries left.")
|
810
|
+
raise if retries == 0
|
811
|
+
|
812
|
+
retries -= 1
|
813
|
+
retry
|
814
|
+
end
|
815
|
+
end
|
816
|
+
|
751
817
|
def create_resource_group(resource_group_name, resource_group)
|
752
818
|
retries = config[:azure_api_retries]
|
753
819
|
begin
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kitchen-azurerm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stuart Preston
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: azure_mgmt_network
|
@@ -130,14 +130,14 @@ dependencies:
|
|
130
130
|
requirements:
|
131
131
|
- - '='
|
132
132
|
- !ruby/object:Gem::Version
|
133
|
-
version: 1.2
|
133
|
+
version: 1.4.2
|
134
134
|
type: :development
|
135
135
|
prerelease: false
|
136
136
|
version_requirements: !ruby/object:Gem::Requirement
|
137
137
|
requirements:
|
138
138
|
- - '='
|
139
139
|
- !ruby/object:Gem::Version
|
140
|
-
version: 1.2
|
140
|
+
version: 1.4.2
|
141
141
|
- !ruby/object:Gem::Dependency
|
142
142
|
name: rspec
|
143
143
|
requirement: !ruby/object:Gem::Requirement
|