kitchen-dsc 0.9.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f85b4e08d3cce5d8e8023cbfeee34b3529dca80f
4
- data.tar.gz: 17f38a13535a39115dcdbb8216096418e39a2a9f
3
+ metadata.gz: 0043ea70755d3de429c6744f3103a484c9841cec
4
+ data.tar.gz: 005604228f4f2424e72fb41dc9e5a09c1ca9d42e
5
5
  SHA512:
6
- metadata.gz: c4ecfa02f5cef6df1c1b43b4727580bee86df0986aa3a97d385d6badd38f5a3be2940d250f4e91ecd070f5a184c7a4a7e11463ae12aaf7ffb6800d7526ae0dc6
7
- data.tar.gz: 75159d184589220d0a37fee3b15b42c161a3bff167de64b885376df9f20cecddbe7ad435d9f191c86a61eab4f4048ef7987f5dc8a7c7dd5f0376611d55bea58f
6
+ metadata.gz: 65587a52d7f8d0a40d014cc5f28b8c18a32a69512bd22cf1776a545878c638526559f4ccdabe07db6b95ffc33c92e0a90d75b1d3fa376cf29f5dc19a1e49f1e0
7
+ data.tar.gz: 8fb1f84cb6d84cfa0b949e45e2b4bf0aba3dcfd653dcf4ce688f685e1ab501f7e8c1f20d35dda377017199b5417cc947deb70f537e61e0931dfe81727c7aa5d2
data/README.md CHANGED
@@ -1,108 +1,108 @@
1
- [![Gem Version](https://badge.fury.io/rb/kitchen-dsc.svg)](http://badge.fury.io/rb/kitchen-dsc)
2
-
3
- # kitchen-dsc
4
- A Test Kitchen Provisioner for PowerShell DSC
5
-
6
-
7
- ## Requirements
8
- You'll need a driver box with WMF4 or greater (ONLY WINDOWS SYSTEMS)
9
-
10
- ## Installation & Setup
11
- You'll need the test-kitchen & kitchen-dsc gems installed in your system, along with kitchen-vagrant or some ther suitable driver for test-kitchen.
12
-
13
- ### Note:
14
- You will see a delay in the return of the run details due to an difference in how the verbose stream is returned for DSC runs between WMF versions, so I return the verbose stream after the job completes. I'd love to live stream the results, but that'll take a bit more experimentation. (PR's welcome!)
15
-
16
- ## Example Configurations
17
- * [Repository Style Testing](https://github.com/smurawski/dsc-kitchen-project)
18
- * [Module Style Testing](https://github.com/powershellorg/cwebadministration/tree/smurawski/adding_tests)
19
-
20
- ## Configuration Settings
21
- * configuration_script_folder
22
- * Defaults to 'examples'.
23
- * The location of a PowerShell script(s) containing the DSC configuration command(s).
24
-
25
- * configuration_script
26
- * Defaults to 'dsc_configuration.ps1'
27
- * The name of the PowerShell script containing the DSC configuration command(s) (and possibly configuration data)
28
-
29
- * configuration_name
30
- * Name of the configuration to run, defaults to the suite name.
31
-
32
- * configuration_data
33
- * A YAML representation of what should be passed to the configuration.
34
- * Overrides any configurationdata variable assigned in the configuration script.
35
-
36
- * configuration_data_variable
37
- * Defaults to 'ConfigurationData'
38
- * Name of the variable that contains the ConfigurationData hashtable
39
- * Can be defined in the configuration script or via the `configuration_data` configuration setting.
40
-
41
- * dsc_local_configuration_manager_version
42
- * Defaults to 'wmf4'
43
- * Identifies what version of the LCM is in place
44
- * Other valid values are 'wmf4_with_update' and 'wmf5'
45
- * Currently the only difference between wmf4 and wmf4_with_update/wmf5 is the action_after_reboot and the debug_mode settings. Eventually, I'd like to add support for partial configurations, pull servers, etc..
46
- * In this context, wmf4_with_update refers to wmf4 with KB3000850 applied (to add support for WMF 5 generated configurations, plus some fixes).
47
-
48
- * dsc_local_configuration_manager
49
- * Settings for the LCM
50
- * Defaults are:
51
- * action_after_reboot = 'StopConfiguration' # wmf4_with_update or wmf5
52
- * reboot_if_needed = false
53
- * allow_module_overwrite = false
54
- * certificate_id = nil
55
- * configuration_mode = 'ApplyAndAutoCorrect'
56
- * configuration_mode_frequency_mins = 30 # 15 on wmf5
57
- * debug_mode = 'All' # wmf4_with_update
58
- * refresh_frequency_mins = 15 # 30 on wmf5
59
- * refresh_mode = 'PUSH'
60
-
61
- * modules_from_gallery
62
- * Requires WMF 5
63
- * Takes a string (for one module) or an array (for multiple) to install from the gallery
64
- * Or takes a hash with keys matching the parameters for install-module.
65
- * Name is required.
66
- * Force is automatically used and not required as part of the hash table.
67
- * Repository defaults to either PSGallery or any custom feed defined, but can be overriden here.
68
-
69
- * gallery_name
70
- * Custom PowerShell gallery name to install modules from.
71
- * If there is no package source with this name registered on the machine, then gallery_uri must be configured as well.
72
-
73
- * gallery_uri
74
- * URI for a custom PowerShell gallery feed.
75
-
76
- ### Specific to repository style testing
77
- * modules_path
78
- * Defaults to 'modules'.
79
- * Points to the location of modules containing DSC resources to upload
80
- * This path is relative to the root of the repository (the location of the .kitchen.yml).
81
-
82
- ## Example
83
-
84
- ```yaml
85
- provisioner:
86
- - name: dsc
87
- dsc_local_configuration_manager_version: wmf5
88
- dsc_local_configuration_manager:
89
- reboot_if_needed: true
90
- debug_mode: none
91
- configuration_script_folder: .
92
- configuration_script: SampleConfig.ps1
93
- gallery_uri: https://ci.appveyor.com/nuget/xWebAdministration
94
- gallery_name: xWebDevFeed
95
- modules_from_gallery:
96
- - xWebAdministration
97
- - name: xComputerManagement
98
- requiredversion: 1.4.0.0
99
- repository: PSGallery
100
-
101
- suite:
102
- - name: test
103
- provisioner:
104
- configuration_data:
105
- AllNodes:
106
- - nodename: localhost
107
- role: webserver
1
+ [![Gem Version](https://badge.fury.io/rb/kitchen-dsc.svg)](http://badge.fury.io/rb/kitchen-dsc)
2
+
3
+ # kitchen-dsc
4
+ A Test Kitchen Provisioner for PowerShell DSC
5
+
6
+
7
+ ## Requirements
8
+ You'll need a driver box with WMF4 or greater (ONLY WINDOWS SYSTEMS)
9
+
10
+ ## Installation & Setup
11
+ You'll need the test-kitchen & kitchen-dsc gems installed in your system, along with kitchen-vagrant or some ther suitable driver for test-kitchen.
12
+
13
+ ### Note:
14
+ You will see a delay in the return of the run details due to an difference in how the verbose stream is returned for DSC runs between WMF versions, so I return the verbose stream after the job completes. I'd love to live stream the results, but that'll take a bit more experimentation. (PR's welcome!)
15
+
16
+ ## Example Configurations
17
+ * [Repository Style Testing](https://github.com/smurawski/dsc-kitchen-project)
18
+ * [Module Style Testing](https://github.com/powershellorg/cwebadministration/tree/smurawski/adding_tests)
19
+
20
+ ## Configuration Settings
21
+ * configuration_script_folder
22
+ * Defaults to 'examples'.
23
+ * The location of a PowerShell script(s) containing the DSC configuration command(s).
24
+
25
+ * configuration_script
26
+ * Defaults to 'dsc_configuration.ps1'
27
+ * The name of the PowerShell script containing the DSC configuration command(s) (and possibly configuration data)
28
+
29
+ * configuration_name
30
+ * Name of the configuration to run, defaults to the suite name.
31
+
32
+ * configuration_data
33
+ * A YAML representation of what should be passed to the configuration.
34
+ * Overrides any configurationdata variable assigned in the configuration script.
35
+
36
+ * configuration_data_variable
37
+ * Defaults to 'ConfigurationData'
38
+ * Name of the variable that contains the ConfigurationData hashtable
39
+ * Can be defined in the configuration script or via the `configuration_data` configuration setting.
40
+
41
+ * dsc_local_configuration_manager_version
42
+ * Defaults to 'wmf4'
43
+ * Identifies what version of the LCM is in place
44
+ * Other valid values are 'wmf4_with_update' and 'wmf5'
45
+ * Currently the only difference between wmf4 and wmf4_with_update/wmf5 is the action_after_reboot and the debug_mode settings. Eventually, I'd like to add support for partial configurations, pull servers, etc..
46
+ * In this context, wmf4_with_update refers to wmf4 with KB3000850 applied (to add support for WMF 5 generated configurations, plus some fixes).
47
+
48
+ * dsc_local_configuration_manager
49
+ * Settings for the LCM
50
+ * Defaults are:
51
+ * action_after_reboot = 'StopConfiguration' # wmf4_with_update or wmf5
52
+ * reboot_if_needed = false
53
+ * allow_module_overwrite = false
54
+ * certificate_id = nil
55
+ * configuration_mode = 'ApplyAndAutoCorrect'
56
+ * configuration_mode_frequency_mins = 30 # 15 on wmf5
57
+ * debug_mode = 'All' # wmf4_with_update
58
+ * refresh_frequency_mins = 15 # 30 on wmf5
59
+ * refresh_mode = 'PUSH'
60
+
61
+ * modules_from_gallery
62
+ * Requires WMF 5
63
+ * Takes a string (for one module) or an array (for multiple) to install from the gallery
64
+ * Or takes a hash with keys matching the parameters for install-module.
65
+ * Name is required.
66
+ * Force is automatically used and not required as part of the hash table.
67
+ * Repository defaults to either PSGallery or any custom feed defined, but can be overriden here.
68
+
69
+ * gallery_name
70
+ * Custom PowerShell gallery name to install modules from.
71
+ * If there is no package source with this name registered on the machine, then gallery_uri must be configured as well.
72
+
73
+ * gallery_uri
74
+ * URI for a custom PowerShell gallery feed.
75
+
76
+ ### Specific to repository style testing
77
+ * modules_path
78
+ * Defaults to 'modules'.
79
+ * Points to the location of modules containing DSC resources to upload
80
+ * This path is relative to the root of the repository (the location of the .kitchen.yml).
81
+
82
+ ## Example
83
+
84
+ ```yaml
85
+ provisioner:
86
+ - name: dsc
87
+ dsc_local_configuration_manager_version: wmf5
88
+ dsc_local_configuration_manager:
89
+ reboot_if_needed: true
90
+ debug_mode: none
91
+ configuration_script_folder: .
92
+ configuration_script: SampleConfig.ps1
93
+ gallery_uri: https://ci.appveyor.com/nuget/xWebAdministration
94
+ gallery_name: xWebDevFeed
95
+ modules_from_gallery:
96
+ - xWebAdministration
97
+ - name: xComputerManagement
98
+ requiredversion: 1.4.0.0
99
+ repository: PSGallery
100
+
101
+ suite:
102
+ - name: test
103
+ provisioner:
104
+ configuration_data:
105
+ AllNodes:
106
+ - nodename: localhost
107
+ role: webserver
108
108
  ```
data/kitchen-dsc.gemspec CHANGED
@@ -1,41 +1,41 @@
1
- # encoding: utf-8
2
-
3
- $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
- require 'kitchen-dsc/version'
5
-
6
- Gem::Specification.new do |s|
7
- s.name = 'kitchen-dsc'
8
- s.version = Kitchen::Dsc::VERSION
9
- s.authors = ['Steven Murawski']
10
- s.email = ['smurawski@chef.io']
11
- s.homepage = 'https://github.com/test-kitchen/kitchen-dsc'
12
- s.summary = 'PowerShell DSC provisioner for test-kitchen'
13
- candidates = Dir.glob('lib/**/*') + ['README.md', 'kitchen-dsc.gemspec']
14
- s.files = candidates.sort
15
- s.platform = Gem::Platform::RUBY
16
- s.require_paths = ['lib']
17
- s.rubyforge_project = '[none]'
18
- s.license = 'Apache 2'
19
- s.description = <<-EOF
20
- == DESCRIPTION:
21
-
22
- DSC Provisioner for Test Kitchen
23
-
24
- == FEATURES:
25
-
26
- TBD
27
-
28
- EOF
29
- s.add_dependency 'test-kitchen', '~> 1.10'
30
-
31
- s.add_development_dependency 'countloc', '~> 0.4'
32
- s.add_development_dependency 'rake'
33
- s.add_development_dependency 'rspec', '~> 3.2'
34
- s.add_development_dependency 'simplecov', '~> 0.9'
35
-
36
- # style and complexity libraries are tightly version pinned as newer releases
37
- # may introduce new and undesireable style choices which would be immediately
38
- # enforced in CI
39
- s.add_development_dependency 'finstyle', '1.4.0'
40
- s.add_development_dependency 'cane', '2.6.2'
41
- end
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
+ require 'kitchen-dsc/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'kitchen-dsc'
8
+ s.version = Kitchen::Dsc::VERSION
9
+ s.authors = ['Steven Murawski']
10
+ s.email = ['smurawski@chef.io']
11
+ s.homepage = 'https://github.com/test-kitchen/kitchen-dsc'
12
+ s.summary = 'PowerShell DSC provisioner for test-kitchen'
13
+ candidates = Dir.glob('lib/**/*') + ['README.md', 'kitchen-dsc.gemspec']
14
+ s.files = candidates.sort
15
+ s.platform = Gem::Platform::RUBY
16
+ s.require_paths = ['lib']
17
+ s.rubyforge_project = '[none]'
18
+ s.license = 'Apache 2'
19
+ s.description = <<-EOF
20
+ == DESCRIPTION:
21
+
22
+ DSC Provisioner for Test Kitchen
23
+
24
+ == FEATURES:
25
+
26
+ TBD
27
+
28
+ EOF
29
+ s.add_dependency 'test-kitchen', '~> 1.10'
30
+
31
+ s.add_development_dependency 'countloc', '~> 0.4'
32
+ s.add_development_dependency 'rake'
33
+ s.add_development_dependency 'rspec', '~> 3.2'
34
+ s.add_development_dependency 'simplecov', '~> 0.9'
35
+
36
+ # style and complexity libraries are tightly version pinned as newer releases
37
+ # may introduce new and undesireable style choices which would be immediately
38
+ # enforced in CI
39
+ s.add_development_dependency 'finstyle', '1.4.0'
40
+ s.add_development_dependency 'cane', '2.6.2'
41
+ end
@@ -1,7 +1,7 @@
1
- # encoding: utf-8
2
-
3
- module Kitchen
4
- module Dsc
5
- VERSION = '0.9.0'.freeze
6
- end
7
- end
1
+ # encoding: utf-8
2
+
3
+ module Kitchen
4
+ module Dsc
5
+ VERSION = '0.9.2'.freeze
6
+ end
7
+ end
@@ -1,368 +1,362 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Steven Murawski (<steven.murawski@gmail.com>)
4
- #
5
- # Copyright (C) 2014 Steven Murawski
6
- #
7
- # Licensed under the MIT License.
8
- # See LICENSE for more details
9
-
10
- require 'fileutils'
11
- require 'pathname'
12
- require 'kitchen/provisioner/base'
13
- require 'kitchen/util'
14
-
15
- module Kitchen
16
- module Provisioner
17
- class Dsc < Base
18
- kitchen_provisioner_api_version 2
19
-
20
- attr_accessor :tmp_dir
21
-
22
- default_config :modules_path, 'modules'
23
-
24
- default_config :configuration_script_folder, 'examples'
25
- default_config :configuration_script, 'dsc_configuration.ps1'
26
- default_config :configuration_name do |provisioner|
27
- provisioner.instance.suite.name
28
- end
29
-
30
- default_config :configuration_data_variable, 'ConfigurationData'
31
- default_config :configuration_data
32
-
33
- default_config :nuget_force_bootstrap, true
34
- default_config :gallery_uri
35
- default_config :gallery_name
36
- default_config :modules_from_gallery
37
-
38
- default_config :dsc_local_configuration_manager_version, 'wmf4'
39
- default_config :dsc_local_configuration_manager
40
-
41
- def override_lcm_setting?(name)
42
- if config[:dsc_local_configuration_manager].nil? ||
43
- config[:dsc_local_configuration_manager][name.to_sym].nil?
44
- false
45
- else
46
- true
47
- end
48
- end
49
-
50
- def resolve_lcm_setting(name, default_value)
51
- if override_lcm_setting? name
52
- config[:dsc_local_configuration_manager][name.to_sym]
53
- else
54
- default_value
55
- end
56
- end
57
-
58
- def lcm_settings
59
- {
60
- action_after_reboot: (resolve_lcm_setting 'action_after_reboot', 'StopConfiguration'),
61
- allow_module_overwrite: (resolve_lcm_setting 'allow_module_overwrite', false),
62
- certificate_id: (resolve_lcm_setting 'certificate_id', nil),
63
- configuration_mode: (resolve_lcm_setting 'configuration_mode', 'ApplyAndAutoCorrect'),
64
- debug_mode: (resolve_lcm_setting 'debug_mode', 'All'),
65
- reboot_if_needed: (resolve_lcm_setting 'reboot_if_needed', false),
66
- refresh_mode: (resolve_lcm_setting 'refresh_mode', 'PUSH')
67
- }
68
- end
69
-
70
- def install_command
71
- lcm_config = lcm_settings
72
- case config[:dsc_local_configuration_manager_version]
73
- when 'wmf4_legacy', 'wmf4'
74
- lcm_configuration_script = <<-LCMSETUP
75
- configuration SetupLCM
76
- {
77
- LocalConfigurationManager
78
- {
79
- AllowModuleOverwrite = [bool]::Parse('#{lcm_config[:allow_module_overwrite]}')
80
- CertificateID = '#{lcm_config[:certificate_id].nil? ? '$null' : lcm_config[:certificate_id]}'
81
- ConfigurationMode = '#{lcm_config[:configuration_mode]}'
82
- ConfigurationModeFrequencyMins = #{lcm_config[:configuration_mode_frequency_mins].nil? ? '30' : lcm_config[:configuration_mode_frequency_mins]}
83
- RebootNodeIfNeeded = [bool]::Parse('#{lcm_config[:reboot_if_needed]}')
84
- RefreshFrequencyMins = #{lcm_config[:refresh_frequency_mins].nil? ? '15' : lcm_config[:refresh_frequency_mins]}
85
- RefreshMode = '#{lcm_config[:refresh_mode]}'
86
- }
87
- }
88
- LCMSETUP
89
- when 'wmf4_with_update'
90
- lcm_configuration_script = <<-LCMSETUP
91
- configuration SetupLCM
92
- {
93
- LocalConfigurationManager
94
- {
95
- ActionAfterReboot = '#{lcm_config[:action_after_reboot]}'
96
- AllowModuleOverwrite = [bool]::Parse('#{lcm_config[:allow_module_overwrite]}')
97
- CertificateID = '#{lcm_config[:certificate_id].nil? ? '$null' : lcm_config[:certificate_id]}'
98
- ConfigurationMode = '#{lcm_config[:configuration_mode]}'
99
- ConfigurationModeFrequencyMins = #{lcm_config[:configuration_mode_frequency_mins].nil? ? '30' : lcm_config[:configuration_mode_frequency_mins]}
100
- DebugMode = '#{lcm_config[:debug_mode]}'
101
- RebootNodeIfNeeded = [bool]::Parse('#{lcm_config[:reboot_if_needed]}')
102
- RefreshFrequencyMins = #{lcm_config[:refresh_frequency_mins].nil? ? '15' : lcm_config[:refresh_frequency_mins]}
103
- RefreshMode = '#{lcm_config[:refresh_mode]}'
104
- }
105
- }
106
- LCMSETUP
107
- when 'wmf5'
108
- lcm_configuration_script = <<-LCMSETUP
109
- [DSCLocalConfigurationManager()]
110
- configuration SetupLCM
111
- {
112
- Settings
113
- {
114
- ActionAfterReboot = '#{lcm_config[:action_after_reboot]}'
115
- AllowModuleOverwrite = [bool]::Parse('#{lcm_config[:allow_module_overwrite]}')
116
- CertificateID = '#{lcm_config[:certificate_id].nil? ? '$null' : lcm_config[:certificate_id]}'
117
- ConfigurationMode = '#{lcm_config[:configuration_mode]}'
118
- ConfigurationModeFrequencyMins = #{lcm_config[:configuration_mode_frequency_mins].nil? ? '15' : lcm_config[:configuration_mode_frequency_mins]}
119
- DebugMode = '#{lcm_config[:debug_mode]}'
120
- RebootNodeIfNeeded = [bool]::Parse('#{lcm_config[:reboot_if_needed]}')
121
- RefreshFrequencyMins = #{lcm_config[:refresh_frequency_mins].nil? ? '30' : lcm_config[:refresh_frequency_mins]}
122
- RefreshMode = '#{lcm_config[:refresh_mode]}'
123
- }
124
- }
125
- LCMSETUP
126
- end
127
- full_lcm_configuration_script = <<-EOH
128
- #{lcm_configuration_script}
129
-
130
- $null = SetupLCM
131
- Set-DscLocalConfigurationManager -Path ./SetupLCM | out-null
132
- EOH
133
-
134
- wrap_shell_code(full_lcm_configuration_script)
135
- end
136
- # rubocop:enable Metrics/LineLength
137
-
138
- def setup_config_directory_script
139
- "mkdir (split-path (join-path #{config[:root_path]} #{sandboxed_configuration_script})) -force | out-null"
140
- end
141
-
142
- def powershell_modules
143
- Array(config[:modules_from_gallery]).map do |powershell_module|
144
- params = if powershell_module.is_a? Hash
145
- keys = powershell_module.keys.reject { |k| k.to_s.downcase! == 'force' }
146
- unless keys.any? { |k| k.to_s.downcase! == 'repository' }
147
- keys.push(:repository)
148
- powershell_module[:repository] = psmodule_repository_name
149
- end
150
- keys.map do |key|
151
- "-#{key} #{powershell_module[key]}"
152
- end.join(' ')
153
- else
154
- "-name '#{powershell_module}' -Repository #{psmodule_repository_name}"
155
- end
156
- "install-module #{params} -force | out-null"
157
- end
158
- end
159
-
160
- def nuget_force_bootstrap
161
- return unless config[:nuget_force_bootstrap]
162
- info('Bootstrapping the nuget package provider for PowerShell PackageManagement.')
163
- 'install-packageprovider nuget -force -forcebootstrap | out-null'
164
- end
165
-
166
- def psmodule_repository_name
167
- return 'PSGallery' if config[:gallery_name].nil? && config[:gallery_uri].nil?
168
- return 'testing' if config[:gallery_name].nil?
169
- config[:gallery_name]
170
- end
171
-
172
- def register_psmodule_repository
173
- return if config[:gallery_uri].nil?
174
- info("Registering a new PowerShellGet Repository - #{psmodule_repository_name}")
175
- "register-packagesource -providername PowerShellGet -name '#{psmodule_repository_name}' -location '#{config[:gallery_uri]}' -force -trusted"
176
- end
177
-
178
- def install_module_script
179
- return if config[:modules_from_gallery].nil?
180
- <<-EOH
181
- #{nuget_force_bootstrap}
182
- #{register_psmodule_repository}
183
- #{powershell_modules.join("\n")}
184
- EOH
185
- end
186
-
187
- def install_modules?
188
- config[:dsc_local_configuration_manager_version] == 'wmf5' &&
189
- !config[:modules_from_gallery].nil?
190
- end
191
-
192
- def init_command
193
- script = <<-EOH
194
- #{setup_config_directory_script}
195
- #{install_module_script if install_modules?}
196
- EOH
197
- wrap_shell_code(script)
198
- end
199
-
200
- def create_sandbox
201
- super
202
- info('Staging DSC Resource Modules for copy to the SUT')
203
- if resource_module? || class_resource_module?
204
- prepare_resource_style_directory
205
- else
206
- prepare_repo_style_directory
207
- end
208
- info('Staging DSC configuration script for copy to the SUT')
209
- prepare_configuration_script
210
- end
211
-
212
- def prepare_command
213
- info('Moving DSC Resources onto PSModulePath')
214
- info("Generating the MOF script for the configuration #{config[:configuration_name]}")
215
- stage_resources_and_generate_mof_script = <<-EOH
216
- if (Test-Path (join-path #{config[:root_path]} 'modules'))
217
- {
218
- dir ( join-path #{config[:root_path]} 'modules/*') -directory |
219
- copy-item -destination $env:programfiles/windowspowershell/modules/ -recurse -force
220
- }
221
- if (-not (test-path 'c:/configurations'))
222
- {
223
- mkdir 'c:/configurations' | out-null
224
- }
225
- $ConfigurationScriptPath = Join-path #{config[:root_path]} #{sandboxed_configuration_script}
226
- if (-not (test-path $ConfigurationScriptPath))
227
- {
228
- throw "Failed to find $ConfigurationScriptPath"
229
- }
230
- invoke-expression (get-content $ConfigurationScriptPath -raw)
231
- if (-not (get-command #{config[:configuration_name]}))
232
- {
233
- throw "Failed to create a configuration command #{config[:configuration_name]}"
234
- }
235
-
236
- #{configuration_data_assignment unless config[:configuration_data].nil?}
237
-
238
- $null = #{config[:configuration_name]} -outputpath c:/configurations #{'-configurationdata $' + configuration_data_variable}
239
- EOH
240
- debug("Shelling out: #{stage_resources_and_generate_mof_script}")
241
- wrap_shell_code(stage_resources_and_generate_mof_script)
242
- end
243
- # rubocop:enable Metrics/LineLength
244
-
245
- def configuration_data_variable
246
- config[:configuration_data_variable].nil? ? 'ConfigurationData' : config[:configuration_data_variable]
247
- end
248
-
249
- def configuration_data_assignment
250
- '$' + configuration_data_variable + ' = ' + ps_hash(config[:configuration_data])
251
- end
252
-
253
- def run_command
254
- config[:retry_on_exit_code] = [35] if config[:retry_on_exit_code].empty?
255
- config[:max_retries] = 3 if config[:max_retries] == 1
256
-
257
- info("Running the configuration #{config[:configuration_name]}")
258
- run_configuration_script = <<-EOH
259
- $ProgressPreference = 'SilentlyContinue'
260
- $job = start-dscconfiguration -Path c:/configurations/ -force
261
- $job | wait-job
262
- $verbose_output = $job.childjobs[0].verbose
263
- $verbose_output
264
- if ($verbose_output -match 'A reboot is required to progress further. Please reboot the system.') {
265
- "A reboot is required to continue."
266
- shutdown /r /t 15
267
- exit 35
268
- }
269
- $dsc_errors = $job.childjobs[0].Error
270
- if ($dsc_errors -ne $null) {
271
- $dsc_errors
272
- exit 1
273
- }
274
- EOH
275
-
276
- debug("Shelling out: #{run_configuration_script}")
277
- wrap_shell_code(run_configuration_script)
278
- end
279
-
280
- private
281
-
282
- def resource_module?
283
- module_metadata_file = File.join(config[:kitchen_root], "#{module_name}.psd1")
284
- module_dsc_resource_folder = File.join(config[:kitchen_root], 'DSCResources')
285
- File.exist?(module_metadata_file) &&
286
- File.exist?(module_dsc_resource_folder)
287
- end
288
-
289
- def class_resource_module?
290
- module_metadata_file = File.join(config[:kitchen_root], "#{module_name}.psd1")
291
- module_dsc_resource_folder = File.join(config[:kitchen_root], 'DSCResources')
292
- File.exist?(module_metadata_file) &&
293
- !File.exist?(module_dsc_resource_folder)
294
- end
295
-
296
- def list_files(path)
297
- base_directory_content = Dir.glob(File.join(path, '*'))
298
- nested_directory_content = Dir.glob(File.join(path, '*/**/*'))
299
- all_directory_content = [base_directory_content, nested_directory_content].flatten
300
-
301
- ignore_files = ['Gemfile', 'Gemfile.lock', 'README.md', 'LICENSE.txt']
302
- all_directory_content.reject do |f|
303
- debug("Enumerating #{f}")
304
- ignore_files.include?(File.basename(f)) || File.directory?(f)
305
- end
306
- end
307
-
308
- def module_name
309
- File.basename(config[:kitchen_root])
310
- end
311
-
312
- def prepare_resource_style_directory
313
- sandbox_base_module_path = File.join(sandbox_path, "modules/#{module_name}")
314
-
315
- base = config[:kitchen_root]
316
- list_files(base).each do |src|
317
- dest = File.join(sandbox_base_module_path, src.sub("#{base}/", ''))
318
- FileUtils.mkdir_p(File.dirname(dest))
319
- debug("Staging #{src} ")
320
- debug(" at #{dest}")
321
- FileUtils.cp(src, dest, preserve: true)
322
- end
323
- end
324
-
325
- def prepare_repo_style_directory
326
- module_path = File.join(config[:kitchen_root], config[:modules_path])
327
- sandbox_module_path = File.join(sandbox_path, 'modules')
328
-
329
- if Dir.exist?(module_path)
330
- debug("Moving #{module_path} to #{sandbox_module_path}")
331
- FileUtils.cp_r(module_path, sandbox_module_path)
332
- else
333
- debug("The modules path #{module_path} was not found. Not moving to #{sandbox_module_path}.")
334
- end
335
- end
336
-
337
- def sandboxed_configuration_script
338
- File.join('configuration', config[:configuration_script])
339
- end
340
-
341
- def pad(depth = 0)
342
- ' ' * depth
343
- end
344
-
345
- def ps_hash(obj, depth = 0)
346
- if obj.is_a?(Hash)
347
- obj.map do |k, v|
348
- %(#{pad(depth + 2)}#{ps_hash(k)} = #{ps_hash(v, depth + 2)})
349
- end.join(";\n").insert(0, "@{\n").insert(-1, "\n#{pad(depth)}}")
350
- elsif obj.is_a?(Array)
351
- array_string = obj.map { |v| ps_hash(v, depth + 4) }.join(',')
352
- "#{pad(depth)}@(\n#{array_string}\n)"
353
- else
354
- %("#{obj}")
355
- end
356
- end
357
-
358
- def prepare_configuration_script
359
- configuration_script_file = File.join(config[:configuration_script_folder], config[:configuration_script])
360
- configuration_script_path = File.join(config[:kitchen_root], configuration_script_file)
361
- sandbox_configuration_script_path = File.join(sandbox_path, sandboxed_configuration_script)
362
- FileUtils.mkdir_p(File.dirname(sandbox_configuration_script_path))
363
- debug("Moving #{configuration_script_path} to #{sandbox_configuration_script_path}")
364
- FileUtils.cp(configuration_script_path, sandbox_configuration_script_path)
365
- end
366
- end
367
- end
368
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Steven Murawski (<steven.murawski@gmail.com>)
4
+ #
5
+ # Copyright (C) 2014 Steven Murawski
6
+ #
7
+ # Licensed under the MIT License.
8
+ # See LICENSE for more details
9
+
10
+ require 'fileutils'
11
+ require 'pathname'
12
+ require 'kitchen/provisioner/base'
13
+ require 'kitchen/util'
14
+
15
+ module Kitchen
16
+ module Provisioner
17
+ class Dsc < Base
18
+ kitchen_provisioner_api_version 2
19
+
20
+ attr_accessor :tmp_dir
21
+
22
+ default_config :modules_path, 'modules'
23
+
24
+ default_config :configuration_script_folder, 'examples'
25
+ default_config :configuration_script, 'dsc_configuration.ps1'
26
+ default_config :configuration_name do |provisioner|
27
+ provisioner.instance.suite.name
28
+ end
29
+
30
+ default_config :configuration_data_variable, 'ConfigurationData'
31
+ default_config :configuration_data
32
+
33
+ default_config :nuget_force_bootstrap, true
34
+ default_config :gallery_uri
35
+ default_config :gallery_name
36
+ default_config :modules_from_gallery
37
+
38
+ default_config :dsc_local_configuration_manager_version, 'wmf4'
39
+ default_config :dsc_local_configuration_manager
40
+
41
+ def override_lcm_setting?(name)
42
+ if config[:dsc_local_configuration_manager].nil? ||
43
+ config[:dsc_local_configuration_manager][name.to_sym].nil?
44
+ false
45
+ else
46
+ true
47
+ end
48
+ end
49
+
50
+ def resolve_lcm_setting(name, default_value)
51
+ if override_lcm_setting? name
52
+ config[:dsc_local_configuration_manager][name.to_sym]
53
+ else
54
+ default_value
55
+ end
56
+ end
57
+
58
+ def lcm_settings
59
+ {
60
+ action_after_reboot: (resolve_lcm_setting 'action_after_reboot', 'StopConfiguration'),
61
+ allow_module_overwrite: (resolve_lcm_setting 'allow_module_overwrite', false),
62
+ certificate_id: (resolve_lcm_setting 'certificate_id', nil),
63
+ configuration_mode: (resolve_lcm_setting 'configuration_mode', 'ApplyAndAutoCorrect'),
64
+ debug_mode: (resolve_lcm_setting 'debug_mode', 'All'),
65
+ reboot_if_needed: (resolve_lcm_setting 'reboot_if_needed', false),
66
+ refresh_mode: (resolve_lcm_setting 'refresh_mode', 'PUSH')
67
+ }
68
+ end
69
+
70
+ def install_command
71
+ lcm_config = lcm_settings
72
+ case config[:dsc_local_configuration_manager_version]
73
+ when 'wmf4_legacy', 'wmf4'
74
+ lcm_configuration_script = <<-LCMSETUP
75
+ configuration SetupLCM
76
+ {
77
+ LocalConfigurationManager
78
+ {
79
+ AllowModuleOverwrite = [bool]::Parse('#{lcm_config[:allow_module_overwrite]}')
80
+ CertificateID = '#{lcm_config[:certificate_id].nil? ? '$null' : lcm_config[:certificate_id]}'
81
+ ConfigurationMode = '#{lcm_config[:configuration_mode]}'
82
+ ConfigurationModeFrequencyMins = #{lcm_config[:configuration_mode_frequency_mins].nil? ? '30' : lcm_config[:configuration_mode_frequency_mins]}
83
+ RebootNodeIfNeeded = [bool]::Parse('#{lcm_config[:reboot_if_needed]}')
84
+ RefreshFrequencyMins = #{lcm_config[:refresh_frequency_mins].nil? ? '15' : lcm_config[:refresh_frequency_mins]}
85
+ RefreshMode = '#{lcm_config[:refresh_mode]}'
86
+ }
87
+ }
88
+ LCMSETUP
89
+ when 'wmf4_with_update'
90
+ lcm_configuration_script = <<-LCMSETUP
91
+ configuration SetupLCM
92
+ {
93
+ LocalConfigurationManager
94
+ {
95
+ ActionAfterReboot = '#{lcm_config[:action_after_reboot]}'
96
+ AllowModuleOverwrite = [bool]::Parse('#{lcm_config[:allow_module_overwrite]}')
97
+ CertificateID = '#{lcm_config[:certificate_id].nil? ? '$null' : lcm_config[:certificate_id]}'
98
+ ConfigurationMode = '#{lcm_config[:configuration_mode]}'
99
+ ConfigurationModeFrequencyMins = #{lcm_config[:configuration_mode_frequency_mins].nil? ? '30' : lcm_config[:configuration_mode_frequency_mins]}
100
+ DebugMode = '#{lcm_config[:debug_mode]}'
101
+ RebootNodeIfNeeded = [bool]::Parse('#{lcm_config[:reboot_if_needed]}')
102
+ RefreshFrequencyMins = #{lcm_config[:refresh_frequency_mins].nil? ? '15' : lcm_config[:refresh_frequency_mins]}
103
+ RefreshMode = '#{lcm_config[:refresh_mode]}'
104
+ }
105
+ }
106
+ LCMSETUP
107
+ when 'wmf5'
108
+ lcm_configuration_script = <<-LCMSETUP
109
+ [DSCLocalConfigurationManager()]
110
+ configuration SetupLCM
111
+ {
112
+ Settings
113
+ {
114
+ ActionAfterReboot = '#{lcm_config[:action_after_reboot]}'
115
+ AllowModuleOverwrite = [bool]::Parse('#{lcm_config[:allow_module_overwrite]}')
116
+ CertificateID = '#{lcm_config[:certificate_id].nil? ? '$null' : lcm_config[:certificate_id]}'
117
+ ConfigurationMode = '#{lcm_config[:configuration_mode]}'
118
+ ConfigurationModeFrequencyMins = #{lcm_config[:configuration_mode_frequency_mins].nil? ? '15' : lcm_config[:configuration_mode_frequency_mins]}
119
+ DebugMode = '#{lcm_config[:debug_mode]}'
120
+ RebootNodeIfNeeded = [bool]::Parse('#{lcm_config[:reboot_if_needed]}')
121
+ RefreshFrequencyMins = #{lcm_config[:refresh_frequency_mins].nil? ? '30' : lcm_config[:refresh_frequency_mins]}
122
+ RefreshMode = '#{lcm_config[:refresh_mode]}'
123
+ }
124
+ }
125
+ LCMSETUP
126
+ end
127
+ full_lcm_configuration_script = <<-EOH
128
+ #{lcm_configuration_script}
129
+
130
+ $null = SetupLCM
131
+ Set-DscLocalConfigurationManager -Path ./SetupLCM | out-null
132
+ EOH
133
+
134
+ wrap_powershell_code(full_lcm_configuration_script)
135
+ end
136
+ # rubocop:enable Metrics/LineLength
137
+
138
+ def setup_config_directory_script
139
+ "mkdir (split-path (join-path #{config[:root_path]} #{sandboxed_configuration_script})) -force | out-null"
140
+ end
141
+
142
+ def powershell_modules
143
+ Array(config[:modules_from_gallery]).map do |powershell_module|
144
+ params = if powershell_module.is_a? Hash
145
+ keys = powershell_module.keys.reject { |k| k.to_s.downcase! == 'force' }
146
+ unless keys.any? { |k| k.to_s.downcase! == 'repository' }
147
+ keys.push(:repository)
148
+ powershell_module[:repository] = psmodule_repository_name
149
+ end
150
+ keys.map do |key|
151
+ "-#{key} #{powershell_module[key]}"
152
+ end.join(' ')
153
+ else
154
+ "-name '#{powershell_module}' -Repository #{psmodule_repository_name}"
155
+ end
156
+ "install-module #{params} -force | out-null"
157
+ end
158
+ end
159
+
160
+ def nuget_force_bootstrap
161
+ return unless config[:nuget_force_bootstrap]
162
+ info('Bootstrapping the nuget package provider for PowerShell PackageManagement.')
163
+ 'install-packageprovider nuget -force -forcebootstrap | out-null'
164
+ end
165
+
166
+ def psmodule_repository_name
167
+ return 'PSGallery' if config[:gallery_name].nil? && config[:gallery_uri].nil?
168
+ return 'testing' if config[:gallery_name].nil?
169
+ config[:gallery_name]
170
+ end
171
+
172
+ def register_psmodule_repository
173
+ return if config[:gallery_uri].nil?
174
+ info("Registering a new PowerShellGet Repository - #{psmodule_repository_name}")
175
+ "register-packagesource -providername PowerShellGet -name '#{psmodule_repository_name}' -location '#{config[:gallery_uri]}' -force -trusted"
176
+ end
177
+
178
+ def install_module_script
179
+ return if config[:modules_from_gallery].nil?
180
+ <<-EOH
181
+ #{nuget_force_bootstrap}
182
+ #{register_psmodule_repository}
183
+ #{powershell_modules.join("\n")}
184
+ EOH
185
+ end
186
+
187
+ def install_modules?
188
+ config[:dsc_local_configuration_manager_version] == 'wmf5' &&
189
+ !config[:modules_from_gallery].nil?
190
+ end
191
+
192
+ def init_command
193
+ script = <<-EOH
194
+ #{setup_config_directory_script}
195
+ #{install_module_script if install_modules?}
196
+ EOH
197
+ wrap_powershell_code(script)
198
+ end
199
+
200
+ def create_sandbox
201
+ super
202
+ info('Staging DSC Resource Modules for copy to the SUT')
203
+ if powershell_module?
204
+ prepare_resource_style_directory
205
+ else
206
+ prepare_repo_style_directory
207
+ end
208
+ info('Staging DSC configuration script for copy to the SUT')
209
+ prepare_configuration_script
210
+ end
211
+
212
+ def prepare_command
213
+ info('Moving DSC Resources onto PSModulePath')
214
+ info("Generating the MOF script for the configuration #{config[:configuration_name]}")
215
+ stage_resources_and_generate_mof_script = <<-EOH
216
+ if (Test-Path (join-path #{config[:root_path]} 'modules'))
217
+ {
218
+ dir ( join-path #{config[:root_path]} 'modules/*') -directory |
219
+ copy-item -destination $env:programfiles/windowspowershell/modules/ -recurse -force
220
+ }
221
+ if (-not (test-path 'c:/configurations'))
222
+ {
223
+ mkdir 'c:/configurations' | out-null
224
+ }
225
+ $ConfigurationScriptPath = Join-path #{config[:root_path]} #{sandboxed_configuration_script}
226
+ if (-not (test-path $ConfigurationScriptPath))
227
+ {
228
+ throw "Failed to find $ConfigurationScriptPath"
229
+ }
230
+ invoke-expression (get-content $ConfigurationScriptPath -raw)
231
+ if (-not (get-command #{config[:configuration_name]}))
232
+ {
233
+ throw "Failed to create a configuration command #{config[:configuration_name]}"
234
+ }
235
+
236
+ #{configuration_data_assignment unless config[:configuration_data].nil?}
237
+
238
+ $null = #{config[:configuration_name]} -outputpath c:/configurations #{'-configurationdata $' + configuration_data_variable}
239
+ EOH
240
+ debug("Shelling out: #{stage_resources_and_generate_mof_script}")
241
+ wrap_powershell_code(stage_resources_and_generate_mof_script)
242
+ end
243
+ # rubocop:enable Metrics/LineLength
244
+
245
+ def configuration_data_variable
246
+ config[:configuration_data_variable].nil? ? 'ConfigurationData' : config[:configuration_data_variable]
247
+ end
248
+
249
+ def configuration_data_assignment
250
+ '$' + configuration_data_variable + ' = ' + ps_hash(config[:configuration_data])
251
+ end
252
+
253
+ def run_command
254
+ config[:retry_on_exit_code] = [35] if config[:retry_on_exit_code].empty?
255
+ config[:max_retries] = 3 if config[:max_retries] == 1
256
+
257
+ info("Running the configuration #{config[:configuration_name]}")
258
+ run_configuration_script = <<-EOH
259
+ $job = start-dscconfiguration -Path c:/configurations/ -force
260
+ $job | wait-job
261
+ $verbose_output = $job.childjobs[0].verbose
262
+ $verbose_output
263
+ if ($verbose_output -match 'A reboot is required to progress further. Please reboot the system.') {
264
+ "A reboot is required to continue."
265
+ shutdown /r /t 15
266
+ exit 35
267
+ }
268
+ $dsc_errors = $job.childjobs[0].Error
269
+ if ($dsc_errors -ne $null) {
270
+ $dsc_errors
271
+ exit 1
272
+ }
273
+ EOH
274
+
275
+ debug("Shelling out: #{run_configuration_script}")
276
+ wrap_powershell_code(run_configuration_script)
277
+ end
278
+
279
+ private
280
+
281
+ def wrap_powershell_code(code)
282
+ wrap_shell_code( [ "$ProgressPreference = 'SilentlyContinue';", code ].join("\n") )
283
+ end
284
+
285
+ def powershell_module?
286
+ module_metadata_file = File.join(config[:kitchen_root], "#{module_name}.psd1")
287
+ File.exist?(module_metadata_file)
288
+ end
289
+
290
+ def list_files(path)
291
+ base_directory_content = Dir.glob(File.join(path, '*'))
292
+ nested_directory_content = Dir.glob(File.join(path, '*/**/*'))
293
+ all_directory_content = [base_directory_content, nested_directory_content].flatten
294
+
295
+ ignore_files = ['Gemfile', 'Gemfile.lock', 'README.md', 'LICENSE.txt']
296
+ all_directory_content.reject do |f|
297
+ debug("Enumerating #{f}")
298
+ ignore_files.include?(File.basename(f)) || File.directory?(f)
299
+ end
300
+ end
301
+
302
+ def module_name
303
+ File.basename(config[:kitchen_root])
304
+ end
305
+
306
+ def prepare_resource_style_directory
307
+ sandbox_base_module_path = File.join(sandbox_path, "modules/#{module_name}")
308
+
309
+ base = config[:kitchen_root]
310
+ list_files(base).each do |src|
311
+ dest = File.join(sandbox_base_module_path, src.sub("#{base}/", ''))
312
+ FileUtils.mkdir_p(File.dirname(dest))
313
+ debug("Staging #{src} ")
314
+ debug(" at #{dest}")
315
+ FileUtils.cp(src, dest, preserve: true)
316
+ end
317
+ end
318
+
319
+ def prepare_repo_style_directory
320
+ module_path = File.join(config[:kitchen_root], config[:modules_path])
321
+ sandbox_module_path = File.join(sandbox_path, 'modules')
322
+
323
+ if Dir.exist?(module_path)
324
+ debug("Moving #{module_path} to #{sandbox_module_path}")
325
+ FileUtils.cp_r(module_path, sandbox_module_path)
326
+ else
327
+ debug("The modules path #{module_path} was not found. Not moving to #{sandbox_module_path}.")
328
+ end
329
+ end
330
+
331
+ def sandboxed_configuration_script
332
+ File.join('configuration', config[:configuration_script])
333
+ end
334
+
335
+ def pad(depth = 0)
336
+ ' ' * depth
337
+ end
338
+
339
+ def ps_hash(obj, depth = 0)
340
+ if obj.is_a?(Hash)
341
+ obj.map do |k, v|
342
+ %(#{pad(depth + 2)}#{ps_hash(k)} = #{ps_hash(v, depth + 2)})
343
+ end.join(";\n").insert(0, "@{\n").insert(-1, "\n#{pad(depth)}}")
344
+ elsif obj.is_a?(Array)
345
+ array_string = obj.map { |v| ps_hash(v, depth + 4) }.join(',')
346
+ "#{pad(depth)}@(\n#{array_string}\n)"
347
+ else
348
+ %("#{obj}")
349
+ end
350
+ end
351
+
352
+ def prepare_configuration_script
353
+ configuration_script_file = File.join(config[:configuration_script_folder], config[:configuration_script])
354
+ configuration_script_path = File.join(config[:kitchen_root], configuration_script_file)
355
+ sandbox_configuration_script_path = File.join(sandbox_path, sandboxed_configuration_script)
356
+ FileUtils.mkdir_p(File.dirname(sandbox_configuration_script_path))
357
+ debug("Moving #{configuration_script_path} to #{sandbox_configuration_script_path}")
358
+ FileUtils.cp(configuration_script_path, sandbox_configuration_script_path)
359
+ end
360
+ end
361
+ end
362
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-dsc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Murawski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-17 00:00:00.000000000 Z
11
+ date: 2016-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-kitchen