test-kitchen 1.22.1 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -110
- data/RELEASE_NOTES.md +167 -0
- data/lib/kitchen.rb +1 -0
- data/lib/kitchen/config.rb +13 -0
- data/lib/kitchen/data_munger.rb +63 -2
- data/lib/kitchen/generator/init.rb +0 -1
- data/lib/kitchen/instance.rb +25 -10
- data/lib/kitchen/lifecycle_hooks.rb +135 -0
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +2 -6
- data/lib/kitchen/transport/ssh.rb +1 -5
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/config_spec.rb +3 -0
- data/spec/kitchen/data_munger_spec.rb +107 -0
- data/spec/kitchen/instance_spec.rb +33 -9
- data/spec/kitchen/lifecycle_hooks_spec.rb +171 -0
- data/spec/kitchen/transport/ssh_spec.rb +1 -2
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 885f8d3b08f1f4c860cd55c370cefc6f2b35e87dc2607ce9f6d60c39788bfd86
|
|
4
|
+
data.tar.gz: 352335dacee5a0ed1dbe5067d658bd2cd85bac1d0ec39c49a1283871c8604953
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc58bb9f82520bf0e616620a874d0452ac5ed0889cc7e28f0eb1aacfbb8e609436b65ff6f3f687044c3f896fc4846697cf96c78b8adee54816647c9a2f787373
|
|
7
|
+
data.tar.gz: '0909b191b4dc6c965ccf6e5afb59b67cff485035b049de9bea218c89f31753312ab970ca68217dc4c7f4eaa6b33ea814f67ce5a9cda3e31a0efa0a66bc2a3dd1'
|
data/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
## [v1.
|
|
4
|
-
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.22.0...v1.
|
|
3
|
+
## [v1.23.0](https://github.com/test-kitchen/test-kitchen/tree/v1.23.0) (2018-07-30)
|
|
4
|
+
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.22.0...v1.23.0)
|
|
5
5
|
|
|
6
6
|
**Merged pull requests:**
|
|
7
7
|
|
|
8
|
-
-
|
|
9
|
-
|
|
8
|
+
- Lifecycle hooks [\#1428](https://github.com/test-kitchen/test-kitchen/pull/1428) ([coderanger](https://github.com/coderanger))
|
|
9
|
+
- Minor technical cleanup and unify behavior for files and directories. [\#1401](https://github.com/test-kitchen/test-kitchen/pull/1401) ([coderanger](https://github.com/coderanger))
|
|
10
10
|
|
|
11
11
|
## [v1.22.0](https://github.com/test-kitchen/test-kitchen/tree/v1.22.0) (2018-06-28)
|
|
12
12
|
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.21.2...v1.22.0)
|
|
@@ -21,23 +21,14 @@
|
|
|
21
21
|
- Removing thor upper bound in step with berks [\#1410](https://github.com/test-kitchen/test-kitchen/pull/1410) ([cheeseplus](https://github.com/cheeseplus)
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
## [v1.21.1](https://github.com/test-kitchen/test-kitchen/tree/v1.21.1) (2018-04-18)
|
|
26
25
|
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.21.0...v1.21.1)
|
|
27
26
|
|
|
28
|
-
|
|
29
27
|
- Revert: honor root\_path for location of chef installer script [\#1369]
|
|
30
28
|
|
|
31
29
|
## [v1.21.0](https://github.com/test-kitchen/test-kitchen/tree/v1.21.0) (2018-04-16)
|
|
32
30
|
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.20.0...v1.21.0)
|
|
33
31
|
|
|
34
|
-
**Release Notes:**
|
|
35
|
-
|
|
36
|
-
### Configuration UX improvements
|
|
37
|
-
|
|
38
|
-
Having the kitchen configuration file be hidden has always been a bit odd and so we're moving to using `kitchen.yml` over `.kitchen.yml`.
|
|
39
|
-
This also applies to `kitchen.local.yml` and we've made the change backwards compatible so you're not forced to move over right away. Additionally, we've added support for the environment variables `KITCHEN_YML` and KITCHEN_LOCAL_YML` again preserving compatibility if you're using the `*_YAML` forms.
|
|
40
|
-
|
|
41
32
|
**Merged pull requests:**
|
|
42
33
|
|
|
43
34
|
- Support `\*\_YML` for env vars too, for better UX [\#1398](https://github.com/test-kitchen/test-kitchen/pull/1398) ([coderanger](https://github.com/coderanger))
|
|
@@ -57,58 +48,6 @@ This also applies to `kitchen.local.yml` and we've made the change backwards com
|
|
|
57
48
|
## [v1.20.0](https://github.com/test-kitchen/test-kitchen/tree/v1.20.0) (2018-01-19)
|
|
58
49
|
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.19.2...v1.20.0)
|
|
59
50
|
|
|
60
|
-
**Release Notes:**
|
|
61
|
-
|
|
62
|
-
#### Multiple paths for data_bags
|
|
63
|
-
|
|
64
|
-
Allows a user to use data_bags from an array of directories
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
data_bags_path:
|
|
68
|
-
- 'data_bags'
|
|
69
|
-
- 'test/integrations/data_bags'
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
#### Deprecation Warnings for Configuration Keys
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
$ kitchen list default-centos-7
|
|
76
|
-
$$$$$$ Deprecated configuration detected:
|
|
77
|
-
require_chef_omnibus
|
|
78
|
-
Run 'kitchen doctor' for details.
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
$ kitchen doctor
|
|
83
|
-
$$$$$$ Deprecated configuration detected:
|
|
84
|
-
require_chef_omnibus
|
|
85
|
-
Run 'kitchen doctor' for details.
|
|
86
|
-
|
|
87
|
-
-----> The doctor is in
|
|
88
|
-
**** require_chef_omnibus deprecated
|
|
89
|
-
The 'require_chef_omnibus' attribute with version values will change
|
|
90
|
-
to use the new 'product_version' attribute.
|
|
91
|
-
|
|
92
|
-
Note: 'product_name' must be set in order to use 'product_version'
|
|
93
|
-
until 'product_name' replaces 'require_chef_omnibus' as the default.
|
|
94
|
-
|
|
95
|
-
# New Usage #
|
|
96
|
-
provisioner:
|
|
97
|
-
product_name: <chef or chefdk>
|
|
98
|
-
product_version: 12.0.3
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
#### SSH via an HTTP Proxy
|
|
102
|
-
|
|
103
|
-
This allows configuring the SSH transport to utilize an HTTP Proxy. The following configuration keys have been added to `transport`:
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
ssh_http_proxy_user
|
|
107
|
-
ssh_http_proxy_password
|
|
108
|
-
ssh_http_proxy_port
|
|
109
|
-
ssh_http_proxy
|
|
110
|
-
```
|
|
111
|
-
|
|
112
51
|
**Merged pull requests:**
|
|
113
52
|
|
|
114
53
|
- Support multiple paths for data bags [\#1313](https://github.com/test-kitchen/test-kitchen/pull/1313) ([thomasdziedzic](https://github.com/thomasdziedzic))
|
|
@@ -141,50 +80,6 @@ Removed an extraneous bash shebang that caused the script generated to install c
|
|
|
141
80
|
## [v1.19.0](https://github.com/test-kitchen/test-kitchen/tree/v1.19.0) (2017-11-1)
|
|
142
81
|
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.18.0...v1.19.0)
|
|
143
82
|
|
|
144
|
-
**Release Notes:**
|
|
145
|
-
|
|
146
|
-
#### Driver Commands Removed
|
|
147
|
-
|
|
148
|
-
The `kitchen driver` family of commands have been removed. It was not recommended
|
|
149
|
-
to use them and it was judged to be more harm than good to leave them in. If you
|
|
150
|
-
regularly create new drivers and relied on the skeleton generator, check out
|
|
151
|
-
other code skeleton projects like [`chef generate`](https://blog.chef.io/2014/12/09/guest-post-creating-your-own-chef-cookbook-generator/),
|
|
152
|
-
and [Cookiecutter](https://github.com/audreyr/cookiecutter).
|
|
153
|
-
|
|
154
|
-
#### `kitchen converge -D`
|
|
155
|
-
|
|
156
|
-
When you want to get debug logging for your provisioner or verifier, you can now
|
|
157
|
-
use the new `-D` (or `--debug`) command line option for `kitchen converge`,
|
|
158
|
-
`kitchen verify`, and `kitchen test`. Support has been added to the Chef provisioners,
|
|
159
|
-
avoiding the need to use the `log_level: debug` configuration option every time.
|
|
160
|
-
|
|
161
|
-
#### `exec` Driver
|
|
162
|
-
|
|
163
|
-
A new driver named `exec` is included with Test Kitchen which runs all the
|
|
164
|
-
provisioning and verification commands locally, rather than on a VM. This can
|
|
165
|
-
be used for testing on systems where you've already created the VM yourself and
|
|
166
|
-
installed Test Kitchen on it. Note that this is related but different from the
|
|
167
|
-
included `proxy` driver, which also connects to an existing server, but over
|
|
168
|
-
SSH/WinRM rather than running commands locally.
|
|
169
|
-
|
|
170
|
-
#### `shell` Provisioner `command`
|
|
171
|
-
|
|
172
|
-
Previously the included `shell` provisioner allowed running a user-specified bootstrap
|
|
173
|
-
script. This has been extended to allow specifying a `command` option with a
|
|
174
|
-
string to run, rather than managing a script file.
|
|
175
|
-
|
|
176
|
-
#### Faster Busser
|
|
177
|
-
|
|
178
|
-
The `busser` verifier has been improved to be faster on the second (or beyond)
|
|
179
|
-
verification, or in other cases where the required gems are already present.
|
|
180
|
-
|
|
181
|
-
#### `kitchen doctor`
|
|
182
|
-
|
|
183
|
-
A `kitchen doctor` command has been added, modeled on Homebrew's `brew doctor`.
|
|
184
|
-
This currently doesn't do much, but if you are a Kitchen plugin author, consider
|
|
185
|
-
adding more detailed debugging checks and troubleshooting help to your plugin
|
|
186
|
-
via this system.
|
|
187
|
-
|
|
188
83
|
**Merged pull requests**
|
|
189
84
|
|
|
190
85
|
- Basic framework for kitchen doctor [\#1301](https://github.com/test-kitchen/test-kitchen/pull/1301) ([coderanger](https://github.com/coderanger))
|
|
@@ -224,7 +119,6 @@ via this system.
|
|
|
224
119
|
- New install\_strategy option used in conjunction with product\_name [\#1262](https://github.com/test-kitchen/test-kitchen/pull/1262) ([wrightp](https://github.com/wrightp))
|
|
225
120
|
- Allow command line arguments config in shell provisioner [\#943](https://github.com/test-kitchen/test-kitchen/pull/943) ([mmckinst](https://github.com/mmckinst))
|
|
226
121
|
|
|
227
|
-
|
|
228
122
|
## [v1.17.0](https://github.com/test-kitchen/test-kitchen/tree/v1.17.0) (2017-08-11)
|
|
229
123
|
[Full Changelog](https://github.com/test-kitchen/test-kitchen/compare/v1.16.0...v1.17.0)
|
|
230
124
|
|
data/RELEASE_NOTES.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Test Kitchen 1.23.0 Release Notes
|
|
2
|
+
|
|
3
|
+
## Life Cycle Hooks
|
|
4
|
+
|
|
5
|
+
The life cycle hooks system allows running commands before or after any phase
|
|
6
|
+
of Test Kitchen (`create`, `converge`, `verify`, or `destroy`). Commands can be
|
|
7
|
+
run either locally on your workstation (the default) or remotely on the test instance.
|
|
8
|
+
|
|
9
|
+
These hooks are configured under a new `lifecycle:` section in `kitchen.yml`:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
lifecycle:
|
|
13
|
+
pre_create: echo before
|
|
14
|
+
post_create:
|
|
15
|
+
- echo after
|
|
16
|
+
- local: echo also after
|
|
17
|
+
- remote: echo after but in the instance
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
You can also configure hooks on a single platform or suite:
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
platforms:
|
|
24
|
+
- name: ubuntu-18.04
|
|
25
|
+
lifecycle:
|
|
26
|
+
pre_converge:
|
|
27
|
+
- remote: apt update
|
|
28
|
+
|
|
29
|
+
suites:
|
|
30
|
+
- name: default
|
|
31
|
+
lifecycle:
|
|
32
|
+
post_verify:
|
|
33
|
+
- my_coverage_formatter
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Local commands automatically get some environment variables with information
|
|
37
|
+
about which instance the hook is evaluating against:
|
|
38
|
+
|
|
39
|
+
* `KITCHEN_INSTANCE_NAME` - The full name of the instance
|
|
40
|
+
* `KITCHEN_SUITE_NAME` - The name of the suite of the instance
|
|
41
|
+
* `KITCHEN_PLATFORM_NAME` - The name of the platform of the instance
|
|
42
|
+
* `KITCHEN_INSTANCE_HOSTNAME` - The hostname of the instance as reported by the driver plugin
|
|
43
|
+
|
|
44
|
+
You can also pass additional configuration for local commands:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
lifecycle:
|
|
48
|
+
pre_converge:
|
|
49
|
+
- local: ./setup.sh
|
|
50
|
+
environment:
|
|
51
|
+
API_KEY: asdf1234
|
|
52
|
+
timeout: 60
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Remote commands are normally not allowed during `pre_create` or `post_destroy`
|
|
56
|
+
hooks as there is generally no instance running at that point, but with `pre_destroy`
|
|
57
|
+
hooks you may want to use the `skippable` flag so as to not fail during `kitchen test`:
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
lifecycle:
|
|
61
|
+
pre_destroy:
|
|
62
|
+
- remote: myapp --unregister-license
|
|
63
|
+
skippable: true
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
# Test Kitchen 1.21.0 Release Notes
|
|
67
|
+
|
|
68
|
+
## Configuration UX improvements
|
|
69
|
+
|
|
70
|
+
Having the kitchen configuration file be hidden has always been a bit odd and so we're moving to using `kitchen.yml` over `.kitchen.yml`.
|
|
71
|
+
This also applies to `kitchen.local.yml` and we've made the change backwards compatible so you're not forced to move over right away. Additionally, we've added support for the environment variables `KITCHEN_YML` and KITCHEN_LOCAL_YML` again preserving compatibility if you're using the `*_YAML` forms.
|
|
72
|
+
|
|
73
|
+
# Test Kitchen 1.20.0 Release Notes
|
|
74
|
+
|
|
75
|
+
## Multiple paths for data_bags
|
|
76
|
+
|
|
77
|
+
Allows a user to use data_bags from an array of directories
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
data_bags_path:
|
|
81
|
+
- 'data_bags'
|
|
82
|
+
- 'test/integrations/data_bags'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Deprecation Warnings for Configuration Keys
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
$ kitchen list default-centos-7
|
|
89
|
+
$$$$$$ Deprecated configuration detected:
|
|
90
|
+
require_chef_omnibus
|
|
91
|
+
Run 'kitchen doctor' for details.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
$ kitchen doctor
|
|
96
|
+
$$$$$$ Deprecated configuration detected:
|
|
97
|
+
require_chef_omnibus
|
|
98
|
+
Run 'kitchen doctor' for details.
|
|
99
|
+
|
|
100
|
+
-----> The doctor is in
|
|
101
|
+
**** require_chef_omnibus deprecated
|
|
102
|
+
The 'require_chef_omnibus' attribute with version values will change
|
|
103
|
+
to use the new 'product_version' attribute.
|
|
104
|
+
|
|
105
|
+
Note: 'product_name' must be set in order to use 'product_version'
|
|
106
|
+
until 'product_name' replaces 'require_chef_omnibus' as the default.
|
|
107
|
+
|
|
108
|
+
# New Usage #
|
|
109
|
+
provisioner:
|
|
110
|
+
product_name: <chef or chefdk>
|
|
111
|
+
product_version: 12.0.3
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## SSH via an HTTP Proxy
|
|
115
|
+
|
|
116
|
+
This allows configuring the SSH transport to utilize an HTTP Proxy. The following configuration keys have been added to `transport`:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
ssh_http_proxy_user
|
|
120
|
+
ssh_http_proxy_password
|
|
121
|
+
ssh_http_proxy_port
|
|
122
|
+
ssh_http_proxy
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
# Test Kitchen 1.20.0 Release Notes
|
|
126
|
+
|
|
127
|
+
## Driver Commands Removed
|
|
128
|
+
|
|
129
|
+
The `kitchen driver` family of commands have been removed. It was not recommended
|
|
130
|
+
to use them and it was judged to be more harm than good to leave them in. If you
|
|
131
|
+
regularly create new drivers and relied on the skeleton generator, check out
|
|
132
|
+
other code skeleton projects like [`chef generate`](https://blog.chef.io/2014/12/09/guest-post-creating-your-own-chef-cookbook-generator/),
|
|
133
|
+
and [Cookiecutter](https://github.com/audreyr/cookiecutter).
|
|
134
|
+
|
|
135
|
+
## `kitchen converge -D`
|
|
136
|
+
|
|
137
|
+
When you want to get debug logging for your provisioner or verifier, you can now
|
|
138
|
+
use the new `-D` (or `--debug`) command line option for `kitchen converge`,
|
|
139
|
+
`kitchen verify`, and `kitchen test`. Support has been added to the Chef provisioners,
|
|
140
|
+
avoiding the need to use the `log_level: debug` configuration option every time.
|
|
141
|
+
|
|
142
|
+
## `exec` Driver
|
|
143
|
+
|
|
144
|
+
A new driver named `exec` is included with Test Kitchen which runs all the
|
|
145
|
+
provisioning and verification commands locally, rather than on a VM. This can
|
|
146
|
+
be used for testing on systems where you've already created the VM yourself and
|
|
147
|
+
installed Test Kitchen on it. Note that this is related but different from the
|
|
148
|
+
included `proxy` driver, which also connects to an existing server, but over
|
|
149
|
+
SSH/WinRM rather than running commands locally.
|
|
150
|
+
|
|
151
|
+
## `shell` Provisioner `command`
|
|
152
|
+
|
|
153
|
+
Previously the included `shell` provisioner allowed running a user-specified bootstrap
|
|
154
|
+
script. This has been extended to allow specifying a `command` option with a
|
|
155
|
+
string to run, rather than managing a script file.
|
|
156
|
+
|
|
157
|
+
## Faster Busser
|
|
158
|
+
|
|
159
|
+
The `busser` verifier has been improved to be faster on the second (or beyond)
|
|
160
|
+
verification, or in other cases where the required gems are already present.
|
|
161
|
+
|
|
162
|
+
## `kitchen doctor`
|
|
163
|
+
|
|
164
|
+
A `kitchen doctor` command has been added, modeled on Homebrew's `brew doctor`.
|
|
165
|
+
This currently doesn't do much, but if you are a Kitchen plugin author, consider
|
|
166
|
+
adding more detailed debugging checks and troubleshooting help to your plugin
|
|
167
|
+
via this system.
|
data/lib/kitchen.rb
CHANGED
|
@@ -37,6 +37,7 @@ require "kitchen/driver/base"
|
|
|
37
37
|
require "kitchen/driver/ssh_base"
|
|
38
38
|
require "kitchen/driver/proxy"
|
|
39
39
|
require "kitchen/instance"
|
|
40
|
+
require "kitchen/lifecycle_hooks"
|
|
40
41
|
require "kitchen/transport"
|
|
41
42
|
require "kitchen/transport/base"
|
|
42
43
|
require "kitchen/loader/yaml"
|
data/lib/kitchen/config.rb
CHANGED
|
@@ -245,6 +245,7 @@ module Kitchen
|
|
|
245
245
|
def new_instance(suite, platform, index)
|
|
246
246
|
Instance.new(
|
|
247
247
|
driver: new_driver(suite, platform),
|
|
248
|
+
lifecycle_hooks: new_lifecycle_hooks(suite, platform),
|
|
248
249
|
logger: new_instance_logger(suite, platform, index),
|
|
249
250
|
suite: suite,
|
|
250
251
|
platform: platform,
|
|
@@ -277,6 +278,18 @@ module Kitchen
|
|
|
277
278
|
)
|
|
278
279
|
end
|
|
279
280
|
|
|
281
|
+
# Builds a newly configured LifecycleHooks object, for a given a Suite and
|
|
282
|
+
# Platform.
|
|
283
|
+
#
|
|
284
|
+
# @param suite [Suite,#name] a Suite
|
|
285
|
+
# @param platform [Platform,#name] a Platform
|
|
286
|
+
# @return [LifecycleHooks] a new LifecycleHooks object
|
|
287
|
+
# @api private
|
|
288
|
+
def new_lifecycle_hooks(suite, platform)
|
|
289
|
+
lhdata = data.lifecycle_hooks_data_for(suite.name, platform.name)
|
|
290
|
+
LifecycleHooks.new(lhdata)
|
|
291
|
+
end
|
|
292
|
+
|
|
280
293
|
# Builds a newly configured Provisioner object, for a given Suite and
|
|
281
294
|
# Platform.
|
|
282
295
|
#
|
data/lib/kitchen/data_munger.rb
CHANGED
|
@@ -45,6 +45,7 @@ module Kitchen
|
|
|
45
45
|
convert_legacy_busser_format!
|
|
46
46
|
convert_legacy_driver_http_proxy_format!
|
|
47
47
|
move_chef_data_to_provisioner!
|
|
48
|
+
convert_legacy_pre_create_command!
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
# Generate a new Hash of configuration data that can be used to construct
|
|
@@ -62,6 +63,25 @@ module Kitchen
|
|
|
62
63
|
end
|
|
63
64
|
end
|
|
64
65
|
|
|
66
|
+
# Generate a new Hash of configuration data that can be used to construct
|
|
67
|
+
# a new LifecycleHooks object.
|
|
68
|
+
#
|
|
69
|
+
# @param suite [String] a suite name
|
|
70
|
+
# @param platform [String] a platform name
|
|
71
|
+
# @return [Hash] a new configuration Hash that can be used to construct a
|
|
72
|
+
# new LifecycleHooks
|
|
73
|
+
def lifecycle_hooks_data_for(suite, platform)
|
|
74
|
+
merged_data_for(:lifecycle, suite, platform).tap do |lhdata|
|
|
75
|
+
lhdata.each_key do |k|
|
|
76
|
+
combine_arrays!(lhdata, k, :common, :platform, :suite)
|
|
77
|
+
end
|
|
78
|
+
set_kitchen_config_at!(lhdata, :kitchen_root)
|
|
79
|
+
set_kitchen_config_at!(lhdata, :test_base_path)
|
|
80
|
+
set_kitchen_config_at!(lhdata, :log_level)
|
|
81
|
+
set_kitchen_config_at!(lhdata, :debug)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
65
85
|
# Returns an Array of platform Hashes.
|
|
66
86
|
#
|
|
67
87
|
# @return [Array<Hash>] an Array of Hashes
|
|
@@ -591,6 +611,27 @@ module Kitchen
|
|
|
591
611
|
end
|
|
592
612
|
end
|
|
593
613
|
|
|
614
|
+
def convert_legacy_pre_create_command!
|
|
615
|
+
convert_legacy_pre_create_command_at!(data)
|
|
616
|
+
data.fetch(:platforms, []).each do |platform|
|
|
617
|
+
convert_legacy_pre_create_command_at!(platform)
|
|
618
|
+
end
|
|
619
|
+
data.fetch(:suites, []).each do |suite|
|
|
620
|
+
convert_legacy_pre_create_command_at!(suite)
|
|
621
|
+
end
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
def convert_legacy_pre_create_command_at!(root)
|
|
625
|
+
ddata = root[:driver] || {}
|
|
626
|
+
if ddata.is_a?(Hash) && ddata.include?(:pre_create_command)
|
|
627
|
+
root[:lifecycle] ||= {}
|
|
628
|
+
root[:lifecycle][:pre_create] ||= []
|
|
629
|
+
root[:lifecycle][:pre_create] = Array(root[:lifecycle][:pre_create])
|
|
630
|
+
root[:lifecycle][:pre_create] << { local: ddata[:pre_create_command] }
|
|
631
|
+
ddata.delete(:pre_create_command)
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
|
|
594
635
|
# Performs a prioritized recursive merge of several source Hashes and
|
|
595
636
|
# returns a new merged Hash. For these data sub-hash structures, there are
|
|
596
637
|
# 4 sources for configuration data:
|
|
@@ -758,6 +799,12 @@ module Kitchen
|
|
|
758
799
|
cdata = data.fetch(key, {})
|
|
759
800
|
cdata = cdata.nil? ? {} : cdata.dup
|
|
760
801
|
cdata = { default_key => cdata } if cdata.is_a?(String)
|
|
802
|
+
case key
|
|
803
|
+
when :lifecycle
|
|
804
|
+
cdata.each_key do |k|
|
|
805
|
+
namespace_array!(cdata, k, :common)
|
|
806
|
+
end
|
|
807
|
+
end
|
|
761
808
|
cdata
|
|
762
809
|
end
|
|
763
810
|
|
|
@@ -856,7 +903,14 @@ module Kitchen
|
|
|
856
903
|
pdata = platform_data_for(platform).fetch(key, {})
|
|
857
904
|
pdata = pdata.nil? ? {} : pdata.dup
|
|
858
905
|
pdata = { default_key => pdata } if pdata.is_a?(String)
|
|
859
|
-
|
|
906
|
+
case key
|
|
907
|
+
when :provisioner
|
|
908
|
+
namespace_array!(pdata, :run_list, :platform)
|
|
909
|
+
when :lifecycle
|
|
910
|
+
pdata.each_key do |k|
|
|
911
|
+
namespace_array!(pdata, k, :platform)
|
|
912
|
+
end
|
|
913
|
+
end
|
|
860
914
|
pdata
|
|
861
915
|
end
|
|
862
916
|
|
|
@@ -911,7 +965,14 @@ module Kitchen
|
|
|
911
965
|
sdata = suite_data_for(suite).fetch(key, {})
|
|
912
966
|
sdata = sdata.nil? ? {} : sdata.dup
|
|
913
967
|
sdata = { default_key => sdata } if sdata.is_a?(String)
|
|
914
|
-
|
|
968
|
+
case key
|
|
969
|
+
when :provisioner
|
|
970
|
+
namespace_array!(sdata, :run_list, :suite)
|
|
971
|
+
when :lifecycle
|
|
972
|
+
sdata.each_key do |k|
|
|
973
|
+
namespace_array!(sdata, k, :suite)
|
|
974
|
+
end
|
|
975
|
+
end
|
|
915
976
|
sdata
|
|
916
977
|
end
|
|
917
978
|
|
data/lib/kitchen/instance.rb
CHANGED
|
@@ -56,6 +56,9 @@ module Kitchen
|
|
|
56
56
|
# lifecycle actions
|
|
57
57
|
attr_accessor :driver
|
|
58
58
|
|
|
59
|
+
# @return [LifecycleHooks] lifecycle hooks manager object
|
|
60
|
+
attr_accessor :lifecycle_hooks
|
|
61
|
+
|
|
59
62
|
# @return [Provisioner::Base] provisioner object which will the setup
|
|
60
63
|
# and invocation instructions for configuration management and other
|
|
61
64
|
# automation tools
|
|
@@ -90,20 +93,22 @@ module Kitchen
|
|
|
90
93
|
def initialize(options = {})
|
|
91
94
|
validate_options(options)
|
|
92
95
|
|
|
93
|
-
@suite
|
|
94
|
-
@platform
|
|
95
|
-
@name
|
|
96
|
-
@driver
|
|
97
|
-
@
|
|
98
|
-
@
|
|
99
|
-
@
|
|
100
|
-
@
|
|
101
|
-
@
|
|
96
|
+
@suite = options.fetch(:suite)
|
|
97
|
+
@platform = options.fetch(:platform)
|
|
98
|
+
@name = self.class.name_for(@suite, @platform)
|
|
99
|
+
@driver = options.fetch(:driver)
|
|
100
|
+
@lifecycle_hooks = options.fetch(:lifecycle_hooks)
|
|
101
|
+
@provisioner = options.fetch(:provisioner)
|
|
102
|
+
@transport = options.fetch(:transport)
|
|
103
|
+
@verifier = options.fetch(:verifier)
|
|
104
|
+
@logger = options.fetch(:logger) { Kitchen.logger }
|
|
105
|
+
@state_file = options.fetch(:state_file)
|
|
102
106
|
|
|
103
107
|
setup_driver
|
|
104
108
|
setup_provisioner
|
|
105
109
|
setup_transport
|
|
106
110
|
setup_verifier
|
|
111
|
+
setup_lifecycle_hooks
|
|
107
112
|
end
|
|
108
113
|
|
|
109
114
|
# Returns a displayable representation of the instance.
|
|
@@ -333,6 +338,14 @@ module Kitchen
|
|
|
333
338
|
end
|
|
334
339
|
end
|
|
335
340
|
|
|
341
|
+
# Perform any final configuration or preparation needed for the lifecycle hooks
|
|
342
|
+
# object carry out its duties.
|
|
343
|
+
#
|
|
344
|
+
# @api private
|
|
345
|
+
def setup_lifecycle_hooks
|
|
346
|
+
lifecycle_hooks.finalize_config!(self)
|
|
347
|
+
end
|
|
348
|
+
|
|
336
349
|
# Perform any final configuration or preparation needed for the provisioner
|
|
337
350
|
# object carry out its duties.
|
|
338
351
|
#
|
|
@@ -365,7 +378,9 @@ module Kitchen
|
|
|
365
378
|
def transition_to(desired)
|
|
366
379
|
result = nil
|
|
367
380
|
FSM.actions(last_action, desired).each do |transition|
|
|
368
|
-
|
|
381
|
+
@lifecycle_hooks.run_with_hooks(transition, state_file) do
|
|
382
|
+
result = send("#{transition}_action")
|
|
383
|
+
end
|
|
369
384
|
end
|
|
370
385
|
result
|
|
371
386
|
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Author:: Noah Kantrowitz <noah@coderanger.net>
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2018, Noah Kantrowitz
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
|
|
19
|
+
require "kitchen/errors"
|
|
20
|
+
require "kitchen/shell_out"
|
|
21
|
+
|
|
22
|
+
module Kitchen
|
|
23
|
+
# A helper object used by {Instance} to coordinate lifecycle hook calls from
|
|
24
|
+
# the `lifecycle:` configuration section.
|
|
25
|
+
#
|
|
26
|
+
# @api internal
|
|
27
|
+
# @since 1.22
|
|
28
|
+
class LifecycleHooks
|
|
29
|
+
include Configurable
|
|
30
|
+
include Logging
|
|
31
|
+
include ShellOut
|
|
32
|
+
|
|
33
|
+
def initialize(config)
|
|
34
|
+
init_config(config)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Run a lifecycle phase with the pre and post hooks.
|
|
38
|
+
#
|
|
39
|
+
# @param phase [String] Lifecycle phase which is being executed.
|
|
40
|
+
# @param state_file [StateFile] Instance state file object.
|
|
41
|
+
# @param block [Proc] Block of code implementing the lifecycle phase.
|
|
42
|
+
# @return [void]
|
|
43
|
+
def run_with_hooks(phase, state_file, &block)
|
|
44
|
+
run(instance, phase, state_file, :pre)
|
|
45
|
+
yield
|
|
46
|
+
run(instance, phase, state_file, :post)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
# Execute a specific lifecycle hook.
|
|
52
|
+
#
|
|
53
|
+
# @param instance [Instance] The instance object to run against.
|
|
54
|
+
# @param phase [String] Lifecycle phase which is being executed.
|
|
55
|
+
# @param state_file [StateFile] Instance state file object.
|
|
56
|
+
# @param hook_timing [Symbol] `:pre` or `:post` to indicate which hook to run.
|
|
57
|
+
# @return [void]
|
|
58
|
+
def run(instance, phase, state_file, hook_timing)
|
|
59
|
+
# Yes this has to be a symbol because of how data munger works.
|
|
60
|
+
hook_key = :"#{hook_timing}_#{phase}"
|
|
61
|
+
# No hooks? We're outta here.
|
|
62
|
+
hook_data = Array(config[hook_key])
|
|
63
|
+
return if hook_data.empty?
|
|
64
|
+
hook_data.each do |hook|
|
|
65
|
+
# Coerce the common case of a bare string to be a local command. This
|
|
66
|
+
# is to match the behavior of the old `pre_create_command` semi-hook.
|
|
67
|
+
hook = { local: hook } if hook.is_a?(String)
|
|
68
|
+
if hook.include?(:local)
|
|
69
|
+
# Local command execution on the workstation.
|
|
70
|
+
run_local_hook(instance, state_file, hook)
|
|
71
|
+
elsif hook.include?(:remote)
|
|
72
|
+
# Remote command execution on the test instance.
|
|
73
|
+
run_remote_hook(instance, state_file, hook)
|
|
74
|
+
else
|
|
75
|
+
raise UserError, "Unknown lifecycle hook target #{hook.inspect}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Execute a specific local command hook.
|
|
81
|
+
#
|
|
82
|
+
# @param instance [Instance] The instance object to run against.
|
|
83
|
+
# @param state_file [StateFile] Instance state file object.
|
|
84
|
+
# @param hook [Hash] Hook configration to use.
|
|
85
|
+
# @return [void]
|
|
86
|
+
def run_local_hook(instance, state_file, hook)
|
|
87
|
+
cmd = hook.delete(:local)
|
|
88
|
+
state = state_file.read
|
|
89
|
+
# Set up some environment variables with instance info.
|
|
90
|
+
environment = {
|
|
91
|
+
"KITCHEN_INSTANCE_NAME" => instance.name,
|
|
92
|
+
"KITCHEN_SUITE_NAME" => instance.suite.name,
|
|
93
|
+
"KITCHEN_PLATFORM_NAME" => instance.platform.name,
|
|
94
|
+
"KITCHEN_INSTANCE_HOSTNAME" => state[:hostname].to_s,
|
|
95
|
+
}
|
|
96
|
+
# If the user specified env vars too, fix them up because symbol keys
|
|
97
|
+
# make mixlib-shellout sad.
|
|
98
|
+
if hook[:environment]
|
|
99
|
+
hook[:environment].each do |k, v|
|
|
100
|
+
environment[k.to_s] = v.to_s
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
# Default the cwd to the kitchen root and resolve a relative input cwd against that.
|
|
104
|
+
cwd = if hook[:cwd]
|
|
105
|
+
File.expand_path(hook[:cwd], config[:kitchen_root])
|
|
106
|
+
else
|
|
107
|
+
config[:kitchen_root]
|
|
108
|
+
end
|
|
109
|
+
# Build the options for mixlib-shellout.
|
|
110
|
+
opts = {}.merge(hook).merge(cwd: cwd, environment: environment)
|
|
111
|
+
run_command(cmd, opts)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Execute a specific remote command hook.
|
|
115
|
+
#
|
|
116
|
+
# @param instance [Instance] The instance object to run against.
|
|
117
|
+
# @param state_file [StateFile] Instance state file object.
|
|
118
|
+
# @param hook [Hash] Hook configration to use.
|
|
119
|
+
# @return [void]
|
|
120
|
+
def run_remote_hook(instance, state_file, hook)
|
|
121
|
+
# Check if we're in a state that makes sense to even try.
|
|
122
|
+
unless instance.last_action
|
|
123
|
+
if hook[:skippable]
|
|
124
|
+
# Just not even trying.
|
|
125
|
+
return
|
|
126
|
+
else
|
|
127
|
+
raise UserError, "Cannot use remote lifecycle hooks during phases when the instance is not available"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
cmd = hook.delete(:remote)
|
|
131
|
+
conn = instance.transport.connection(state_file.read)
|
|
132
|
+
conn.execute(cmd)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -234,14 +234,10 @@ module Kitchen
|
|
|
234
234
|
case opts[:type]
|
|
235
235
|
when :directory
|
|
236
236
|
FileUtils.mkdir_p(dest)
|
|
237
|
-
|
|
238
|
-
src.each { |x| FileUtils.cp_r(Util.list_directory(x), dest) }
|
|
239
|
-
else
|
|
240
|
-
FileUtils.cp_r(Util.list_directory(src), dest)
|
|
241
|
-
end
|
|
237
|
+
Array(src).each { |dir| FileUtils.cp_r(Util.list_directory(dir), dest) }
|
|
242
238
|
when :file
|
|
243
239
|
FileUtils.mkdir_p(File.dirname(dest))
|
|
244
|
-
FileUtils.cp_r(
|
|
240
|
+
Array(src).each { |file| FileUtils.cp_r(file, dest) }
|
|
245
241
|
end
|
|
246
242
|
end
|
|
247
243
|
|
|
@@ -517,17 +517,13 @@ module Kitchen
|
|
|
517
517
|
# net-ssh to ~> 4.2, this will prevent InSpec from being used in
|
|
518
518
|
# Chef v12 because of it pinning to a v3 of net-ssh.
|
|
519
519
|
#
|
|
520
|
-
def
|
|
520
|
+
def verify_host_key_option
|
|
521
521
|
current_net_ssh = Net::SSH::Version::CURRENT
|
|
522
522
|
new_option_version = Net::SSH::Version[4, 2, 0]
|
|
523
523
|
|
|
524
524
|
current_net_ssh >= new_option_version ? :verify_host_key : :paranoid
|
|
525
525
|
end
|
|
526
526
|
|
|
527
|
-
def verify_host_key_option
|
|
528
|
-
self.class.verify_host_key_option
|
|
529
|
-
end
|
|
530
|
-
|
|
531
527
|
# Creates a new SSH Connection instance and save it for potential future
|
|
532
528
|
# reuse.
|
|
533
529
|
#
|
data/lib/kitchen/version.rb
CHANGED
data/spec/kitchen/config_spec.rb
CHANGED
|
@@ -295,6 +295,7 @@ describe Kitchen::Config do
|
|
|
295
295
|
let(:munger) do
|
|
296
296
|
stub(
|
|
297
297
|
driver_data_for: { "junk" => true },
|
|
298
|
+
lifecycle_hooks_data_for: { "junk" => true },
|
|
298
299
|
provisioner_data_for: { "junk" => true },
|
|
299
300
|
transport_data_for: { "junk" => true },
|
|
300
301
|
verifier_data_for: { "junk" => true }
|
|
@@ -309,6 +310,7 @@ describe Kitchen::Config do
|
|
|
309
310
|
Kitchen::Verifier.stubs(:for_plugin).returns("verifier")
|
|
310
311
|
Kitchen::Logger.stubs(:new).returns("logger")
|
|
311
312
|
Kitchen::StateFile.stubs(:new).returns("state_file")
|
|
313
|
+
Kitchen::LifecycleHooks.stubs(:new).returns("lifecycle_hooks")
|
|
312
314
|
|
|
313
315
|
Kitchen::DataMunger.stubs(:new).returns(munger)
|
|
314
316
|
config.stubs(:platforms).returns(platforms)
|
|
@@ -384,6 +386,7 @@ describe Kitchen::Config do
|
|
|
384
386
|
driver: "driver",
|
|
385
387
|
logger: "logger",
|
|
386
388
|
suite: suites.first,
|
|
389
|
+
lifecycle_hooks: "lifecycle_hooks",
|
|
387
390
|
platform: platforms.first,
|
|
388
391
|
provisioner: "provisioner",
|
|
389
392
|
transport: "transport",
|
|
@@ -2689,5 +2689,112 @@ module Kitchen # rubocop:disable Metrics/ModuleLength
|
|
|
2689
2689
|
end
|
|
2690
2690
|
end
|
|
2691
2691
|
end
|
|
2692
|
+
|
|
2693
|
+
describe "lifecycle_hooks stuff" do
|
|
2694
|
+
it "handles a single global hook" do
|
|
2695
|
+
DataMunger.new(
|
|
2696
|
+
{
|
|
2697
|
+
lifecycle: {
|
|
2698
|
+
pre_create: "echo foo"
|
|
2699
|
+
},
|
|
2700
|
+
platforms: [{ name: "plat" }],
|
|
2701
|
+
suites: [{ name: "sweet" }],
|
|
2702
|
+
},
|
|
2703
|
+
{}
|
|
2704
|
+
).lifecycle_hooks_data_for("sweet", "plat").must_equal(
|
|
2705
|
+
pre_create: ["echo foo"]
|
|
2706
|
+
)
|
|
2707
|
+
end
|
|
2708
|
+
|
|
2709
|
+
it "handles multiple global hooks" do
|
|
2710
|
+
DataMunger.new(
|
|
2711
|
+
{
|
|
2712
|
+
lifecycle: {
|
|
2713
|
+
pre_create: "echo foo",
|
|
2714
|
+
post_converge: ["echo bar", { local: "echo baz" }],
|
|
2715
|
+
pre_verify: [{ remote: "echo other" }],
|
|
2716
|
+
},
|
|
2717
|
+
platforms: [{ name: "plat" }],
|
|
2718
|
+
suites: [{ name: "sweet" }],
|
|
2719
|
+
},
|
|
2720
|
+
{}
|
|
2721
|
+
).lifecycle_hooks_data_for("sweet", "plat").must_equal(
|
|
2722
|
+
pre_create: ["echo foo"],
|
|
2723
|
+
post_converge: ["echo bar", { local: "echo baz" }],
|
|
2724
|
+
pre_verify: [{ remote: "echo other" }]
|
|
2725
|
+
)
|
|
2726
|
+
end
|
|
2727
|
+
|
|
2728
|
+
it "handles hooks in platforms and suites" do
|
|
2729
|
+
DataMunger.new(
|
|
2730
|
+
{
|
|
2731
|
+
lifecycle: {
|
|
2732
|
+
pre_create: "echo foo",
|
|
2733
|
+
post_create: "echo post"
|
|
2734
|
+
},
|
|
2735
|
+
platforms: [{
|
|
2736
|
+
name: "plat",
|
|
2737
|
+
lifecycle: {
|
|
2738
|
+
pre_create: "echo bar"
|
|
2739
|
+
}
|
|
2740
|
+
}],
|
|
2741
|
+
suites: [{
|
|
2742
|
+
name: "sweet",
|
|
2743
|
+
lifecycle: {
|
|
2744
|
+
pre_create: "echo baz"
|
|
2745
|
+
}
|
|
2746
|
+
}],
|
|
2747
|
+
},
|
|
2748
|
+
{}
|
|
2749
|
+
).lifecycle_hooks_data_for("sweet", "plat").must_equal(
|
|
2750
|
+
pre_create: ["echo foo", "echo bar", "echo baz"],
|
|
2751
|
+
post_create: ["echo post"]
|
|
2752
|
+
)
|
|
2753
|
+
end
|
|
2754
|
+
|
|
2755
|
+
it "munges a global legacy pre_create_command" do
|
|
2756
|
+
DataMunger.new(
|
|
2757
|
+
{
|
|
2758
|
+
driver: {
|
|
2759
|
+
pre_create_command: "echo bar"
|
|
2760
|
+
},
|
|
2761
|
+
lifecycle: {
|
|
2762
|
+
pre_create: "echo foo"
|
|
2763
|
+
},
|
|
2764
|
+
platforms: [{ name: "plat" }],
|
|
2765
|
+
suites: [{ name: "sweet" }],
|
|
2766
|
+
},
|
|
2767
|
+
{}
|
|
2768
|
+
).lifecycle_hooks_data_for("sweet", "plat").must_equal(
|
|
2769
|
+
pre_create: ["echo foo", { local: "echo bar" }]
|
|
2770
|
+
)
|
|
2771
|
+
end
|
|
2772
|
+
|
|
2773
|
+
it "munges a platform/suite legacy pre_create_commands" do
|
|
2774
|
+
DataMunger.new(
|
|
2775
|
+
{
|
|
2776
|
+
lifecycle: {
|
|
2777
|
+
pre_create: "echo foo"
|
|
2778
|
+
},
|
|
2779
|
+
platforms: [{
|
|
2780
|
+
name: "plat",
|
|
2781
|
+
driver: {
|
|
2782
|
+
pre_create_command: "echo bar"
|
|
2783
|
+
}
|
|
2784
|
+
}],
|
|
2785
|
+
suites: [{
|
|
2786
|
+
name: "sweet",
|
|
2787
|
+
driver: {
|
|
2788
|
+
pre_create_command: "echo baz"
|
|
2789
|
+
}
|
|
2790
|
+
}],
|
|
2791
|
+
},
|
|
2792
|
+
{}
|
|
2793
|
+
).lifecycle_hooks_data_for("sweet", "plat").must_equal(
|
|
2794
|
+
pre_create: ["echo foo", { local: "echo bar" }, { local: "echo baz" }]
|
|
2795
|
+
)
|
|
2796
|
+
end
|
|
2797
|
+
|
|
2798
|
+
end
|
|
2692
2799
|
end
|
|
2693
2800
|
end
|
|
@@ -95,17 +95,18 @@ class LegacyDriver < Kitchen::Driver::SSHBase
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
describe Kitchen::Instance do
|
|
98
|
-
let(:driver)
|
|
99
|
-
let(:logger_io)
|
|
100
|
-
let(:logger)
|
|
101
|
-
let(:instance)
|
|
102
|
-
let(:
|
|
103
|
-
let(:
|
|
104
|
-
let(:
|
|
105
|
-
let(:
|
|
98
|
+
let(:driver) { Kitchen::Driver::Dummy.new({}) }
|
|
99
|
+
let(:logger_io) { StringIO.new }
|
|
100
|
+
let(:logger) { Kitchen::Logger.new(logdev: logger_io) }
|
|
101
|
+
let(:instance) { Kitchen::Instance.new(opts) }
|
|
102
|
+
let(:lifecycle_hooks) { Kitchen::LifecycleHooks.new({}) }
|
|
103
|
+
let(:provisioner) { Kitchen::Provisioner::Dummy.new({}) }
|
|
104
|
+
let(:state_file) { DummyStateFile.new }
|
|
105
|
+
let(:transport) { Kitchen::Transport::Dummy.new({}) }
|
|
106
|
+
let(:verifier) { Kitchen::Verifier::Dummy.new({}) }
|
|
106
107
|
|
|
107
108
|
let(:opts) do
|
|
108
|
-
{ suite: suite, platform: platform, driver: driver,
|
|
109
|
+
{ suite: suite, platform: platform, driver: driver, lifecycle_hooks: lifecycle_hooks,
|
|
109
110
|
provisioner: provisioner, verifier: verifier,
|
|
110
111
|
logger: logger, state_file: state_file, transport: transport }
|
|
111
112
|
end
|
|
@@ -477,6 +478,13 @@ describe Kitchen::Instance do
|
|
|
477
478
|
logger_io.string
|
|
478
479
|
.must_match regex_for("Finished creating #{instance.to_str}")
|
|
479
480
|
end
|
|
481
|
+
|
|
482
|
+
it "calls lifecycle hooks" do
|
|
483
|
+
lifecycle_hooks.expects(:run).with(instance, :create, state_file, :pre)
|
|
484
|
+
lifecycle_hooks.expects(:run).with(instance, :create, state_file, :post)
|
|
485
|
+
|
|
486
|
+
instance.create
|
|
487
|
+
end
|
|
480
488
|
end
|
|
481
489
|
|
|
482
490
|
describe "with last_action of create" do
|
|
@@ -525,6 +533,15 @@ describe Kitchen::Instance do
|
|
|
525
533
|
logger_io.string
|
|
526
534
|
.must_match regex_for("Finished converging #{instance.to_str}")
|
|
527
535
|
end
|
|
536
|
+
|
|
537
|
+
it "calls lifecycle hooks" do
|
|
538
|
+
lifecycle_hooks.expects(:run).with(instance, :create, state_file, :pre)
|
|
539
|
+
lifecycle_hooks.expects(:run).with(instance, :create, state_file, :post)
|
|
540
|
+
lifecycle_hooks.expects(:run).with(instance, :converge, state_file, :pre)
|
|
541
|
+
lifecycle_hooks.expects(:run).with(instance, :converge, state_file, :post)
|
|
542
|
+
|
|
543
|
+
instance.converge
|
|
544
|
+
end
|
|
528
545
|
end
|
|
529
546
|
|
|
530
547
|
describe "with last action of create" do
|
|
@@ -542,6 +559,13 @@ describe Kitchen::Instance do
|
|
|
542
559
|
|
|
543
560
|
state_file.read[:last_action].must_equal "converge"
|
|
544
561
|
end
|
|
562
|
+
|
|
563
|
+
it "calls lifecycle hooks" do
|
|
564
|
+
lifecycle_hooks.expects(:run).with(instance, :converge, state_file, :pre)
|
|
565
|
+
lifecycle_hooks.expects(:run).with(instance, :converge, state_file, :post)
|
|
566
|
+
|
|
567
|
+
instance.converge
|
|
568
|
+
end
|
|
545
569
|
end
|
|
546
570
|
|
|
547
571
|
describe "with last action of converge" do
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Author:: Noah Kantrowitz <noah@coderanger.net>
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2018, Noah Kantrowitz
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
|
|
19
|
+
require_relative "../spec_helper"
|
|
20
|
+
|
|
21
|
+
require "kitchen/errors"
|
|
22
|
+
require "kitchen/lifecycle_hooks"
|
|
23
|
+
|
|
24
|
+
describe Kitchen::LifecycleHooks do
|
|
25
|
+
let(:suite) { mock("suite").tap { |i| i.stubs(name: "default") } }
|
|
26
|
+
let(:platform) { mock("platform").tap { |i| i.stubs(name: "toaster-1.0") } }
|
|
27
|
+
let(:state_file) { mock("state_file").tap { |s| s.stubs(read: { hostname: "localhost" }) } }
|
|
28
|
+
let(:connection) { mock("connection") }
|
|
29
|
+
let(:transport) { mock("transport").tap { |t| t.stubs(:connection).with({ hostname: "localhost" }).returns(connection) } }
|
|
30
|
+
let(:last_action) { :create }
|
|
31
|
+
let(:instance) { mock("instance").tap { |i| i.stubs(name: "default-toaster-10", transport: transport, last_action: last_action, suite: suite, platform: platform) } }
|
|
32
|
+
let(:config) { { kitchen_root: "/kitchen" } }
|
|
33
|
+
let(:lifecycle_hooks) { Kitchen::LifecycleHooks.new(config).tap { |lh| lh.finalize_config!(instance) } }
|
|
34
|
+
|
|
35
|
+
def run_lifecycle_hooks
|
|
36
|
+
lifecycle_hooks.run_with_hooks(:create, state_file) {}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Pull this out because it's used in a bunch of tests.
|
|
40
|
+
STANDARD_LOCAL_OPTIONS = {
|
|
41
|
+
cwd: "/kitchen",
|
|
42
|
+
environment: {
|
|
43
|
+
"KITCHEN_INSTANCE_NAME" => "default-toaster-10",
|
|
44
|
+
"KITCHEN_SUITE_NAME" => "default",
|
|
45
|
+
"KITCHEN_PLATFORM_NAME" => "toaster-1.0",
|
|
46
|
+
"KITCHEN_INSTANCE_HOSTNAME" => "localhost",
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
it "runs a single local command" do
|
|
51
|
+
config.update(post_create: ["echo foo"])
|
|
52
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", STANDARD_LOCAL_OPTIONS)
|
|
53
|
+
run_lifecycle_hooks
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "runs multiple local commands" do
|
|
57
|
+
config.update(post_create: ["echo foo", { local: "echo bar" }])
|
|
58
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", STANDARD_LOCAL_OPTIONS)
|
|
59
|
+
lifecycle_hooks.expects(:run_command).with("echo bar", STANDARD_LOCAL_OPTIONS)
|
|
60
|
+
run_lifecycle_hooks
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "runs multiple local hooks" do
|
|
64
|
+
config.update(pre_create: ["echo foo"], post_create: ["echo bar"])
|
|
65
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", STANDARD_LOCAL_OPTIONS)
|
|
66
|
+
lifecycle_hooks.expects(:run_command).with("echo bar", STANDARD_LOCAL_OPTIONS)
|
|
67
|
+
run_lifecycle_hooks
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "runs a local command with a user option" do
|
|
71
|
+
config.update(post_create: [{ local: "echo foo", user: "bar" }])
|
|
72
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", {
|
|
73
|
+
cwd: "/kitchen",
|
|
74
|
+
user: "bar",
|
|
75
|
+
environment: {
|
|
76
|
+
"KITCHEN_INSTANCE_NAME" => "default-toaster-10",
|
|
77
|
+
"KITCHEN_SUITE_NAME" => "default",
|
|
78
|
+
"KITCHEN_PLATFORM_NAME" => "toaster-1.0",
|
|
79
|
+
"KITCHEN_INSTANCE_HOSTNAME" => "localhost",
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
run_lifecycle_hooks
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "runs a local command with environment options" do
|
|
86
|
+
config.update(post_create: [{ local: "echo foo", environment: { FOO: "one", BAR: "two" } }])
|
|
87
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", {
|
|
88
|
+
cwd: "/kitchen",
|
|
89
|
+
environment: {
|
|
90
|
+
"FOO" => "one",
|
|
91
|
+
"BAR" => "two",
|
|
92
|
+
"KITCHEN_INSTANCE_NAME" => "default-toaster-10",
|
|
93
|
+
"KITCHEN_SUITE_NAME" => "default",
|
|
94
|
+
"KITCHEN_PLATFORM_NAME" => "toaster-1.0",
|
|
95
|
+
"KITCHEN_INSTANCE_HOSTNAME" => "localhost",
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
run_lifecycle_hooks
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "runs a local command with a relative cwd option" do
|
|
102
|
+
config.update(post_create: [{ local: "echo foo", cwd: "test" }])
|
|
103
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", {
|
|
104
|
+
cwd: os_safe_root_path("/kitchen/test"),
|
|
105
|
+
environment: {
|
|
106
|
+
"KITCHEN_INSTANCE_NAME" => "default-toaster-10",
|
|
107
|
+
"KITCHEN_SUITE_NAME" => "default",
|
|
108
|
+
"KITCHEN_PLATFORM_NAME" => "toaster-1.0",
|
|
109
|
+
"KITCHEN_INSTANCE_HOSTNAME" => "localhost",
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
run_lifecycle_hooks
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "runs a local command with an absolute cwd option" do
|
|
116
|
+
config.update(post_create: [{ local: "echo foo", cwd: "/test" }])
|
|
117
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", {
|
|
118
|
+
cwd: os_safe_root_path("/test"),
|
|
119
|
+
environment: {
|
|
120
|
+
"KITCHEN_INSTANCE_NAME" => "default-toaster-10",
|
|
121
|
+
"KITCHEN_SUITE_NAME" => "default",
|
|
122
|
+
"KITCHEN_PLATFORM_NAME" => "toaster-1.0",
|
|
123
|
+
"KITCHEN_INSTANCE_HOSTNAME" => "localhost",
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
run_lifecycle_hooks
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "runs a single remote command" do
|
|
130
|
+
config.update(post_create: [{ remote: "echo foo" }])
|
|
131
|
+
lifecycle_hooks.expects(:run_command).never
|
|
132
|
+
connection.expects(:execute).with("echo foo")
|
|
133
|
+
run_lifecycle_hooks
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "rejects unknown hook targets" do
|
|
137
|
+
config.update(post_create: [{ banana: "echo foo" }])
|
|
138
|
+
lifecycle_hooks.expects(:run_command).never
|
|
139
|
+
proc { run_lifecycle_hooks }.must_raise Kitchen::UserError
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "runs mixed local and remote commands" do
|
|
143
|
+
config.update(post_create: ["echo foo", { local: "echo bar" }, { remote: "echo baz" }])
|
|
144
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", STANDARD_LOCAL_OPTIONS)
|
|
145
|
+
lifecycle_hooks.expects(:run_command).with("echo bar", STANDARD_LOCAL_OPTIONS)
|
|
146
|
+
connection.expects(:execute).with("echo baz")
|
|
147
|
+
run_lifecycle_hooks
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
describe "with no last_action" do
|
|
151
|
+
let(:last_action) { nil }
|
|
152
|
+
|
|
153
|
+
it "runs local commands" do
|
|
154
|
+
config.update(post_create: [{ local: "echo foo" }])
|
|
155
|
+
lifecycle_hooks.expects(:run_command).with("echo foo", STANDARD_LOCAL_OPTIONS)
|
|
156
|
+
run_lifecycle_hooks
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "fails on remote commands" do
|
|
160
|
+
config.update(post_create: [{ remote: "echo foo" }])
|
|
161
|
+
lifecycle_hooks.expects(:run_command).never
|
|
162
|
+
proc { run_lifecycle_hooks }.must_raise Kitchen::UserError
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "ignores skippable remote commands" do
|
|
166
|
+
config.update(post_create: [{ remote: "echo foo", skippable: true }])
|
|
167
|
+
lifecycle_hooks.expects(:run_command).never
|
|
168
|
+
run_lifecycle_hooks
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
@@ -188,9 +188,8 @@ describe Kitchen::Transport::Ssh do
|
|
|
188
188
|
end
|
|
189
189
|
|
|
190
190
|
it "sets the :verify_host_key flag to false" do
|
|
191
|
-
verify_host_key_option = Kitchen::Transport::Ssh.verify_host_key_option
|
|
192
191
|
klass.expects(:new).with do |hash|
|
|
193
|
-
hash[
|
|
192
|
+
hash[:verify_host_key] == false
|
|
194
193
|
end
|
|
195
194
|
|
|
196
195
|
make_connection
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: test-kitchen
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Fletcher Nichol
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-07-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: mixlib-shellout
|
|
@@ -336,6 +336,7 @@ files:
|
|
|
336
336
|
- LICENSE
|
|
337
337
|
- MAINTAINERS.md
|
|
338
338
|
- README.md
|
|
339
|
+
- RELEASE_NOTES.md
|
|
339
340
|
- Rakefile
|
|
340
341
|
- appveyor.yml
|
|
341
342
|
- bin/kitchen
|
|
@@ -384,6 +385,7 @@ files:
|
|
|
384
385
|
- lib/kitchen/generator/init.rb
|
|
385
386
|
- lib/kitchen/instance.rb
|
|
386
387
|
- lib/kitchen/lazy_hash.rb
|
|
388
|
+
- lib/kitchen/lifecycle_hooks.rb
|
|
387
389
|
- lib/kitchen/loader/yaml.rb
|
|
388
390
|
- lib/kitchen/logger.rb
|
|
389
391
|
- lib/kitchen/logging.rb
|
|
@@ -439,6 +441,7 @@ files:
|
|
|
439
441
|
- spec/kitchen/errors_spec.rb
|
|
440
442
|
- spec/kitchen/instance_spec.rb
|
|
441
443
|
- spec/kitchen/lazy_hash_spec.rb
|
|
444
|
+
- spec/kitchen/lifecycle_hooks_spec.rb
|
|
442
445
|
- spec/kitchen/loader/yaml_spec.rb
|
|
443
446
|
- spec/kitchen/logger_spec.rb
|
|
444
447
|
- spec/kitchen/logging_spec.rb
|
|
@@ -525,7 +528,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
525
528
|
version: '0'
|
|
526
529
|
requirements: []
|
|
527
530
|
rubyforge_project:
|
|
528
|
-
rubygems_version: 2.7.
|
|
531
|
+
rubygems_version: 2.7.6
|
|
529
532
|
signing_key:
|
|
530
533
|
specification_version: 4
|
|
531
534
|
summary: Test Kitchen is an integration tool for developing and testing infrastructure
|
|
@@ -563,6 +566,7 @@ test_files:
|
|
|
563
566
|
- spec/kitchen/errors_spec.rb
|
|
564
567
|
- spec/kitchen/instance_spec.rb
|
|
565
568
|
- spec/kitchen/lazy_hash_spec.rb
|
|
569
|
+
- spec/kitchen/lifecycle_hooks_spec.rb
|
|
566
570
|
- spec/kitchen/loader/yaml_spec.rb
|
|
567
571
|
- spec/kitchen/logger_spec.rb
|
|
568
572
|
- spec/kitchen/logging_spec.rb
|