vagrant-lxc 0.2.0 → 0.3.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.vimrc +1 -1
  4. data/CHANGELOG.md +22 -0
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +10 -9
  7. data/README.md +43 -29
  8. data/boxes/quantal64/download-ubuntu +21 -20
  9. data/boxes/quantal64/lxc-template +11 -11
  10. data/boxes/quantal64/metadata.json +1 -1
  11. data/development/Vagrantfile +8 -4
  12. data/example/Vagrantfile +3 -15
  13. data/lib/vagrant-lxc.rb +0 -2
  14. data/lib/vagrant-lxc/action.rb +1 -14
  15. data/lib/vagrant-lxc/action/boot.rb +8 -9
  16. data/lib/vagrant-lxc/action/check_created.rb +6 -2
  17. data/lib/vagrant-lxc/action/check_running.rb +6 -2
  18. data/lib/vagrant-lxc/action/compress_rootfs.rb +1 -1
  19. data/lib/vagrant-lxc/action/create.rb +15 -7
  20. data/lib/vagrant-lxc/action/created.rb +6 -2
  21. data/lib/vagrant-lxc/action/destroy.rb +6 -2
  22. data/lib/vagrant-lxc/action/disconnect.rb +5 -1
  23. data/lib/vagrant-lxc/action/forced_halt.rb +3 -3
  24. data/lib/vagrant-lxc/action/forward_ports.rb +2 -2
  25. data/lib/vagrant-lxc/action/handle_box_metadata.rb +38 -27
  26. data/lib/vagrant-lxc/action/is_running.rb +6 -2
  27. data/lib/vagrant-lxc/action/share_folders.rb +8 -8
  28. data/lib/vagrant-lxc/config.rb +20 -10
  29. data/lib/vagrant-lxc/driver.rb +162 -0
  30. data/lib/vagrant-lxc/driver/builder.rb +21 -0
  31. data/lib/vagrant-lxc/{container → driver}/cli.rb +16 -11
  32. data/lib/vagrant-lxc/driver/fetch_ip_from_dnsmasq.rb +41 -0
  33. data/lib/vagrant-lxc/driver/fetch_ip_with_attach.rb +29 -0
  34. data/lib/vagrant-lxc/errors.rb +10 -0
  35. data/lib/vagrant-lxc/plugin.rb +4 -0
  36. data/lib/vagrant-lxc/provider.rb +14 -11
  37. data/lib/vagrant-lxc/version.rb +1 -1
  38. data/spec/fixtures/sample-ip-addr-output +2 -0
  39. data/spec/spec_helper.rb +1 -0
  40. data/spec/unit/action/compress_rootfs_spec.rb +4 -4
  41. data/spec/unit/action/forward_ports_spec.rb +3 -3
  42. data/spec/unit/action/handle_box_metadata_spec.rb +52 -26
  43. data/spec/unit/{container → driver}/cli_spec.rb +17 -19
  44. data/spec/unit/driver_spec.rb +173 -0
  45. data/tasks/boxes.rake +3 -3
  46. metadata +13 -15
  47. data/lib/vagrant-lxc/action/base_action.rb +0 -11
  48. data/lib/vagrant-lxc/action/network.rb +0 -21
  49. data/lib/vagrant-lxc/container.rb +0 -141
  50. data/lib/vagrant-lxc/machine_state.rb +0 -25
  51. data/spec/fixtures/sample-ifconfig-output +0 -18
  52. data/spec/unit/container_spec.rb +0 -147
  53. data/spec/unit/machine_state_spec.rb +0 -39
data/example/Vagrantfile CHANGED
@@ -1,34 +1,22 @@
1
1
  # -*- mode: ruby -*-
2
2
  # vi: set ft=ruby :
3
3
 
4
- def local_cache(box_name)
5
- cache_dir = File.join(File.expand_path(Vagrant::Environment::DEFAULT_HOME),
6
- 'cache',
7
- 'apt',
8
- box_name)
9
- partial_dir = File.join(cache_dir, 'partial')
10
- FileUtils.mkdir_p(partial_dir) unless File.exists? partial_dir
11
- cache_dir
12
- end
13
-
14
4
  # Not really needed, but useful while developing so that vagrant picks it up
15
5
  Vagrant.require_plugin 'vagrant-lxc'
16
6
 
17
7
  Vagrant.configure("2") do |config|
18
8
  config.vm.box = "quantal64"
19
- config.vm.box_url = 'http://dl.dropbox.com/u/13510779/lxc-quantal64-2013-03-31.box'
9
+ config.vm.box_url = 'http://dl.dropbox.com/u/13510779/lxc-quantal64-2013-04-10.box'
20
10
  # Uncomment if you want to try out a box built locally
21
11
  # config.vm.box_url = '../boxes/output/lxc-quantal64.box'
22
12
  config.vm.hostname = 'lxc-quantal64-example'
23
13
 
24
14
  config.vm.synced_folder "/tmp", "/vagrant_data"
25
15
 
26
- cache_dir = local_cache(config.vm.box)
27
- config.vm.synced_folder cache_dir, "/var/cache/apt/archives"
28
16
 
29
17
  config.vm.provider :lxc do |lxc|
30
- lxc.start_opts << 'lxc.cgroup.memory.limit_in_bytes=400M'
31
- lxc.start_opts << 'lxc.cgroup.memory.memsw.limit_in_bytes=500M'
18
+ lxc.customize 'cgroup.memory.limit_in_bytes', '400M'
19
+ lxc.customize 'cgroup.memory.memsw.limit_in_bytes', '500M'
32
20
  end
33
21
 
34
22
  config.vm.provision :shell, :inline => <<-SCRIPT
data/lib/vagrant-lxc.rb CHANGED
@@ -1,4 +1,2 @@
1
1
  require "vagrant-lxc/version"
2
2
  require "vagrant-lxc/plugin"
3
-
4
- I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../locales/en.yml')
@@ -1,7 +1,3 @@
1
- # TODO: Remove base action
2
- require 'vagrant-lxc/action/base_action'
3
-
4
- # TODO: Use require_relative
5
1
  require 'vagrant-lxc/action/boot'
6
2
  require 'vagrant-lxc/action/check_created'
7
3
  require 'vagrant-lxc/action/check_running'
@@ -15,7 +11,6 @@ require 'vagrant-lxc/action/forced_halt'
15
11
  require 'vagrant-lxc/action/forward_ports'
16
12
  require 'vagrant-lxc/action/handle_box_metadata'
17
13
  require 'vagrant-lxc/action/is_running'
18
- require 'vagrant-lxc/action/network'
19
14
  require 'vagrant-lxc/action/setup_package_files'
20
15
  require 'vagrant-lxc/action/share_folders'
21
16
 
@@ -42,11 +37,6 @@ module Vagrant
42
37
  end
43
38
  end
44
39
 
45
- # We could do this here as VirtualBox does, but at least for now its better
46
- # to be explicit and have the full constant name in order to easily spot
47
- # what we implemented and what is builtin on Vagrant.
48
- #
49
- # include Vagrant::Action::Builtin
50
40
 
51
41
  # This action boots the VM, assuming the VM is in a state that requires
52
42
  # a bootup (i.e. not saved).
@@ -56,11 +46,8 @@ module Vagrant
56
46
  b.use Vagrant::Action::Builtin::Provision
57
47
  b.use Vagrant::Action::Builtin::EnvSet, :port_collision_repair => true
58
48
  # b.use PrepareForwardedPortCollisionParams
59
- # b.use ClearSharedFolders
60
49
  b.use ShareFolders
61
- b.use Network
62
50
  b.use Vagrant::Action::Builtin::SetHostname
63
- # b.use Customize
64
51
  b.use ForwardPorts
65
52
  b.use Boot
66
53
  end
@@ -135,7 +122,7 @@ module Vagrant
135
122
  b2.use Disconnect
136
123
  b2.use ClearForwardedPorts
137
124
  b2.use Vagrant::Action::Builtin::Call, Vagrant::Action::Builtin::GracefulHalt, :stopped, :running do |env2, b3|
138
- if !env2[:result] && env2[:machine].provider.state.running?
125
+ if !env2[:result]
139
126
  b3.use ForcedHalt
140
127
  end
141
128
  end
@@ -1,20 +1,19 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class Boot < BaseAction
4
+ class Boot
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
10
  @env = env
7
11
 
8
12
  config = env[:machine].provider_config
9
13
 
10
- # Allows this middleware to be called multiple times. We need to
11
- # support this as base boxes might have after create scripts which
12
- # require SSH access
13
- unless env[:machine].state.running?
14
- env[:ui].info I18n.t("vagrant.actions.vm.boot.booting")
15
- env[:machine].provider.container.start(config)
16
- raise Vagrant::Errors::VMFailedToBoot if !wait_for_boot
17
- end
14
+ env[:ui].info I18n.t("vagrant.actions.vm.boot.booting")
15
+ env[:machine].provider.driver.start(config.customizations)
16
+ raise Vagrant::Errors::VMFailedToBoot if !wait_for_boot
18
17
 
19
18
  @app.call env
20
19
  end
@@ -1,9 +1,13 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class CheckCreated < BaseAction
4
+ class CheckCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
- unless env[:machine].state.created?
10
+ if env[:machine].state.id == :not_created
7
11
  raise Vagrant::Errors::VMNotCreatedError
8
12
  end
9
13
 
@@ -1,9 +1,13 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class CheckRunning < BaseAction
4
+ class CheckRunning
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
- unless env[:machine].state.running?
10
+ if env[:machine].state.id != :running
7
11
  raise Vagrant::Errors::VMNotRunningError
8
12
  end
9
13
 
@@ -12,7 +12,7 @@ module Vagrant
12
12
  raise Vagrant::Errors::VMPowerOffToPackage if env[:machine].provider.state.id != :stopped
13
13
 
14
14
  env[:ui].info I18n.t("vagrant.actions.lxc.compressing_rootfs")
15
- @rootfs = env['package.rootfs'] = env[:machine].provider.container.compress_rootfs
15
+ @rootfs = env['package.rootfs'] = env[:machine].provider.driver.compress_rootfs
16
16
 
17
17
  @app.call env
18
18
 
@@ -1,16 +1,24 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class Create < BaseAction
4
+ class Create
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
- base_name = env[:root_path].basename.to_s
7
- base_name.gsub!(/[^-a-z0-9_]/i, "")
10
+ container_name = env[:root_path].basename.to_s
11
+ container_name.gsub!(/[^-a-z0-9_]/i, "")
12
+ container_name << "-#{Time.now.to_i}"
13
+
14
+ env[:machine].provider.driver.create(
15
+ container_name,
16
+ env[:lxc_template_src],
17
+ env[:lxc_template_opts]
18
+ )
8
19
 
9
- target_rootfs_path = env[:machine].provider_config.target_rootfs_path
20
+ env[:machine].id = container_name
10
21
 
11
- machine_id = env[:machine].provider.container.create(base_name, target_rootfs_path, env[:machine].box.metadata)
12
- env[:machine].id = machine_id
13
- env[:just_created] = true
14
22
  @app.call env
15
23
  end
16
24
  end
@@ -1,10 +1,14 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class Created < BaseAction
4
+ class Created
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
10
  # Set the result to be true if the machine is created.
7
- env[:result] = env[:machine].state.created?
11
+ env[:result] = env[:machine].state.id != :not_created
8
12
 
9
13
  # Call the next if we have one (but we shouldn't, since this
10
14
  # middleware is built to run with the Call-type middlewares)
@@ -1,10 +1,14 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class Destroy < BaseAction
4
+ class Destroy
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
10
  env[:ui].info I18n.t("vagrant.actions.vm.destroy.destroying")
7
- env[:machine].provider.container.destroy
11
+ env[:machine].provider.driver.destroy
8
12
  env[:machine].id = nil
9
13
  @app.call env
10
14
  end
@@ -1,7 +1,11 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class Disconnect < BaseAction
4
+ class Disconnect
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
10
  @app.call env
7
11
  # FIXME: Vagrant >= 1.1.3 should not need this
@@ -7,11 +7,11 @@ module Vagrant
7
7
  end
8
8
 
9
9
  def call(env)
10
- if env[:machine].provider.state.running?
10
+ if env[:machine].provider.state.id == :running
11
11
  env[:ui].info I18n.t("vagrant.actions.vm.halt.force")
12
- # TODO: Container#halt is kinda graceful as well, if it doesn't
12
+ # TODO: Driver#halt is kinda graceful as well, if it doesn't
13
13
  # work we can issue a lxc-stop.
14
- env[:machine].provider.container.halt
14
+ env[:machine].provider.driver.halt
15
15
  end
16
16
 
17
17
  @app.call(env)
@@ -29,7 +29,7 @@ module Vagrant
29
29
  end
30
30
 
31
31
  def forward_ports
32
- @container_ip = @env[:machine].provider.container.assigned_ip
32
+ @container_ip = @env[:machine].provider.driver.assigned_ip
33
33
 
34
34
  @env[:forwarded_ports].each do |fp|
35
35
  message_attributes = {
@@ -63,7 +63,7 @@ module Vagrant
63
63
  end
64
64
 
65
65
  def redirect_port(host, guest)
66
- redir_cmd = "sudo redir --laddr=127.0.0.1 --lport=#{host} --cport=#{guest} --caddr=#{@container_ip}"
66
+ redir_cmd = "sudo redir --laddr=127.0.0.1 --lport=#{host} --cport=#{guest} --caddr=#{@container_ip} 2>/dev/null"
67
67
 
68
68
  @logger.debug "Forwarding port with `#{redir_cmd}`"
69
69
  fork { exec redir_cmd }
@@ -2,45 +2,56 @@ module Vagrant
2
2
  module LXC
3
3
  module Action
4
4
  # Prepare arguments to be used for lxc-create
5
- class HandleBoxMetadata < BaseAction
6
- LXC_TEMPLATES_PATH = Pathname.new("/usr/share/lxc/templates")
7
- TEMP_PREFIX = "vagrant-lxc-rootfs-temp-"
8
-
5
+ class HandleBoxMetadata
9
6
  def initialize(app, env)
10
- super
7
+ @app = app
11
8
  @logger = Log4r::Logger.new("vagrant::lxc::action::handle_box_metadata")
12
9
  end
13
10
 
14
11
  def call(env)
15
- env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
16
- :name => env[:machine].box.name)
12
+ @env = env
13
+ @box = @env[:machine].box
17
14
 
18
- rootfs_cache = Dir.mktmpdir(TEMP_PREFIX)
19
- box = env[:machine].box
20
- template_name = "vagrant-#{box.name}"
15
+ @env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
16
+ :name => @env[:machine].box.name)
21
17
 
22
- # Prepends "lxc-" to the template file so that `lxc-create` is able to find it
23
- lxc_template_src = box.directory.join('lxc-template').to_s
24
- unless File.exists?(lxc_template_src)
25
- raise Errors::TemplateFileMissing.new name: box.name
26
- end
27
- dest = LXC_TEMPLATES_PATH.join("lxc-#{template_name}").to_s
28
- @logger.debug('Copying LXC template into place')
29
- system(%Q[sudo su root -c "cp #{lxc_template_src} #{dest}"])
18
+ @logger.debug 'Validating box contents'
19
+ validate_box
30
20
 
31
- @logger.debug('Extracting rootfs')
32
- # TODO: Ideally the compressed rootfs should not output errors...
33
- system(%Q[sudo su root -c "cd #{box.directory} && tar xfz rootfs.tar.gz -C #{rootfs_cache} 2>/dev/null"])
21
+ @logger.debug 'Setting box options on environment'
22
+ @env[:lxc_template_opts] = template_opts
23
+ @env[:lxc_template_src] = template_src
24
+
25
+ @app.call env
26
+ end
34
27
 
35
- box.metadata.merge!(
36
- 'template-name' => template_name,
37
- 'rootfs-cache-path' => rootfs_cache
28
+ def template_src
29
+ @template_src ||= @box.directory.join('lxc-template').to_s
30
+ end
31
+
32
+ def template_opts
33
+ @template_opts ||= @box.metadata.fetch('template-opts', {}).dup.merge!(
34
+ '--tarball' => rootfs_tarball,
35
+ '--auth-key' => Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s
38
36
  )
37
+ end
39
38
 
40
- @app.call(env)
39
+ def rootfs_tarball
40
+ @rootfs_tarball ||= @box.directory.join('rootfs.tar.gz').to_s
41
+ end
42
+
43
+ def validate_box
44
+ if @box.metadata.fetch('version').to_i != 2
45
+ raise Errors::InvalidBoxVersion.new name: @box.name
46
+ end
41
47
 
42
- ensure
43
- system %Q[sudo su root -c "rm -rf #{rootfs_cache}"]
48
+ unless File.exists?(template_src)
49
+ raise Errors::TemplateFileMissing.new name: @box.name
50
+ end
51
+
52
+ unless File.exists?(rootfs_tarball)
53
+ raise Errors::RootFSTarballMissing.new name: @box.name
54
+ end
44
55
  end
45
56
  end
46
57
  end
@@ -1,9 +1,13 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class IsRunning < BaseAction
4
+ class IsRunning
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
- env[:result] = env[:machine].state.running?
10
+ env[:result] = env[:machine].state.id == :running
7
11
 
8
12
  # Call the next if we have one (but we shouldn't, since this
9
13
  # middleware is built to run with the Call-type middlewares)
@@ -1,11 +1,15 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  module Action
4
- class ShareFolders < BaseAction
4
+ class ShareFolders
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
5
9
  def call(env)
6
10
  @env = env
7
11
  prepare_folders
8
- add_start_opts
12
+ add_override_configs
9
13
  @app.call env
10
14
  end
11
15
 
@@ -14,9 +18,6 @@ module Vagrant
14
18
  def shared_folders
15
19
  {}.tap do |result|
16
20
  @env[:machine].config.vm.synced_folders.each do |id, data|
17
- # Ignore NFS shared folders
18
- next if data[:nfs]
19
-
20
21
  # This to prevent overwriting the actual shared folders data
21
22
  result[id] = data.dup
22
23
  end
@@ -43,7 +44,7 @@ module Vagrant
43
44
  end
44
45
  end
45
46
 
46
- def add_start_opts
47
+ def add_override_configs
47
48
  @env[:ui].info I18n.t("vagrant.actions.lxc.share_folders.preparing")
48
49
 
49
50
  folders = []
@@ -56,8 +57,7 @@ module Vagrant
56
57
  @env[:ui].info(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
57
58
  :guest_path => data[:guestpath]))
58
59
  end
59
- config = @env[:machine].provider_config
60
- @env[:machine].provider.container.share_folders(folders, config)
60
+ @env[:machine].provider.driver.share_folders(folders)
61
61
  end
62
62
  end
63
63
  end
@@ -1,21 +1,31 @@
1
1
  module Vagrant
2
2
  module LXC
3
3
  class Config < Vagrant.plugin("2", :config)
4
- # An array of options to be passed to lxc-start when booting the machine.
4
+ # An array of container's configuration overrides to be provided to `lxc-start`.
5
5
  #
6
6
  # @return [Array]
7
- attr_reader :start_opts
8
-
9
- # Base directory to store container's rootfs
10
- #
11
- # Defaults to nil, which means it will be stored wherever the lxc template
12
- # tells it to be stored
13
- attr_accessor :target_rootfs_path
7
+ attr_reader :customizations
14
8
 
15
9
  def initialize
16
- @start_opts = []
17
- @target_rootfs_path = nil
10
+ @customizations = []
11
+ end
12
+
13
+ # Customize the container by calling `lxc-start` with the given
14
+ # configuration overrides.
15
+ #
16
+ # For example, if you want to set the memory limit, you can use it
17
+ # like: config.customize 'cgroup.memory.limit_in_bytes', '400M'
18
+ #
19
+ # When `lxc-start`ing the container, vagrant-lxc will pass in
20
+ # "-s lxc.cgroup.memory.limit_in_bytes=400M" to it.
21
+ #
22
+ # @param [String] key Configuration key to override
23
+ # @param [String] value Configuration value to override
24
+ def customize(key, value)
25
+ @customizations << [key, value]
18
26
  end
27
+
28
+ # TODO: At some point in the future it would be nice to validate these options
19
29
  end
20
30
  end
21
31
  end