vagabond 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -224,7 +224,7 @@ class Lxc
224
224
 
225
225
  # Stop the container
226
226
  def stop
227
- run_command("#{sudo}lxc-stop -n #{name}")
227
+ run_command("#{sudo}lxc-stop -n #{name}", :allow_failure_retry => 3)
228
228
  run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure_retry => 2)
229
229
  end
230
230
 
@@ -276,13 +276,14 @@ class Lxc
276
276
  shlout.run_command
277
277
  shlout.error!
278
278
  rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed, Mixlib::ShellOut::CommandTimeout
279
- if(args[:allow_failure])
280
- true
281
- elsif(retries > 0)
279
+ if(retries > 0)
282
280
  Chef::Log.warn "LXC run command failed: #{cmd}"
283
281
  Chef::Log.warn "Retrying command. #{args[:allow_failure_retry].to_i - retries} of #{args[:allow_failure_retry].to_i} retries remain"
282
+ sleep(0.3)
284
283
  retries -= 1
285
284
  retry
285
+ elsif(args[:allow_failure])
286
+ true
286
287
  else
287
288
  raise
288
289
  end
@@ -5,7 +5,7 @@ description "Chef driven Linux Containers"
5
5
  long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
6
6
  version "0.1.1"
7
7
 
8
- supports 'ubuntu', '12.04'
8
+ supports 'ubuntu'
9
9
 
10
- depends 'omnibus_updater'
10
+ suggests 'omnibus_updater'
11
11
  suggests 'bridger'
@@ -308,7 +308,6 @@ action :clone do
308
308
  end
309
309
 
310
310
  lxc_config new_resource.name do
311
- config new_resource.config
312
311
  action :create
313
312
  notifies :restart, resources(:lxc_service => "lxc config_restart[#{new_resource.name}]"), :immediately
314
313
  end
@@ -1,4 +1,8 @@
1
+ default[:vagabond][:bases][:ubuntu_1004][:template] = 'ubuntu'
2
+ default[:vagabond][:bases][:ubuntu_1004][:template_options] = {'--release' => 'lucid'}
3
+ default[:vagabond][:bases][:ubuntu_1204][:template] = 'ubuntu'
1
4
  default[:vagabond][:bases][:ubuntu_1204][:template_options] = {'--release' => 'precise'}
5
+ default[:vagabond][:bases][:ubuntu_1210][:template] = 'ubuntu'
2
6
  default[:vagabond][:bases][:ubuntu_1210][:template_options] = {'--release' => 'quantal'}
3
7
  default[:vagabond][:bases][:centos_58][:template] = 'centos'
4
8
  default[:vagabond][:bases][:centos_58][:template_options] = {'--release' => '5', '--releaseminor' => '8'}
@@ -10,3 +14,4 @@ default[:vagabond][:bases][:debian_6][:template] = 'debian'
10
14
  default[:vagabond][:bases][:debian_6][:create_environment] = {'SUITE' => 'squeeze'}
11
15
  default[:vagabond][:bases][:debian_7][:template] = 'debian'
12
16
  default[:vagabond][:bases][:debian_7][:create_environment] = {'SUITE' => 'wheezy'}
17
+ default[:vagabond][:customs] = {}
@@ -1,8 +1,23 @@
1
- include_recipe 'lxc::install_dependencies'
1
+ include_recipe 'lxc'
2
2
 
3
- cookbook_file '/usr/share/lxc/templates/lxc-centos' do
4
- source 'lxc-centos'
5
- mode 0755
3
+ ruby_block 'LXC template: lxc-centos' do
4
+ block do
5
+ dir = %w(/usr/share /usr/lib).map do |prefix|
6
+ if(File.directory?(d = File.join(prefix, 'lxc/templates')))
7
+ d
8
+ end
9
+ end.compact.first
10
+ raise 'Failed to locate LXC template directory' unless dir
11
+ cfl = Chef::Resource::CookbookFile.new(
12
+ ::File.join(dir, 'lxc-centos'),
13
+ run_context
14
+ )
15
+ cfl.source 'lxc-centos'
16
+ cfl.mode 0755
17
+ cfl.cookbook cookbook_name.to_s
18
+ cfl.action :nothing
19
+ cfl.run_action(:create)
20
+ end
6
21
  end
7
22
 
8
23
  node[:vagabond][:bases].each do |name, options|
@@ -14,9 +29,9 @@ node[:vagabond][:bases].each do |name, options|
14
29
  'upgrade -y -q',
15
30
  'install curl -y -q'
16
31
  ]
17
- if(%w(debian ubuntu).include?(options[:template]))
32
+ if(!options[:template].scan(%r{debian|ubuntu}).empty?)
18
33
  pkg_man = 'apt-get'
19
- elsif(%w(fedora centos).include?(options[:template]))
34
+ elsif(!options[:template].scan(%r{fedora|centos}).empty?)
20
35
  pkg_man = 'yum'
21
36
  end
22
37
  if(pkg_man)
@@ -40,14 +55,22 @@ node[:vagabond][:bases].each do |name, options|
40
55
  'curl -L https://www.opscode.com/chef/install.sh | bash'
41
56
  ]
42
57
  end
58
+ end
59
+
60
+ node[:vagabond][:customs].each do |name, options|
43
61
 
62
+ lxc_container name do
63
+ action :clone
64
+ base_container options[:base]
65
+ end
66
+
44
67
  if(options[:memory])
45
68
  lxc_config name do
46
69
  cgroup(
47
- 'memory.limit_in_bytes' => options[:memory][:maximum_ram],
70
+ 'memory.limit_in_bytes' => options[:memory][:ram],
48
71
  'memory.memsw.limit_in_bytes' => (
49
- Vagabond.get_bytes(options[:memory][:maximum_ram]) +
50
- Vagabond.get_bytes(options[:memory][:maximum_swap])
72
+ Vagabond.get_bytes(options[:memory][:ram]) +
73
+ Vagabond.get_bytes(options[:memory][:swap])
51
74
  )
52
75
  )
53
76
  end
@@ -0,0 +1,20 @@
1
+ module Vagabond
2
+ class CheffileLoader
3
+
4
+ attr_reader :cookbooks
5
+
6
+ def initialize(path=nil)
7
+ @cookbooks = []
8
+ load(path) if path
9
+ end
10
+
11
+ def cookbook(name, *args)
12
+ cookbooks[name] = args
13
+ end
14
+
15
+ def load(path)
16
+ instance_eval(File.read(path))
17
+ end
18
+
19
+ end
20
+ end
@@ -1,3 +1,5 @@
1
+ require 'vagabond/constants'
2
+
1
3
  module Vagabond
2
4
  module Helpers
3
5
  private
@@ -11,7 +13,70 @@ module Vagabond
11
13
  end
12
14
 
13
15
  def debug(s)
14
- ui.info "#{ui.color('DEBUG:', :red, :bold)} #{s}" if Config[:debug]
16
+ ui.info "#{ui.color('DEBUG:', :red, :bold)} #{s}" if options[:debug]
17
+ end
18
+
19
+ def generated_name(n=nil)
20
+ n = name unless n
21
+ if(@_gn.nil? || @_gn[n].nil?)
22
+ @_gn ||= Mash.new
23
+ s = Digest::MD5.new
24
+ s << @vagabondfile.path
25
+ @_gn[n] = "#{n}-#{s.hexdigest}"
26
+ end
27
+ @_gn[n]
28
+ end
29
+
30
+ def setup_ui(ui=nil)
31
+ unless(ui)
32
+ Chef::Config[:color] = options[:color].nil? ? true : options[:color]
33
+ @ui = Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
34
+ else
35
+ @ui = ui
36
+ end
37
+ options[:debug] = STDOUT if options[:debug]
38
+ self.class.ui = @ui
39
+ end
40
+
41
+ def execute
42
+ if(public_methods.include?(@action.to_sym))
43
+ send(@action)
44
+ else
45
+ ui.error "Invalid action received: #{@action}"
46
+ exit EXIT_CODES[:invalid_action]
47
+ end
48
+ end
49
+
50
+ def generate_hash
51
+ Digest::MD5.hexdigest(@vagabondfile.path)
52
+ end
53
+
54
+ def direct_container_command(command, args={})
55
+ _lxc = args[:lxc] || lxc
56
+ com = "#{sudo}ssh root@#{lxc.container_ip} -i /opt/hw-lxc-config/id_rsa -oStrictHostKeyChecking=no '#{command}'"
57
+ debug(com)
58
+ begin
59
+ cmd = Mixlib::ShellOut.new(com,
60
+ :live_stream => args[:live_stream] || options[:debug],
61
+ :timeout => args[:timeout] || 1200
62
+ )
63
+ cmd.run_command
64
+ cmd.error!
65
+ true
66
+ rescue
67
+ raise if args[:raise_on_failure]
68
+ false
69
+ end
70
+ end
71
+
72
+ class << self
73
+ def included(klass)
74
+ klass.class_eval do
75
+ class << self
76
+ attr_accessor :ui
77
+ end
78
+ end
79
+ end
15
80
  end
16
81
 
17
82
  end
@@ -1,5 +1,7 @@
1
1
  require 'digest/sha2'
2
+ require 'json'
2
3
  require 'vagabond/helpers'
4
+ require 'vagabond/constants'
3
5
 
4
6
  module Vagabond
5
7
  class InternalConfiguration
@@ -8,14 +10,26 @@ module Vagabond
8
10
 
9
11
  attr_reader :config
10
12
  attr_reader :ui
13
+ attr_reader :options
14
+ attr_accessor :force_bases
11
15
 
12
- def initialize(v_config, ui)
13
- @v_config = v_config
14
- @config = Mash.new(:mappings => Mash.new)
16
+ def initialize(vagabondfile, ui, options, args={})
17
+ @vagabondfile = vagabondfile
15
18
  @checksums = Mash.new
16
19
  @ui = ui
20
+ @options = options
17
21
  create_store
18
22
  load_existing
23
+ @config = Mash.new(
24
+ :mappings => Mash.new,
25
+ :template_mappings => Mash.new,
26
+ :test_mappings => Mash.new
27
+ ).merge(config)
28
+ @force_bases = args[:force_bases] || []
29
+ ensure_state
30
+ end
31
+
32
+ def ensure_state
19
33
  store_checksums
20
34
  write_dna_json
21
35
  write_solo_rb
@@ -41,13 +55,15 @@ module Vagabond
41
55
  File.read(path)
42
56
  )
43
57
  )
58
+ else
59
+ @config = Mash.new
44
60
  end
45
61
  end
46
62
 
47
63
  def store_path
48
64
  FileUtils.mkdir_p(
49
65
  File.join(
50
- File.dirname(@v_config.path), '.vagabond'
66
+ File.dirname(@vagabondfile.path), '.vagabond'
51
67
  )
52
68
  )
53
69
  end
@@ -61,26 +77,33 @@ module Vagabond
61
77
  end
62
78
 
63
79
  def write_dna_json
64
- conf = Mash.new
65
- @v_config.config[:boxes].map(&:last).map{|i| i[:template]}.compact.uniq.each do |t|
66
- conf[t] = Mash.new(:enabled => true)
80
+ conf = Mash.new(:bases => Mash.new, :customs => Mash.new)
81
+ (Array(@vagabondfile[:nodes]).map(&:last).map{|i| i[:template]}.compact + Array(force_bases)).uniq.each do |t|
82
+ conf[:bases][t] = Mash.new(:enabled => true) if BASE_TEMPLATES.include?(t.to_s)
67
83
  end
68
- if(@v_config.config[:templates])
69
- @v_config.config[:templates].each do |t|
70
- conf[t] ||= Mash.new
71
- conf[t].merge!(@v_config[:templates][t])
84
+ Array(@vagabondfile[:templates]).each do |t_name, opts|
85
+ if(BASE_TEMPLATES.include?(opts[:base].to_s))
86
+ conf[:bases][opts[:base]] = Mash.new(:enabled => true)
87
+ if(opts.has_key?(:memory) && !opts[:memory].is_a?(Hash))
88
+ opts[:memory][:ram] = opts[:memory].to_s
89
+ end
90
+ conf[:customs][generated_name(t_name)] = opts
91
+ config[:template_mappings][t_name] = generated_name(t_name)
92
+ else
93
+ ui.fatal "Invalid base template encountered: #{t}"
94
+ ui.info ui.color(" -> Valid base templates: #{BASE_TEMPLATES.sort.join(', ')}", :red)
95
+ exit EXIT_CODES[:invalid_base_template]
72
96
  end
73
97
  end
74
98
  File.open(dna_path, 'w') do |file|
75
99
  file.write(
76
100
  JSON.dump(
77
- :vagabond => {
78
- :bases => conf
79
- },
101
+ :vagabond => conf,
80
102
  :run_list => %w(recipe[vagabond])
81
103
  )
82
104
  )
83
105
  end
106
+ save
84
107
  end
85
108
 
86
109
  def write_solo_rb
@@ -106,9 +129,9 @@ module Vagabond
106
129
  end
107
130
 
108
131
  def solo_needed?
109
- if(Config[:force_solo])
132
+ if(options[:force_solo])
110
133
  true
111
- elsif(Config[:disable_solo])
134
+ elsif(options[:disable_solo])
112
135
  false
113
136
  else
114
137
  [dna_path, solo_path].detect do |path|
@@ -133,13 +156,14 @@ module Vagabond
133
156
  end
134
157
 
135
158
  def run_solo
136
- ui.info ui.color('Ensuring expected system state (creating required template containers)', :yellow)
159
+ ui.info ui.color('Ensuring expected system state (creating required base containers)', :yellow)
137
160
  ui.info ui.color(' - This can take a while...', :yellow)
138
- com = "#{Config[:sudo]}chef-solo -j #{File.join(store_path, 'dna.json')} -c #{File.join(store_path, 'solo.rb')}"
161
+ com = "#{options[:sudo]}chef-solo -j #{File.join(store_path, 'dna.json')} -c #{File.join(store_path, 'solo.rb')}"
139
162
  debug(com)
140
- cmd = Mixlib::ShellOut.new(com, :timeout => 1200, :live_stream => Config[:debug])
163
+ cmd = Mixlib::ShellOut.new(com, :timeout => 12000, :live_stream => options[:debug])
141
164
  cmd.run_command
142
165
  cmd.error!
166
+ ui.info ui.color(' -> COMPLETE!', :yellow)
143
167
  end
144
168
 
145
169
  def save
@@ -0,0 +1,311 @@
1
+ require 'thor'
2
+ require 'chef'
3
+ require 'kitchen/busser'
4
+
5
+ %w(helpers vagabondfile vagabond server helpers/cheffile_loader).each do |dep|
6
+ require "vagabond/#{dep}"
7
+ end
8
+
9
+ module Vagabond
10
+ class Kitchen < Thor
11
+
12
+ include Thor::Actions
13
+ include Helpers
14
+
15
+ class << self
16
+ def basename
17
+ 'vagabond kitchen'
18
+ end
19
+ end
20
+
21
+ self.class_exec(&Vagabond::CLI_OPTIONS)
22
+
23
+ attr_reader :kitchen
24
+ attr_reader :platform_map
25
+ attr_reader :vagabondfile
26
+ attr_reader :ui
27
+ attr_reader :name
28
+ attr_reader :action
29
+
30
+ def initialize(*args)
31
+ super
32
+ end
33
+
34
+ desc 'teardown COOKBOOK', 'Destroy containers related to COOKBOOK test'
35
+ method_option(:platform,
36
+ :type => :string,
37
+ :desc => 'Specify platform to destroy'
38
+ )
39
+ method_option(:suite,
40
+ :type => :string,
41
+ :desc => 'Specify suite to destroy'
42
+ )
43
+ def teardown(cookbook)
44
+ ui.info "#{ui.color('Vagabond:', :bold)} - Kitchen teardown for cookbook #{ui.color(name, :red)}"
45
+ plats = [platform || options[:platform] || platform_map.keys].flatten
46
+ plats.each do |plat|
47
+ validate_platform!(plat)
48
+ ui.info ui.color(" -> Tearing down platform: #{plat}", :red)
49
+ vagabond_instance(:destroy, plat).send(:execute)
50
+ ui.info ui.color(" -> Teardown of platform: #{plat} - COMPLETE!", :red)
51
+ end
52
+ end
53
+
54
+ desc 'test COOKBOOK', 'Run test kitchen on COOKBOOK'
55
+ method_option(:platform,
56
+ :type => :string,
57
+ :desc => 'Specify platform to test'
58
+ )
59
+ method_option(:cluster,
60
+ :type => :string,
61
+ :desc => 'Specify cluster to test'
62
+ )
63
+ method_option(:teardown,
64
+ :type => :boolean,
65
+ :default => true,
66
+ :desc => 'Teardown nodes automatically after testing'
67
+ )
68
+ method_option(:parallel,
69
+ :type => :boolean,
70
+ :default => false,
71
+ :desc => 'Build test nodes in parallel'
72
+ )
73
+ method_option(:suites,
74
+ :type => :string,
75
+ :desc => 'Specify suites to test [suite1,suite2,...]'
76
+ )
77
+ def test(cookbook)
78
+ setup(cookbook, :test)
79
+ ui.info "#{ui.color('Vagabond:', :bold)} - Kitchen testing for cookbook #{ui.color(name, :cyan)}"
80
+ results = Mash.new
81
+ platforms = [options[:platform] || platform_map.keys].flatten
82
+ if(options[:cluster])
83
+ ui.info ui.color(" -> Cluster Testing #{options[:cluster]}!", :yellow)
84
+ if(kitchen[:clusters].nil? || kitchen[:clusters][options[:cluster]].nil?)
85
+ ui.fatal "Requested cluster is not defined: #{options[:cluster]}"
86
+ exit EXIT_CODES[:cluster_invalid]
87
+ end
88
+ serv = Server.new
89
+ serv.options = options
90
+ serv.auto_upload # upload everything : make optional?
91
+ suites = kitchen[:clusters][options[:cluster]]
92
+ platforms.each do |platform|
93
+ %w(local_server_provision test destroy).each do |action|
94
+ suites.each do |suite_name|
95
+ res = self.send("#{action}_node", platform, suite_name)
96
+ if(action == 'test')
97
+ results[platform] ||=[]
98
+ results[platform] << {
99
+ :suite_name => suite_name,
100
+ :result => res
101
+ }
102
+ end
103
+ end
104
+ end
105
+ end
106
+ else
107
+ suites = options[:suites] ? options[:suites].split(',') : ['default']
108
+ platforms.each do |platform|
109
+ suites.each do |suite_name|
110
+ provision_node(platform, suite_name)
111
+ results[platform] ||= []
112
+ results[platform] << {
113
+ :suite_name => suite_name,
114
+ :result => test_node(platform, suite_name)
115
+ }
116
+ destroy_node(platform, suite_name)
117
+ end
118
+ end
119
+ end
120
+ ui.info ui.color('Kitchen Test Results:', :bold)
121
+ results.each do |platform, infos|
122
+ ui.info " Platform: #{ui.color(platform, :blue, :bold)}"
123
+ infos.each do |res|
124
+ ui.info " Suite: #{res[:suite_name]} -> #{res[:result] ? ui.color('SUCCESS!', :green) : ui.color('FAILED!', :red)}"
125
+ end
126
+ end
127
+ end
128
+
129
+ protected
130
+
131
+ def local_server_provision_node(platform, suite_name)
132
+ run_list = generate_runlist(platform, suite_name)
133
+ v_inst = vagabond_instance(:up, platform, :suite_name => suite_name, :run_list => run_list)
134
+ raise "ERROR! No local chef!" unless v_inst.options[:knife_opts]
135
+ v_inst.send(:execute)
136
+ end
137
+
138
+ # TODO: Handle failed provision!
139
+ def provision_node(platform, suite_name)
140
+ run_list = generate_runlist(platform, suite_name)
141
+ ui.info ui.color(" -> Provisioning suite #{suite_name} on platform: #{platform}", :cyan)
142
+ v_inst = vagabond_instance(:create, platform, :suite_name => suite_name)
143
+ v_inst.send(:execute)
144
+ solo_path = configure_for(v_inst.name, platform, suite_name, run_list, :dna, :cookbooks)
145
+ v_inst.send(:provision_solo, solo_path)
146
+ end
147
+
148
+ def test_node(platform, suite_name)
149
+ v_inst = vagabond_instance(:create, platform, :suite_name => suite_name)
150
+ busser = bus_node(v_inst, suite_name)
151
+ ui.info "#{ui.color('Kitchen:', :bold)} Running tests..."
152
+ cmd = busser.run_cmd
153
+ res = cmd.to_s.empty? ? true : v_inst.send(:direct_container_command, cmd, :live_stream => STDOUT)
154
+ ui.info "\n -> #{ui.color('Testing', :bold, :cyan)} #{name} suite #{suite_name} on platform #{platform}: #{res ? ui.color('SUCCESS!', :green, :bold) : ui.color('FAILED', :red)}"
155
+ res
156
+ end
157
+
158
+ def destroy_node(platform, suite_name)
159
+ if(options[:teardown])
160
+ v_inst = vagabond_instance(:destroy, platform, :suite_name => suite_name)
161
+ v_inst.send(:execute)
162
+ end
163
+ end
164
+
165
+ def setup(name, action)
166
+ @options = options.dup
167
+ @vagabondfile = Vagabondfile.new(options[:vagabond_file])
168
+ setup_ui
169
+ @name = name
170
+ @action = action
171
+ load_kitchen_yml
172
+ end
173
+
174
+ def configure_for(l_name, platform, suite_name, runlist, *args)
175
+ dir = File.join(File.dirname(vagabondfile.path), ".vagabond/node_configs/#{l_name}")
176
+ FileUtils.mkdir_p(dir)
177
+ _args = [args.include?(:integration) ? :integration : nil].compact
178
+ write_dna(l_name, suite_name, dir, platform, runlist, *_args) if args.include?(:dna)
179
+ load_cookbooks(l_name, suite_name, dir, platform, runlist, *_args) if args.include?(:cookbooks)
180
+ write_solo_config(dir) if args.include?(:cookbooks) && !args.include?(:integration)
181
+ dir
182
+ end
183
+
184
+ def write_solo_config(dir)
185
+ File.open(File.join(dir, 'solo.rb'), 'w') do |file|
186
+ file.write("cookbook_path '#{File.join(dir, 'cookbooks')}'\n")
187
+ end
188
+ end
189
+
190
+ def write_dna(l_name, suite_name, dir, platform, runlist, *args)
191
+ key = args.include?(:integration) ? :integration_suites : :suites
192
+ dna = Mash.new
193
+ dna.merge!(platform_map[platform][:attributes] || {})
194
+ s_args = kitchen[:suites].detect{|s|s[:name] == suite_name}
195
+ if(s_args)
196
+ dna.merge!(s_args)
197
+ end
198
+ dna[:run_list] = runlist
199
+ File.open(File.join(dir, 'dna.json'), 'w') do |file|
200
+ file.write(JSON.dump(dna))
201
+ end
202
+ end
203
+
204
+ def cookbook_path
205
+ Chef::CookbookLoader.new(
206
+ File.join(File.dirname(vagabondfile.path), 'cookbooks')
207
+ ).load_cookbooks[name].root_dir
208
+ end
209
+
210
+ def load_cookbooks(l_name, suite_name, dir, platform, runlist, *_args)
211
+ contents = ['site "http://community.opscode.com/api/v1"']
212
+ contents << "cookbook '#{name}', :path => '#{cookbook_path}'"
213
+ contents << "cookbook 'minitest-handler'"
214
+ # TODO - Customs from kitchen. Customs from root. Customs from cookbook
215
+ File.open(File.join(dir, 'Cheffile'), 'w') do |file|
216
+ file.write(contents.join("\n"))
217
+ end
218
+ com = "librarian-chef update"
219
+ debug(com)
220
+ c = Mixlib::ShellOut.new(com, :live_stream => options[:debug], :cwd => dir)
221
+ c.run_command
222
+ c.error!
223
+ end
224
+
225
+ def bus_node(v_inst, suite_name)
226
+ unless(::Kitchen::Busser::DEFAULT_TEST_ROOT == c_path = File.join(cookbook_path, 'test/integration'))
227
+ ::Kitchen::Busser.send(:remove_const, :DEFAULT_TEST_ROOT)
228
+ ::Kitchen::Busser.const_set(:DEFAULT_TEST_ROOT, File.join(cookbook_path, 'test/integration'))
229
+ end
230
+ busser = ::Kitchen::Busser.new(suite_name)
231
+ ui.info "#{ui.color('Kitchen:', :bold)} Setting up..."
232
+ %w(setup_cmd sync_cmd).each do |cmd|
233
+ com = busser.send(cmd)
234
+ next if com.to_s.empty?
235
+ v_inst.send(:direct_container_command, com)
236
+ end
237
+ busser
238
+ end
239
+
240
+ def vagabond_instance(action, platform, args={})
241
+ options[:disable_name_validate] = true
242
+ v = Vagabond.new
243
+ v.options = options
244
+ v.send(:setup, action, [name, platform, args[:suite_name]].compact.join('-'),
245
+ :ui => ui,
246
+ :template => platform_map[platform][:template],
247
+ :disable_name_validate => true,
248
+ :ui => ui
249
+ )
250
+ v.internal_config.force_bases = platform_map[platform][:template]
251
+ v.internal_config.ensure_state
252
+ v.mappings_key = :test_mappings
253
+ v.config = Mash.new(
254
+ :template => platform_map[platform][:template],
255
+ :run_list => args[:run_list]
256
+ )
257
+ v.lxc = Lxc.new(
258
+ v.internal_config[v.mappings_key][v.name]
259
+ ) if v.internal_config[v.mappings_key][v.name]
260
+ v
261
+ end
262
+
263
+ def load_kitchen_yml
264
+ y_path = File.join(
265
+ File.dirname(vagabondfile.path), 'cookbooks', name, '.kitchen.yml'
266
+ )
267
+ if(File.exists?(y_path))
268
+ @kitchen = Mash.new(YAML.load(File.read(y_path)))
269
+ else
270
+ ui.fatal "Cookbook #{name} does not have a .kitchen.yml file defined!"
271
+ ui.info ui.color(" -> Path: #{y_path}", :red)
272
+ exit EXIT_CODES[:kitchen_missing_yml]
273
+ end
274
+ end
275
+
276
+ def platform_map
277
+ @platform_map ||= Mash.new(Hash[*(
278
+ kitchen[:platforms].map do |plat|
279
+ [
280
+ plat[:name], Mash.new(
281
+ :template => plat[:driver_config][:box].scan(
282
+ %r{([^-]+-[^-]+)$}
283
+ ).flatten.first.to_s.gsub('.', '').gsub('-', '_'),
284
+ :run_list => plat[:run_list],
285
+ :attributes => plat[:attributes]
286
+ )
287
+ ]
288
+ end.flatten
289
+ )])
290
+ end
291
+
292
+ def generate_runlist(platform, suite)
293
+ r = platform_map[platform][:run_list]
294
+ kitchen_suite = kitchen[:suites].detect do |k_s|
295
+ k_s[:name] == suite
296
+ end
297
+ if(kitchen_suite && kitchen_suite[:run_list])
298
+ r |= kitchen_suite[:run_list]
299
+ end
300
+ r.uniq
301
+ end
302
+
303
+ def validate_platform!(plat)
304
+ unless(platform_map[plat])
305
+ ui.fatal "Requested platform does not exist: #{ui.color(plat, :red)}"
306
+ ui.info " -> Available platforms: #{platform_map.keys.sort.join(', ')}"
307
+ exit EXIT_CODES[:kitchen_invalid_platform]
308
+ end
309
+ end
310
+ end
311
+ end