test-kitchen 0.7.0 → 1.0.0.alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.gitignore +20 -0
  2. data/.travis.yml +11 -0
  3. data/.yardopts +3 -0
  4. data/Gemfile +13 -0
  5. data/Guardfile +11 -0
  6. data/LICENSE +15 -0
  7. data/README.md +131 -0
  8. data/Rakefile +69 -0
  9. data/bin/kitchen +9 -4
  10. data/features/cli.feature +17 -0
  11. data/features/cli_init.feature +156 -0
  12. data/features/support/env.rb +14 -0
  13. data/lib/kitchen/busser.rb +166 -0
  14. data/lib/kitchen/chef_data_uploader.rb +156 -0
  15. data/lib/kitchen/cli.rb +540 -0
  16. data/lib/kitchen/collection.rb +55 -0
  17. data/lib/kitchen/color.rb +46 -0
  18. data/lib/kitchen/config.rb +223 -0
  19. data/lib/kitchen/driver/base.rb +180 -0
  20. data/lib/kitchen/driver/dummy.rb +81 -0
  21. data/lib/kitchen/driver/ssh_base.rb +192 -0
  22. data/lib/kitchen/driver.rb +42 -0
  23. data/lib/kitchen/errors.rb +52 -0
  24. data/lib/kitchen/instance.rb +327 -0
  25. data/lib/kitchen/instance_actor.rb +42 -0
  26. data/lib/kitchen/loader/yaml.rb +105 -0
  27. data/lib/kitchen/logger.rb +145 -0
  28. data/{cookbooks/test-kitchen/libraries/helpers.rb → lib/kitchen/logging.rb} +13 -9
  29. data/lib/kitchen/manager.rb +45 -0
  30. data/lib/kitchen/metadata_chopper.rb +52 -0
  31. data/lib/kitchen/platform.rb +61 -0
  32. data/lib/kitchen/rake_tasks.rb +59 -0
  33. data/lib/kitchen/shell_out.rb +65 -0
  34. data/lib/kitchen/state_file.rb +88 -0
  35. data/lib/kitchen/suite.rb +76 -0
  36. data/lib/kitchen/thor_tasks.rb +62 -0
  37. data/lib/kitchen/util.rb +79 -0
  38. data/{cookbooks/test-kitchen/recipes/erlang.rb → lib/kitchen/version.rb} +9 -6
  39. data/lib/kitchen.rb +98 -0
  40. data/lib/vendor/hash_recursive_merge.rb +74 -0
  41. data/spec/kitchen/collection_spec.rb +80 -0
  42. data/spec/kitchen/color_spec.rb +54 -0
  43. data/spec/kitchen/config_spec.rb +201 -0
  44. data/spec/kitchen/driver/dummy_spec.rb +191 -0
  45. data/spec/kitchen/instance_spec.rb +162 -0
  46. data/spec/kitchen/loader/yaml_spec.rb +243 -0
  47. data/spec/kitchen/platform_spec.rb +48 -0
  48. data/spec/kitchen/state_file_spec.rb +122 -0
  49. data/spec/kitchen/suite_spec.rb +64 -0
  50. data/spec/spec_helper.rb +47 -0
  51. data/templates/plugin/driver.rb.erb +23 -0
  52. data/templates/plugin/license_apachev2.erb +15 -0
  53. data/templates/plugin/license_gplv2.erb +18 -0
  54. data/templates/plugin/license_gplv3.erb +16 -0
  55. data/templates/plugin/license_mit.erb +22 -0
  56. data/templates/plugin/license_reserved.erb +5 -0
  57. data/templates/plugin/version.rb.erb +12 -0
  58. data/test-kitchen.gemspec +44 -0
  59. metadata +290 -82
  60. data/config/Cheffile +0 -47
  61. data/config/Kitchenfile +0 -39
  62. data/config/Vagrantfile +0 -114
  63. data/cookbooks/test-kitchen/attributes/default.rb +0 -25
  64. data/cookbooks/test-kitchen/metadata.rb +0 -27
  65. data/cookbooks/test-kitchen/recipes/chef.rb +0 -19
  66. data/cookbooks/test-kitchen/recipes/compat.rb +0 -39
  67. data/cookbooks/test-kitchen/recipes/default.rb +0 -51
  68. data/cookbooks/test-kitchen/recipes/ruby.rb +0 -29
  69. data/lib/test-kitchen/cli/destroy.rb +0 -36
  70. data/lib/test-kitchen/cli/init.rb +0 -37
  71. data/lib/test-kitchen/cli/platform_list.rb +0 -37
  72. data/lib/test-kitchen/cli/project_info.rb +0 -44
  73. data/lib/test-kitchen/cli/ssh.rb +0 -36
  74. data/lib/test-kitchen/cli/status.rb +0 -36
  75. data/lib/test-kitchen/cli/test.rb +0 -68
  76. data/lib/test-kitchen/cli.rb +0 -282
  77. data/lib/test-kitchen/dsl.rb +0 -63
  78. data/lib/test-kitchen/environment.rb +0 -166
  79. data/lib/test-kitchen/platform.rb +0 -79
  80. data/lib/test-kitchen/project/base.rb +0 -159
  81. data/lib/test-kitchen/project/cookbook.rb +0 -97
  82. data/lib/test-kitchen/project/cookbook_copy.rb +0 -58
  83. data/lib/test-kitchen/project/ruby.rb +0 -37
  84. data/lib/test-kitchen/project/supported_platforms.rb +0 -75
  85. data/lib/test-kitchen/project.rb +0 -23
  86. data/lib/test-kitchen/runner/base.rb +0 -154
  87. data/lib/test-kitchen/runner/openstack/dsl.rb +0 -39
  88. data/lib/test-kitchen/runner/openstack/environment.rb +0 -141
  89. data/lib/test-kitchen/runner/openstack.rb +0 -147
  90. data/lib/test-kitchen/runner/vagrant.rb +0 -95
  91. data/lib/test-kitchen/runner.rb +0 -21
  92. data/lib/test-kitchen/scaffold.rb +0 -88
  93. data/lib/test-kitchen/ui.rb +0 -73
  94. data/lib/test-kitchen/version.rb +0 -21
  95. data/lib/test-kitchen.rb +0 -34
@@ -1,282 +0,0 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- require 'test-kitchen/environment'
20
- require 'test-kitchen/ui'
21
- require 'mixlib/cli'
22
-
23
- module TestKitchen
24
- module CLI
25
- class Kitchen
26
- include Mixlib::CLI
27
-
28
- option :platform,
29
- :long => "--platform PLATFORM",
30
- :description => "The platform to use. If not specified tests will be run against all platforms.",
31
- :default => nil
32
-
33
- option :configuration,
34
- :long => "--configuration CONFIG",
35
- :description => "The project configuration to test. Defaults to all configurations."
36
-
37
- option :runner,
38
- :short => "-r RUNNER",
39
- :long => "--runner RUNNER",
40
- :description => "The underlying virtualization platform to test with."
41
-
42
- option :teardown,
43
- :boolean => true,
44
- :default => false,
45
- :long => "--teardown",
46
- :description => "Teardown test nodes between runs."
47
-
48
- option :help,
49
- :short => "-h",
50
- :long => "--help",
51
- :description => "Show this message",
52
- :on => :tail,
53
- :boolean => true,
54
- :show_options => true,
55
- :exit => 0
56
-
57
- option :version,
58
- :short => "-v",
59
- :long => "--version",
60
- :description => "Show Test Kitchen version",
61
- :boolean => true,
62
- :proc => lambda {|v| puts "test-kitchen: #{::TestKitchen::VERSION}"},
63
- :exit => 0
64
-
65
- attr_accessor :runner
66
- attr_accessor :env
67
- attr_accessor :ui
68
-
69
- def command_help?
70
- ARGV.last == '--help'
71
- end
72
-
73
- def scaffolding?
74
- ARGV == ['init']
75
- end
76
-
77
- def run
78
- validate_and_parse_options
79
- quiet_traps
80
- Kitchen.run(ARGV, options)
81
- exit 0
82
- end
83
-
84
- def initialize(argv=[])
85
- $stdout.sync = true
86
- $stderr.sync = true
87
- super()
88
- parse_options(argv)
89
- @ui = TestKitchen::UI.new(STDOUT, STDERR, STDIN, {})
90
-
91
- # TODO: Move this out of the constructor
92
- load_environment unless command_help? || scaffolding?
93
- end
94
-
95
- def load_environment
96
- @env = TestKitchen::Environment.new(:ui => @ui).tap{|e| e.load!}
97
- end
98
-
99
- def runner
100
- @runner ||= begin
101
- # CLI option takes precedence, then project
102
- runner_name = config[:runner] || env.project.runner || env.default_runner
103
- runner_class = TestKitchen::Runner.targets[runner_name]
104
- runner = runner_class.new(env, config)
105
- end
106
- end
107
-
108
- # Class Methods
109
-
110
- def self.run(argv, options={})
111
- load_commands
112
- subcommand_class = Kitchen.subcommand_class_from(argv)
113
- subcommand_class.options = options.merge!(subcommand_class.options)
114
-
115
- instance = subcommand_class.new(ARGV)
116
- instance.run
117
- end
118
-
119
- def self.load_commands
120
- @commands_loaded ||= begin
121
- if subcommand_files = Dir[File.join(TestKitchen.source_root, 'lib', 'test-kitchen', 'cli', '*.rb')]
122
- subcommand_files.each { |subcommand| Kernel.load subcommand.to_s }
123
- end
124
- true
125
- end
126
- end
127
-
128
- NO_COMMAND_GIVEN = "You need to pass a sub-command (e.g., kitchen SUB-COMMAND)\n"
129
-
130
- # BEGIN CARGO CULT FROM Chef::Knife
131
- def self.inherited(subclass)
132
- unless subclass.unnamed?
133
- subcommands[subclass.snake_case_name] = subclass
134
- end
135
- end
136
-
137
- def self.subcommands
138
- @@subcommands ||= {}
139
- end
140
-
141
- def self.subcommand_category
142
- @category || snake_case_name.split('_').first unless unnamed?
143
- end
144
-
145
- def self.snake_case_name
146
- convert_to_snake_case(name.split('::').last) unless unnamed?
147
- end
148
-
149
- def self.convert_to_snake_case(str, namespace=nil)
150
- str = str.dup
151
- str.sub!(/^#{namespace}(\:\:)?/, '') if namespace
152
- str.gsub!(/[A-Z]/) {|s| "_" + s}
153
- str.downcase!
154
- str.sub!(/^\_/, "")
155
- str
156
- end
157
-
158
- # Does this class have a name? (Classes created via Class.new don't)
159
- def self.unnamed?
160
- name.nil? || name.empty?
161
- end
162
-
163
- def self.subcommands_by_category
164
- unless @subcommands_by_category
165
- @subcommands_by_category = Hash.new { |hash, key| hash[key] = [] }
166
- subcommands.each do |snake_cased, klass|
167
- @subcommands_by_category[klass.subcommand_category] << snake_cased
168
- end
169
- end
170
- @subcommands_by_category
171
- end
172
-
173
- # Print the list of subcommands knife knows about. If +preferred_category+
174
- # is given, only subcommands in that category are shown
175
- def self.list_commands(preferred_category=nil)
176
- load_commands
177
-
178
- category_desc = preferred_category ? preferred_category + " " : ''
179
- $stdout.puts "Available #{category_desc}subcommands: (for details, kitchen SUB-COMMAND --help)\n\n"
180
-
181
- if preferred_category && subcommands_by_category.key?(preferred_category)
182
- commands_to_show = {preferred_category => subcommands_by_category[preferred_category]}
183
- else
184
- commands_to_show = subcommands_by_category
185
- end
186
-
187
- commands_to_show.sort.each do |category, commands|
188
- next if category =~ /deprecated/i
189
- $stdout.puts "** #{category.upcase} COMMANDS **"
190
- commands.each do |command|
191
- $stdout.puts subcommands[command].banner if subcommands[command]
192
- end
193
- $stdout.puts
194
- end
195
- end
196
-
197
- def self.subcommand_class_from(args)
198
- command_words = args.select {|arg| arg =~ /^(([[:alnum:]])[[:alnum:]\_\-]+)$/ }
199
-
200
- subcommand_class = nil
201
-
202
- while ( !subcommand_class ) && ( !command_words.empty? )
203
- snake_case_class_name = command_words.join("_")
204
- unless subcommand_class = subcommands[snake_case_class_name]
205
- command_words.pop
206
- end
207
- end
208
- # see if we got the command as e.g., knife node-list
209
- subcommand_class ||= subcommands[args.first.gsub('-', '_')]
210
- subcommand_class || subcommand_not_found!(args)
211
- end
212
-
213
- # :nodoc:
214
- # Error out and print usage. probably becuase the arguments given by the
215
- # user could not be resolved to a subcommand.
216
- def self.subcommand_not_found!(args)
217
- $stderr.puts "Cannot find sub command for: '#{args.join(' ')}'"
218
- list_commands
219
- exit 10
220
- end
221
- # END CARGO CULT FROM Chef::Knife
222
-
223
- private
224
-
225
- # BEGIN CARGO CULT FROM Chef::Application::Knife
226
- def quiet_traps
227
- trap("TERM") do
228
- exit 1
229
- end
230
-
231
- trap("INT") do
232
- exit 2
233
- end
234
- end
235
-
236
- def validate_and_parse_options
237
- # Checking ARGV validity *before* parse_options because parse_options
238
- # mangles ARGV in some situations
239
- if no_command_given?
240
- print_help_and_exit(1, NO_COMMAND_GIVEN)
241
- elsif no_subcommand_given?
242
- if (want_help? || want_version?)
243
- print_help_and_exit
244
- else
245
- print_help_and_exit(2, NO_COMMAND_GIVEN)
246
- end
247
- end
248
- end
249
-
250
- def no_subcommand_given?
251
- ARGV[0] =~ /^-/
252
- end
253
-
254
- def no_command_given?
255
- ARGV.empty?
256
- end
257
-
258
- def want_help?
259
- ARGV[0] =~ /^(--help|-h)$/
260
- end
261
-
262
- def want_version?
263
- ARGV[0] =~ /^(--version|-v)$/
264
- end
265
-
266
- def print_help_and_exit(exitcode=1, fatal_message=nil)
267
- $stderr.puts(fatal_message) if fatal_message
268
-
269
- begin
270
- self.parse_options
271
- rescue OptionParser::InvalidOption => e
272
- puts "#{e}\n"
273
- end
274
- puts self.opt_parser
275
- puts
276
- TestKitchen::CLI::Kitchen.list_commands
277
- exit exitcode
278
- end
279
- # END CARGO CULT FROM Chef::Application::Knife
280
- end
281
- end
282
- end
@@ -1,63 +0,0 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- require 'hashr'
19
- require 'test-kitchen/project'
20
- require 'test-kitchen/platform'
21
- require 'test-kitchen/runner/openstack/dsl'
22
-
23
- module TestKitchen
24
- module DSL
25
-
26
- module BasicDSL
27
- def integration_test(name, &block)
28
- env.project = Project::Ruby.new(name.to_s, &block)
29
- end
30
-
31
- def platform(name, &block)
32
- env.platforms[name.to_s] = Platform.new(name, &block)
33
- end
34
-
35
- def default_runner(name)
36
- env.default_runner = name
37
- end
38
- end
39
- module CookbookDSL
40
- def cookbook(name, &block)
41
- env.project = Project::Cookbook.new(name.to_s, &block)
42
- end
43
- end
44
-
45
- class File
46
- include BasicDSL
47
- include CookbookDSL
48
-
49
- attr_reader :env
50
-
51
- def load(path, env)
52
- @env = env
53
- begin
54
- self.instance_eval(::File.read(path))
55
- rescue SyntaxError
56
- env.ui.info('Your Kitchenfile could not be loaded. Please check it for errors.', :red)
57
- raise
58
- end
59
- end
60
- end
61
-
62
- end
63
- end
@@ -1,166 +0,0 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- require 'fileutils'
20
- require 'hashr'
21
- require 'pathname'
22
- require 'yajl'
23
-
24
- module TestKitchen
25
-
26
- class Environment
27
-
28
- attr_reader :root_path
29
- attr_reader :tmp_path
30
- attr_reader :cache_path
31
- attr_reader :config
32
- attr_reader :ui
33
- attr_reader :kitchenfile_name
34
- attr_accessor :project
35
- attr_accessor :default_runner
36
-
37
- KITCHEN_SUBDIRS = [".", "kitchen", "test/kitchen"]
38
-
39
- def initialize(options={})
40
-
41
- options[:kitchenfile_name] ||= []
42
- options[:kitchenfile_name] = [options[:kitchenfile_name]] if !options[:kitchenfile_name].is_a?(Array)
43
- options[:kitchenfile_name] += ["Kitchenfile", "kitchenfile"]
44
- @kitchenfile_name = options[:kitchenfile_name]
45
-
46
- if options[:ignore_kitchenfile] || ! root_path
47
- @root_path = Pathname.new(Dir.pwd) + 'test' + 'kitchen'
48
- @project = Project::Cookbook.new(File.basename(Dir.pwd))
49
- end
50
-
51
- @default_runner = "vagrant"
52
- @tmp_path = root_path.join('.kitchen')
53
- @cache_path = tmp_path.join('.cache')
54
- @ui = options[:ui]
55
-
56
- setup_tmp_path
57
- end
58
-
59
- # Inspired by Vagrant::Environment.root_path...danke Mitchell!
60
- #
61
- # The root path is the path where the top-most (loaded last)
62
- # Vagrantfile resides. It can be considered the project root for
63
- # this environment.
64
- #
65
- # @return [String]
66
- def root_path
67
- return @root_path if defined?(@root_path)
68
-
69
- KITCHEN_SUBDIRS.each do |dir|
70
- path = Pathname.new(Dir.pwd).join(dir)
71
- found = kitchenfile_name.find do |rootfile|
72
- path.join(rootfile).exist?
73
- end
74
- @root_path = path if found
75
- end
76
-
77
- @root_path
78
- end
79
-
80
- def platforms
81
- @platforms ||= {}
82
- end
83
-
84
- def all_platforms
85
- Hash[*platforms.values.map do |p|
86
- p.versions.map{|key,value| ["#{p.name}-#{key}", value]}
87
- end.flatten]
88
- end
89
-
90
- def platform_names
91
- all_platforms.keys
92
- end
93
-
94
- def create_tmp_file(file_name, contents)
95
- File.open(tmp_path.join(file_name), 'w') do |f|
96
- f.write(contents)
97
- end
98
- end
99
-
100
- def cookbook_paths
101
- @cookbook_paths ||= begin
102
- p = [tmp_path.join('cookbooks').to_s]
103
- p << root_path.join('cookbooks').to_s if root_path.join('cookbooks').exist?
104
- p
105
- end
106
- end
107
-
108
- def setup_tmp_path
109
- # pre-create required dirs
110
- [ tmp_path, cache_path ].each do |dir|
111
- FileUtils.mkdir_p(dir)
112
- end
113
- end
114
-
115
- #---------------------------------------------------------------
116
- # Load Methods
117
- #---------------------------------------------------------------
118
-
119
- # Returns a boolean representing if the environment has been
120
- # loaded or not.
121
- #
122
- # @return [Bool]
123
- def loaded?
124
- !!@loaded
125
- end
126
-
127
- def load!
128
- if !loaded?
129
- @loaded = true
130
- load_kitchenfiles
131
- end
132
-
133
- self
134
- end
135
-
136
- private
137
-
138
- # Inspired by Vagrant::Environment.find_vagrantfile...danke Mitchell!
139
- #
140
- # Finds the Kitchenfile in the given directory.
141
- #
142
- # @param [Pathname] path Path to search in.
143
- # @return [Pathname]
144
- def find_kitchenfile(search_path)
145
- @kitchenfile_name.each do |kitchenfile|
146
- current_path = search_path.join(kitchenfile)
147
- return current_path if current_path.exist?
148
- end
149
-
150
- nil
151
- end
152
-
153
- def load_kitchenfiles
154
- # load Kitchenfile that ships with gem...seeds defaults
155
- kitchenfiles = [File.expand_path("config/Kitchenfile", TestKitchen.source_root)]
156
- # Load the user's Kitchenfile
157
- kitchenfiles << find_kitchenfile(root_path) if root_path
158
-
159
- kitchenfiles.flatten.compact.each do |kitchenfile|
160
- dsl_file = DSL::File.new
161
- dsl_file.load(kitchenfile, self)
162
- end
163
- end
164
-
165
- end
166
- end
@@ -1,79 +0,0 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- require 'hashr'
20
- require 'chef/mixin/params_validate'
21
-
22
- module TestKitchen
23
- class Platform
24
- include Chef::Mixin::ParamsValidate
25
-
26
- attr_reader :name, :versions
27
-
28
- def initialize(name, &block)
29
- raise ArgumentError, "Platform name must be specified" if name.nil? || name.empty?
30
-
31
- @name = name
32
- @versions = {}
33
- instance_eval(&block) if block_given?
34
- end
35
-
36
- def version(name, &block)
37
- versions[name.to_s] = Version.new(name, &block)
38
- end
39
-
40
- class Version
41
- include Chef::Mixin::ParamsValidate
42
-
43
- attr_reader :name
44
-
45
- # Virtual Box Specific Attributes
46
- attr_writer :box, :box_url
47
-
48
- def initialize(name, &block)
49
- raise ArgumentError, "Version name must be specified" if name.nil? || name.empty?
50
- @name = name
51
- instance_eval(&block) if block_given?
52
- end
53
-
54
- OPENSTACK_OPTIONS = {
55
- :image_id => nil, :flavor_id => nil, :install_chef => false,
56
- :install_chef_cmd => "curl -L http://www.opscode.com/chef/install.sh | sudo bash",
57
- :keyname => nil, :instance_name => nil, :ssh_user => "root", :ssh_key => nil}
58
-
59
- OPENSTACK_OPTIONS.each do |option, default|
60
- attr_writer option
61
- define_method(option) do |*args|
62
- arg = args.first
63
- set_or_return(option, arg, default.nil? ? {} : {:default => default})
64
- end
65
- end
66
-
67
-
68
- def box(arg=nil)
69
- set_or_return(:box, arg, {})
70
- end
71
-
72
- def box_url(arg=nil)
73
- set_or_return(:box_url, arg, {})
74
- end
75
-
76
- end
77
-
78
- end
79
- end