vagabond 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/CHANGELOG.md +18 -0
  2. data/README.md +125 -4
  3. data/bin/vagabond +43 -16
  4. data/lib/vagabond/actions/cluster.rb +66 -0
  5. data/lib/vagabond/actions/create.rb +12 -7
  6. data/lib/vagabond/actions/destroy.rb +69 -15
  7. data/lib/vagabond/actions/init.rb +75 -0
  8. data/lib/vagabond/actions/provision.rb +4 -2
  9. data/lib/vagabond/actions/status.rb +33 -22
  10. data/lib/vagabond/actions/up.rb +8 -1
  11. data/lib/vagabond/bootstraps/server-zero.erb +20 -0
  12. data/lib/vagabond/bootstraps/server.erb +3 -2
  13. data/lib/vagabond/constants.rb +0 -15
  14. data/lib/vagabond/cookbooks/lxc/CHANGELOG.md +16 -0
  15. data/lib/vagabond/cookbooks/lxc/Gemfile +3 -2
  16. data/lib/vagabond/cookbooks/lxc/Gemfile.lock +30 -121
  17. data/lib/vagabond/cookbooks/lxc/README.md +43 -14
  18. data/lib/vagabond/cookbooks/lxc/attributes/default.rb +3 -3
  19. data/lib/vagabond/cookbooks/lxc/files/default/lxc-awesome-ephemeral +499 -0
  20. data/lib/vagabond/cookbooks/lxc/libraries/lxc.rb +223 -58
  21. data/lib/vagabond/cookbooks/lxc/libraries/lxc_file_config.rb +3 -0
  22. data/lib/vagabond/cookbooks/lxc/libraries/monkey.rb +51 -0
  23. data/lib/vagabond/cookbooks/lxc/metadata.rb +6 -5
  24. data/lib/vagabond/cookbooks/lxc/providers/config.rb +9 -16
  25. data/lib/vagabond/cookbooks/lxc/providers/container.rb +241 -229
  26. data/lib/vagabond/cookbooks/lxc/providers/default.rb +57 -0
  27. data/lib/vagabond/cookbooks/lxc/providers/ephemeral.rb +40 -0
  28. data/lib/vagabond/cookbooks/lxc/providers/fstab.rb +13 -54
  29. data/lib/vagabond/cookbooks/lxc/providers/interface.rb +13 -67
  30. data/lib/vagabond/cookbooks/lxc/providers/service.rb +14 -14
  31. data/lib/vagabond/cookbooks/lxc/recipes/default.rb +17 -4
  32. data/lib/vagabond/cookbooks/lxc/recipes/install_dependencies.rb +1 -1
  33. data/lib/vagabond/cookbooks/lxc/resources/config.rb +2 -2
  34. data/lib/vagabond/cookbooks/lxc/resources/container.rb +31 -6
  35. data/lib/vagabond/cookbooks/lxc/resources/default.rb +12 -0
  36. data/lib/vagabond/cookbooks/lxc/resources/ephemeral.rb +13 -0
  37. data/lib/vagabond/cookbooks/lxc/resources/fstab.rb +2 -1
  38. data/lib/vagabond/cookbooks/lxc/resources/interface.rb +6 -3
  39. data/lib/vagabond/cookbooks/lxc/resources/service.rb +1 -1
  40. data/lib/vagabond/cookbooks/lxc/templates/default/file_content.erb +2 -0
  41. data/lib/vagabond/cookbooks/lxc/templates/default/interface.erb +9 -3
  42. data/lib/vagabond/cookbooks/vagabond/README.md +10 -0
  43. data/lib/vagabond/cookbooks/vagabond/attributes/default.rb +1 -0
  44. data/lib/vagabond/cookbooks/vagabond/files/default/lxc-centos +13 -6
  45. data/lib/vagabond/cookbooks/vagabond/metadata.rb +1 -0
  46. data/lib/vagabond/cookbooks/vagabond/recipes/default.rb +46 -4
  47. data/lib/vagabond/cookbooks/vagabond/recipes/zero.rb +9 -0
  48. data/lib/vagabond/errors.rb +23 -0
  49. data/lib/vagabond/helpers.rb +41 -14
  50. data/lib/vagabond/internal_configuration.rb +120 -27
  51. data/lib/vagabond/kitchen.rb +143 -63
  52. data/lib/vagabond/knife.rb +8 -5
  53. data/lib/vagabond/layout.rb +16 -0
  54. data/lib/vagabond/monkey/kitchen_config.rb +23 -0
  55. data/lib/vagabond/server.rb +79 -63
  56. data/lib/vagabond/spec.rb +345 -0
  57. data/lib/vagabond/uploader.rb +30 -0
  58. data/lib/vagabond/uploader/berkshelf.rb +53 -0
  59. data/lib/vagabond/uploader/knife.rb +24 -0
  60. data/lib/vagabond/uploader/librarian.rb +31 -0
  61. data/lib/vagabond/vagabond.rb +30 -11
  62. data/lib/vagabond/vagabondfile.rb +40 -5
  63. data/lib/vagabond/version.rb +1 -1
  64. data/vagabond.gemspec +5 -2
  65. metadata +75 -15
  66. data/lib/vagabond/cookbooks/lxc/resources/#container.rb# +0 -28
  67. data/lib/vagabond/cookbooks/lxc/test/kitchen/Kitchenfile +0 -7
  68. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/metadata.rb +0 -2
  69. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/centos_lxc.rb +0 -0
  70. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/chef-bootstrap.rb +0 -0
  71. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/lxc_files.rb +0 -0
  72. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/lxc_templates.rb +0 -0
  73. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/ubuntu_lxc.rb +0 -0
@@ -1,3 +1,21 @@
1
+ ## v0.2.2
2
+ * Migration to elecksee gem for LXC management
3
+ * Addition of chef-zero support for local chef server
4
+ * Updated testing for standalone cookbook testing
5
+ * Updated support for dependency resolvers (librarian and berkshelf)
6
+ * Addition of `spec` support
7
+ * Better isolation around sudo usage
8
+ * Cleaned `internal_configuration` and added automatic reloading on detected changes
9
+ * Added `cluster` support to Vagabondfile for easily building multiple nodes
10
+ * New `init` command for base setup
11
+ * Lots and lots of bug fixes and feature enhancements
12
+ * Output relevant information on bad command
13
+ * Huge thanks to all those that helped test, debug, and add features especially:
14
+ * Jesse Nelson - https://github.com/spheromak
15
+ * Bryan Berry - https://github.com/bryanwb
16
+ * Sean Escriva - https://github.com/webframp
17
+
18
+
1
19
  ## v0.2.0
2
20
  * Migrate to thor
3
21
  * Clean up option usage
data/README.md CHANGED
@@ -15,8 +15,8 @@ instead of full blown VMs which means things are faster. Lots
15
15
  faster.
16
16
 
17
17
  Vagabond is built for Chef. The tooling within Vagabond is targeted
18
- at Chef. As the initial development push on Vagabond slows, this
19
- tooling will become optionally swappable (applicable bits at least).
18
+ at Chef. After the initial development has slowed, the Chef specifics
19
+ will be pulled into a plugin.
20
20
 
21
21
  ## Installation
22
22
 
@@ -29,7 +29,7 @@ $ gem install vagabond
29
29
  ## How does it work
30
30
 
31
31
  Currently, this is built to run within a classic Chef repository.
32
- It requires a `Vagabond` file, that simply outputs a Hash. The file
32
+ It requires a `Vagabondfile` file, that simply outputs a Hash. The file
33
33
  is Ruby though, so you can do lots of crazy stuff to build the
34
34
  Hash you return. Heres a simple example:
35
35
 
@@ -58,6 +58,23 @@ Now, to create a node, simply run:
58
58
  $ vagabond up db
59
59
  ```
60
60
 
61
+ This command will bootstrap the installation of LXC utilities and base
62
+ containers prior to starting up a linux container. It does this by
63
+ running the vagabond chef recipe embedded in this gem at
64
+ `lib/vagabond/cookbooks/vagabond/recipes/default.rb`.
65
+
66
+ To only prepare your system for LXC fun and generate a simple vagabond
67
+ file, do the following:
68
+
69
+ ```
70
+ $ vagabond init
71
+ ```
72
+
73
+ This command runs the chef recipe and generates a basic Vagabondfile and
74
+ creates the base containers specified in that file. Those base
75
+ containers are Ubuntu 12.04 and CentOS 6.3. This creation process will
76
+ take a while so now is a good time to get a fresh pot of coffee.
77
+
61
78
  Pretty simple, right?
62
79
 
63
80
  ### Templates available
@@ -131,6 +148,103 @@ chef server. Looking for example? See the `USAGE` file!
131
148
 
132
149
  Double awesome
133
150
 
151
+ ## Infrastructure testing
152
+
153
+ Cookbook tests are great and they help keep cookbooks stable and prevent
154
+ regressions. But what about tests for integrating cookbooks into an existing
155
+ infrastructure? Or upgrading an existing cookbook? The tests bundled with
156
+ the cookbook can happily pass with no indication of how it may affect other
157
+ resources within the infrastructure. So lets fix this.
158
+
159
+ Currently infrastructure tests are built using serverspec[1]. Test kitchen support
160
+ for infrastructure testing is in the works, but is still a moving target. So
161
+ lets look at how we can set this up. First, initialize the specs:
162
+
163
+ ```
164
+ $ vagabond spec init
165
+ ```
166
+
167
+ Next, we need to define the layout of the infrastructure. This is done by
168
+ populating the `Layout` file in the `spec` directory. Just like everything
169
+ else, this is just a ruby file that is expected to spit out a Hash. An
170
+ example file would look like this:
171
+
172
+ ```ruby
173
+ # spec/Layout
174
+ {
175
+ :defaults => {
176
+ :platform => 'ubuntu_1204',
177
+ :environment => 'testing',
178
+ :union => 'aufs'
179
+ },
180
+ :definitions => {
181
+ :test_node => {
182
+ :run_list => %w(role[base])
183
+ }
184
+ },
185
+ :clusters => {
186
+ :my_cluster => {
187
+ :overrides => {
188
+ :environment => '_default'
189
+ },
190
+ :nodes => ['test_node'] * 3
191
+ }
192
+ }
193
+ }
194
+ ```
195
+
196
+ ### :defaults
197
+
198
+ These are the default configuration options used for creating the containers
199
+ for testing. These are the same configurations used when creating the nodes
200
+ in the Vagabondfile.
201
+
202
+ ### :definitions
203
+
204
+ These are the definitions of your nodes. Any options here that were defined
205
+ within the `:defaults` section will be overridden.
206
+
207
+ ### :clusters
208
+
209
+ These are the clusters of nodes that describe the infrastructure. The key
210
+ provides the identifier name used from the `spec` command. The `:overrides`
211
+ are cluster specific overrides that are applied to all nodes when created.
212
+ The `:nodes` is an array of `:definitions` keys for nodes to build. The
213
+ keys can be repeated `n` times to provide multiple nodes of a specific type.
214
+
215
+ ### Usage
216
+
217
+ ```
218
+ $ vagabond spec my_cluster
219
+ ```
220
+
221
+ ### Applying specs
222
+
223
+ Specs are applied based on the run list describing the node. After the local
224
+ chef server has been created (if required), all nodes have been created, and
225
+ all nodes provisioned vagabond will run back through all nodes applying the
226
+ applicable specs. Specs are very straight forward and only use SSH connections
227
+ to spec the node. An example spec:
228
+
229
+ ```ruby
230
+ require 'spec_helper'
231
+
232
+ describe 'cron' do
233
+ it{ should be_enabled }
234
+ it{ should be_running }
235
+ end
236
+ ```
237
+
238
+ ### Spec real infrastructure
239
+
240
+ Since specs only require an SSH connection to test nodes, we can run specs
241
+ against actual live infrastructure to see if it is currently in a valid
242
+ state based on existing specs. Awesome!
243
+
244
+ ```
245
+ $ vagabond spec my_cluster --environment production
246
+ ```
247
+
134
248
  ## Important note
135
249
 
136
250
  Until namespaces hit Linux proper, vagabond `sudo`s its way around. You
@@ -163,6 +277,13 @@ get help making things better!
163
277
  * Base updates and pull requests on the `develop` branch
164
278
  * Please don't update core files like `version.rb` or `vagabond.gemspec`
165
279
 
280
+ ## Contributors
281
+
282
+ * [Bryan Berry](https://github.com/bryanwb)
283
+ * [Jesse Nelson](https://github.com/spheromak)
284
+ * [Sean Escriva](https://github.com/webframp)
285
+ * [Xabier de Zuazo](https://github.com/zuazo)
286
+
166
287
  ## Infos
167
288
 
168
- * Repository: https://github.com/chrisroberts/vagabond
289
+ * Repository: https://github.com/chrisroberts/vagabond
@@ -4,25 +4,52 @@ Signal.trap('INT'){ exit 255 }
4
4
 
5
5
  require 'rubygems'
6
6
  require 'vagabond'
7
+ require 'vagabond/errors'
7
8
 
8
9
  if(ARGV.include?('--version') || ARGV.include?('-v'))
9
10
  require 'vagabond/vagabond'
10
11
  Vagabond::Vagabond.new.send(:version)
12
+ elsif(%w(help --help -h).include?(ARGV.first))
13
+ puts "-- Vagabond --\n"
14
+ require 'vagabond/vagabond'
15
+ Object.send(:remove_const, :ARGV)
16
+ ARGV = %w(help)
17
+ Vagabond::Vagabond.start
18
+ %w(server knife kitchen spec).each do |key|
19
+ puts "-- #{key.capitalize} --\n"
20
+ require "vagabond/#{key}"
21
+ Object.send(:remove_const, :ARGV)
22
+ ARGV = %w(help)
23
+ Vagabond.const_get(key.capitalize).start
24
+ end
11
25
  else
12
- case arg = ARGV.shift
13
- when 'server'
14
- require 'vagabond/server'
15
- Vagabond::Server
16
- when 'knife'
17
- require 'vagabond/knife'
18
- ARGV.unshift(arg) unless ARGV.empty?
19
- Vagabond::Knife
20
- when 'test', 'kitchen'
21
- require 'vagabond/kitchen'
22
- Vagabond::Kitchen
23
- else
24
- require 'vagabond/vagabond'
25
- ARGV.unshift(arg)
26
- Vagabond::Vagabond
27
- end.start
26
+ begin
27
+ case arg = ARGV.shift
28
+ when 'server'
29
+ require 'vagabond/server'
30
+ Vagabond::Server
31
+ when 'knife'
32
+ require 'vagabond/knife'
33
+ ARGV.unshift(arg) unless ARGV.empty?
34
+ Vagabond::Knife
35
+ when 'test', 'kitchen'
36
+ require 'vagabond/kitchen'
37
+ Vagabond::Kitchen
38
+ when 'spec'
39
+ require 'vagabond/spec'
40
+ Vagabond::Spec
41
+ else
42
+ require 'vagabond/vagabond'
43
+ ARGV.unshift(arg)
44
+ Vagabond::Vagabond
45
+ end.start
46
+ rescue Vagabond::VagabondError => e
47
+ exit e.exit_code
48
+ rescue Exception => e
49
+ $stderr.puts "Vagabond exiting. Reason: #{e}"
50
+ if(ENV['VAGABOND_EXIT_DEBUG'])
51
+ puts "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
52
+ end
53
+ exit -1
54
+ end
28
55
  end
@@ -0,0 +1,66 @@
1
+ module Vagabond
2
+ module Actions
3
+ module Cluster
4
+ class << self
5
+ def included(klass)
6
+ klass.class_eval do
7
+ class << self
8
+ def _cluster_options
9
+ [[
10
+ :auto_provision, :type => :boolean,
11
+ :desc => 'Automatically provision nodes', :default => true
12
+ ],
13
+ [
14
+ :delay, :type => :numeric, :default => 0,
15
+ :desc => 'Add delay between provisions (helpful for indexing)'
16
+ ],
17
+ [
18
+ :parallel, :type => :boolean, :default => false,
19
+ :desc => 'Build nodes in parallel'
20
+ ]
21
+ ]
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def _cluster
29
+ clr = vagabondfile[:clusters][name] if vagabondfile[:clusters]
30
+ if(clr)
31
+ ui.info "#{ui.color('Vagabond:', :bold)} Building cluster - #{ui.color(name, :green)}"
32
+ if(vagabondfile[:local_chef_server] && vagabondfile[:local_chef_server][:enabled])
33
+ require 'vagabond/server'
34
+ srv = ::Vagabond::Server.new
35
+ srv.send(:setup, 'up')
36
+ srv.execute
37
+ # Reload so we get proper values
38
+ load_configurations
39
+ end
40
+ cluster_instances = clr.map do |n|
41
+ ui.info "Building #{n} for cluster!"
42
+ v_inst = Vagabond.new
43
+ v_inst.options = options.dup
44
+ v_inst.send(:setup, 'up', n, :ui => ui)
45
+ v_inst.execute
46
+ if(options[:delay].to_i > 0 && n != clr.last)
47
+ ui.warn "Delay requested between node processing. Sleeping for #{options[:delay].to_i} seconds."
48
+ sleep(options[:delay].to_i)
49
+ end
50
+ v_inst
51
+ end
52
+ if(options[:parallel])
53
+ ui.info "Waiting for parallel completes!"
54
+ cluster_instances.map do |inst|
55
+ inst.wait_for_completion
56
+ end
57
+ end
58
+ ui.info " -> #{ui.color("Built cluster #{name}", :green)}"
59
+ else
60
+ ui.error "Cluster name provided does not exist: #{name}"
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -1,3 +1,5 @@
1
+ require 'elecksee/ephemeral'
2
+
1
3
  module Vagabond
2
4
  module Actions
3
5
  module Create
@@ -21,14 +23,17 @@ module Vagabond
21
23
  tmpl = internal_config[:template_mappings][tmpl]
22
24
  elsif(!BASE_TEMPLATES.include?(tmpl))
23
25
  ui.fatal "Template requested for node does not exist: #{tmpl}"
24
- exit EXIT_CODES[:invalid_template]
26
+ raise VagabondError::InvalidTemplate.new(tmpl)
27
+ end
28
+ unless(config[:device])
29
+ config[:directory] = true
25
30
  end
26
- bind_path = File.expand_path(File.dirname(vagabondfile.path))
27
- com = "#{sudo}lxc-start-ephemeral -d -b #{bind_path} -o #{tmpl}"
28
- debug(com)
29
- c = Mixlib::ShellOut.new("#{com} && sleep 3", :live_stream => options[:debug])
30
- c.run_command
31
- e_name = c.stdout.split("\n").last.split(' ').last.strip
31
+ config[:daemon] = true
32
+ config[:original] = tmpl
33
+ config[:bind] = File.expand_path(File.dirname(vagabondfile.store_path))
34
+ ephemeral = Lxc::Ephemeral.new(config)
35
+ ephemeral.start!(:fork)
36
+ e_name = ephemeral.name
32
37
  @internal_config[mappings_key][name] = e_name
33
38
  @internal_config.save
34
39
  @lxc = Lxc.new(e_name)
@@ -2,27 +2,76 @@ module Vagabond
2
2
  module Actions
3
3
  module Destroy
4
4
 
5
+ class << self
6
+ def included(klass)
7
+ klass.class_eval do
8
+ class << self
9
+ def _cluster_options
10
+ [
11
+ [
12
+ :cluster, :type => :boolean,
13
+ :desc => 'Destroy cluster of nodes with provided name', :default => false
14
+ ]
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+
5
23
  def _destroy
6
24
  name_required!
7
- if(lxc.exists?)
8
- ui.info "#{ui.color('Vagabond:', :bold)} Destroying node: #{ui.color(name, :red)}"
9
- do_destroy
10
- ui.info ui.color(' -> DESTROYED', :red)
25
+ if(options[:cluster])
26
+ nodes = vagabondfile[:clusters][name] if vagabondfile[:clusters]
27
+ if(nodes)
28
+ ui.info "#{ui.color('Vagabond:', :bold)} Destroying cluster - #{ui.color(name, :red)}"
29
+ else
30
+ ui.error "Cluster name provided does not exist: #{name}"
31
+ nodes = []
32
+ end
11
33
  else
12
- ui.error "Node not created: #{name}"
34
+ nodes = [name, @leftover_args].flatten.compact
35
+ end
36
+ nodes.each do |n|
37
+ next unless n.is_a?(String)
38
+ @name = n
39
+ load_configurations
40
+ if(lxc.exists?)
41
+ ui.info "#{ui.color('Vagabond:', :bold)} Destroying node: #{ui.color(name, :red)}"
42
+ do_destroy
43
+ ui.info ui.color(' -> DESTROYED', :red)
44
+ else
45
+ ui.error "Node not created: #{name}"
46
+ end
13
47
  end
14
48
  end
15
49
 
16
50
  private
17
51
 
18
52
  def do_destroy
19
- lxc.stop if lxc.running?
20
- com = "#{options[:sudo]}lxc-destroy -n #{lxc.name}"
21
- debug(com)
22
- cmd = Mixlib::ShellOut.new(com, :live_stream => options[:debug])
23
- cmd.run_command
24
- cmd.error!
25
- if(cmd.stderr.include?('skipping'))
53
+ lxc.shutdown if lxc.running?
54
+ ui.info 'Waiting for graceful shutdown and cleanup...'
55
+ 5.times do
56
+ break unless lxc.exists?
57
+ sleep(1)
58
+ end
59
+ if(lxc.exists?)
60
+ com = "#{options[:sudo]}lxc-destroy -n #{lxc.name}"
61
+ debug(com)
62
+ cmd = Mixlib::ShellOut.new(com, :live_stream => options[:debug])
63
+ cmd.run_command
64
+ force_umount_if_required!
65
+ end
66
+ internal_config[mappings_key].delete(name)
67
+ internal_config.save
68
+ end
69
+
70
+ def force_umount_if_required!
71
+ mount = %x{mount}.split("\n").find_all do |line|
72
+ line.include?(lxc.name)
73
+ end
74
+ unless(mount.empty?)
26
75
  ui.info ui.color(' -> Failed to unmount some resources. Forcing manually.', :yellow)
27
76
  %w(rootfs ephemeralbind).each do |mnt|
28
77
  com = "#{options[:sudo]}umount /var/lib/lxc/#{lxc.name}/#{mnt}"
@@ -33,10 +82,15 @@ module Vagabond
33
82
  debug(com)
34
83
  cmd = Mixlib::ShellOut.new(com, :live_stream => options[:debug])
35
84
  cmd.run_command
36
- cmd.error!
37
- internal_config[mappings_key].delete(name)
38
85
  end
39
- internal_config.save
86
+ # check for tmpfs and umount too
87
+ tmp = mount.detect{|x|x.include?('rootfs')}.scan(%r{upperdir=[^,]+}).first.to_s.split('=').last
88
+ if(tmp)
89
+ com = "#{options[:sudo]}umount #{tmp}"
90
+ debug(com)
91
+ cmd = Mixlib::ShellOut.new(com, :live_stream => options[:debug])
92
+ cmd.run_command
93
+ end
40
94
  end
41
95
  end
42
96
  end