vagrant-lxc 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 )