jamie 0.1.0.alpha1 → 0.1.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
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