test-kitchen 1.0.0.rc.1 → 1.0.0.rc.2

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: 531f23b775d0e1852010f3405773b4a36e938126
4
- data.tar.gz: 7d447f5dca58df770141b9184606632bc4ae4a61
3
+ metadata.gz: 893be3400f70816247b46d2128c8a649b2c95996
4
+ data.tar.gz: 4888b33cdfe04efa18da5cdc5312d940e63d760f
5
5
  SHA512:
6
- metadata.gz: 39879c2db849837769c3375cae413a18521fd28978456336703c005c4aef3913dd1e20e83d55485ae9e8e9cd5dd0b7d2f7f1fa3f5d9c5aa51aab5e8995c482fb
7
- data.tar.gz: fb4e14f632ae4fecb40cb34c83df2cdad2bcb784bd41168cae3fbe2ffad8e043399444ac721b44c907dafddcd9f55c3ae834f4b9e3d208c1e4c911999f284a36
6
+ metadata.gz: a8613b788d26d13cd0e5b7f72f29cc286fd2ee74ce1c0f51f42b1bbcde2d376c244cff8cf623cca1ecfc6d4d4101e879ad378543f6e18d19bf01f377f89d811e
7
+ data.tar.gz: a9a22957290e20d68f309d61dd2fe6fa5292ab41bc8e73ef22fb0c1da593615232d712b4350b516cf61e1eb113807cee606482ed258e7b6426d92cc3ff2ffaba
data/CHANGELOG.md CHANGED
@@ -1,50 +1,74 @@
1
+ ## 1.0.0.rc.2 / 2013-11-30
2
+
3
+ ### Changes
4
+
5
+ * Generate a more explict form for driver & provisioner in `kitchen init`. ([@fnichol][])
6
+ * Set `Busser[:sudo]` to `false` by default. ([@fnichol][])
7
+
8
+ ### Bug fixes
9
+
10
+ * Properly handle `encrypted_data_bag_secret_key_path` under a suite. ([@fnichol][])
11
+ * Pull request [#265][]: Busser Fixes for Greybeard UNIX. ([@schisamo][])
12
+ * Pull request [#265][]: Busser config key name is `sudo` not `use_sudo`. ([@schisamo][])
13
+
14
+ ### New features
15
+
16
+ * Add diagnostic facility to Test Kitchen, usable with `kitchen diagnose`. ([@fnichol][])
17
+
18
+ ### Improvements
19
+
20
+ * Pull request [#266][]: Generate more a helpful error when supplying an invalid Regexp with CLI. ([@fnichol][])
21
+ * Improve logging of file transfers to instances in converge action. ([@fnichol][])
22
+ * Add feature test coverage for `kitchen list` subcommand. ([@fnichol][])
23
+
24
+
1
25
  ## 1.0.0.rc.1 / 2013-11-28
2
26
 
3
27
  ### Changes
4
28
 
5
- * Busser now installs into /tmp/busser by default on instances. (@fnichol)
6
- * Test Kitchen now works out of /tmp/kitchen for all providers by default. (@fnichol)
7
- * Remove Chef Omnibus `GEM_PATH` inclusion in Busser `GEM_PATH`. This fully isolates Busser and its runner plugins to a `GEM_HOME` and `GEM_PATH` in `<busser_root_path>/gems`. (@fnichol)
8
- * Add --provisioner to `kitchen init` to override default, chef\_solo. (@fnichol)
29
+ * Busser now installs into /tmp/busser by default on instances. ([@fnichol][])
30
+ * Test Kitchen now works out of /tmp/kitchen for all providers by default. ([@fnichol][])
31
+ * Remove Chef Omnibus `GEM_PATH` inclusion in Busser `GEM_PATH`. This fully isolates Busser and its runner plugins to a `GEM_HOME` and `GEM_PATH` in `<busser_root_path>/gems`. ([@fnichol][])
32
+ * Add --provisioner to `kitchen init` to override default, chef\_solo. ([@fnichol][])
9
33
 
10
34
  ### Bug fixes
11
35
 
12
- * Issue #240, issue #242, pull request #258: Fix Busser and Chef Zero sandboxing so that each tool is completely isolated from the Omnibus packages gems and each other. (@fnichol, @schisamo)
36
+ * Issue [#240][], issue [#242][], pull request [#258][]: Fix Busser and Chef Zero sandboxing so that each tool is completely isolated from the Omnibus packages gems and each other. ([@fnichol][], [@schisamo][])
13
37
 
14
38
  ### New features
15
39
 
16
40
  * Beef up Provisioners so that they resemble Drivers with user, default, inherited, and computed configuration..
17
- * Use `chef-client -z` (local mode) with ChefZero Provisioner for Chef versions >= 11.8.0. Support older versions of Chef with a best-effort fallback shim to use chef-zero. (@fnichol)
18
- * `kitchen list --debug` mode greatly improved showing rendered configuration for each Instance's Driver, Provisioner, and Busser configuration. (@fnichol)
19
- * Pull request #249: Add a data\_path which will be sync'd to the instance in the same manner as roles and data bags. (@oferrigni)
20
- * Test Kitchen no longer requires a cookbook to run; kitchen init anywhere! (@fnichol)
21
- * All settings in solo.rb (for ChefSolo) and client.rb (for ChefZero) can be modified or added with a `solo_rb:` or `client_rb:` block inside a `provisioner:` block. (@fnichol)
22
- * Add :ruby_bindr in a busser config block to set Busser's alternative remote path to Ruby. (@fnichol)
23
- * Busser install root can be configured and is relocatable, defaults to /tmp/busser. (@fnichol)
24
- * Test Kitchen root can be configured and is relocatable, defaults to /tmp/kitchen. (@fnichol)
25
- * Support installing a specific version of Busser. (@fnichol)
41
+ * Use `chef-client -z` (local mode) with ChefZero Provisioner for Chef versions >= 11.8.0. Support older versions of Chef with a best-effort fallback shim to use chef-zero. ([@fnichol][])
42
+ * `kitchen list --debug` mode greatly improved showing rendered configuration for each Instance's Driver, Provisioner, and Busser configuration. ([@fnichol][])
43
+ * Pull request [#249][]: Add a data\_path which will be sync'd to the instance in the same manner as roles and data bags. ([@oferrigni][])
44
+ * Test Kitchen no longer requires a cookbook to run; kitchen init anywhere! ([@fnichol][])
45
+ * All settings in solo.rb (for ChefSolo) and client.rb (for ChefZero) can be modified or added with a `solo_rb:` or `client_rb:` block inside a `provisioner:` block. ([@fnichol][])
46
+ * Add :ruby_bindr in a busser config block to set Busser's alternative remote path to Ruby. ([@fnichol][])
47
+ * Busser install root can be configured and is relocatable, defaults to /tmp/busser. ([@fnichol][])
48
+ * Test Kitchen root can be configured and is relocatable, defaults to /tmp/kitchen. ([@fnichol][])
49
+ * Support installing a specific version of Busser. ([@fnichol][])
26
50
 
27
51
  ### Improvements
28
52
 
29
- * Greatly simplify default .kitchen.yml. (@fnichol, @sethvargo)
30
- * Massive internal refactoring data manipulation logic. Data code now lives in Kitchen::DataMunger and was properly TDD'ed from the ground up with a full test suite. (@fnichol)
31
- * `require_chef_ommnibus` will default to `true` for all Chef provisioners and so can be omitted from .kitchen.yml files in most cases. (@fnichol)
32
- * Pull request #262: Use a configurable glob pattern to select Chef cookbook files. (@fnichol)
33
- * Pull request #141: Do not create a gitignore if there is no git repo. (@sethvargo)
34
- * Improve `kitchen init` smarts for detecting gems already in Gemfile. (@fnichol)
35
- * Expand all Chef-related local paths in Provisioner::ChefBase. (@fnichol)
36
- * Issue #227: Handle absolute paths. (@sethvargo)
37
- * Cope with nil values for run\_list and attributes entries in .kitchen.yml. (@fnichol)
38
- * Allow for nil values for `provisioner:`, `driver:`, & `busser:`. (@fnichol)
39
- * Pull request #253: Fix TravisCI badges. (@arangamani)
40
- * Pull request #254: Update references to test-kitchen org. (@josephholsten)
41
- * Pull request #256: Changed 'passed' to 'passing' in the Destroy options documentation. (@scarolan)
42
- * Pull request #259: Fix inconsistent date in CHANGELOG. (@ryansouza)
43
- * Extract Berkshelf & Librarian-Chef resolver code to classes. (@fnichol)
44
- * Full spec coverage for Suite. (@fnichol)
45
- * Full spec coverage for Platform. (@fnichol)
46
- * Full spec coverage for Instance. (@fnichol)
47
- * Full spec coverage for Kitchen::Provisioner.for\_plugin (@fnichol)
53
+ * Greatly simplify default .kitchen.yml. ([@fnichol][], [@sethvargo][])
54
+ * Massive internal refactoring data manipulation logic. Data code now lives in Kitchen::DataMunger and was properly TDD'ed from the ground up with a full test suite. ([@fnichol][])
55
+ * `require_chef_ommnibus` will default to `true` for all Chef provisioners and so can be omitted from .kitchen.yml files in most cases. ([@fnichol][])
56
+ * Pull request [#262][]: Use a configurable glob pattern to select Chef cookbook files. ([@fnichol][])
57
+ * Pull request [#141][]: Do not create a gitignore if there is no git repo. ([@sethvargo][])
58
+ * Improve `kitchen init` smarts for detecting gems already in Gemfile. ([@fnichol][])
59
+ * Expand all Chef-related local paths in Provisioner::ChefBase. ([@fnichol][])
60
+ * Issue [#227][]: Handle absolute paths. ([@sethvargo][])
61
+ * Cope with nil values for run\_list and attributes entries in .kitchen.yml. ([@fnichol][])
62
+ * Allow for nil values for `provisioner:`, `driver:`, & `busser:`. ([@fnichol][])
63
+ * Pull request [#253][]: Fix TravisCI badges. ([@arangamani][])
64
+ * Pull request [#254][]: Update references to test-kitchen org. ([@josephholsten][])
65
+ * Pull request [#256][]: Changed 'passed' to 'passing' in the Destroy options documentation. ([@scarolan][])
66
+ * Pull request [#259][]: Fix inconsistent date in CHANGELOG. ([@ryansouza][])
67
+ * Extract Berkshelf & Librarian-Chef resolver code to classes. ([@fnichol][])
68
+ * Full spec coverage for Suite. ([@fnichol][])
69
+ * Full spec coverage for Platform. ([@fnichol][])
70
+ * Full spec coverage for Instance. ([@fnichol][])
71
+ * Full spec coverage for Kitchen::Provisioner.for\_plugin ([@fnichol][])
48
72
 
49
73
 
50
74
  ## 1.0.0.beta.4 / 2013-11-01
@@ -302,6 +326,7 @@ The initial release.
302
326
  [#136]: https://github.com/opscode/test-kitchen/issues/136
303
327
  [#137]: https://github.com/opscode/test-kitchen/issues/137
304
328
  [#140]: https://github.com/opscode/test-kitchen/issues/140
329
+ [#141]: https://github.com/opscode/test-kitchen/issues/141
305
330
  [#142]: https://github.com/opscode/test-kitchen/issues/142
306
331
  [#147]: https://github.com/opscode/test-kitchen/issues/147
307
332
  [#151]: https://github.com/opscode/test-kitchen/issues/151
@@ -325,8 +350,20 @@ The initial release.
325
350
  [#217]: https://github.com/opscode/test-kitchen/issues/217
326
351
  [#218]: https://github.com/opscode/test-kitchen/issues/218
327
352
  [#222]: https://github.com/opscode/test-kitchen/issues/222
353
+ [#227]: https://github.com/opscode/test-kitchen/issues/227
328
354
  [#231]: https://github.com/opscode/test-kitchen/issues/231
329
355
  [#235]: https://github.com/opscode/test-kitchen/issues/235
356
+ [#240]: https://github.com/opscode/test-kitchen/issues/240
357
+ [#242]: https://github.com/opscode/test-kitchen/issues/242
358
+ [#249]: https://github.com/opscode/test-kitchen/issues/249
359
+ [#253]: https://github.com/opscode/test-kitchen/issues/253
360
+ [#254]: https://github.com/opscode/test-kitchen/issues/254
361
+ [#256]: https://github.com/opscode/test-kitchen/issues/256
362
+ [#258]: https://github.com/opscode/test-kitchen/issues/258
363
+ [#259]: https://github.com/opscode/test-kitchen/issues/259
364
+ [#262]: https://github.com/opscode/test-kitchen/issues/262
365
+ [#265]: https://github.com/opscode/test-kitchen/issues/265
366
+ [#266]: https://github.com/opscode/test-kitchen/issues/266
330
367
  [@ChrisLundquist]: https://github.com/ChrisLundquist
331
368
  [@adamhjk]: https://github.com/adamhjk
332
369
  [@arangamani]: https://github.com/arangamani
@@ -349,15 +386,17 @@ The initial release.
349
386
  [@manul]: https://github.com/manul
350
387
  [@mattray]: https://github.com/mattray
351
388
  [@mconigliaro]: https://github.com/mconigliaro
389
+ [@oferrigni]: https://github.com/oferrigni
352
390
  [@patcon]: https://github.com/patcon
353
391
  [@portertech]: https://github.com/portertech
354
392
  [@reset]: https://github.com/reset
355
393
  [@rteabeault]: https://github.com/rteabeault
356
394
  [@ryansouza]: https://github.com/ryansouza
357
395
  [@saketoba]: https://github.com/saketoba
396
+ [@scarolan]: https://github.com/scarolan
358
397
  [@schisamo]: https://github.com/schisamo
359
398
  [@scotthain]: https://github.com/scotthain
360
399
  [@sethvargo]: https://github.com/sethvargo
361
400
  [@smith]: https://github.com/smith
362
401
  [@stevendanna]: https://github.com/stevendanna
363
- [@thommay]: https://github.com/thommay
402
+ [@thommay]: https://github.com/thommay
@@ -21,7 +21,11 @@ Feature: Add Test Kitchen support to an existing project
21
21
  And a directory named "test/integration/default" should exist
22
22
  And the file ".gitignore" should contain ".kitchen/"
23
23
  And the file ".gitignore" should contain ".kitchen.local.yml"
24
- And the file ".kitchen.yml" should contain "driver: vagrant"
24
+ And the file ".kitchen.yml" should contain:
25
+ """
26
+ driver:
27
+ name: vagrant
28
+ """
25
29
  And a file named "Gemfile" should not exist
26
30
  And a file named "Rakefile" should not exist
27
31
  And a file named "Thorfile" should not exist
@@ -104,24 +108,40 @@ Feature: Add Test Kitchen support to an existing project
104
108
  first driver given
105
109
  Given an empty file named "Gemfile"
106
110
  When I successfully run `kitchen init --driver=kitchen-bluebox kitchen-wakka`
107
- Then the file ".kitchen.yml" should contain "driver: bluebox"
111
+ Then the file ".kitchen.yml" should contain:
112
+ """
113
+ driver:
114
+ name: bluebox
115
+ """
108
116
 
109
117
  Scenario: Running init with no drivers sets the plugin_driver to the
110
118
  dummy driver
111
119
  Given an empty file named "Gemfile"
112
120
  When I successfully run `kitchen init --no-driver`
113
- Then the file ".kitchen.yml" should contain "driver: dummy"
121
+ Then the file ".kitchen.yml" should contain:
122
+ """
123
+ driver:
124
+ name: dummy
125
+ """
114
126
 
115
127
  Scenario: Running init without a provisioner sets the default provisioner
116
128
  to chef_solo in .kitchen.yml
117
129
  Given an empty file named "Gemfile"
118
130
  When I successfully run `kitchen init --no-driver`
119
- Then the file ".kitchen.yml" should contain "provisioner: chef_solo"
131
+ Then the file ".kitchen.yml" should contain:
132
+ """
133
+ provisioner:
134
+ name: chef_solo
135
+ """
120
136
 
121
137
  Scenario: Running init with a provisioner sets the provisioner in .kitchen.yml
122
138
  Given an empty file named "Gemfile"
123
139
  When I successfully run `kitchen init --no-driver --provisioner=chef_zero`
124
- Then the file ".kitchen.yml" should contain "provisioner: chef_zero"
140
+ Then the file ".kitchen.yml" should contain:
141
+ """
142
+ provisioner:
143
+ name: chef_zero
144
+ """
125
145
 
126
146
  Scenario: Running with a Rakefile file appends Kitchen tasks
127
147
  Given an empty file named "Gemfile"
@@ -172,8 +192,11 @@ Feature: Add Test Kitchen support to an existing project
172
192
  Then the file ".kitchen.yml" should contain exactly:
173
193
  """
174
194
  ---
175
- driver: vagrant
176
- provisioner: chef_solo
195
+ driver:
196
+ name: vagrant
197
+
198
+ provisioner:
199
+ name: chef_solo
177
200
 
178
201
  platforms:
179
202
  - name: ubuntu-12.04
@@ -0,0 +1,62 @@
1
+ Feature: Listing Test Kitchen instances
2
+ In order to understand how the .kitchen.yml is consumed
3
+ As a user of Test Kitchen
4
+ I want to run a command to see the state of my instances
5
+
6
+ Background:
7
+ Given a file named ".kitchen.yml" with:
8
+ """
9
+ ---
10
+ driver: dummy
11
+ provisioner: chef_solo
12
+
13
+ platforms:
14
+ - name: ubuntu-13.04
15
+ - name: centos-6.4
16
+
17
+ suites:
18
+ - name: foobar
19
+ """
20
+
21
+ Scenario: Listing instances
22
+ When I run `kitchen list`
23
+ Then the exit status should be 0
24
+ And the output should contain "foobar-ubuntu-1304"
25
+ And the output should contain "foobar-centos-64"
26
+
27
+ Scenario: Listing instances with the --bare option
28
+ When I run `kitchen list --bare`
29
+ Then the exit status should be 0
30
+ And the output should contain exactly:
31
+ """
32
+ foobar-ubuntu-1304
33
+ foobar-centos-64
34
+
35
+ """
36
+
37
+ Scenario: Listing instances with a simple regular expression glob
38
+ When I successfully run `kitchen list ubun --bare`
39
+ Then the output should contain exactly:
40
+ """
41
+ foobar-ubuntu-1304
42
+
43
+ """
44
+
45
+ Scenario: Listing instances with a Ruby regular expression glob, requiring
46
+ signle quoting on the command line
47
+ When I successfully run `kitchen list '^foo.*\-(10|13)04$' --bare`
48
+ Then the output should contain exactly:
49
+ """
50
+ foobar-ubuntu-1304
51
+
52
+ """
53
+
54
+ Scenario: Listing instances with a regular expression yielding no results
55
+ When I run `kitchen list freebsd --bare`
56
+ Then the exit status should not be 0
57
+ And the output should contain "No instances for regex `freebsd', try running `kitchen list'"
58
+
59
+ Scenario: Listing instances with a bad regular expression
60
+ When I run `kitchen list *centos* --bare`
61
+ Then the exit status should not be 0
62
+ And the output should contain "Invalid Ruby regular expression"
data/lib/kitchen.rb CHANGED
@@ -32,6 +32,7 @@ require 'kitchen/color'
32
32
  require 'kitchen/collection'
33
33
  require 'kitchen/config'
34
34
  require 'kitchen/data_munger'
35
+ require 'kitchen/diagnostic'
35
36
  require 'kitchen/driver'
36
37
  require 'kitchen/driver/base'
37
38
  require 'kitchen/driver/proxy'
@@ -37,35 +37,36 @@ module Kitchen
37
37
  # @option opts [String] :instance_ruby_bindir path to the directory
38
38
  # containing the Ruby binary on the remote instance
39
39
  # @option opts [TrueClass, FalseClass] :sudo whether or not to invoke
40
- # sudo before commands requiring root access (default: `true`)
40
+ # sudo before commands requiring root access (default: `false`)
41
41
  def initialize(suite_name, opts = {})
42
42
  validate_options(suite_name)
43
43
 
44
44
  kitchen_root = opts.fetch(:kitchen_root) { Dir.pwd }
45
45
  test_base_path = opts.fetch(:test_base_path, Kitchen::DEFAULT_TEST_DIR)
46
46
 
47
- @test_base_path = File.expand_path(test_base_path, kitchen_root)
48
- @suite_name = suite_name
49
- @use_sudo = opts.fetch(:sudo, true)
50
- @ruby_bindir = opts.fetch(:instance_ruby_bindir, DEFAULT_RUBY_BINDIR)
51
- @root_path = opts.fetch(:root_path, DEFAULT_ROOT_PATH)
52
- @version_string = opts.fetch(:version, "busser")
53
- @busser_bin = File.join(@root_path, "bin/busser")
47
+ @config = Hash.new
48
+ @config[:kitchen_root] = kitchen_root
49
+ @config[:test_base_path] = File.expand_path(test_base_path, kitchen_root)
50
+ @config[:suite_name] = suite_name
51
+ @config[:sudo] = opts.fetch(:sudo, false)
52
+ @config[:ruby_bindir] = opts.fetch(:ruby_bindir, DEFAULT_RUBY_BINDIR)
53
+ @config[:root_path] = opts.fetch(:root_path, DEFAULT_ROOT_PATH)
54
+ @config[:version] = opts.fetch(:version, "busser")
55
+ @config[:busser_bin] = opts.fetch(:busser_bin, File.join(@config[:root_path], "bin/busser"))
54
56
  end
55
57
 
56
58
  # Returns the name of this busser, suitable for display in a CLI.
57
59
  #
58
60
  # @return [String] name of this busser
59
61
  def name
60
- suite_name
62
+ config[:suite_name]
61
63
  end
62
64
 
63
65
  # Returns an array of configuration keys.
64
66
  #
65
67
  # @return [Array] array of configuration keys
66
68
  def config_keys
67
- [:test_base_path, :ruby_bindir, :root_path, :version_string,
68
- :busser_bin, :use_sudo, :suite_name]
69
+ config.keys
69
70
  end
70
71
 
71
72
  # Provides hash-like access to configuration keys.
@@ -73,7 +74,16 @@ module Kitchen
73
74
  # @param attr [Object] configuration key
74
75
  # @return [Object] value at configuration key
75
76
  def [](attr)
76
- config_keys.include?(attr) ? self.send(attr) : nil
77
+ config[attr]
78
+ end
79
+
80
+ # Returns a Hash of configuration and other useful diagnostic information.
81
+ #
82
+ # @return [Hash] a diagnostic hash
83
+ def diagnose
84
+ result = Hash.new
85
+ config_keys.sort.each { |k| result[k] = config[k] }
86
+ result
77
87
  end
78
88
 
79
89
  # Returns a command string which installs Busser, and installs all
@@ -88,17 +98,17 @@ module Kitchen
88
98
  @setup_cmd ||= if local_suite_files.empty?
89
99
  nil
90
100
  else
101
+ setup_cmd = []
102
+ setup_cmd << busser_setup_env
103
+ setup_cmd << "if ! #{sudo}#{config[:ruby_bindir]}/gem list busser -i >/dev/null"
104
+ setup_cmd << "then #{sudo}#{config[:ruby_bindir]}/gem install #{gem_install_args}"
105
+ setup_cmd << "fi"
106
+ setup_cmd << "gem_bindir=`#{config[:ruby_bindir]}/ruby -rrubygems -e \"puts Gem.bindir\"`"
107
+ setup_cmd << "#{sudo}${gem_bindir}/busser setup"
108
+ setup_cmd << "#{sudo}#{config[:busser_bin]} plugin install #{plugins.join(' ')}"
109
+
91
110
  # use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
92
- <<-INSTALL_CMD.gsub(/^ {10}/, '')
93
- sh -c '
94
- #{busser_setup_env}
95
- if ! #{sudo}#{ruby_bindir}/gem list busser -i >/dev/null; then
96
- #{sudo}#{ruby_bindir}/gem install #{gem_install_args}
97
- fi
98
- gem_bindir=`#{ruby_bindir}/ruby -rrubygems -e "puts Gem.bindir"`
99
- #{sudo}${gem_bindir}/busser setup
100
- #{sudo}#{busser_bin} plugin install #{plugins.join(' ')}'
101
- INSTALL_CMD
111
+ "sh -c '#{setup_cmd.join('; ')}'"
102
112
  end
103
113
  end
104
114
 
@@ -114,13 +124,14 @@ module Kitchen
114
124
  @sync_cmd ||= if local_suite_files.empty?
115
125
  nil
116
126
  else
127
+ sync_cmd = []
128
+ sync_cmd << busser_setup_env
129
+ sync_cmd << "#{sudo}#{config[:busser_bin]} suite cleanup"
130
+ sync_cmd << "#{local_suite_files.map { |f| stream_file(f, remote_file(f, config[:suite_name])) }.join}"
131
+ sync_cmd << "#{helper_files.map { |f| stream_file(f, remote_file(f, "helpers")) }.join}"
132
+
117
133
  # use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
118
- <<-INSTALL_CMD.gsub(/^ {10}/, '')
119
- sh -c '
120
- #{sudo}#{busser_bin} suite cleanup
121
- #{local_suite_files.map { |f| stream_file(f, remote_file(f, suite_name)) }.join}
122
- #{helper_files.map { |f| stream_file(f, remote_file(f, "helpers")) }.join}'
123
- INSTALL_CMD
134
+ "sh -c '#{sync_cmd.join('; ')}'"
124
135
  end
125
136
  end
126
137
 
@@ -132,7 +143,16 @@ module Kitchen
132
143
  # @return [String] a command string to run the test suites, or nil if no
133
144
  # work needs to be performed
134
145
  def run_cmd
135
- @run_cmd ||= local_suite_files.empty? ? nil : "#{sudo}#{busser_bin} test"
146
+ @run_cmd ||= if local_suite_files.empty?
147
+ nil
148
+ else
149
+ run_cmd = []
150
+ run_cmd << busser_setup_env
151
+ run_cmd << "#{sudo}#{config[:busser_bin]} test"
152
+
153
+ # use Bourne (/bin/sh) as Bash does not exist on all Unix flavors
154
+ "sh -c '#{run_cmd.join('; ')}'"
155
+ end
136
156
  end
137
157
 
138
158
  private
@@ -140,13 +160,7 @@ module Kitchen
140
160
  DEFAULT_RUBY_BINDIR = "/opt/chef/embedded/bin".freeze
141
161
  DEFAULT_ROOT_PATH = "/tmp/busser".freeze
142
162
 
143
- attr_reader :test_base_path
144
- attr_reader :ruby_bindir
145
- attr_reader :root_path
146
- attr_reader :version_string
147
- attr_reader :busser_bin
148
- attr_reader :use_sudo
149
- attr_reader :suite_name
163
+ attr_reader :config
150
164
 
151
165
  def validate_options(suite_name)
152
166
  if suite_name.nil?
@@ -160,24 +174,26 @@ module Kitchen
160
174
  end
161
175
 
162
176
  def plugins
163
- Dir.glob(File.join(test_base_path, suite_name, "*")).reject { |d|
177
+ glob = File.join(config[:test_base_path], config[:suite_name], "*")
178
+ Dir.glob(glob).reject { |d|
164
179
  ! File.directory?(d) || non_suite_dirs.include?(File.basename(d))
165
180
  }.map { |d| "busser-#{File.basename(d)}" }.sort.uniq
166
181
  end
167
182
 
168
183
  def local_suite_files
169
- Dir.glob(File.join(test_base_path, suite_name, "*/**/*")).reject do |f|
184
+ glob = File.join(config[:test_base_path], config[:suite_name], "*/**/*")
185
+ Dir.glob(glob).reject do |f|
170
186
  f[/(data|data_bags|environments|nodes|roles)/] || File.directory?(f)
171
187
  end
172
188
  end
173
189
 
174
190
  def helper_files
175
- Dir.glob(File.join(test_base_path, "helpers", "*/**/*"))
191
+ Dir.glob(File.join(config[:test_base_path], "helpers", "*/**/*"))
176
192
  end
177
193
 
178
194
  def remote_file(file, dir)
179
- local_prefix = File.join(test_base_path, dir)
180
- "$(#{sudo}#{busser_bin} suite path)/".concat(file.sub(%r{^#{local_prefix}/}, ''))
195
+ local_prefix = File.join(config[:test_base_path], dir)
196
+ "$(#{sudo}#{config[:busser_bin]} suite path)/".concat(file.sub(%r{^#{local_prefix}/}, ''))
181
197
  end
182
198
 
183
199
  def stream_file(local_path, remote_path)
@@ -185,27 +201,21 @@ module Kitchen
185
201
  md5 = Digest::MD5.hexdigest(local_file)
186
202
  perms = sprintf("%o", File.stat(local_path).mode)[2, 4]
187
203
  stream_cmd = [
188
- "#{sudo}#{busser_bin}",
204
+ "#{sudo}#{config[:busser_bin]}",
189
205
  "deserialize",
190
206
  "--destination=#{remote_path}",
191
207
  "--md5sum=#{md5}",
192
208
  "--perms=#{perms}"
193
209
  ].join(" ")
194
210
 
195
- <<-STREAMFILE.gsub(/^ {8}/, '')
196
- echo "Uploading #{remote_path} (mode=#{perms})"
197
- #{sudo}cat <<"__EOFSTREAM__" | #{sudo}#{stream_cmd}
198
- #{Base64.encode64(local_file)}
199
- __EOFSTREAM__
200
- STREAMFILE
211
+ stream_file_cmd = []
212
+ stream_file_cmd << %{echo "Uploading #{remote_path} (mode=#{perms})"}
213
+ stream_file_cmd << %{echo "#{Base64.encode64(local_file).gsub("\n", '')}" | #{sudo}#{stream_cmd}}
214
+ stream_file_cmd.join('; ')
201
215
  end
202
216
 
203
217
  def sudo
204
- use_sudo ? "sudo -E " : ""
205
- end
206
-
207
- def busser_gem
208
- "busser"
218
+ config[:sudo] ? "sudo -E " : ""
209
219
  end
210
220
 
211
221
  def non_suite_dirs
@@ -214,16 +224,16 @@ module Kitchen
214
224
 
215
225
  def busser_setup_env
216
226
  [
217
- %{BUSSER_ROOT="#{root_path}"},
218
- %{GEM_HOME="#{root_path}/gems"},
219
- %{GEM_PATH="#{root_path}/gems"},
220
- %{GEM_CACHE="#{root_path}/gems/cache"},
221
- %{; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE;}
227
+ %{BUSSER_ROOT="#{config[:root_path]}"},
228
+ %{GEM_HOME="#{config[:root_path]}/gems"},
229
+ %{GEM_PATH="#{config[:root_path]}/gems"},
230
+ %{GEM_CACHE="#{config[:root_path]}/gems/cache"},
231
+ %{; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE}
222
232
  ].join(" ")
223
233
  end
224
234
 
225
235
  def gem_install_args
226
- gem, version = version_string.split("@")
236
+ gem, version = config[:version].split("@")
227
237
  gem, version = "busser", gem if gem =~ /^\d+\.\d+\.\d+/
228
238
 
229
239
  args = gem
data/lib/kitchen/cli.rb CHANGED
@@ -41,8 +41,9 @@ module Kitchen
41
41
  super
42
42
  $stdout.sync = true
43
43
  Kitchen.logger = Kitchen.default_file_logger
44
+ @loader = Kitchen::Loader::YAML.new(ENV['KITCHEN_YAML'])
44
45
  @config = Kitchen::Config.new(
45
- :loader => Kitchen::Loader::YAML.new(ENV['KITCHEN_YAML']),
46
+ :loader => @loader,
46
47
  :log_level => ENV.fetch('KITCHEN_LOG', "info").downcase.to_sym
47
48
  )
48
49
  end
@@ -51,14 +52,15 @@ module Kitchen
51
52
  method_option :bare, :aliases => "-b", :type => :boolean,
52
53
  :desc => "List the name of each instance only, one per line"
53
54
  method_option :debug, :aliases => "-d", :type => :boolean,
54
- :desc => "Show computed driver configuration for each instance"
55
+ :desc => "[Deprecated] Please use `kitchen diagnose'"
55
56
  method_option :log_level, :aliases => "-l",
56
57
  :desc => "Set the log level (debug, info, warn, error, fatal)"
57
58
  def list(*args)
58
59
  update_config!
59
60
  result = parse_subcommand(args.first)
60
61
  if options[:debug]
61
- Array(result).each { |i| debug_instance(i) }
62
+ die task, "The --debug flag on the list subcommand is deprecated, " +
63
+ "please use `kitchen diagnose'."
62
64
  elsif options[:bare]
63
65
  say Array(result).map { |i| i.name }.join("\n")
64
66
  else
@@ -66,6 +68,34 @@ module Kitchen
66
68
  end
67
69
  end
68
70
 
71
+ desc "diganose [(all|<REGEX>)]", "Show computed diagnostic configuration"
72
+ method_option :log_level, :aliases => "-l",
73
+ :desc => "Set the log level (debug, info, warn, error, fatal)"
74
+ method_option :loader, :type => :boolean,
75
+ :desc => "Include data loader diagnostics"
76
+ method_option :instances, :type => :boolean, :default => true,
77
+ :desc => "Include instances diagnostics"
78
+ method_option :all, :type => :boolean,
79
+ :desc => "Include all diagnostics"
80
+ def diagnose(*args)
81
+ update_config!
82
+
83
+ loader = if options[:all] || options[:loader]
84
+ @loader
85
+ else
86
+ nil
87
+ end
88
+ instances = if options[:all] || options[:instances]
89
+ parse_subcommand(args.first)
90
+ else
91
+ []
92
+ end
93
+
94
+ require 'yaml'
95
+ Kitchen::Diagnostic.new(:loader => loader, :instances => instances).
96
+ read.to_yaml.each_line { |line| say(line) }
97
+ end
98
+
69
99
  [:create, :converge, :setup, :verify, :destroy].each do |action|
70
100
  desc(
71
101
  "#{action} [(all|<REGEX>)] [opts]",
@@ -308,7 +338,13 @@ module Kitchen
308
338
  end
309
339
 
310
340
  def get_filtered_instances(regexp)
311
- result = @config.instances.get_all(/#{regexp}/)
341
+ result = begin
342
+ @config.instances.get_all(/#{regexp}/)
343
+ rescue RegexpError => e
344
+ die task, "Invalid Ruby regular expression, " +
345
+ "you may need to single quote the argument. " +
346
+ "Please try again or consult http://rubular.com/ (#{e.message})"
347
+ end
312
348
 
313
349
  if result.empty?
314
350
  die task, "No instances for regex `#{regexp}', try running `kitchen list'"
@@ -335,24 +371,6 @@ module Kitchen
335
371
  ]
336
372
  end
337
373
 
338
- def debug_instance(instance)
339
- say "--------"
340
- say "Instance: #{instance.name}"
341
- say "Driver (#{instance.driver.name}):"
342
- instance.driver.config_keys.sort.each do |key|
343
- say " #{key}: #{instance.driver[key].inspect}"
344
- end
345
- say "Provisioner (#{instance.provisioner.name}):"
346
- instance.provisioner.config_keys.sort.each do |key|
347
- say " #{key}: #{instance.provisioner[key].inspect}"
348
- end
349
- say "Busser (#{instance.busser.name}):"
350
- instance.busser.config_keys.sort.each do |key|
351
- say " #{key}: #{instance.busser[key].inspect}"
352
- end
353
- say ""
354
- end
355
-
356
374
  def color_pad(string)
357
375
  string + set_color("", :white)
358
376
  end
@@ -85,8 +85,9 @@ module Kitchen
85
85
 
86
86
  def convert_legacy_chef_paths_format!
87
87
  data.fetch(:suites, []).each do |suite|
88
- %w{data data_bags environments nodes roles}.each do |key|
89
- move_chef_data_to_provisioner_at!(suite, "#{key}_path".to_sym)
88
+ %w{data data_bags encrypted_data_bag_secret_key
89
+ environments nodes roles}.each do |key|
90
+ move_chef_data_to_provisioner_at!(suite, "#{key}_path".to_sym)
90
91
  end
91
92
  end
92
93
  end
@@ -0,0 +1,61 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2013, Fletcher Nichol
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/util'
20
+
21
+ module Kitchen
22
+
23
+ # Combines and compiles diagnostic information about a Test Kitchen
24
+ # configuration suitable for support and troubleshooting.
25
+ #
26
+ # @author Fletcher Nichol <fnichol@nichol.ca>
27
+ class Diagnostic
28
+
29
+ def initialize(options = {})
30
+ @loader = options.fetch(:loader, nil)
31
+ @instances = options.fetch(:instances, [])
32
+ @result = Hash.new
33
+ end
34
+
35
+ def read
36
+ prepare_common
37
+ prepare_loader
38
+ prepare_instances
39
+
40
+ Util.stringified_hash(result)
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :result, :loader, :instances
46
+
47
+ def prepare_common
48
+ result[:timestamp] = Time.now.gmtime
49
+ result[:kitchen_version] = Kitchen::VERSION
50
+ end
51
+
52
+ def prepare_loader
53
+ result[:loader] = loader.diagnose if loader
54
+ end
55
+
56
+ def prepare_instances
57
+ result[:instances] = Hash.new
58
+ Array(instances).each { |i| result[:instances][i.name] = i.diagnose }
59
+ end
60
+ end
61
+ end
@@ -122,6 +122,15 @@ module Kitchen
122
122
  # documented dependency is missing from the system
123
123
  def verify_dependencies ; end
124
124
 
125
+ # Returns a Hash of configuration and other useful diagnostic information.
126
+ #
127
+ # @return [Hash] a diagnostic hash
128
+ def diagnose
129
+ result = Hash.new
130
+ config_keys.sort.each { |k| result[k] = config[k] }
131
+ result
132
+ end
133
+
125
134
  protected
126
135
 
127
136
  attr_reader :config
@@ -113,7 +113,9 @@ module Kitchen
113
113
  def transfer_path(locals, remote, connection)
114
114
  return if locals.nil? || Array(locals).empty?
115
115
 
116
+ info("Transfering files to #{instance.to_str}")
116
117
  locals.each { |local| connection.upload_path!(local, remote) }
118
+ debug("Transfer complete")
117
119
  rescue SSHFailed, Net::SSH::Exception => ex
118
120
  raise ActionFailed, ex.message
119
121
  end
@@ -193,6 +193,18 @@ module Kitchen
193
193
  Kernel.exec(command, *args, options)
194
194
  end
195
195
 
196
+ # Returns a Hash of configuration and other useful diagnostic information.
197
+ #
198
+ # @return [Hash] a diagnostic hash
199
+ def diagnose
200
+ result = Hash.new
201
+ [:state_file, :driver, :provisioner, :busser].each do |sym|
202
+ obj = send(sym)
203
+ result[sym] = obj.respond_to?(:diagnose) ? obj.diagnose : :unknown
204
+ end
205
+ result
206
+ end
207
+
196
208
  def last_action
197
209
  state_file.read[:last_action]
198
210
  end
@@ -62,6 +62,28 @@ module Kitchen
62
62
  Util.symbolized_hash(combined_hash)
63
63
  end
64
64
 
65
+ # Returns a Hash of configuration and other useful diagnostic information.
66
+ #
67
+ # @return [Hash] a diagnostic hash
68
+ def diagnose
69
+ result = Hash.new
70
+ result[:proces_erb] = @process_erb
71
+ result[:process_local] = @process_local
72
+ result[:process_global] = @process_global
73
+ if File.exists?(global_config_file)
74
+ result[:global_config] =
75
+ { :filename => global_config_file, :raw_data => global_yaml }
76
+ end
77
+ result[:project_config] =
78
+ { :filename => config_file, :raw_data => yaml }
79
+ if File.exists?(local_config_file)
80
+ result[:local_config] =
81
+ { :filename => local_config_file, :raw_data => local_yaml }
82
+ end
83
+ result[:combined_config] = { :raw_data => combined_hash }
84
+ result
85
+ end
86
+
65
87
  protected
66
88
 
67
89
  def default_config_file
@@ -72,6 +72,15 @@ module Kitchen
72
72
 
73
73
  def cleanup_sandbox ; end
74
74
 
75
+ # Returns a Hash of configuration and other useful diagnostic information.
76
+ #
77
+ # @return [Hash] a diagnostic hash
78
+ def diagnose
79
+ result = Hash.new
80
+ config_keys.sort.each { |k| result[k] = config[k] }
81
+ result
82
+ end
83
+
75
84
  protected
76
85
 
77
86
  attr_reader :config
@@ -62,7 +62,7 @@ module Kitchen
62
62
  end
63
63
 
64
64
  default_config :encrypted_data_bag_secret_key_path do |provisioner|
65
- provisioner.calculate_path("encrypted_data_bag_secret", :file)
65
+ provisioner.calculate_path("encrypted_data_bag_secret_key", :file)
66
66
  end
67
67
 
68
68
  def instance=(instance)
@@ -131,7 +131,8 @@ module Kitchen
131
131
  attr_reader :tmpdir
132
132
 
133
133
  def expand_paths!
134
- paths = %w{test_base data data_bags environments nodes roles}
134
+ paths = %w{test_base data data_bags encrypted_data_bag_secret_key
135
+ environments nodes roles}
135
136
  paths.map{ |p| "#{p}_path".to_sym }.each do |key|
136
137
  unless config[key].nil?
137
138
  config[key] = File.expand_path(config[key], config[:kitchen_root])
@@ -170,6 +171,7 @@ module Kitchen
170
171
  def create_chef_sandbox
171
172
  @tmpdir = Dir.mktmpdir("#{instance.name}-sandbox-")
172
173
  File.chmod(0755, @tmpdir)
174
+ info("Preparing files for transfer")
173
175
  debug("Creating local sandbox in #{tmpdir}")
174
176
 
175
177
  yield if block_given?
@@ -278,7 +280,7 @@ module Kitchen
278
280
  end
279
281
 
280
282
  def filter_only_cookbook_files
281
- info("Removing non-cookbook files in sandbox")
283
+ info("Removing non-cookbook files before transfer")
282
284
  FileUtils.rm(all_files_in_cookbooks - only_cookbook_files)
283
285
  end
284
286
 
@@ -67,6 +67,16 @@ module Kitchen
67
67
  FileUtils.rm_f(file_name) if File.exists?(file_name)
68
68
  end
69
69
 
70
+ # Returns a Hash of configuration and other useful diagnostic information.
71
+ #
72
+ # @return [Hash] a diagnostic hash
73
+ def diagnose
74
+ raw = read
75
+ result = Hash.new
76
+ raw.keys.sort.each { |k| result[k] = raw[k] }
77
+ result
78
+ end
79
+
70
80
  private
71
81
 
72
82
  attr_reader :file_name
@@ -18,5 +18,5 @@
18
18
 
19
19
  module Kitchen
20
20
 
21
- VERSION = "1.0.0.rc.1"
21
+ VERSION = "1.0.0.rc.2"
22
22
  end
@@ -1260,7 +1260,7 @@ module Kitchen
1260
1260
  describe "legacy chef paths from suite" do
1261
1261
 
1262
1262
  LEGACY_CHEF_PATHS = [:data_path, :data_bags_path, :environments_path,
1263
- :nodes_path, :roles_path]
1263
+ :nodes_path, :roles_path, :encrypted_data_bag_secret_key_path]
1264
1264
 
1265
1265
  LEGACY_CHEF_PATHS.each do |key|
1266
1266
 
@@ -1,6 +1,9 @@
1
1
  ---
2
- driver: <%= config[:driver_plugin] %>
3
- provisioner: <%= config[:provisioner] %>
2
+ driver:
3
+ name: <%= config[:driver_plugin] %>
4
+
5
+ provisioner:
6
+ name: <%= config[:provisioner] %>
4
7
 
5
8
  platforms:
6
9
  - name: ubuntu-12.04
data/test-kitchen.gemspec CHANGED
@@ -9,9 +9,9 @@ Gem::Specification.new do |gem|
9
9
  gem.license = 'Apache 2.0'
10
10
  gem.authors = ['Fletcher Nichol']
11
11
  gem.email = ['fnichol@nichol.ca']
12
- gem.description = %q{A Chef convergence integration test harness}
12
+ gem.description = %q{A convergence integration test harness for configuration management systems.}
13
13
  gem.summary = gem.description
14
- gem.homepage = 'https://github.com/opscode/test-kitchen'
14
+ gem.homepage = 'https://github.com/test-kitchen/test-kitchen'
15
15
 
16
16
  gem.files = `git ls-files`.split($/)
17
17
  gem.executables = %w(kitchen)
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.0.0.rc.1
4
+ version: 1.0.0.rc.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fletcher Nichol
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-28 00:00:00.000000000 Z
11
+ date: 2013-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-shellout
@@ -248,7 +248,7 @@ dependencies:
248
248
  - - ~>
249
249
  - !ruby/object:Gem::Version
250
250
  version: '0.8'
251
- description: A Chef convergence integration test harness
251
+ description: A convergence integration test harness for configuration management systems.
252
252
  email:
253
253
  - fnichol@nichol.ca
254
254
  executables:
@@ -270,6 +270,7 @@ files:
270
270
  - features/kitchen_driver_create_command.feature
271
271
  - features/kitchen_driver_discover_command.feature
272
272
  - features/kitchen_init_command.feature
273
+ - features/kitchen_list_command.feature
273
274
  - features/sink_command.feature
274
275
  - features/step_definitions/gem_steps.rb
275
276
  - features/step_definitions/git_steps.rb
@@ -281,6 +282,7 @@ files:
281
282
  - lib/kitchen/color.rb
282
283
  - lib/kitchen/config.rb
283
284
  - lib/kitchen/data_munger.rb
285
+ - lib/kitchen/diagnostic.rb
284
286
  - lib/kitchen/driver.rb
285
287
  - lib/kitchen/driver/base.rb
286
288
  - lib/kitchen/driver/dummy.rb
@@ -349,7 +351,7 @@ files:
349
351
  - templates/driver/version.rb.erb
350
352
  - templates/init/kitchen.yml.erb
351
353
  - test-kitchen.gemspec
352
- homepage: https://github.com/opscode/test-kitchen
354
+ homepage: https://github.com/test-kitchen/test-kitchen
353
355
  licenses:
354
356
  - Apache 2.0
355
357
  metadata: {}
@@ -372,12 +374,13 @@ rubyforge_project:
372
374
  rubygems_version: 2.0.3
373
375
  signing_key:
374
376
  specification_version: 4
375
- summary: A Chef convergence integration test harness
377
+ summary: A convergence integration test harness for configuration management systems.
376
378
  test_files:
377
379
  - features/kitchen_command.feature
378
380
  - features/kitchen_driver_create_command.feature
379
381
  - features/kitchen_driver_discover_command.feature
380
382
  - features/kitchen_init_command.feature
383
+ - features/kitchen_list_command.feature
381
384
  - features/sink_command.feature
382
385
  - features/step_definitions/gem_steps.rb
383
386
  - features/step_definitions/git_steps.rb