vagrant-lxc-2.1-patch 1.4.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 +7 -0
- data/.gitignore +31 -0
- data/.rspec +2 -0
- data/.travis.yml +10 -0
- data/.vimrc +1 -0
- data/BOXES.md +47 -0
- data/CHANGELOG.md +510 -0
- data/CONTRIBUTING.md +24 -0
- data/Gemfile +24 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +187 -0
- data/Rakefile +3 -0
- data/lib/vagrant-lxc.rb +10 -0
- data/lib/vagrant-lxc/action.rb +234 -0
- data/lib/vagrant-lxc/action/boot.rb +42 -0
- data/lib/vagrant-lxc/action/clear_forwarded_ports.rb +56 -0
- data/lib/vagrant-lxc/action/compress_rootfs.rb +30 -0
- data/lib/vagrant-lxc/action/create.rb +57 -0
- data/lib/vagrant-lxc/action/destroy.rb +18 -0
- data/lib/vagrant-lxc/action/destroy_confirm.rb +17 -0
- data/lib/vagrant-lxc/action/fetch_ip_with_lxc_info.rb +43 -0
- data/lib/vagrant-lxc/action/forced_halt.rb +20 -0
- data/lib/vagrant-lxc/action/forward_ports.rb +121 -0
- data/lib/vagrant-lxc/action/gc_private_network_bridges.rb +47 -0
- data/lib/vagrant-lxc/action/handle_box_metadata.rb +94 -0
- data/lib/vagrant-lxc/action/prepare_nfs_settings.rb +64 -0
- data/lib/vagrant-lxc/action/prepare_nfs_valid_ids.rb +19 -0
- data/lib/vagrant-lxc/action/private_networks.rb +46 -0
- data/lib/vagrant-lxc/action/setup_package_files.rb +60 -0
- data/lib/vagrant-lxc/action/warn_networks.rb +25 -0
- data/lib/vagrant-lxc/command/root.rb +58 -0
- data/lib/vagrant-lxc/command/sudoers.rb +97 -0
- data/lib/vagrant-lxc/config.rb +73 -0
- data/lib/vagrant-lxc/driver.rb +288 -0
- data/lib/vagrant-lxc/driver/cli.rb +166 -0
- data/lib/vagrant-lxc/errors.rb +62 -0
- data/lib/vagrant-lxc/plugin.rb +51 -0
- data/lib/vagrant-lxc/provider.rb +101 -0
- data/lib/vagrant-lxc/provider/cap/public_address.rb +17 -0
- data/lib/vagrant-lxc/sudo_wrapper.rb +104 -0
- data/lib/vagrant-lxc/synced_folder.rb +72 -0
- data/lib/vagrant-lxc/version.rb +5 -0
- data/locales/en.yml +82 -0
- data/scripts/lxc-template +171 -0
- data/scripts/pipework +422 -0
- data/spec/Vagrantfile +26 -0
- data/spec/fixtures/sample-ip-addr-output +2 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/support/.gitkeep +0 -0
- data/spec/unit/action/clear_forwarded_ports_spec.rb +43 -0
- data/spec/unit/action/compress_rootfs_spec.rb +29 -0
- data/spec/unit/action/forward_ports_spec.rb +117 -0
- data/spec/unit/action/handle_box_metadata_spec.rb +126 -0
- data/spec/unit/action/setup_package_files_spec.rb +83 -0
- data/spec/unit/driver/cli_spec.rb +263 -0
- data/spec/unit/driver_spec.rb +268 -0
- data/spec/unit/support/unit_example_group.rb +38 -0
- data/spec/unit_helper.rb +17 -0
- data/tasks/spec.rake +40 -0
- data/templates/sudoers.rb.erb +129 -0
- data/vagrant-lxc.gemspec +20 -0
- data/vagrant-spec.config.rb +24 -0
- metadata +119 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module LXC
|
3
|
+
module Action
|
4
|
+
class Boot
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
@env = env
|
11
|
+
|
12
|
+
config = env[:machine].provider_config
|
13
|
+
|
14
|
+
utsname = env[:machine].config.vm.hostname || env[:machine].id
|
15
|
+
config.customize 'uts.name', utsname
|
16
|
+
|
17
|
+
# Fix apparmor issues when starting Ubuntu 14.04 containers
|
18
|
+
# See https://github.com/fgrehm/vagrant-lxc/issues/278 for more information
|
19
|
+
if Dir.exists?('/sys/fs/pstore')
|
20
|
+
config.customize 'mount.entry', '/sys/fs/pstore sys/fs/pstore none bind,optional 0 0'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Make selinux read-only, see
|
24
|
+
# https://github.com/fgrehm/vagrant-lxc/issues/301
|
25
|
+
if Dir.exists?('/sys/fs/selinux')
|
26
|
+
config.customize 'mount.entry', '/sys/fs/selinux sys/fs/selinux none bind,ro 0 0'
|
27
|
+
end
|
28
|
+
|
29
|
+
if config.tmpfs_mount_size && !config.tmpfs_mount_size.empty?
|
30
|
+
# Make /tmp a tmpfs to prevent init scripts from nuking synced folders mounted in here
|
31
|
+
config.customize 'mount.entry', "tmpfs tmp tmpfs nodev,nosuid,size=#{config.tmpfs_mount_size} 0 0"
|
32
|
+
end
|
33
|
+
|
34
|
+
env[:ui].info I18n.t("vagrant_lxc.messages.starting")
|
35
|
+
env[:machine].provider.driver.start(config.customizations)
|
36
|
+
|
37
|
+
@app.call env
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module LXC
|
3
|
+
module Action
|
4
|
+
class ClearForwardedPorts
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
@logger = Log4r::Logger.new("vagrant::lxc::action::clear_forwarded_ports")
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
@env = env
|
12
|
+
|
13
|
+
if redir_pids.any?
|
14
|
+
env[:ui].info I18n.t("vagrant.actions.vm.clear_forward_ports.deleting")
|
15
|
+
redir_pids.each do |pid|
|
16
|
+
next unless is_redir_pid?(pid[0])
|
17
|
+
@logger.debug "Killing pid #{pid[0]}"
|
18
|
+
if pid[1]
|
19
|
+
system "sudo pkill -TERM -P #{pid[0]}"
|
20
|
+
else
|
21
|
+
system "pkill -TERM -P #{pid[0]}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@logger.info "Removing redir pids files"
|
26
|
+
remove_redir_pids
|
27
|
+
else
|
28
|
+
@logger.info "No redir pids found"
|
29
|
+
end
|
30
|
+
|
31
|
+
@app.call env
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def redir_pids
|
37
|
+
@redir_pids = Dir[@env[:machine].data_dir.join('pids').to_s + "/redir_*.pid"].map do |file|
|
38
|
+
port_number = File.basename(file).split(/[^\d]/).join
|
39
|
+
[ File.read(file).strip.chomp , Integer(port_number) <= 1024 ]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_redir_pid?(pid)
|
44
|
+
@logger.debug "Checking if #{pid} is a redir process with `ps -o cmd= #{pid}`"
|
45
|
+
`ps -o cmd= #{pid}`.strip.chomp =~ /redir/
|
46
|
+
end
|
47
|
+
|
48
|
+
def remove_redir_pids
|
49
|
+
Dir[@env[:machine].data_dir.join('pids').to_s + "/redir_*.pid"].each do |file|
|
50
|
+
File.delete file
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
module LXC
|
5
|
+
module Action
|
6
|
+
class CompressRootFS
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
raise Vagrant::Errors::VMPowerOffToPackage if env[:machine].provider.state.id != :stopped
|
13
|
+
|
14
|
+
env[:ui].info I18n.t("vagrant.actions.lxc.compressing_rootfs")
|
15
|
+
@rootfs = env['package.rootfs'] = env[:machine].provider.driver.compress_rootfs
|
16
|
+
|
17
|
+
@app.call env
|
18
|
+
|
19
|
+
recover # called to remove the rootfs tarball
|
20
|
+
end
|
21
|
+
|
22
|
+
def recover(*)
|
23
|
+
if @rootfs && File.exist?(@rootfs)
|
24
|
+
FileUtils.rm_rf(File.dirname @rootfs)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module LXC
|
3
|
+
module Action
|
4
|
+
class Create
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
config = env[:machine].provider_config
|
11
|
+
container_name = config.container_name
|
12
|
+
|
13
|
+
case container_name
|
14
|
+
when :machine
|
15
|
+
container_name = env[:machine].name.to_s
|
16
|
+
when String
|
17
|
+
# Nothing to do here, move along...
|
18
|
+
else
|
19
|
+
container_name = generate_container_name(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
backingstore = config.backingstore
|
23
|
+
if backingstore.nil?
|
24
|
+
backingstore = config.privileged ? "best" : "dir"
|
25
|
+
end
|
26
|
+
driver = env[:machine].provider.driver
|
27
|
+
driver.create(
|
28
|
+
container_name,
|
29
|
+
backingstore,
|
30
|
+
config.backingstore_options,
|
31
|
+
env[:lxc_template_src],
|
32
|
+
env[:lxc_template_config],
|
33
|
+
env[:lxc_template_opts]
|
34
|
+
)
|
35
|
+
driver.update_config_keys
|
36
|
+
|
37
|
+
env[:machine].id = container_name
|
38
|
+
|
39
|
+
@app.call env
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_container_name(env)
|
43
|
+
container_name = "#{env[:root_path].basename}_#{env[:machine].name}"
|
44
|
+
container_name.gsub!(/[^-a-z0-9_]/i, "")
|
45
|
+
|
46
|
+
# milliseconds + random number suffix to allow for simultaneous
|
47
|
+
# `vagrant up` of the same box in different dirs
|
48
|
+
container_name << "_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
|
49
|
+
|
50
|
+
# Trim container name to 64 chars, keeping "randomness"
|
51
|
+
trim_point = container_name.size > 64 ? -64 : -(container_name.size)
|
52
|
+
container_name[trim_point..-1]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module LXC
|
3
|
+
module Action
|
4
|
+
class Destroy
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info I18n.t("vagrant.actions.vm.destroy.destroying")
|
11
|
+
env[:machine].provider.driver.destroy
|
12
|
+
env[:machine].id = nil
|
13
|
+
@app.call env
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "vagrant/action/builtin/confirm"
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
module LXC
|
5
|
+
module Action
|
6
|
+
class DestroyConfirm < Vagrant::Action::Builtin::Confirm
|
7
|
+
def initialize(app, env)
|
8
|
+
force_key = :force_confirm_destroy
|
9
|
+
message = I18n.t("vagrant.commands.destroy.confirmation",
|
10
|
+
:name => env[:machine].name)
|
11
|
+
|
12
|
+
super(app, env, message, force_key)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module LXC
|
3
|
+
module Action
|
4
|
+
class FetchIpWithLxcInfo
|
5
|
+
# Include this so we can use `Subprocess` more easily.
|
6
|
+
include Vagrant::Util::Retryable
|
7
|
+
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_info")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
env[:machine_ip] ||= assigned_ip(env)
|
15
|
+
ensure
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def assigned_ip(env)
|
20
|
+
config = env[:machine].provider_config
|
21
|
+
fetch_ip_tries = config.fetch_ip_tries
|
22
|
+
driver = env[:machine].provider.driver
|
23
|
+
ip = ''
|
24
|
+
retryable(:on => LXC::Errors::ExecuteError, :tries => fetch_ip_tries, :sleep => 3) do
|
25
|
+
unless ip = get_container_ip_from_ip_addr(driver)
|
26
|
+
# retry
|
27
|
+
raise LXC::Errors::ExecuteError, :command => "lxc-info"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
ip
|
31
|
+
end
|
32
|
+
|
33
|
+
# From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385
|
34
|
+
def get_container_ip_from_ip_addr(driver)
|
35
|
+
output = driver.info '-iH'
|
36
|
+
if output =~ /^([0-9.]+)/
|
37
|
+
return $1.to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module LXC
|
3
|
+
module Action
|
4
|
+
class ForcedHalt
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
if env[:machine].provider.state.id == :running
|
11
|
+
env[:ui].info I18n.t("vagrant_lxc.messages.force_shutdown")
|
12
|
+
env[:machine].provider.driver.forced_halt
|
13
|
+
end
|
14
|
+
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
module LXC
|
5
|
+
module Action
|
6
|
+
class ForwardPorts
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
@logger = Log4r::Logger.new("vagrant::lxc::action::forward_ports")
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@env = env
|
14
|
+
|
15
|
+
# Get the ports we're forwarding
|
16
|
+
env[:forwarded_ports] = compile_forwarded_ports(env[:machine].config)
|
17
|
+
|
18
|
+
if @env[:forwarded_ports].any? and not redir_installed?
|
19
|
+
raise Errors::RedirNotInstalled
|
20
|
+
end
|
21
|
+
|
22
|
+
# Warn if we're port forwarding to any privileged ports
|
23
|
+
env[:forwarded_ports].each do |fp|
|
24
|
+
if fp[:host] <= 1024
|
25
|
+
env[:ui].warn I18n.t("vagrant.actions.vm.forward_ports.privileged_ports")
|
26
|
+
break
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Continue, we need the VM to be booted in order to grab its IP
|
31
|
+
@app.call env
|
32
|
+
|
33
|
+
if @env[:forwarded_ports].any?
|
34
|
+
env[:ui].info I18n.t("vagrant.actions.vm.forward_ports.forwarding")
|
35
|
+
forward_ports
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def forward_ports
|
40
|
+
@env[:forwarded_ports].each do |fp|
|
41
|
+
message_attributes = {
|
42
|
+
# TODO: Add support for multiple adapters
|
43
|
+
:adapter => 'eth0',
|
44
|
+
:guest_port => fp[:guest],
|
45
|
+
:host_port => fp[:host]
|
46
|
+
}
|
47
|
+
|
48
|
+
# TODO: Remove adapter from logging
|
49
|
+
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.forwarding_entry",
|
50
|
+
message_attributes))
|
51
|
+
|
52
|
+
redir_pid = redirect_port(
|
53
|
+
fp[:host_ip],
|
54
|
+
fp[:host],
|
55
|
+
fp[:guest_ip] || @env[:machine].provider.ssh_info[:host],
|
56
|
+
fp[:guest]
|
57
|
+
)
|
58
|
+
store_redir_pid(fp[:host], redir_pid)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def compile_forwarded_ports(config)
|
65
|
+
mappings = {}
|
66
|
+
|
67
|
+
config.vm.networks.each do |type, options|
|
68
|
+
next if options[:disabled]
|
69
|
+
|
70
|
+
# TODO: Deprecate this behavior of "automagically" skipping ssh forwarded ports
|
71
|
+
if type == :forwarded_port && options[:id] != 'ssh'
|
72
|
+
if options.fetch(:host_ip, '').to_s.strip.empty?
|
73
|
+
options[:host_ip] = '127.0.0.1'
|
74
|
+
end
|
75
|
+
mappings[options[:host]] = options
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
mappings.values
|
80
|
+
end
|
81
|
+
|
82
|
+
def redirect_port(host_ip, host_port, guest_ip, guest_port)
|
83
|
+
if redir_version >= 3
|
84
|
+
params = %W( :#{host_port} #{guest_ip}:#{guest_port} )
|
85
|
+
params[0] = "#{host_ip}:#{host_port}" if host_ip
|
86
|
+
else
|
87
|
+
params = %W( --lport=#{host_port} --caddr=#{guest_ip} --cport=#{guest_port} )
|
88
|
+
params.unshift "--laddr=#{host_ip}" if host_ip
|
89
|
+
end
|
90
|
+
params << '--syslog' if ENV['REDIR_LOG']
|
91
|
+
if host_port < 1024
|
92
|
+
redir_cmd = "sudo redir #{params.join(' ')} 2>/dev/null"
|
93
|
+
else
|
94
|
+
redir_cmd = "redir #{params.join(' ')} 2>/dev/null"
|
95
|
+
end
|
96
|
+
@logger.debug "Forwarding port with `#{redir_cmd}`"
|
97
|
+
spawn redir_cmd
|
98
|
+
end
|
99
|
+
|
100
|
+
def store_redir_pid(host_port, redir_pid)
|
101
|
+
data_dir = @env[:machine].data_dir.join('pids')
|
102
|
+
data_dir.mkdir unless data_dir.directory?
|
103
|
+
|
104
|
+
data_dir.join("redir_#{host_port}.pid").open('w') do |pid_file|
|
105
|
+
pid_file.write(redir_pid)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def redir_version
|
110
|
+
# For some weird reason redir prints version information in STDERR
|
111
|
+
_, version, _ = Open3.capture3 "redir --version"
|
112
|
+
version.split('.')[0].to_i
|
113
|
+
end
|
114
|
+
|
115
|
+
def redir_installed?
|
116
|
+
system "which redir > /dev/null"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module LXC
|
3
|
+
module Action
|
4
|
+
class GcPrivateNetworkBridges
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
was_running = env[:machine].provider.state.id == :running
|
11
|
+
|
12
|
+
# Continue execution, we need the container to be stopped
|
13
|
+
@app.call(env)
|
14
|
+
|
15
|
+
was_running = was_running && env[:machine].provider.state.id != :running
|
16
|
+
|
17
|
+
if was_running && private_network_configured?(env[:machine].config)
|
18
|
+
private_network_configured?(env[:machine].config)
|
19
|
+
remove_bridges_that_are_not_in_use(env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def private_network_configured?(config)
|
24
|
+
config.vm.networks.find do |type, _|
|
25
|
+
type.to_sym == :private_network
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_bridges_that_are_not_in_use(env)
|
30
|
+
env[:machine].config.vm.networks.find do |type, config|
|
31
|
+
next if type.to_sym != :private_network
|
32
|
+
|
33
|
+
bridge = config.fetch(:lxc__bridge_name)
|
34
|
+
driver = env[:machine].provider.driver
|
35
|
+
|
36
|
+
if ! driver.bridge_is_in_use?(bridge)
|
37
|
+
env[:ui].info I18n.t("vagrant_lxc.messages.remove_bridge", name: bridge)
|
38
|
+
unless ['lxcbr0', 'virbr0'].include? bridge
|
39
|
+
driver.remove_bridge(bridge)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|