kitchen-dsc 0.10.0 → 0.10.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2306c243f65cad6f2d2080a500d65fe71a875e53
4
- data.tar.gz: b6d307e16a48a0c85d5500816d5c4c14e82077d6
3
+ metadata.gz: 15912b49fe3ff3144d49f605434b15e05fb155bf
4
+ data.tar.gz: 7cc40f3a658927a59ca6d6f1241392943244677e
5
5
  SHA512:
6
- metadata.gz: d6d4e0db90b1476db78803a3641b2a650d52ae9baab67ef01356cc5cab114bc2af2f4f79e5ddc94a6f22b7d39b136b42b74c59a27ba79ecab062dc7fe79d2c2d
7
- data.tar.gz: dcce1e8063ea43ecfea9ac0f50d2d82e40158dc2d12150d66b8c4c63e8d3cf9d9205a2e955d1d75377e2963050a43bc9afd393a54002c1d6b63dfcca327e93bc
6
+ metadata.gz: e26cd1fccd5af9d09ffef4dc1a0ca1075d3f25d48155525a5f2fbaeef5fa978818f818377b42e86679acb8bc3d91e210521a5f7903e0de5931a644195714611b
7
+ data.tar.gz: 14e5db6f434eb11ef8dcadf47ee70fbcdbc06c30e54fc7636036c5cefe48d04b49003dc86e4279a65f7d6372c4f6433d87b0a93ea122a2756f9b8f9ea7d84fde
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
  ```
@@ -1,48 +1,48 @@
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.9"
30
- s.add_dependency "dsc_lcm_configuration"
31
-
32
- s.add_development_dependency "countloc", "~> 0.4"
33
- s.add_development_dependency "rake"
34
- s.add_development_dependency "rspec", "~> 3.2"
35
- s.add_development_dependency "simplecov", "~> 0.9"
36
- s.add_development_dependency "minitest", "~> 5.3"
37
- s.add_development_dependency "yard", "~> 0.8"
38
- s.add_development_dependency "pry"
39
- s.add_development_dependency "pry-stack_explorer"
40
- s.add_development_dependency "pry-byebug"
41
- s.add_development_dependency "rb-readline"
42
-
43
- # style and complexity libraries are tightly version pinned as newer releases
44
- # may introduce new and undesireable style choices which would be immediately
45
- # enforced in CI
46
- s.add_development_dependency "finstyle", "1.4.0"
47
- s.add_development_dependency "cane", "2.6.2"
48
- 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.9"
30
+ s.add_dependency "dsc_lcm_configuration"
31
+
32
+ s.add_development_dependency "countloc", "~> 0.4"
33
+ s.add_development_dependency "rake"
34
+ s.add_development_dependency "rspec", "~> 3.2"
35
+ s.add_development_dependency "simplecov", "~> 0.9"
36
+ s.add_development_dependency "minitest", "~> 5.3"
37
+ s.add_development_dependency "yard", "~> 0.8"
38
+ s.add_development_dependency "pry"
39
+ s.add_development_dependency "pry-stack_explorer"
40
+ s.add_development_dependency "pry-byebug"
41
+ s.add_development_dependency "rb-readline"
42
+
43
+ # style and complexity libraries are tightly version pinned as newer releases
44
+ # may introduce new and undesireable style choices which would be immediately
45
+ # enforced in CI
46
+ s.add_development_dependency "finstyle", "1.4.0"
47
+ s.add_development_dependency "cane", "2.6.2"
48
+ end
@@ -1,7 +1,7 @@
1
- # encoding: utf-8
2
-
3
- module Kitchen
4
- module Dsc
5
- VERSION = '0.10.0'.freeze
6
- end
7
- end
1
+ # encoding: utf-8
2
+
3
+ module Kitchen
4
+ module Dsc
5
+ VERSION = '0.10.1'.freeze
6
+ end
7
+ end
@@ -1,291 +1,311 @@
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 Apache 2 License.
8
- # See LICENSE for more details
9
-
10
- require "fileutils"
11
- require "pathname"
12
- require "kitchen/provisioner/base"
13
- require "kitchen/util"
14
- require "dsc_lcm_configuration"
15
-
16
- module Kitchen
17
- module Provisioner
18
- class Dsc < Base
19
- kitchen_provisioner_api_version 2
20
-
21
- attr_accessor :tmp_dir
22
-
23
- default_config :modules_path, "modules"
24
-
25
- default_config :configuration_script_folder, "examples"
26
- default_config :configuration_script, "dsc_configuration.ps1"
27
- default_config :configuration_name do |provisioner|
28
- provisioner.instance.suite.name
29
- end
30
-
31
- default_config :configuration_data_variable, "ConfigurationData"
32
- default_config :configuration_data
33
-
34
- default_config :nuget_force_bootstrap, true
35
- default_config :gallery_uri
36
- default_config :gallery_name
37
- default_config :modules_from_gallery
38
-
39
- default_config :dsc_local_configuration_manager_version, "wmf4"
40
- default_config :dsc_local_configuration_manager, {}
41
-
42
- def finalize_config!(instance)
43
- config[:dsc_local_configuration_manager] = lcm.lcm_config
44
- super(instance)
45
- end
46
-
47
- def install_command
48
- full_lcm_configuration_script = <<-EOH
49
- #{lcm.lcm_configuration_script}
50
-
51
- $null = SetupLCM
52
- Set-DscLocalConfigurationManager -Path ./SetupLCM | out-null
53
- EOH
54
-
55
- wrap_powershell_code(full_lcm_configuration_script)
56
- end
57
-
58
- def init_command
59
- script = <<-EOH
60
- #{setup_config_directory_script}
61
- #{install_module_script if install_modules?}
62
- EOH
63
- wrap_powershell_code(script)
64
- end
65
-
66
- def create_sandbox
67
- super
68
- info("Staging DSC Resource Modules for copy to the SUT")
69
- if powershell_module?
70
- prepare_resource_style_directory
71
- else
72
- prepare_repo_style_directory
73
- end
74
- info("Staging DSC configuration script for copy to the SUT")
75
- prepare_configuration_script
76
- end
77
-
78
- def prepare_command
79
- info("Moving DSC Resources onto PSModulePath")
80
- info("Generating the MOF script for the configuration #{config[:configuration_name]}")
81
- stage_resources_and_generate_mof_script = <<-EOH
82
- if (Test-Path (join-path #{config[:root_path]} 'modules'))
83
- {
84
- dir ( join-path #{config[:root_path]} 'modules/*') -directory |
85
- copy-item -destination $env:programfiles/windowspowershell/modules/ -recurse -force
86
- }
87
- if (-not (test-path 'c:/configurations'))
88
- {
89
- mkdir 'c:/configurations' | out-null
90
- }
91
- $ConfigurationScriptPath = Join-path #{config[:root_path]} #{sandboxed_configuration_script}
92
- if (-not (test-path $ConfigurationScriptPath))
93
- {
94
- throw "Failed to find $ConfigurationScriptPath"
95
- }
96
- invoke-expression (get-content $ConfigurationScriptPath -raw)
97
- if (-not (get-command #{config[:configuration_name]}))
98
- {
99
- throw "Failed to create a configuration command #{config[:configuration_name]}"
100
- }
101
-
102
- #{configuration_data_assignment unless config[:configuration_data].nil?}
103
-
104
- $null = #{config[:configuration_name]} -outputpath c:/configurations #{"-configurationdata $" + configuration_data_variable}
105
- EOH
106
- debug("Shelling out: #{stage_resources_and_generate_mof_script}")
107
- wrap_powershell_code(stage_resources_and_generate_mof_script)
108
- end
109
-
110
- def run_command
111
- config[:retry_on_exit_code] = [35] if config[:retry_on_exit_code].empty?
112
- config[:max_retries] = 3 if config[:max_retries] == 1
113
-
114
- info("Running the configuration #{config[:configuration_name]}")
115
- run_configuration_script = <<-EOH
116
- $job = start-dscconfiguration -Path c:/configurations/ -force
117
- $job | wait-job
118
- $verbose_output = $job.childjobs[0].verbose
119
- $verbose_output
120
- if ($verbose_output -match 'A reboot is required to progress further. Please reboot the system.') {
121
- "A reboot is required to continue."
122
- shutdown /r /t 15
123
- exit 35
124
- }
125
- $dsc_errors = $job.childjobs[0].Error
126
- if ($dsc_errors -ne $null) {
127
- $dsc_errors
128
- exit 1
129
- }
130
- EOH
131
-
132
- debug("Shelling out: #{run_configuration_script}")
133
- wrap_powershell_code(run_configuration_script)
134
- end
135
-
136
- private
137
-
138
- def lcm
139
- @lcm ||= begin
140
- lcm_version = config[:dsc_local_configuration_manager_version]
141
- lcm_config = config[:dsc_local_configuration_manager]
142
- DscLcmConfiguration::Factory.create(lcm_version, lcm_config)
143
- end
144
- end
145
-
146
- def setup_config_directory_script
147
- "mkdir (split-path (join-path #{config[:root_path]} #{sandboxed_configuration_script})) -force | out-null"
148
- end
149
-
150
- def powershell_module_params(module_specification_hash)
151
- keys = module_specification_hash.keys.reject { |k| k.to_s.casecmp('force') == 0 }
152
- unless keys.any? { |k| k.to_s.downcase == 'repository' }
153
- keys.push(:repository)
154
- module_specification_hash[:repository] = psmodule_repository_name
155
- end
156
- keys.map { |key| "-#{key} #{module_specification_hash[key]}" }.join(' ')
157
- end
158
-
159
- def powershell_modules
160
- Array(config[:modules_from_gallery]).map do |powershell_module|
161
- params = if powershell_module.is_a? Hash
162
- powershell_module_params(powershell_module)
163
- else
164
- "-name '#{powershell_module}' -Repository #{psmodule_repository_name}"
165
- end
166
- "install-module #{params} -force | out-null"
167
- end
168
- end
169
-
170
- def nuget_force_bootstrap
171
- return unless config[:nuget_force_bootstrap]
172
- info("Bootstrapping the nuget package provider for PowerShell PackageManagement.")
173
- "install-packageprovider nuget -force -forcebootstrap | out-null"
174
- end
175
-
176
- def psmodule_repository_name
177
- return "PSGallery" if config[:gallery_name].nil? && config[:gallery_uri].nil?
178
- return "testing" if config[:gallery_name].nil?
179
- config[:gallery_name]
180
- end
181
-
182
- def register_psmodule_repository
183
- return if config[:gallery_uri].nil?
184
- info("Registering a new PowerShellGet Repository - #{psmodule_repository_name}")
185
- "register-packagesource -providername PowerShellGet -name '#{psmodule_repository_name}' -location '#{config[:gallery_uri]}' -force -trusted"
186
- end
187
-
188
- def install_module_script
189
- return if config[:modules_from_gallery].nil?
190
- <<-EOH
191
- #{nuget_force_bootstrap}
192
- #{register_psmodule_repository}
193
- #{powershell_modules.join("\n")}
194
- EOH
195
- end
196
-
197
- def install_modules?
198
- config[:dsc_local_configuration_manager_version] == "wmf5" &&
199
- !config[:modules_from_gallery].nil?
200
- end
201
-
202
- def configuration_data_variable
203
- config[:configuration_data_variable].nil? ? "ConfigurationData" : config[:configuration_data_variable]
204
- end
205
-
206
- def configuration_data_assignment
207
- "$" + configuration_data_variable + " = " + ps_hash(config[:configuration_data])
208
- end
209
-
210
- def wrap_powershell_code(code)
211
- wrap_shell_code(["$ProgressPreference = 'SilentlyContinue';", code].join("\n"))
212
- end
213
-
214
- def powershell_module?
215
- module_metadata_file = File.join(config[:kitchen_root], "#{module_name}.psd1")
216
- File.exist?(module_metadata_file)
217
- end
218
-
219
- def list_files(path)
220
- base_directory_content = Dir.glob(File.join(path, "*"))
221
- nested_directory_content = Dir.glob(File.join(path, "*/**/*"))
222
- all_directory_content = [base_directory_content, nested_directory_content].flatten
223
-
224
- ignore_files = ["Gemfile", "Gemfile.lock", "README.md", "LICENSE.txt"]
225
- all_directory_content.reject do |f|
226
- debug("Enumerating #{f}")
227
- ignore_files.include?(File.basename(f)) || File.directory?(f)
228
- end
229
- end
230
-
231
- def module_name
232
- File.basename(config[:kitchen_root])
233
- end
234
-
235
- def prepare_resource_style_directory
236
- sandbox_base_module_path = File.join(sandbox_path, "modules/#{module_name}")
237
-
238
- base = config[:kitchen_root]
239
- list_files(base).each do |src|
240
- dest = File.join(sandbox_base_module_path, src.sub("#{base}/", ""))
241
- FileUtils.mkdir_p(File.dirname(dest))
242
- debug("Staging #{src} ")
243
- debug(" at #{dest}")
244
- FileUtils.cp(src, dest, :preserve => true)
245
- end
246
- end
247
-
248
- def prepare_repo_style_directory
249
- module_path = File.join(config[:kitchen_root], config[:modules_path])
250
- sandbox_module_path = File.join(sandbox_path, "modules")
251
-
252
- if Dir.exist?(module_path)
253
- debug("Moving #{module_path} to #{sandbox_module_path}")
254
- FileUtils.cp_r(module_path, sandbox_module_path)
255
- else
256
- debug("The modules path #{module_path} was not found. Not moving to #{sandbox_module_path}.")
257
- end
258
- end
259
-
260
- def sandboxed_configuration_script
261
- File.join("configuration", config[:configuration_script])
262
- end
263
-
264
- def pad(depth = 0)
265
- " " * depth
266
- end
267
-
268
- def ps_hash(obj, depth = 0)
269
- if obj.is_a?(Hash)
270
- obj.map do |k, v|
271
- %{#{pad(depth + 2)}#{ps_hash(k)} = #{ps_hash(v, depth + 2)}}
272
- end.join(";\n").insert(0, "@{\n").insert(-1, "\n#{pad(depth)}}")
273
- elsif obj.is_a?(Array)
274
- array_string = obj.map { |v| ps_hash(v, depth + 4) }.join(",")
275
- "#{pad(depth)}@(\n#{array_string}\n)"
276
- else
277
- %{"#{obj}"}
278
- end
279
- end
280
-
281
- def prepare_configuration_script
282
- configuration_script_file = File.join(config[:configuration_script_folder], config[:configuration_script])
283
- configuration_script_path = File.join(config[:kitchen_root], configuration_script_file)
284
- sandbox_configuration_script_path = File.join(sandbox_path, sandboxed_configuration_script)
285
- FileUtils.mkdir_p(File.dirname(sandbox_configuration_script_path))
286
- debug("Moving #{configuration_script_path} to #{sandbox_configuration_script_path}")
287
- FileUtils.cp(configuration_script_path, sandbox_configuration_script_path)
288
- end
289
- end
290
- end
291
- 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 Apache 2 License.
8
+ # See LICENSE for more details
9
+
10
+ require "fileutils"
11
+ require "pathname"
12
+ require "kitchen/provisioner/base"
13
+ require "kitchen/util"
14
+ require "dsc_lcm_configuration"
15
+
16
+ module Kitchen
17
+ module Provisioner
18
+ class Dsc < Base
19
+ kitchen_provisioner_api_version 2
20
+
21
+ attr_accessor :tmp_dir
22
+
23
+ default_config :modules_path, "modules"
24
+
25
+ default_config :configuration_script_folder, "examples"
26
+ default_config :configuration_script, "dsc_configuration.ps1"
27
+ default_config :configuration_name do |provisioner|
28
+ provisioner.instance.suite.name
29
+ end
30
+
31
+ default_config :configuration_data_variable, "ConfigurationData"
32
+ default_config :configuration_data
33
+
34
+ default_config :nuget_force_bootstrap, true
35
+ default_config :gallery_uri
36
+ default_config :gallery_name
37
+ default_config :modules_from_gallery
38
+
39
+ default_config :dsc_local_configuration_manager_version, "wmf4"
40
+ default_config :dsc_local_configuration_manager, {}
41
+
42
+ def finalize_config!(instance)
43
+ config[:dsc_local_configuration_manager] = lcm.lcm_config
44
+ super(instance)
45
+ end
46
+
47
+ def install_command
48
+ full_lcm_configuration_script = <<-EOH
49
+ #{lcm.lcm_configuration_script}
50
+
51
+ $null = SetupLCM
52
+ Set-DscLocalConfigurationManager -Path ./SetupLCM | out-null
53
+ EOH
54
+
55
+ wrap_powershell_code(full_lcm_configuration_script)
56
+ end
57
+
58
+ def init_command
59
+ script = <<-EOH
60
+ #{setup_config_directory_script}
61
+ #{install_module_script if install_modules?}
62
+ EOH
63
+ wrap_powershell_code(script)
64
+ end
65
+
66
+ def create_sandbox
67
+ super
68
+ info("Staging DSC Resource Modules for copy to the SUT")
69
+ if powershell_module?
70
+ prepare_resource_style_directory
71
+ else
72
+ prepare_repo_style_directory
73
+ end
74
+ info("Staging DSC configuration script for copy to the SUT")
75
+ prepare_configuration_script
76
+ end
77
+
78
+ def prepare_command
79
+ info("Moving DSC Resources onto PSModulePath")
80
+ info("Generating the MOF script for the configuration #{config[:configuration_name]}")
81
+ stage_resources_and_generate_mof_script = <<-EOH
82
+
83
+ if(Test-Path c:/configurations)
84
+ {
85
+ Remove-Item -Recurse -Force c:/configurations
86
+ }
87
+
88
+ $Error.clear()
89
+
90
+ if (Test-Path (join-path #{config[:root_path]} 'modules'))
91
+ {
92
+ dir ( join-path #{config[:root_path]} 'modules/*') -directory |
93
+ copy-item -destination $env:programfiles/windowspowershell/modules/ -recurse -force
94
+ }
95
+ if (-not (test-path 'c:/configurations'))
96
+ {
97
+ mkdir 'c:/configurations' | out-null
98
+ }
99
+ $ConfigurationScriptPath = Join-path #{config[:root_path]} #{sandboxed_configuration_script}
100
+ if (-not (test-path $ConfigurationScriptPath))
101
+ {
102
+ throw "Failed to find $ConfigurationScriptPath"
103
+ }
104
+ invoke-expression (get-content $ConfigurationScriptPath -raw)
105
+
106
+ if (-not (get-command #{config[:configuration_name]}))
107
+ {
108
+ throw "Failed to create a configuration command #{config[:configuration_name]}"
109
+ }
110
+
111
+ #{configuration_data_assignment unless config[:configuration_data].nil?}
112
+
113
+ try{
114
+ $null = #{config[:configuration_name]} -outputpath c:/configurations #{"-configurationdata $" + configuration_data_variable}
115
+ }
116
+ catch{
117
+ }
118
+
119
+ if($Error -ne $null)
120
+ {
121
+ $Error[-1]
122
+ exit 1
123
+ }
124
+
125
+ EOH
126
+ debug("Shelling out: #{stage_resources_and_generate_mof_script}")
127
+ wrap_powershell_code(stage_resources_and_generate_mof_script)
128
+ end
129
+
130
+ def run_command
131
+ config[:retry_on_exit_code] = [35] if config[:retry_on_exit_code].empty?
132
+ config[:max_retries] = 3 if config[:max_retries] == 1
133
+
134
+ info("Running the configuration #{config[:configuration_name]}")
135
+ run_configuration_script = <<-EOH
136
+ $job = start-dscconfiguration -Path c:/configurations/ -force
137
+ $job | wait-job
138
+ $verbose_output = $job.childjobs[0].verbose
139
+ $verbose_output
140
+ if ($verbose_output -match 'A reboot is required to progress further. Please reboot the system.') {
141
+ "A reboot is required to continue."
142
+ shutdown /r /t 15
143
+ exit 35
144
+ }
145
+ $dsc_errors = $job.childjobs[0].Error
146
+ if ($dsc_errors -ne $null) {
147
+ $dsc_errors
148
+ exit 1
149
+ }
150
+ EOH
151
+
152
+ debug("Shelling out: #{run_configuration_script}")
153
+ wrap_powershell_code(run_configuration_script)
154
+ end
155
+
156
+ private
157
+
158
+ def lcm
159
+ @lcm ||= begin
160
+ lcm_version = config[:dsc_local_configuration_manager_version]
161
+ lcm_config = config[:dsc_local_configuration_manager]
162
+ DscLcmConfiguration::Factory.create(lcm_version, lcm_config)
163
+ end
164
+ end
165
+
166
+ def setup_config_directory_script
167
+ "mkdir (split-path (join-path #{config[:root_path]} #{sandboxed_configuration_script})) -force | out-null"
168
+ end
169
+
170
+ def powershell_module_params(module_specification_hash)
171
+ keys = module_specification_hash.keys.reject { |k| k.to_s.casecmp('force') == 0 }
172
+ unless keys.any? { |k| k.to_s.downcase == 'repository' }
173
+ keys.push(:repository)
174
+ module_specification_hash[:repository] = psmodule_repository_name
175
+ end
176
+ keys.map { |key| "-#{key} #{module_specification_hash[key]}" }.join(' ')
177
+ end
178
+
179
+ def powershell_modules
180
+ Array(config[:modules_from_gallery]).map do |powershell_module|
181
+ params = if powershell_module.is_a? Hash
182
+ powershell_module_params(powershell_module)
183
+ else
184
+ "-name '#{powershell_module}' -Repository #{psmodule_repository_name}"
185
+ end
186
+ "install-module #{params} -force | out-null"
187
+ end
188
+ end
189
+
190
+ def nuget_force_bootstrap
191
+ return unless config[:nuget_force_bootstrap]
192
+ info("Bootstrapping the nuget package provider for PowerShell PackageManagement.")
193
+ "install-packageprovider nuget -force -forcebootstrap | out-null"
194
+ end
195
+
196
+ def psmodule_repository_name
197
+ return "PSGallery" if config[:gallery_name].nil? && config[:gallery_uri].nil?
198
+ return "testing" if config[:gallery_name].nil?
199
+ config[:gallery_name]
200
+ end
201
+
202
+ def register_psmodule_repository
203
+ return if config[:gallery_uri].nil?
204
+ info("Registering a new PowerShellGet Repository - #{psmodule_repository_name}")
205
+ "register-packagesource -providername PowerShellGet -name '#{psmodule_repository_name}' -location '#{config[:gallery_uri]}' -force -trusted"
206
+ end
207
+
208
+ def install_module_script
209
+ return if config[:modules_from_gallery].nil?
210
+ <<-EOH
211
+ #{nuget_force_bootstrap}
212
+ #{register_psmodule_repository}
213
+ #{powershell_modules.join("\n")}
214
+ EOH
215
+ end
216
+
217
+ def install_modules?
218
+ config[:dsc_local_configuration_manager_version] == "wmf5" &&
219
+ !config[:modules_from_gallery].nil?
220
+ end
221
+
222
+ def configuration_data_variable
223
+ config[:configuration_data_variable].nil? ? "ConfigurationData" : config[:configuration_data_variable]
224
+ end
225
+
226
+ def configuration_data_assignment
227
+ "$" + configuration_data_variable + " = " + ps_hash(config[:configuration_data])
228
+ end
229
+
230
+ def wrap_powershell_code(code)
231
+ wrap_shell_code(["$ProgressPreference = 'SilentlyContinue';", code].join("\n"))
232
+ end
233
+
234
+ def powershell_module?
235
+ module_metadata_file = File.join(config[:kitchen_root], "#{module_name}.psd1")
236
+ File.exist?(module_metadata_file)
237
+ end
238
+
239
+ def list_files(path)
240
+ base_directory_content = Dir.glob(File.join(path, "*"))
241
+ nested_directory_content = Dir.glob(File.join(path, "*/**/*"))
242
+ all_directory_content = [base_directory_content, nested_directory_content].flatten
243
+
244
+ ignore_files = ["Gemfile", "Gemfile.lock", "README.md", "LICENSE.txt"]
245
+ all_directory_content.reject do |f|
246
+ debug("Enumerating #{f}")
247
+ ignore_files.include?(File.basename(f)) || File.directory?(f)
248
+ end
249
+ end
250
+
251
+ def module_name
252
+ File.basename(config[:kitchen_root])
253
+ end
254
+
255
+ def prepare_resource_style_directory
256
+ sandbox_base_module_path = File.join(sandbox_path, "modules/#{module_name}")
257
+
258
+ base = config[:kitchen_root]
259
+ list_files(base).each do |src|
260
+ dest = File.join(sandbox_base_module_path, src.sub("#{base}/", ""))
261
+ FileUtils.mkdir_p(File.dirname(dest))
262
+ debug("Staging #{src} ")
263
+ debug(" at #{dest}")
264
+ FileUtils.cp(src, dest, :preserve => true)
265
+ end
266
+ end
267
+
268
+ def prepare_repo_style_directory
269
+ module_path = File.join(config[:kitchen_root], config[:modules_path])
270
+ sandbox_module_path = File.join(sandbox_path, "modules")
271
+
272
+ if Dir.exist?(module_path)
273
+ debug("Moving #{module_path} to #{sandbox_module_path}")
274
+ FileUtils.cp_r(module_path, sandbox_module_path)
275
+ else
276
+ debug("The modules path #{module_path} was not found. Not moving to #{sandbox_module_path}.")
277
+ end
278
+ end
279
+
280
+ def sandboxed_configuration_script
281
+ File.join("configuration", config[:configuration_script])
282
+ end
283
+
284
+ def pad(depth = 0)
285
+ " " * depth
286
+ end
287
+
288
+ def ps_hash(obj, depth = 0)
289
+ if obj.is_a?(Hash)
290
+ obj.map do |k, v|
291
+ %{#{pad(depth + 2)}#{ps_hash(k)} = #{ps_hash(v, depth + 2)}}
292
+ end.join(";\n").insert(0, "@{\n").insert(-1, "\n#{pad(depth)}}")
293
+ elsif obj.is_a?(Array)
294
+ array_string = obj.map { |v| ps_hash(v, depth + 4) }.join(",")
295
+ "#{pad(depth)}@(\n#{array_string}\n)"
296
+ else
297
+ %{"#{obj}"}
298
+ end
299
+ end
300
+
301
+ def prepare_configuration_script
302
+ configuration_script_file = File.join(config[:configuration_script_folder], config[:configuration_script])
303
+ configuration_script_path = File.join(config[:kitchen_root], configuration_script_file)
304
+ sandbox_configuration_script_path = File.join(sandbox_path, sandboxed_configuration_script)
305
+ FileUtils.mkdir_p(File.dirname(sandbox_configuration_script_path))
306
+ debug("Moving #{configuration_script_path} to #{sandbox_configuration_script_path}")
307
+ FileUtils.cp(configuration_script_path, sandbox_configuration_script_path)
308
+ end
309
+ end
310
+ end
311
+ end