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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/.vimrc +1 -0
  6. data/BOXES.md +47 -0
  7. data/CHANGELOG.md +510 -0
  8. data/CONTRIBUTING.md +24 -0
  9. data/Gemfile +24 -0
  10. data/Guardfile +7 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +187 -0
  13. data/Rakefile +3 -0
  14. data/lib/vagrant-lxc.rb +10 -0
  15. data/lib/vagrant-lxc/action.rb +234 -0
  16. data/lib/vagrant-lxc/action/boot.rb +42 -0
  17. data/lib/vagrant-lxc/action/clear_forwarded_ports.rb +56 -0
  18. data/lib/vagrant-lxc/action/compress_rootfs.rb +30 -0
  19. data/lib/vagrant-lxc/action/create.rb +57 -0
  20. data/lib/vagrant-lxc/action/destroy.rb +18 -0
  21. data/lib/vagrant-lxc/action/destroy_confirm.rb +17 -0
  22. data/lib/vagrant-lxc/action/fetch_ip_with_lxc_info.rb +43 -0
  23. data/lib/vagrant-lxc/action/forced_halt.rb +20 -0
  24. data/lib/vagrant-lxc/action/forward_ports.rb +121 -0
  25. data/lib/vagrant-lxc/action/gc_private_network_bridges.rb +47 -0
  26. data/lib/vagrant-lxc/action/handle_box_metadata.rb +94 -0
  27. data/lib/vagrant-lxc/action/prepare_nfs_settings.rb +64 -0
  28. data/lib/vagrant-lxc/action/prepare_nfs_valid_ids.rb +19 -0
  29. data/lib/vagrant-lxc/action/private_networks.rb +46 -0
  30. data/lib/vagrant-lxc/action/setup_package_files.rb +60 -0
  31. data/lib/vagrant-lxc/action/warn_networks.rb +25 -0
  32. data/lib/vagrant-lxc/command/root.rb +58 -0
  33. data/lib/vagrant-lxc/command/sudoers.rb +97 -0
  34. data/lib/vagrant-lxc/config.rb +73 -0
  35. data/lib/vagrant-lxc/driver.rb +288 -0
  36. data/lib/vagrant-lxc/driver/cli.rb +166 -0
  37. data/lib/vagrant-lxc/errors.rb +62 -0
  38. data/lib/vagrant-lxc/plugin.rb +51 -0
  39. data/lib/vagrant-lxc/provider.rb +101 -0
  40. data/lib/vagrant-lxc/provider/cap/public_address.rb +17 -0
  41. data/lib/vagrant-lxc/sudo_wrapper.rb +104 -0
  42. data/lib/vagrant-lxc/synced_folder.rb +72 -0
  43. data/lib/vagrant-lxc/version.rb +5 -0
  44. data/locales/en.yml +82 -0
  45. data/scripts/lxc-template +171 -0
  46. data/scripts/pipework +422 -0
  47. data/spec/Vagrantfile +26 -0
  48. data/spec/fixtures/sample-ip-addr-output +2 -0
  49. data/spec/spec_helper.rb +35 -0
  50. data/spec/support/.gitkeep +0 -0
  51. data/spec/unit/action/clear_forwarded_ports_spec.rb +43 -0
  52. data/spec/unit/action/compress_rootfs_spec.rb +29 -0
  53. data/spec/unit/action/forward_ports_spec.rb +117 -0
  54. data/spec/unit/action/handle_box_metadata_spec.rb +126 -0
  55. data/spec/unit/action/setup_package_files_spec.rb +83 -0
  56. data/spec/unit/driver/cli_spec.rb +263 -0
  57. data/spec/unit/driver_spec.rb +268 -0
  58. data/spec/unit/support/unit_example_group.rb +38 -0
  59. data/spec/unit_helper.rb +17 -0
  60. data/tasks/spec.rake +40 -0
  61. data/templates/sudoers.rb.erb +129 -0
  62. data/vagrant-lxc.gemspec +20 -0
  63. data/vagrant-spec.config.rb +24 -0
  64. 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