vagrant-lxc 0.4.0 → 0.5.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.
@@ -0,0 +1,79 @@
1
+ module Vagrant
2
+ module LXC
3
+ class SudoWrapper
4
+ # Include this so we can use `Subprocess` more easily.
5
+ include Vagrant::Util::Retryable
6
+
7
+ def initialize(wrapper_path = nil)
8
+ @wrapper_path = wrapper_path
9
+ @logger = Log4r::Logger.new("vagrant::lxc::shell")
10
+ end
11
+
12
+ def run(*command)
13
+ command.unshift @wrapper_path if @wrapper_path
14
+ execute *(['sudo'] + command)
15
+ end
16
+
17
+ def su_c(command)
18
+ su_command = if @wrapper_path
19
+ "#{@wrapper_path} \"#{command}\""
20
+ else
21
+ "su root -c \"#{command}\""
22
+ end
23
+ @logger.debug "Running 'sudo #{su_command}'"
24
+ system "sudo #{su_command}"
25
+ end
26
+
27
+ private
28
+
29
+ # TODO: Review code below this line, it was pretty much a copy and
30
+ # paste from VirtualBox base driver and has no tests
31
+ def execute(*command, &block)
32
+ # Get the options hash if it exists
33
+ opts = {}
34
+ opts = command.pop if command.last.is_a?(Hash)
35
+
36
+ tries = 0
37
+ tries = 3 if opts[:retryable]
38
+
39
+ sleep = opts.fetch(:sleep, 1)
40
+
41
+ # Variable to store our execution result
42
+ r = nil
43
+
44
+ retryable(:on => LXC::Errors::ExecuteError, :tries => tries, :sleep => sleep) do
45
+ # Execute the command
46
+ r = raw(*command, &block)
47
+
48
+ # If the command was a failure, then raise an exception that is
49
+ # nicely handled by Vagrant.
50
+ if r.exit_code != 0
51
+ if @interrupted
52
+ @logger.info("Exit code != 0, but interrupted. Ignoring.")
53
+ else
54
+ raise LXC::Errors::ExecuteError, :command => command.inspect
55
+ end
56
+ end
57
+ end
58
+
59
+ # Return the output, making sure to replace any Windows-style
60
+ # newlines with Unix-style.
61
+ r.stdout.gsub("\r\n", "\n")
62
+ end
63
+
64
+ def raw(*command, &block)
65
+ int_callback = lambda do
66
+ @interrupted = true
67
+ @logger.info("Interrupted.")
68
+ end
69
+
70
+ # Append in the options for subprocess
71
+ command << { :notify => [:stdout, :stderr] }
72
+
73
+ Vagrant::Util::Busy.busy(int_callback) do
74
+ Vagrant::Util::Subprocess.execute(*command, &block)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,5 +1,5 @@
1
1
  module Vagrant
2
2
  module LXC
3
- VERSION = "0.4.0"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
data/locales/en.yml CHANGED
@@ -44,3 +44,9 @@ en:
44
44
  lxc_template_file_missing: |-
45
45
  The template file used for creating the container was not found for %{name}
46
46
  box.
47
+
48
+ lxc_not_installed: |-
49
+ The `lxc` package does not seem to be installed or is not accessible on the PATH.
50
+
51
+ lxc_redir_not_installed: |-
52
+ `redir` is not installed or is not accessible on the PATH.
@@ -29,7 +29,7 @@ describe Vagrant::LXC::Action::ClearForwardedPorts do
29
29
 
30
30
  context 'with a valid redir pid' do
31
31
  it 'kills known processes' do
32
- subject.should have_received(:system).with("sudo pkill -TERM -P #{pid}")
32
+ subject.should have_received(:system).with("pkill -TERM -P #{pid}")
33
33
  end
34
34
  end
35
35
 
@@ -37,7 +37,7 @@ describe Vagrant::LXC::Action::ClearForwardedPorts do
37
37
  let(:pid_cmd) { 'sudo ls' }
38
38
 
39
39
  it 'does not kill the process' do
40
- subject.should_not have_received(:system).with("sudo pkill -TERM -P #{pid}")
40
+ subject.should_not have_received(:system).with("pkill -TERM -P #{pid}")
41
41
  end
42
42
  end
43
43
  end
@@ -1,5 +1,7 @@
1
1
  require 'unit_helper'
2
2
 
3
+ require 'tmpdir'
4
+ require 'vagrant-lxc/errors'
3
5
  require 'vagrant-lxc/action/forward_ports'
4
6
 
5
7
  describe Vagrant::LXC::Action::ForwardPorts do
@@ -7,13 +9,14 @@ describe Vagrant::LXC::Action::ForwardPorts do
7
9
  let(:env) { {machine: machine, ui: double(info: true)} }
8
10
  let(:machine) { double(:machine) }
9
11
  let!(:data_dir) { Pathname.new(Dir.mktmpdir) }
10
- let(:networks) { [[:other_config, {}], [:forwarded_port, {guest: guest_port, host: host_port}]] }
12
+ let(:provider) { instance_double('Vagrant::LXC::Provider', ssh_info: {host: container_ip}) }
13
+ let(:host_ip) { '127.0.0.1' }
11
14
  let(:host_port) { 8080 }
12
15
  let(:guest_port) { 80 }
13
- let(:provider) { instance_double('Vagrant::LXC::Provider', driver: driver) }
14
- let(:driver) { instance_double('Vagrant::LXC::Driver', assigned_ip: container_ip) }
15
16
  let(:container_ip) { '10.0.1.234' }
16
17
  let(:pid) { 'a-pid' }
18
+ let(:forward_conf) { {guest: guest_port, host: host_port, host_ip: host_ip} }
19
+ let(:networks) { [[:other_config, {}], [:forwarded_port, forward_conf]] }
17
20
 
18
21
  subject { described_class.new(app, env) }
19
22
 
@@ -23,19 +26,36 @@ describe Vagrant::LXC::Action::ForwardPorts do
23
26
 
24
27
  subject.stub(exec: true)
25
28
  subject.stub(spawn: pid)
26
- subject.call(env)
27
29
  end
28
30
 
29
31
  after { FileUtils.rm_rf data_dir.to_s }
30
32
 
31
33
  it 'forwards ports using redir' do
34
+ subject.stub(system: true)
35
+ subject.call(env)
36
+ subject.should have_received(:spawn).with(
37
+ "redir --laddr=#{host_ip} --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
38
+ )
39
+ end
40
+
41
+ it 'skips --laddr parameter if host_ip is nil' do
42
+ forward_conf.delete(:host_ip)
43
+ subject.stub(system: true)
44
+ subject.call(env)
32
45
  subject.should have_received(:spawn).with(
33
- "sudo redir --laddr=127.0.0.1 --lport=#{host_port} --cport=#{guest_port} --caddr=#{container_ip} 2>/dev/null"
46
+ "redir --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
34
47
  )
35
48
  end
36
49
 
37
50
  it "stores redir pids on machine's data dir" do
51
+ subject.stub(system: true)
52
+ subject.call(env)
38
53
  pid_file = data_dir.join('pids', "redir_#{host_port}.pid").read
39
54
  pid_file.should == pid
40
55
  end
56
+
57
+ it 'raises RedirNotInstalled error if `redir` is not installed' do
58
+ subject.stub(system: false)
59
+ lambda { subject.call(env) }.should raise_error(Vagrant::LXC::Errors::RedirNotInstalled)
60
+ end
41
61
  end
@@ -3,6 +3,10 @@ require 'unit_helper'
3
3
  require 'vagrant-lxc/driver/cli'
4
4
 
5
5
  describe Vagrant::LXC::Driver::CLI do
6
+ let(:sudo_wrapper) { instance_double('Vagrant::LXC::SudoWrapper', run: true) }
7
+
8
+ subject { described_class.new(sudo_wrapper) }
9
+
6
10
  describe 'list' do
7
11
  let(:lxc_ls_out) { "dup-container\na-container dup-container" }
8
12
  let(:result) { @result }
@@ -41,7 +45,7 @@ describe Vagrant::LXC::Driver::CLI do
41
45
  let(:config_file) { 'config' }
42
46
  let(:template_args) { { '--extra-param' => 'param', '--other' => 'value' } }
43
47
 
44
- subject { described_class.new(name) }
48
+ subject { described_class.new(sudo_wrapper, name) }
45
49
 
46
50
  before do
47
51
  subject.stub(:run) { |*args| @run_args = args }
@@ -64,7 +68,7 @@ describe Vagrant::LXC::Driver::CLI do
64
68
  describe 'destroy' do
65
69
  let(:name) { 'a-container-for-destruction' }
66
70
 
67
- subject { described_class.new(name) }
71
+ subject { described_class.new(sudo_wrapper, name) }
68
72
 
69
73
  before do
70
74
  subject.stub(:run)
@@ -78,7 +82,7 @@ describe Vagrant::LXC::Driver::CLI do
78
82
 
79
83
  describe 'start' do
80
84
  let(:name) { 'a-container' }
81
- subject { described_class.new(name) }
85
+ subject { described_class.new(sudo_wrapper, name) }
82
86
 
83
87
  before do
84
88
  subject.stub(:run)
@@ -92,19 +96,11 @@ describe Vagrant::LXC::Driver::CLI do
92
96
  '--name', name
93
97
  )
94
98
  end
95
-
96
- it 'uses provided array to override container configs' do
97
- subject.start([['config', 'value'], ['other', 'value']])
98
- subject.should have_received(:run).with(:start, '-d', '--name', name,
99
- '-s', 'lxc.config=value',
100
- '-s', 'lxc.other=value'
101
- )
102
- end
103
99
  end
104
100
 
105
101
  describe 'shutdown' do
106
102
  let(:name) { 'a-running-container' }
107
- subject { described_class.new(name) }
103
+ subject { described_class.new(sudo_wrapper, name) }
108
104
 
109
105
  before do
110
106
  subject.stub(:run)
@@ -118,7 +114,7 @@ describe Vagrant::LXC::Driver::CLI do
118
114
 
119
115
  describe 'state' do
120
116
  let(:name) { 'a-container' }
121
- subject { described_class.new(name) }
117
+ subject { described_class.new(sudo_wrapper, name) }
122
118
 
123
119
  before do
124
120
  subject.stub(:run).and_return("state: STOPPED\npid: 2")
@@ -138,7 +134,7 @@ describe Vagrant::LXC::Driver::CLI do
138
134
  let(:name) { 'a-running-container' }
139
135
  let(:command) { ['ls', 'cat /tmp/file'] }
140
136
  let(:command_output) { 'folders list' }
141
- subject { described_class.new(name) }
137
+ subject { described_class.new(sudo_wrapper, name) }
142
138
 
143
139
  before do
144
140
  subject.stub(run: command_output)
@@ -6,9 +6,9 @@ require 'vagrant-lxc/driver/cli'
6
6
 
7
7
  describe Vagrant::LXC::Driver do
8
8
  describe 'container name validation' do
9
- let(:unknown_container) { described_class.new('unknown', cli) }
10
- let(:valid_container) { described_class.new('valid', cli) }
11
- let(:new_container) { described_class.new(nil) }
9
+ let(:unknown_container) { described_class.new('unknown', nil, cli) }
10
+ let(:valid_container) { described_class.new('valid', nil, cli) }
11
+ let(:new_container) { described_class.new(nil, nil) }
12
12
  let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', list: ['valid']) }
13
13
 
14
14
  it 'raises a ContainerNotFound error if an unknown container name gets provided' do
@@ -39,7 +39,7 @@ describe Vagrant::LXC::Driver do
39
39
  let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' }
40
40
  let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', :create => true, :name= => true) }
41
41
 
42
- subject { described_class.new(nil, cli) }
42
+ subject { described_class.new(nil, nil, cli) }
43
43
 
44
44
  before do
45
45
  subject.stub(:import_template).and_yield(template_name)
@@ -62,7 +62,7 @@ describe Vagrant::LXC::Driver do
62
62
  describe 'destruction' do
63
63
  let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', destroy: true) }
64
64
 
65
- subject { described_class.new('name', cli) }
65
+ subject { described_class.new('name', nil, cli) }
66
66
 
67
67
  before { subject.destroy }
68
68
 
@@ -75,8 +75,9 @@ describe Vagrant::LXC::Driver do
75
75
  let(:customizations) { [['a', '1'], ['b', '2']] }
76
76
  let(:internal_customization) { ['internal', 'customization'] }
77
77
  let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', start: true) }
78
+ let(:sudo) { instance_double('Vagrant::LXC::SudoWrapper', su_c: true) }
78
79
 
79
- subject { described_class.new('name', cli) }
80
+ subject { described_class.new('name', sudo, cli) }
80
81
 
81
82
  before do
82
83
  cli.stub(:transition_to).and_yield(cli)
@@ -84,8 +85,12 @@ describe Vagrant::LXC::Driver do
84
85
  subject.start(customizations)
85
86
  end
86
87
 
88
+ it 'prunes previous customizations before writing'
89
+
90
+ it 'writes configurations to config file'
91
+
87
92
  it 'starts container with configured customizations' do
88
- cli.should have_received(:start).with(customizations + [internal_customization], nil)
93
+ cli.should have_received(:start)
89
94
  end
90
95
 
91
96
  it 'expects a transition to running state to take place' do
@@ -96,7 +101,7 @@ describe Vagrant::LXC::Driver do
96
101
  describe 'halt' do
97
102
  let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', shutdown: true) }
98
103
 
99
- subject { described_class.new('name', cli) }
104
+ subject { described_class.new('name', nil, cli) }
100
105
 
101
106
  before do
102
107
  cli.stub(:transition_to).and_yield(cli)
@@ -124,45 +129,21 @@ describe Vagrant::LXC::Driver do
124
129
  let(:cli_state) { :something }
125
130
  let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', state: cli_state) }
126
131
 
127
- subject { described_class.new('name', cli) }
132
+ subject { described_class.new('name', nil, cli) }
128
133
 
129
134
  it 'delegates to cli' do
130
135
  subject.state.should == cli_state
131
136
  end
132
137
  end
133
138
 
134
- pending 'assigned ip' do
135
- # This ip is set on the sample-ip-addr-output fixture
136
- let(:ip) { "10.0.254.137" }
137
- let(:ifconfig_output) { File.read('spec/fixtures/sample-ip-addr-output') }
138
- let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', :attach => ifconfig_output) }
139
-
140
- subject { described_class.new('name', cli) }
141
-
142
- context 'when ip for eth0 gets returned from lxc-attach call' do
143
- it 'gets parsed from `ip addr` output' do
144
- subject.assigned_ip.should == ip
145
- cli.should have_received(:attach).with(
146
- '/sbin/ip',
147
- '-4',
148
- 'addr',
149
- 'show',
150
- 'scope',
151
- 'global',
152
- 'eth0',
153
- namespaces: 'network'
154
- )
155
- end
156
- end
157
- end
158
-
159
139
  describe 'folder sharing' do
160
140
  let(:shared_folder) { {guestpath: '/vagrant', hostpath: '/path/to/host/dir'} }
161
141
  let(:folders) { [shared_folder] }
162
142
  let(:rootfs_path) { Pathname('/path/to/rootfs') }
163
143
  let(:expected_guest_path) { "#{rootfs_path}/vagrant" }
144
+ let(:sudo_wrapper) { instance_double('Vagrant::LXC::SudoWrapper', run: true) }
164
145
 
165
- subject { described_class.new('name') }
146
+ subject { described_class.new('name', sudo_wrapper) }
166
147
 
167
148
  before do
168
149
  subject.stub(rootfs_path: rootfs_path, system: true)
@@ -170,7 +151,7 @@ describe Vagrant::LXC::Driver do
170
151
  end
171
152
 
172
153
  it "creates guest folder under container's rootfs" do
173
- subject.should have_received(:system).with("sudo mkdir -p #{expected_guest_path}")
154
+ sudo_wrapper.should have_received(:run).with("mkdir", "-p", expected_guest_path)
174
155
  end
175
156
 
176
157
  it 'adds a mount.entry to its local customizations' do
data/tasks/boxes.rake CHANGED
@@ -57,6 +57,7 @@ end
57
57
 
58
58
  puppet = ENV['PUPPET'] == '1'
59
59
  babushka = ENV['BABUSHKA'] == '1'
60
+ salt = ENV['SALT'] == '1'
60
61
 
61
62
  namespace :boxes do
62
63
  namespace :ubuntu do
@@ -65,20 +66,25 @@ namespace :boxes do
65
66
  desc 'Build an Ubuntu Precise 64 bits box'
66
67
  BuildUbuntuBoxTaskV3.
67
68
  new(:precise64,
68
- :precise, 'amd64', puppet: puppet, babushka: babushka)
69
+ :precise, 'amd64', puppet: puppet, babushka: babushka, salt: salt)
69
70
 
70
71
  desc 'Build an Ubuntu Quantal 64 bits box'
71
72
  BuildUbuntuBoxTaskV3.
72
73
  new(:quantal64,
73
- :quantal, 'amd64', puppet: puppet, babushka: babushka)
74
+ :quantal, 'amd64', puppet: puppet, babushka: babushka, salt: salt)
74
75
 
75
76
  desc 'Build an Ubuntu Raring 64 bits box'
76
77
  BuildUbuntuBoxTaskV3.
77
78
  new(:raring64,
78
- :raring, 'amd64', puppet: puppet, babushka: babushka)
79
+ :raring, 'amd64', puppet: puppet, babushka: babushka, salt: salt)
80
+
81
+ desc 'Build an Ubuntu Saucy 64 bits box'
82
+ BuildUbuntuBoxTaskV3.
83
+ new(:saucy64,
84
+ :saucy, 'amd64', puppet: puppet, babushka: babushka, salt: salt)
79
85
 
80
86
  desc 'Build all Ubuntu boxes'
81
- task :all => %w( precise64 quantal64 raring64 )
87
+ task :all => %w( precise64 quantal64 raring64 saucy64 )
82
88
  end
83
89
  end
84
90
 
@@ -87,17 +93,17 @@ namespace :boxes do
87
93
  desc 'Build an Debian Squeeze 64 bits box'
88
94
  BuildDebianBoxTaskV3.
89
95
  new(:squeeze64,
90
- :squeeze, 'amd64', puppet: puppet, babushka: babushka)
96
+ :squeeze, 'amd64', puppet: puppet, babushka: babushka, salt: false)
91
97
 
92
98
  desc 'Build an Debian Wheezy 64 bits box'
93
99
  BuildDebianBoxTaskV3.
94
100
  new(:wheezy64,
95
- :wheezy, 'amd64', puppet: puppet, babushka: babushka)
101
+ :wheezy, 'amd64', puppet: puppet, babushka: babushka, salt: false)
96
102
 
97
103
  desc 'Build an Debian Sid/unstable 64 bits box'
98
104
  BuildDebianBoxTaskV3.
99
105
  new(:sid64,
100
- :sid, 'amd64', puppet: puppet, babushka: babushka)
106
+ :sid, 'amd64', puppet: puppet, babushka: babushka, salt: false)
101
107
 
102
108
  desc 'Build all Debian boxes'
103
109
  task :all => %w( squeeze64 wheezy64 sid64 )
data/tasks/boxes.v2.rake CHANGED
@@ -14,6 +14,7 @@ class BuildGenericBoxTaskV2 < ::Rake::TaskLib
14
14
  @install_chef = opts.fetch(:chef, false)
15
15
  @install_puppet = opts.fetch(:puppet, true)
16
16
  @install_babushka = opts.fetch(:babushka, true)
17
+ @install_salt = opts.fetch(:salt, true)
17
18
  @file = opts[:file] || default_box_file
18
19
  @scripts_path = Pathname(Dir.pwd).join('boxes')
19
20
 
@@ -86,7 +87,7 @@ class BuildGenericBoxTaskV2 < ::Rake::TaskLib
86
87
  end
87
88
 
88
89
  def install_cfg_engines
89
- [ :puppet, :chef, :babushka ].each do |cfg_engine|
90
+ [ :puppet, :chef, :babushka, :salt ].each do |cfg_engine|
90
91
  next unless instance_variable_get :"@install_#{cfg_engine}"
91
92
  script_name = "install-#{cfg_engine}"
92
93
  run script_name
@@ -125,6 +126,7 @@ end
125
126
  chef = ENV['CHEF'] == '1'
126
127
  puppet = ENV['PUPPET'] == '1'
127
128
  babushka = ENV['BABUSHKA'] == '1'
129
+ salt = ENV['SALT'] == '1'
128
130
 
129
131
  namespace :boxes do
130
132
  namespace :v2 do
@@ -134,21 +136,26 @@ namespace :boxes do
134
136
  desc 'Build an Ubuntu Precise 64 bits box'
135
137
  BuildUbuntuBoxTaskV2.
136
138
  new(:precise64,
137
- :precise, 'amd64', chef: chef, puppet: puppet, babushka: babushka)
139
+ :precise, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt)
138
140
 
139
141
  desc 'Build an Ubuntu Quantal 64 bits box'
140
142
  BuildUbuntuBoxTaskV2.
141
143
  new(:quantal64,
142
- :quantal, 'amd64', chef: chef, puppet: puppet, babushka: babushka)
144
+ :quantal, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt)
143
145
 
144
146
  # FIXME: Find out how to install chef on raring
145
147
  desc 'Build an Ubuntu Raring 64 bits box'
146
148
  BuildUbuntuBoxTaskV2.
147
149
  new(:raring64,
148
- :raring, 'amd64', chef: chef, puppet: puppet, babushka: babushka)
150
+ :raring, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt)
151
+
152
+ desc 'Build an Ubuntu Saucy 64 bits box'
153
+ BuildUbuntuBoxTaskV2.
154
+ new(:saucy64,
155
+ :saucy, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt)
149
156
 
150
157
  desc 'Build all Ubuntu boxes'
151
- task :all => %w( precise64 quantal64 raring64 )
158
+ task :all => %w( precise64 quantal64 raring64 saucy64 )
152
159
  end
153
160
  end
154
161
 
@@ -158,17 +165,17 @@ namespace :boxes do
158
165
  desc 'Build an Debian Squeeze 64 bits box'
159
166
  BuildDebianBoxTaskV2.
160
167
  new(:squeeze64,
161
- :squeeze, 'amd64', chef: false, puppet: puppet, babushka: babushka)
168
+ :squeeze, 'amd64', chef: false, puppet: puppet, babushka: babushka, salt: false)
162
169
 
163
170
  desc 'Build an Debian Wheezy 64 bits box'
164
171
  BuildDebianBoxTaskV2.
165
172
  new(:wheezy64,
166
- :wheezy, 'amd64', chef: false, puppet: puppet, babushka: babushka)
173
+ :wheezy, 'amd64', chef: false, puppet: puppet, babushka: babushka, salt: false)
167
174
 
168
175
  desc 'Build an Debian Sid/unstable 64 bits box'
169
176
  BuildDebianBoxTaskV2.
170
177
  new(:sid64,
171
- :sid, 'amd64', chef: false, puppet: puppet, babushka: babushka)
178
+ :sid, 'amd64', chef: false, puppet: puppet, babushka: babushka, salt: false)
172
179
 
173
180
  desc 'Build all Debian boxes'
174
181
  task :all => %w( squeeze64 wheezy64 sid64 )