kitchen-dsc 0.10.0 → 0.10.1

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: 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