vagrant-lxc 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,11 +0,0 @@
1
- module Vagrant
2
- module LXC
3
- module Action
4
- class BaseAction
5
- def initialize(app, env)
6
- @app = app
7
- end
8
- end
9
- end
10
- end
11
- end
@@ -1,21 +0,0 @@
1
- module Vagrant
2
- module LXC
3
- module Action
4
- class Network < BaseAction
5
- def call(env)
6
- # TODO: Validate network configuration prior to anything below
7
- @env = env
8
-
9
- env[:machine].config.vm.networks.each do |type, options|
10
- # We only handle private networks
11
- next if type != :private_network
12
- env[:machine].provider_config.start_opts << "lxc.network.ipv4=#{options[:ip]}/24"
13
- end
14
-
15
- # Continue the middleware chain.
16
- @app.call(env)
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,141 +0,0 @@
1
- require 'securerandom'
2
-
3
- require "vagrant-lxc/errors"
4
- require "vagrant-lxc/container/cli"
5
-
6
- require "vagrant/util/retryable"
7
- require "vagrant/util/subprocess"
8
-
9
- module Vagrant
10
- module LXC
11
- class Container
12
- # Root folder where containers are stored
13
- CONTAINERS_PATH = '/var/lib/lxc'
14
-
15
- # Include this so we can use `Subprocess` more easily.
16
- include Vagrant::Util::Retryable
17
-
18
- # This is raised if the container can't be found when initializing it with
19
- # a name.
20
- class NotFound < StandardError; end
21
-
22
- attr_reader :name
23
-
24
- def initialize(name, cli = CLI.new(name))
25
- @name = name
26
- @cli = cli
27
- @logger = Log4r::Logger.new("vagrant::provider::lxc::container")
28
- end
29
-
30
- def validate!
31
- raise NotFound if @name && ! @cli.list.include?(@name)
32
- end
33
-
34
- def base_path
35
- Pathname.new("#{CONTAINERS_PATH}/#{@name}")
36
- end
37
-
38
- def rootfs_path
39
- Pathname.new(base_path.join('config').read.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1])
40
- end
41
-
42
- def create(base_name, target_rootfs_path, metadata = {})
43
- @logger.debug('Creating container using lxc-create...')
44
-
45
- @name = "#{base_name}-#{SecureRandom.hex(6)}"
46
- public_key = Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s
47
- meta_opts = metadata.fetch('template-opts', {}).merge(
48
- '--auth-key' => public_key,
49
- '--cache' => metadata.fetch('rootfs-cache-path')
50
- )
51
-
52
- @cli.name = @name
53
- @cli.create(metadata.fetch('template-name'), target_rootfs_path, meta_opts)
54
-
55
- @name
56
- end
57
-
58
- def share_folders(folders, config)
59
- folders.each do |folder|
60
- guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, ''))
61
- unless guestpath.directory?
62
- begin
63
- system "sudo mkdir -p #{guestpath.to_s}"
64
- rescue Errno::EACCES
65
- raise Vagrant::Errors::SharedFolderCreateFailed,
66
- :path => guestpath.to_s
67
- end
68
- end
69
-
70
- config.start_opts << "lxc.mount.entry=#{folder[:hostpath]} #{guestpath} none bind 0 0"
71
- end
72
- end
73
-
74
- def start(config)
75
- @logger.info('Starting container...')
76
-
77
- opts = config.start_opts.dup
78
- if ENV['LXC_START_LOG_FILE']
79
- extra = ['-o', ENV['LXC_START_LOG_FILE'], '-l', 'DEBUG']
80
- end
81
-
82
- @cli.transition_to(:running) { |c| c.start(opts, (extra || nil)) }
83
- end
84
-
85
- def halt
86
- @logger.info('Shutting down container...')
87
-
88
- # TODO: issue an lxc-stop if a timeout gets reached
89
- @cli.transition_to(:stopped) { |c| c.shutdown }
90
- end
91
-
92
- def destroy
93
- @cli.destroy
94
- end
95
-
96
- # TODO: This needs to be reviewed and specs needs to be written
97
- def compress_rootfs
98
- # TODO: Our template should not depend on container's arch
99
- arch = base_path.join('config').read.match(/^lxc\.arch\s+=\s+(.+)$/)[1]
100
- rootfs_dirname = File.dirname rootfs_path
101
- basename = rootfs_path.to_s.gsub(/^#{Regexp.escape rootfs_dirname}\//, '')
102
- # TODO: Pass in tmpdir so we can clean up from outside
103
- target_path = "#{Dir.mktmpdir}/rootfs.tar.gz"
104
-
105
- Dir.chdir base_path do
106
- @logger.info "Compressing '#{rootfs_path}' rootfs to #{target_path}"
107
- system "sudo rm -f rootfs.tar.gz && sudo bsdtar -s /#{basename}/rootfs-#{arch}/ --numeric-owner -czf #{target_path} #{basename}/* 2>/dev/null"
108
-
109
- @logger.info "Changing rootfs tarbal owner"
110
- system "sudo chown #{ENV['USER']}:#{ENV['USER']} #{target_path}"
111
- end
112
-
113
- target_path
114
- end
115
-
116
- def state
117
- if @name
118
- @cli.state
119
- end
120
- end
121
-
122
- def assigned_ip
123
- ip = ''
124
- retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do
125
- unless ip = get_container_ip_from_ifconfig
126
- # retry
127
- raise LXC::Errors::ExecuteError, :command => "lxc-attach"
128
- end
129
- end
130
- ip
131
- end
132
-
133
- def get_container_ip_from_ifconfig
134
- output = @cli.attach '/sbin/ifconfig', '-v', 'eth0', namespaces: 'network'
135
- if output =~ /\s+inet addr:([0-9.]+)\s+/
136
- return $1.to_s
137
- end
138
- end
139
- end
140
- end
141
- end
@@ -1,25 +0,0 @@
1
- module Vagrant
2
- module LXC
3
- class MachineState < Vagrant::MachineState
4
- CREATED_STATES = %w( running stopped ).map!(&:to_sym)
5
-
6
- def initialize(state_id)
7
- short = state_id.to_s.gsub("_", " ")
8
- long = I18n.t("vagrant.commands.status.#{state_id}")
9
- super(state_id, short, long)
10
- end
11
-
12
- def created?
13
- CREATED_STATES.include?(self.id)
14
- end
15
-
16
- def off?
17
- self.id == :stopped
18
- end
19
-
20
- def running?
21
- self.id == :running
22
- end
23
- end
24
- end
25
- end
@@ -1,18 +0,0 @@
1
- eth0 Link encap:Ethernet HWaddr 00:16:3e:7c:dd:44
2
- inet addr:10.0.3.109 Bcast:10.0.3.255 Mask:255.255.255.0
3
- inet6 addr: fe80::216:3eff:fe7c:dd44/64 Scope:Link
4
- UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
5
- RX packets:204 errors:0 dropped:0 overruns:0 frame:0
6
- TX packets:203 errors:0 dropped:0 overruns:0 carrier:0
7
- collisions:0 txqueuelen:1000
8
- RX bytes:29663 (29.6 KB) TX bytes:30168 (30.1 KB)
9
-
10
- lo Link encap:Local Loopback
11
- inet addr:127.0.0.1 Mask:255.0.0.0
12
- inet6 addr: ::1/128 Scope:Host
13
- UP LOOPBACK RUNNING MTU:16436 Metric:1
14
- RX packets:73 errors:0 dropped:0 overruns:0 frame:0
15
- TX packets:73 errors:0 dropped:0 overruns:0 carrier:0
16
- collisions:0 txqueuelen:0
17
- RX bytes:34173 (34.1 KB) TX bytes:34173 (34.1 KB)
18
-
@@ -1,147 +0,0 @@
1
- require 'unit_helper'
2
-
3
- require 'vagrant'
4
- require 'vagrant-lxc/container'
5
-
6
- describe Vagrant::LXC::Container do
7
- let(:name) { nil }
8
- subject { described_class.new(name) }
9
-
10
- describe 'container name validation' do
11
- let(:unknown_container) { described_class.new('unknown', cli) }
12
- let(:valid_container) { described_class.new('valid', cli) }
13
- let(:new_container) { described_class.new(nil) }
14
- let(:cli) { fire_double('Vagrant::LXC::Container::CLI', list: ['valid']) }
15
-
16
- it 'raises a NotFound error if an unknown container name gets provided' do
17
- expect {
18
- unknown_container.validate!
19
- }.to raise_error(Vagrant::LXC::Container::NotFound)
20
- end
21
-
22
- it 'does not raise a NotFound error if a valid container name gets provided' do
23
- expect {
24
- valid_container.validate!
25
- }.to_not raise_error(Vagrant::LXC::Container::NotFound)
26
- end
27
-
28
- it 'does not raise a NotFound error if nil is provider as name' do
29
- expect {
30
- new_container.validate!
31
- }.to_not raise_error(Vagrant::LXC::Container::NotFound)
32
- end
33
- end
34
-
35
- describe 'creation' do
36
- let(:base_name) { 'container-name' }
37
- let(:suffix) { 'random-suffix' }
38
- let(:template_name) { 'template-name' }
39
- let(:rootfs_cache) { '/path/to/cache' }
40
- let(:target_rootfs) { '/path/to/rootfs' }
41
- let(:public_key_path) { Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s }
42
- let(:cli) { fire_double('Vagrant::LXC::Container::CLI', :create => true, :name= => true) }
43
-
44
- subject { described_class.new(name, cli) }
45
-
46
- before do
47
- SecureRandom.stub(hex: suffix)
48
- subject.create base_name, target_rootfs, 'template-name' => template_name, 'rootfs-cache-path' => rootfs_cache, 'template-opts' => { '--foo' => 'bar'}
49
- end
50
-
51
- it 'creates container with the right arguments' do
52
- cli.should have_received(:name=).with("#{base_name}-#{suffix}")
53
- cli.should have_received(:create).with(
54
- template_name,
55
- target_rootfs,
56
- '--auth-key' => public_key_path,
57
- '--cache' => rootfs_cache,
58
- '--foo' => 'bar'
59
- )
60
- end
61
- end
62
-
63
- describe 'destruction' do
64
- let(:name) { 'container-name' }
65
- let(:cli) { fire_double('Vagrant::LXC::Container::CLI', destroy: true) }
66
-
67
- subject { described_class.new(name, cli) }
68
-
69
- before { subject.destroy }
70
-
71
- it 'delegates to cli object' do
72
- cli.should have_received(:destroy)
73
- end
74
- end
75
-
76
- describe 'start' do
77
- let(:config) { mock(:config, start_opts: ['a=1', 'b=2']) }
78
- let(:name) { 'container-name' }
79
- let(:cli) { fire_double('Vagrant::LXC::Container::CLI', start: true) }
80
-
81
- subject { described_class.new(name, cli) }
82
-
83
- before do
84
- cli.stub(:transition_to).and_yield(cli)
85
- end
86
-
87
- it 'starts container with configured lxc settings' do
88
- cli.should_receive(:start).with(['a=1', 'b=2'], nil)
89
- subject.start(config)
90
- end
91
-
92
- it 'expects a transition to running state to take place' do
93
- cli.should_receive(:transition_to).with(:running)
94
- subject.start(config)
95
- end
96
- end
97
-
98
- describe 'halt' do
99
- let(:name) { 'container-name' }
100
- let(:cli) { fire_double('Vagrant::LXC::Container::CLI', shutdown: true) }
101
-
102
- subject { described_class.new(name, cli) }
103
-
104
- before do
105
- cli.stub(:transition_to).and_yield(cli)
106
- end
107
-
108
- it 'delegates to cli shutdown' do
109
- cli.should_receive(:shutdown)
110
- subject.halt
111
- end
112
-
113
- it 'expects a transition to running state to take place' do
114
- cli.should_receive(:transition_to).with(:stopped)
115
- subject.halt
116
- end
117
- end
118
-
119
- describe 'state' do
120
- let(:name) { 'random-container-name' }
121
- let(:cli_state) { :something }
122
- let(:cli) { fire_double('Vagrant::LXC::Container::CLI', state: cli_state) }
123
-
124
- subject { described_class.new(name, cli) }
125
-
126
- it 'delegates to cli' do
127
- subject.state.should == cli_state
128
- end
129
- end
130
-
131
- describe 'assigned ip' do
132
- # This ip is set on the sample-ifconfig-output fixture
133
- let(:ip) { "10.0.3.109" }
134
- let(:ifconfig_output) { File.read('spec/fixtures/sample-ifconfig-output') }
135
- let(:name) { 'random-container-name' }
136
- let(:cli) { fire_double('Vagrant::LXC::Container::CLI', :attach => ifconfig_output) }
137
-
138
- subject { described_class.new(name, cli) }
139
-
140
- context 'when ip for eth0 gets returned from lxc-attach call' do
141
- it 'gets parsed from ifconfig output' do
142
- subject.assigned_ip.should == ip
143
- cli.should have_received(:attach).with('/sbin/ifconfig', '-v', 'eth0', namespaces: 'network')
144
- end
145
- end
146
- end
147
- end
@@ -1,39 +0,0 @@
1
- require 'unit_helper'
2
-
3
- require 'vagrant-lxc/machine_state'
4
-
5
- describe Vagrant::LXC::MachineState do
6
- describe 'short description' do
7
- subject { described_class.new(:not_created) }
8
-
9
- it 'is a humanized version of state id' do
10
- subject.short_description.should == 'not created'
11
- end
12
- end
13
-
14
- describe 'long description' do
15
- subject { described_class.new(:short_name) }
16
- before { I18n.stub(t: 'some really long description') }
17
-
18
- it 'is a localized version of the state id' do
19
- subject.long_description.should == 'some really long description'
20
- I18n.should have_received(:t).with('vagrant.commands.status.short_name')
21
- end
22
- end
23
-
24
- context 'when state id is :running' do
25
- subject { described_class.new(:running) }
26
-
27
- it { should be_created }
28
- it { should be_running }
29
- it { should_not be_off }
30
- end
31
-
32
- context 'when state id is :stopped' do
33
- subject { described_class.new(:stopped) }
34
-
35
- it { should be_created }
36
- it { should be_off }
37
- it { should_not be_running }
38
- end
39
- end