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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.vimrc +1 -1
- data/CHANGELOG.md +22 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +10 -9
- data/README.md +43 -29
- data/boxes/quantal64/download-ubuntu +21 -20
- data/boxes/quantal64/lxc-template +11 -11
- data/boxes/quantal64/metadata.json +1 -1
- data/development/Vagrantfile +8 -4
- data/example/Vagrantfile +3 -15
- data/lib/vagrant-lxc.rb +0 -2
- data/lib/vagrant-lxc/action.rb +1 -14
- data/lib/vagrant-lxc/action/boot.rb +8 -9
- data/lib/vagrant-lxc/action/check_created.rb +6 -2
- data/lib/vagrant-lxc/action/check_running.rb +6 -2
- data/lib/vagrant-lxc/action/compress_rootfs.rb +1 -1
- data/lib/vagrant-lxc/action/create.rb +15 -7
- data/lib/vagrant-lxc/action/created.rb +6 -2
- data/lib/vagrant-lxc/action/destroy.rb +6 -2
- data/lib/vagrant-lxc/action/disconnect.rb +5 -1
- data/lib/vagrant-lxc/action/forced_halt.rb +3 -3
- data/lib/vagrant-lxc/action/forward_ports.rb +2 -2
- data/lib/vagrant-lxc/action/handle_box_metadata.rb +38 -27
- data/lib/vagrant-lxc/action/is_running.rb +6 -2
- data/lib/vagrant-lxc/action/share_folders.rb +8 -8
- data/lib/vagrant-lxc/config.rb +20 -10
- data/lib/vagrant-lxc/driver.rb +162 -0
- data/lib/vagrant-lxc/driver/builder.rb +21 -0
- data/lib/vagrant-lxc/{container → driver}/cli.rb +16 -11
- data/lib/vagrant-lxc/driver/fetch_ip_from_dnsmasq.rb +41 -0
- data/lib/vagrant-lxc/driver/fetch_ip_with_attach.rb +29 -0
- data/lib/vagrant-lxc/errors.rb +10 -0
- data/lib/vagrant-lxc/plugin.rb +4 -0
- data/lib/vagrant-lxc/provider.rb +14 -11
- data/lib/vagrant-lxc/version.rb +1 -1
- data/spec/fixtures/sample-ip-addr-output +2 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/action/compress_rootfs_spec.rb +4 -4
- data/spec/unit/action/forward_ports_spec.rb +3 -3
- data/spec/unit/action/handle_box_metadata_spec.rb +52 -26
- data/spec/unit/{container → driver}/cli_spec.rb +17 -19
- data/spec/unit/driver_spec.rb +173 -0
- data/tasks/boxes.rake +3 -3
- metadata +13 -15
- data/lib/vagrant-lxc/action/base_action.rb +0 -11
- data/lib/vagrant-lxc/action/network.rb +0 -21
- data/lib/vagrant-lxc/container.rb +0 -141
- data/lib/vagrant-lxc/machine_state.rb +0 -25
- data/spec/fixtures/sample-ifconfig-output +0 -18
- data/spec/unit/container_spec.rb +0 -147
- data/spec/unit/machine_state_spec.rb +0 -39
@@ -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
|
-
|
data/spec/unit/container_spec.rb
DELETED
@@ -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
|