jamie 0.1.0.alpha1 → 0.1.0.alpha2

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.
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --readme README.md
2
+ --markup markdown
3
+ --markup-provider maruku
data/Gemfile CHANGED
@@ -1,3 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ group :test do
6
+ gem 'rake', '~> 0.9'
7
+ gem 'pry'
8
+ end
data/Rakefile CHANGED
@@ -1 +1,21 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'cane/rake_task'
3
+ require 'tailor/rake_task'
4
+
5
+ desc "Run cane to check quality metrics"
6
+ Cane::RakeTask.new do |cane|
7
+ cane.abc_exclude = %w(
8
+ Jamie::RakeTasks#define
9
+ Jamie::Vagrant.define_vagrant_vm
10
+ )
11
+ cane.style_exclude = %w(
12
+ lib/jamie/core_ext.rb
13
+ )
14
+ cane.doc_exclude = %w(
15
+ lib/jamie/core_ext.rb
16
+ )
17
+ end
18
+
19
+ Tailor::RakeTask.new
20
+
21
+ task :default => [ :cane, :tailor ]
data/jamie.gemspec CHANGED
@@ -17,7 +17,11 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
- gem.add_dependency 'hashie'
21
20
  gem.add_dependency 'mixlib-shellout'
22
21
  gem.add_dependency 'vagrant', '~> 1.0.5'
22
+
23
+ gem.add_development_dependency 'yard'
24
+ gem.add_development_dependency 'maruku'
25
+ gem.add_development_dependency 'cane'
26
+ gem.add_development_dependency 'tailor'
23
27
  end
data/lib/jamie.rb CHANGED
@@ -1,111 +1,387 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- require 'hashie/dash'
4
- require 'mixlib/shellout'
5
3
  require 'yaml'
6
4
 
7
- require "jamie/version"
5
+ require 'jamie/core_ext'
6
+ require 'jamie/version'
8
7
 
9
8
  module Jamie
10
- class Platform < Hashie::Dash
11
- property :name, :required => true
12
- property :vagrant_box
13
- property :vagrant_box_url
14
- property :base_run_list, :default => []
15
- end
16
-
17
- class Suite < Hashie::Dash
18
- property :name, :required => true
19
- property :run_list, :required => true
20
- property :json, :default => Hash.new
21
- end
22
9
 
10
+ # Base configuration class for Jamie. This class exposes configuration such
11
+ # as the location of the Jamie YAML file, instances, log_levels, etc.
23
12
  class Config
24
- attr_writer :yaml
13
+
14
+ attr_writer :yaml_file
25
15
  attr_writer :platforms
26
16
  attr_writer :suites
27
- attr_writer :backend
28
17
  attr_writer :log_level
29
18
  attr_writer :data_bags_base_path
30
19
 
31
- def yaml
32
- @yaml ||= File.join(Dir.pwd, '.jamie.yml')
20
+ # Default path to the Jamie YAML file
21
+ DEFAULT_YAML_FILE = File.join(Dir.pwd, '.jamie.yml').freeze
22
+
23
+ # Default log level verbosity
24
+ DEFAULT_LOG_LEVEL = :info
25
+
26
+ # Default driver plugin to use
27
+ DEFAULT_DRIVER_PLUGIN = "vagrant".freeze
28
+
29
+ # Default base path which may contain `data_bags/` directories
30
+ DEFAULT_DATA_BAGS_BASE_PATH = File.join(Dir.pwd, 'test/integration').freeze
31
+
32
+ # Creates a new configuration.
33
+ #
34
+ # @param yaml_file [String] optional path to Jamie YAML file
35
+ def initialize(yaml_file = nil)
36
+ @yaml_file = yaml_file
33
37
  end
34
38
 
39
+ # @return [Array<Platform>] all defined platforms which will be used in
40
+ # convergence integration
35
41
  def platforms
36
- @platforms ||=
37
- Array(yaml_data["platforms"]).map { |hash| Platform.new(hash) }
42
+ @platforms ||= Array(yaml["platforms"]).map { |hash| new_platform(hash) }
38
43
  end
39
44
 
45
+ # @return [Array<Suite>] all defined suites which will be used in
46
+ # convergence integration
40
47
  def suites
41
- @suites ||=
42
- Array(yaml_data["suites"]).map { |hash| Suite.new(hash) }
48
+ @suites ||= Array(yaml["suites"]).map { |hash| Suite.new(hash) }
43
49
  end
44
50
 
45
- def backend
46
- @backend ||= backend_for(yaml_data["backend"] || "vagrant")
51
+ # @return [Array<Instance>] all instances, resulting from all platform and
52
+ # suite combinations
53
+ def instances
54
+ @instances ||= suites.map { |suite|
55
+ platforms.map { |platform| Instance.new(suite, platform) }
56
+ }.flatten
47
57
  end
48
58
 
59
+ # @return [String] path to the Jamie YAML file
60
+ def yaml_file
61
+ @yaml_file ||= DEFAULT_YAML_FILE
62
+ end
63
+
64
+ # @return [Symbol] log level verbosity
49
65
  def log_level
50
- @log_level ||= :info
66
+ @log_level ||= DEFAULT_LOG_LEVEL
51
67
  end
52
68
 
69
+ # @return [String] base path that may contain a common `data_bags/`
70
+ # directory or an instance's `data_bags/` directory
53
71
  def data_bags_base_path
54
- default_path = File.join(Dir.pwd, 'test/integration')
72
+ @data_bags_path ||= DEFAULT_DATA_BAGS_BASE_PATH
73
+ end
55
74
 
56
- @data_bags_path ||= File.directory?(default_path) ? default_path : nil
75
+ private
76
+
77
+ def new_platform(hash)
78
+ mpc = merge_platform_config(hash)
79
+ mpc['driver'] = new_driver(mpc['driver_plugin'], mpc['driver_config'])
80
+ Platform.new(mpc)
57
81
  end
58
82
 
59
- def instances
60
- result = []
61
- suites.each do |suite|
62
- platforms.each do |platform|
63
- result << instance_name(suite, platform)
64
- end
83
+ def new_driver(plugin, config)
84
+ Driver.for_plugin(plugin, config)
85
+ end
86
+
87
+ def yaml
88
+ @yaml ||= YAML.load_file(File.expand_path(yaml_file))
89
+ end
90
+
91
+ def merge_platform_config(platform_config)
92
+ default_driver_config.rmerge(common_driver_config.rmerge(platform_config))
93
+ end
94
+
95
+ def default_driver_config
96
+ { 'driver_plugin' => DEFAULT_DRIVER_PLUGIN }
97
+ end
98
+
99
+ def common_driver_config
100
+ yaml.select { |key, value| %w(driver_plugin driver_config).include?(key) }
101
+ end
102
+ end
103
+
104
+ # A Chef run_list and attribute hash that will be used in a convergence
105
+ # integration.
106
+ class Suite
107
+
108
+ # @return [String] logical name of this suite
109
+ attr_reader :name
110
+
111
+ # @return [Array] Array of Chef run_list items
112
+ attr_reader :run_list
113
+
114
+ # @return [Hash] Hash of Chef node attributes
115
+ attr_reader :json
116
+
117
+ # Constructs a new suite.
118
+ #
119
+ # @param [Hash] options configuration for a new suite
120
+ # @option options [String] :name logical name of this suit (**Required**)
121
+ # @option options [String] :run_list Array of Chef run_list items
122
+ # (**Required**)
123
+ # @option options [Hash] :json Hash of Chef node attributes
124
+ def initialize(options = {})
125
+ validate_options(options)
126
+
127
+ @name = options['name']
128
+ @run_list = options['run_list']
129
+ @json = options['json'] || Hash.new
130
+ end
131
+
132
+ private
133
+
134
+ def validate_options(options)
135
+ if options['name'].nil?
136
+ raise ArgumentError, "The option 'name' is required."
137
+ end
138
+ if options['run_list'].nil?
139
+ raise ArgumentError, "The option 'run_list' is required."
65
140
  end
66
- result
141
+ end
142
+ end
143
+
144
+ # A target operating system environment in which convergence integration
145
+ # will take place. This may represent a specific operating system, version,
146
+ # and machine architecture.
147
+ class Platform
148
+
149
+ # @return [String] logical name of this platform
150
+ attr_reader :name
151
+
152
+ # @return [Driver::Base] driver object which will manage this platform's
153
+ # lifecycle actions
154
+ attr_reader :driver
155
+
156
+ # @return [Array] Array of Chef run_list items
157
+ attr_reader :run_list
158
+
159
+ # @return [Hash] Hash of Chef node attributes
160
+ attr_reader :json
161
+
162
+ # Constructs a new platform.
163
+ #
164
+ # @param [Hash] options configuration for a new platform
165
+ # @option options [String] :name logical name of this platform
166
+ # (**Required**)
167
+ # @option options [Driver::Base] :driver subclass of Driver::Base which
168
+ # will manage this platform's lifecycle actions (**Required**)
169
+ # @option options [Array<String>] :run_list Array of Chef run_list
170
+ # items
171
+ # @option options [Hash] :json Hash of Chef node attributes
172
+ def initialize(options = {})
173
+ validate_options(options)
174
+
175
+ @name = options['name']
176
+ @driver = options['driver']
177
+ @run_list = Array(options['run_list'])
178
+ @json = options['json'] || Hash.new
67
179
  end
68
180
 
69
181
  private
70
182
 
71
- def yaml_data
72
- @yaml_data ||= YAML.load_file(yaml)
183
+ def validate_options(options)
184
+ if options['name'].nil?
185
+ raise ArgumentError, "The option 'name' is required."
186
+ end
187
+ if options['driver'].nil?
188
+ raise ArgumentError, "The option 'driver' is required."
189
+ end
73
190
  end
191
+ end
192
+
193
+ # An instance of a suite running on a platform. A created instance may be a
194
+ # local virtual machine, cloud instance, container, or even a bare metal
195
+ # server, which is determined by the platform's driver.
196
+ class Instance
74
197
 
75
- def instance_name(suite, platform)
198
+ # @return [Suite] the test suite configuration
199
+ attr_reader :suite
200
+
201
+ # @return [Platform] the target platform configuration
202
+ attr_reader :platform
203
+
204
+ # Creates a new instance, given a suite and a platform.
205
+ #
206
+ # @param suite [Suite] a suite
207
+ # @param platform [Platform] a platform
208
+ def initialize(suite, platform)
209
+ @suite = suite
210
+ @platform = platform
211
+ end
212
+
213
+ # @return [String] name of this instance
214
+ def name
76
215
  "#{suite.name}-#{platform.name}".gsub(/_/, '-').gsub(/\./, '')
77
216
  end
78
217
 
79
- def backend_for(backend)
80
- klass = Jamie::Backend.const_get(backend.capitalize)
81
- klass.new
218
+ # Returns a combined run_list starting with the platform's run_list
219
+ # followed by the suite's run_list.
220
+ #
221
+ # @return [Array] combined run_list from suite and platform
222
+ def run_list
223
+ Array(platform.run_list) + Array(suite.run_list)
224
+ end
225
+
226
+ # Returns a merged hash of Chef node attributes with values from the
227
+ # suite overriding values from the platform.
228
+ #
229
+ # @return [Hash] merged hash of Chef node attributes
230
+ def json
231
+ platform.json.rmerge(suite.json)
232
+ end
233
+
234
+ # Creates this instance.
235
+ #
236
+ # @see Driver::Base#create
237
+ # @return [self] this instance, used to chain actions
238
+ #
239
+ # @todo rescue Driver::ActionFailed and return some kind of null object
240
+ # to gracfully stop action chaining
241
+ def create
242
+ puts "-----> Creating instance #{name}"
243
+ platform.driver.create(self)
244
+ puts " Creation of instance #{name} complete."
245
+ self
246
+ end
247
+
248
+ # Converges this running instance.
249
+ #
250
+ # @see Driver::Base#converge
251
+ # @return [self] this instance, used to chain actions
252
+ #
253
+ # @todo rescue Driver::ActionFailed and return some kind of null object
254
+ # to gracfully stop action chaining
255
+ def converge
256
+ puts "-----> Converging instance #{name}"
257
+ platform.driver.converge(self)
258
+ puts " Convergence of instance #{name} complete."
259
+ self
260
+ end
261
+
262
+ # Verifies this converged instance by executing tests.
263
+ #
264
+ # @see Driver::Base#verify
265
+ # @return [self] this instance, used to chain actions
266
+ #
267
+ # @todo rescue Driver::ActionFailed and return some kind of null object
268
+ # to gracfully stop action chaining
269
+ def verify
270
+ puts "-----> Verifying instance #{name}"
271
+ platform.driver.verify(self)
272
+ puts " Verification of instance #{name} complete."
273
+ self
274
+ end
275
+
276
+ # Destroys this instance.
277
+ #
278
+ # @see Driver::Base#destroy
279
+ # @return [self] this instance, used to chain actions
280
+ #
281
+ # @todo rescue Driver::ActionFailed and return some kind of null object
282
+ # to gracfully stop action chaining
283
+ def destroy
284
+ puts "-----> Destroying instance #{name}"
285
+ platform.driver.destroy(self)
286
+ puts " Destruction of instance #{name} complete."
287
+ self
288
+ end
289
+
290
+ # Tests this instance by creating, converging and verifying. If this
291
+ # instance is running, it will be pre-emptively destroyed to ensure a
292
+ # clean slate. The instance will be left post-verify in a running state.
293
+ #
294
+ # @see #destroy
295
+ # @see #create
296
+ # @see #converge
297
+ # @see #verify
298
+ # @return [self] this instance, used to chain actions
299
+ #
300
+ # @todo rescue Driver::ActionFailed and return some kind of null object
301
+ # to gracfully stop action chaining
302
+ def test
303
+ puts "-----> Cleaning up any prior instances of #{name}"
304
+ destroy
305
+ puts "-----> Testing instance #{name}"
306
+ create
307
+ converge
308
+ verify
309
+ puts " Testing of instance #{name} complete."
310
+ self
82
311
  end
83
312
  end
84
313
 
85
- module Backend
86
- class CommandFailed < StandardError ; end
314
+ module Driver
315
+
316
+ # Wrapped exception for any internally raised driver exceptions.
317
+ class ActionFailed < StandardError ; end
318
+
319
+ # Returns an instance of a driver given a plugin type string.
320
+ #
321
+ # @param plugin [String] a driver plugin type, which will be constantized
322
+ # @return [Driver::Base] a driver instance
323
+ def self.for_plugin(plugin, config)
324
+ require "jamie/driver/#{plugin}"
325
+
326
+ klass = self.const_get(plugin.capitalize)
327
+ klass.new(config)
328
+ end
329
+
330
+ # Base class for a driver. A driver is responsible for carrying out the
331
+ # lifecycle activities of an instance, such as creating, converging, and
332
+ # destroying an instance.
333
+ class Base
334
+
335
+ def initialize(config)
336
+ @config = config
337
+ self.class.defaults.each do |attr, value|
338
+ @config[attr] = value unless @config[attr]
339
+ end
340
+ end
341
+
342
+ # Provides hash-like access to configuration keys.
343
+ #
344
+ # @param attr [Object] configuration key
345
+ # @return [Object] value at configuration key
346
+ def [](attr)
347
+ @config[attr]
348
+ end
349
+
350
+ # Creates an instance.
351
+ #
352
+ # @param instance [Instance] an instance
353
+ # @raise [ActionFailed] if the action could not be completed
354
+ def create(instance) ; end
355
+
356
+ # Converges a running instance.
357
+ #
358
+ # @param instance [Instance] an instance
359
+ # @raise [ActionFailed] if the action could not be completed
360
+ def converge(instance) ; end
87
361
 
88
- class Vagrant
89
- def up(instance)
90
- exec! "vagrant up #{instance}"
91
- rescue Mixlib::ShellOut::ShellCommandFailed => ex
92
- raise CommandFailed, ex.message
362
+ # Destroys an instance.
363
+ #
364
+ # @param instance [Instance] an instance
365
+ # @raise [ActionFailed] if the action could not be completed
366
+ def destroy(instance) ; end
367
+
368
+ # Verifies a converged instance.
369
+ #
370
+ # @param instance [Instance] an instance
371
+ # @raise [ActionFailed] if the action could not be completed
372
+ def verify(instance)
373
+ # Subclass may choose to implement
374
+ puts " Nothing to do!"
93
375
  end
94
376
 
95
- def destroy(instance)
96
- exec! "vagrant destroy #{instance} -f"
97
- rescue Mixlib::ShellOut::ShellCommandFailed => ex
98
- raise CommandFailed, ex.message
377
+ private
378
+
379
+ def self.defaults
380
+ @defaults ||= Hash.new
99
381
  end
100
382
 
101
- def exec!(cmd)
102
- puts "-----> [vagrant command] #{cmd}"
103
- shellout = Mixlib::ShellOut.new(
104
- cmd, :live_stream => STDOUT, :timeout => 60000
105
- )
106
- shellout.run_command
107
- puts "-----> Command '#{cmd}' ran in #{shellout.execution_time} seconds."
108
- shellout.error!
383
+ def self.default_config(attr, value)
384
+ defaults[attr] = value
109
385
  end
110
386
  end
111
387
  end
@@ -0,0 +1,74 @@
1
+ #
2
+ # = Hash Recursive Merge
3
+ #
4
+ # Merges a Ruby Hash recursively, Also known as deep merge.
5
+ # Recursive version of Hash#merge and Hash#merge!.
6
+ #
7
+ # Category:: Ruby
8
+ # Package:: Hash
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # Copyright:: 2007-2008 The Authors
11
+ # License:: MIT License
12
+ # Link:: http://www.simonecarletti.com/
13
+ # Source:: http://gist.github.com/gists/6391/
14
+ #
15
+ module HashRecursiveMerge
16
+
17
+ #
18
+ # Recursive version of Hash#merge!
19
+ #
20
+ # Adds the contents of +other_hash+ to +hsh+,
21
+ # merging entries in +hsh+ with duplicate keys with those from +other_hash+.
22
+ #
23
+ # Compared with Hash#merge!, this method supports nested hashes.
24
+ # When both +hsh+ and +other_hash+ contains an entry with the same key,
25
+ # it merges and returns the values from both arrays.
26
+ #
27
+ # h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
28
+ # h2 = {"b" => 254, "c" => {"c1" => 16, "c3" => 94}}
29
+ # h1.rmerge!(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
30
+ #
31
+ # Simply using Hash#merge! would return
32
+ #
33
+ # h1.merge!(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
34
+ #
35
+ def rmerge!(other_hash)
36
+ merge!(other_hash) do |key, oldval, newval|
37
+ oldval.class == self.class ? oldval.rmerge!(newval) : newval
38
+ end
39
+ end
40
+
41
+ #
42
+ # Recursive version of Hash#merge
43
+ #
44
+ # Compared with Hash#merge!, this method supports nested hashes.
45
+ # When both +hsh+ and +other_hash+ contains an entry with the same key,
46
+ # it merges and returns the values from both arrays.
47
+ #
48
+ # Compared with Hash#merge, this method provides a different approch
49
+ # for merging nasted hashes.
50
+ # If the value of a given key is an Hash and both +other_hash+ abd +hsh
51
+ # includes the same key, the value is merged instead replaced with
52
+ # +other_hash+ value.
53
+ #
54
+ # h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
55
+ # h2 = {"b" => 254, "c" => {"c1" => 16, "c3" => 94}}
56
+ # h1.rmerge(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
57
+ #
58
+ # Simply using Hash#merge would return
59
+ #
60
+ # h1.merge(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
61
+ #
62
+ def rmerge(other_hash)
63
+ r = {}
64
+ merge(other_hash) do |key, oldval, newval|
65
+ r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+
72
+ class Hash
73
+ include HashRecursiveMerge
74
+ end
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'mixlib/shellout'
4
+
5
+ require 'jamie'
6
+
7
+ module Jamie
8
+
9
+ module Driver
10
+
11
+ # Vagrant driver for Jamie. It communicates to Vagrant via the CLI.
12
+ class Vagrant < Jamie::Driver::Base
13
+
14
+ default_config 'memory', '256'
15
+
16
+ def create(instance)
17
+ run "vagrant up #{instance.name} --no-provision"
18
+ end
19
+
20
+ def converge(instance)
21
+ run "vagrant provision #{instance.name}"
22
+ end
23
+
24
+ def destroy(instance)
25
+ run "vagrant destroy #{instance.name} -f"
26
+ end
27
+
28
+ private
29
+
30
+ def run(cmd)
31
+ puts " [vagrant command] '#{cmd}'"
32
+ shellout = Mixlib::ShellOut.new(
33
+ cmd, :live_stream => STDOUT, :timeout => 60000
34
+ )
35
+ shellout.run_command
36
+ puts " [vagrant command] '#{cmd}' ran " +
37
+ "in #{shellout.execution_time} seconds."
38
+ shellout.error!
39
+ rescue Mixlib::ShellOut::ShellCommandFailed => ex
40
+ raise ActionFailed, ex.message
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'rake'
4
+ require 'rake/tasklib'
5
+
6
+ require 'jamie'
7
+
8
+ module Jamie
9
+
10
+ # Jamie Rake task generator.
11
+ class RakeTasks < ::Rake::TaskLib
12
+
13
+ # @return [String] prefix name of all Jamie tasks
14
+ attr_accessor :name
15
+
16
+ # @return [Jamie::Config] a Jamie config object
17
+ attr_accessor :config
18
+
19
+ # Creates Jamie Rake tasks and allows the callee to configure it.
20
+ #
21
+ # @yield [self] gives itself to the block
22
+ def initialize(name = :jamie)
23
+ @name = name
24
+ @config = Jamie::Config.new
25
+ yield self if block_given?
26
+ define
27
+ end
28
+
29
+ private
30
+
31
+ def define
32
+ namespace name do
33
+ config.instances.each do |instance|
34
+ desc "Run #{instance.name} test instance"
35
+ task instance.name do
36
+ instance.test
37
+ end
38
+
39
+ namespace instance.name do
40
+ desc "Destroy #{instance.name} test instance"
41
+ task :destroy do
42
+ instance.destroy
43
+ end
44
+ end
45
+ end
46
+
47
+ desc "Destroy all instances"
48
+ task :destroy => config.instances.map { |i| "#{i.name}:destroy" }
49
+ end
50
+
51
+ desc "Run Jamie integration"
52
+ task name => config.instances.map { |i| "#{name}:#{i.name}" }
53
+ end
54
+ end
55
+ end
data/lib/jamie/vagrant.rb CHANGED
@@ -6,12 +6,15 @@ require 'vagrant'
6
6
  require 'jamie'
7
7
 
8
8
  module Jamie
9
+
9
10
  module Vagrant
11
+
12
+ # A Vagrant confiuration class which wraps a Jamie::Config instance.
10
13
  class Config < ::Vagrant::Config::Base
11
14
  extend Forwardable
12
15
 
13
- def_delegators :@config, :yaml, :yaml=, :platforms, :platforms=,
14
- :suites, :suites=, :log_level, :log_level=,
16
+ def_delegators :@config, :suites, :suites=, :platforms, :platforms=,
17
+ :instances, :yaml_file, :yaml_file=, :log_level, :log_level=,
15
18
  :data_bags_base_path, :data_bags_base_path=, :yaml_data
16
19
 
17
20
  def initialize
@@ -19,41 +22,38 @@ module Jamie
19
22
  end
20
23
  end
21
24
 
22
- def self.init!
23
- ::Vagrant.config_keys.register(:jamie) { Jamie::Vagrant::Config }
24
- end
25
-
25
+ # Defines all Vagrant virtual machines, one for each instance.
26
+ #
27
+ # @param config [Vagrant::Config::Top] Vagrant top level config object
26
28
  def self.define_vms(config)
27
- config.jamie.suites.each do |suite|
28
- config.jamie.platforms.each do |platform|
29
- define_vagrant_vm(config, suite, platform)
30
- end
29
+ config.jamie.instances.each do |instance|
30
+ define_vagrant_vm(config, instance)
31
31
  end
32
32
  end
33
33
 
34
34
  private
35
35
 
36
- def self.define_vagrant_vm(config, suite, platform)
37
- name = "#{suite.name}-#{platform.name}".gsub(/_/, '-').gsub(/\./, '')
36
+ def self.define_vagrant_vm(config, instance)
37
+ driver = instance.platform.driver
38
38
 
39
- config.vm.define name do |c|
40
- c.vm.box = platform.vagrant_box
41
- c.vm.box_url = platform.vagrant_box_url if platform.vagrant_box_url
42
- c.vm.host_name = "#{name}.vagrantup.com"
43
- c.vm.customize ["modifyvm", :id, "--memory", "256"]
39
+ config.vm.define instance.name do |c|
40
+ c.vm.box = driver['box']
41
+ c.vm.box_url = driver['box_url'] if driver['box_url']
42
+ c.vm.host_name = "#{instance.name}.vagrantup.com"
43
+ c.vm.customize ["modifyvm", :id, "--memory", driver['memory']]
44
44
 
45
45
  c.vm.provision :chef_solo do |chef|
46
46
  chef.log_level = config.jamie.log_level
47
- chef.run_list = platform.base_run_list + Array(suite.run_list)
48
- chef.json = suite.json
49
- chef.data_bags_path = calculate_data_bags_path(config, name)
47
+ chef.run_list = instance.run_list
48
+ chef.json = instance.json
49
+ chef.data_bags_path = calculate_data_bags_path(config, instance)
50
50
  end
51
51
  end
52
52
  end
53
53
 
54
- def self.calculate_data_bags_path(config, instance_name)
54
+ def self.calculate_data_bags_path(config, instance)
55
55
  base_path = config.jamie.data_bags_base_path
56
- instance_data_bags_path = File.join(base_path, instance_name, "data_bags")
56
+ instance_data_bags_path = File.join(base_path, instance.name, "data_bags")
57
57
  common_data_bags_path = File.join(base_path, "data_bags")
58
58
 
59
59
  if File.directory?(instance_data_bags_path)
@@ -67,4 +67,4 @@ module Jamie
67
67
  end
68
68
  end
69
69
 
70
- Jamie::Vagrant.init!
70
+ Vagrant.config_keys.register(:jamie) { Jamie::Vagrant::Config }
data/lib/jamie/version.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module Jamie
2
- VERSION = "0.1.0.alpha1"
4
+
5
+ VERSION = "0.1.0.alpha2"
3
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jamie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha1
4
+ version: 0.1.0.alpha2
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-01 00:00:00.000000000 Z
12
+ date: 2012-12-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: hashie
15
+ name: mixlib-shellout
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
@@ -28,14 +28,30 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
30
  - !ruby/object:Gem::Dependency
31
- name: mixlib-shellout
31
+ name: vagrant
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.5
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.5
46
+ - !ruby/object:Gem::Dependency
47
+ name: yard
32
48
  requirement: !ruby/object:Gem::Requirement
33
49
  none: false
34
50
  requirements:
35
51
  - - ! '>='
36
52
  - !ruby/object:Gem::Version
37
53
  version: '0'
38
- type: :runtime
54
+ type: :development
39
55
  prerelease: false
40
56
  version_requirements: !ruby/object:Gem::Requirement
41
57
  none: false
@@ -44,21 +60,53 @@ dependencies:
44
60
  - !ruby/object:Gem::Version
45
61
  version: '0'
46
62
  - !ruby/object:Gem::Dependency
47
- name: vagrant
63
+ name: maruku
48
64
  requirement: !ruby/object:Gem::Requirement
49
65
  none: false
50
66
  requirements:
51
- - - ~>
67
+ - - ! '>='
52
68
  - !ruby/object:Gem::Version
53
- version: 1.0.5
54
- type: :runtime
69
+ version: '0'
70
+ type: :development
55
71
  prerelease: false
56
72
  version_requirements: !ruby/object:Gem::Requirement
57
73
  none: false
58
74
  requirements:
59
- - - ~>
75
+ - - ! '>='
60
76
  - !ruby/object:Gem::Version
61
- version: 1.0.5
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: cane
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: tailor
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
62
110
  description: A Chef convergence integration test harness
63
111
  email:
64
112
  - fnichol@nichol.ca
@@ -67,13 +115,17 @@ extensions: []
67
115
  extra_rdoc_files: []
68
116
  files:
69
117
  - .gitignore
118
+ - .travis.yml
119
+ - .yardopts
70
120
  - Gemfile
71
121
  - LICENSE
72
122
  - README.md
73
123
  - Rakefile
74
124
  - jamie.gemspec
75
125
  - lib/jamie.rb
76
- - lib/jamie/rake_task.rb
126
+ - lib/jamie/core_ext.rb
127
+ - lib/jamie/driver/vagrant.rb
128
+ - lib/jamie/rake_tasks.rb
77
129
  - lib/jamie/vagrant.rb
78
130
  - lib/jamie/version.rb
79
131
  homepage: ''
@@ -88,6 +140,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
140
  - - ! '>='
89
141
  - !ruby/object:Gem::Version
90
142
  version: '0'
143
+ segments:
144
+ - 0
145
+ hash: -4553058254287566395
91
146
  required_rubygems_version: !ruby/object:Gem::Requirement
92
147
  none: false
93
148
  requirements:
@@ -101,3 +156,4 @@ signing_key:
101
156
  specification_version: 3
102
157
  summary: A Chef convergence integration test harness
103
158
  test_files: []
159
+ has_rdoc:
@@ -1,52 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require 'rake'
4
- require 'rake/tasklib'
5
-
6
- require 'jamie'
7
-
8
- module Jamie
9
- module Rake
10
- class Tasks < ::Rake::TaskLib
11
- attr_accessor :name
12
-
13
- def initialize(name = :jamie)
14
- @name = name
15
- yield self if block_given?
16
- define
17
- end
18
-
19
- def define
20
- config = Jamie::Config.new
21
-
22
- namespace(name) do
23
- config.instances.each do |instance_name|
24
- desc "Run #{instance_name} integration"
25
- task(instance_name) do
26
- puts "-----> Cleaning up any prior instances of #{instance_name}"
27
- config.backend.destroy(instance_name)
28
- puts "-----> Bringing up instance #{instance_name}"
29
- config.backend.up(instance_name)
30
- puts "-----> Instance #{instance_name} completed."
31
- end
32
-
33
- namespace(instance_name) do
34
- desc "Destroy #{instance_name} instance"
35
- task :destroy do
36
- puts "-----> Destroying any prior instances of #{instance_name}"
37
- config.backend.destroy(instance_name)
38
- puts "-----> Instance #{instance_name} destruction complete."
39
- end
40
- end
41
- end
42
-
43
- desc "Destroy all instances"
44
- task :destroy => config.instances.map { |i| "#{i}:destroy" }
45
- end
46
-
47
- desc "Run Jamie integration"
48
- task name => config.instances
49
- end
50
- end
51
- end
52
- end