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,62 @@
1
+ require 'vagrant/errors'
2
+
3
+ module Vagrant
4
+ module LXC
5
+ module Errors
6
+ class ExecuteError < Vagrant::Errors::VagrantError
7
+ error_key(:lxc_execute_error)
8
+ attr_reader :stderr, :stdout, :exitcode
9
+ def initialize(message, *args)
10
+ super
11
+ if message.is_a?(Hash)
12
+ @stderr = message[:stderr]
13
+ @stdout = message[:stdout]
14
+ @exitcode = message[:exitcode]
15
+ end
16
+ end
17
+ end
18
+
19
+ # Raised when user interrupts a subprocess
20
+ class SubprocessInterruptError < Vagrant::Errors::VagrantError
21
+ error_key(:lxc_interrupt_error)
22
+ def initialize(message, *args)
23
+ super
24
+ end
25
+ end
26
+
27
+
28
+ class LxcLinuxRequired < Vagrant::Errors::VagrantError
29
+ error_key(:lxc_linux_required)
30
+ end
31
+
32
+ class LxcNotInstalled < Vagrant::Errors::VagrantError
33
+ error_key(:lxc_not_installed)
34
+ end
35
+
36
+ class ContainerAlreadyExists < Vagrant::Errors::VagrantError
37
+ error_key(:lxc_container_already_exists)
38
+ end
39
+
40
+ class CommandNotSupported < Vagrant::Errors::VagrantError
41
+ error_key(:lxc_command_not_supported)
42
+ end
43
+
44
+ # Box related errors
45
+ class TemplateFileMissing < Vagrant::Errors::VagrantError
46
+ error_key(:lxc_template_file_missing)
47
+ end
48
+ class TemplatesDirMissing < Vagrant::Errors::VagrantError
49
+ error_key(:lxc_templates_dir_missing)
50
+ end
51
+ class RootFSTarballMissing < Vagrant::Errors::VagrantError
52
+ error_key(:lxc_invalid_box_version)
53
+ end
54
+ class IncompatibleBox < Vagrant::Errors::VagrantError
55
+ error_key(:lxc_incompatible_box)
56
+ end
57
+ class RedirNotInstalled < Vagrant::Errors::VagrantError
58
+ error_key(:lxc_redir_not_installed)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,51 @@
1
+ require 'vagrant'
2
+
3
+ module Vagrant
4
+ module LXC
5
+ class Plugin < Vagrant.plugin("2")
6
+ name "vagrant-lxc"
7
+ description <<-EOF
8
+ The LXC provider allows Vagrant to manage and control
9
+ LXC-based virtual machines.
10
+ EOF
11
+
12
+ provider(:lxc, parallel: true, priority: 7) do
13
+ require File.expand_path("../provider", __FILE__)
14
+ init!
15
+ Provider
16
+ end
17
+
18
+ command "lxc" do
19
+ require_relative 'command/root'
20
+ init!
21
+ Command::Root
22
+ end
23
+
24
+ config(:lxc, :provider) do
25
+ require File.expand_path("../config", __FILE__)
26
+ init!
27
+ Config
28
+ end
29
+
30
+ synced_folder(:lxc) do
31
+ require File.expand_path("../synced_folder", __FILE__)
32
+ SyncedFolder
33
+ end
34
+
35
+ provider_capability("lxc", "public_address") do
36
+ require_relative "provider/cap/public_address"
37
+ Provider::Cap::PublicAddress
38
+ end
39
+
40
+ protected
41
+
42
+ def self.init!
43
+ return if defined?(@_init)
44
+ I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
45
+ I18n.reload!
46
+ @_init = true
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,101 @@
1
+ require "log4r"
2
+
3
+ require "vagrant-lxc/action"
4
+ require "vagrant-lxc/driver"
5
+
6
+ module Vagrant
7
+ module LXC
8
+ class Provider < Vagrant.plugin("2", :provider)
9
+ attr_reader :driver
10
+
11
+ def self.usable?(raise_error=false)
12
+ if !Vagrant::Util::Platform.linux?
13
+ raise Errors::LxcLinuxRequired
14
+ end
15
+
16
+ true
17
+ end
18
+
19
+ def initialize(machine)
20
+ @logger = Log4r::Logger.new("vagrant::provider::lxc")
21
+ @machine = machine
22
+
23
+ ensure_lxc_installed!
24
+ machine_id_changed
25
+ end
26
+
27
+ def ensure_lxc_installed!
28
+ begin
29
+ SudoWrapper.new(privileged: @machine.provider_config.privileged).run("which", "lxc-create")
30
+ rescue Vagrant::LXC::Errors::ExecuteError
31
+ raise Errors::LxcNotInstalled
32
+ end
33
+ end
34
+
35
+ # If the machine ID changed, then we need to rebuild our underlying
36
+ # container.
37
+ def machine_id_changed
38
+ id = @machine.id
39
+
40
+ begin
41
+ @logger.debug("Instantiating the container for: #{id.inspect}")
42
+ @driver = Driver.new(id, privileged: @machine.provider_config.privileged)
43
+ @driver.validate!
44
+ rescue Driver::ContainerNotFound
45
+ # The container doesn't exist, so we probably have a stale
46
+ # ID. Just clear the id out of the machine and reload it.
47
+ @logger.debug("Container not found! Clearing saved machine ID and reloading.")
48
+ id = nil
49
+ retry
50
+ end
51
+ end
52
+
53
+ # @see Vagrant::Plugin::V2::Provider#action
54
+ def action(name)
55
+ # Attempt to get the action method from the Action class if it
56
+ # exists, otherwise return nil to show that we don't support the
57
+ # given action.
58
+ action_method = "action_#{name}"
59
+ return LXC::Action.send(action_method) if LXC::Action.respond_to?(action_method)
60
+ nil
61
+ end
62
+
63
+ # Returns the SSH info for accessing the Container.
64
+ def ssh_info
65
+ # If the Container is not running then we cannot possibly SSH into it, so
66
+ # we return nil.
67
+ return nil if state.id != :running
68
+
69
+ # Run a custom action called "ssh_ip" which does what it says and puts
70
+ # the IP found into the `:machine_ip` key in the environment.
71
+ env = @machine.action("ssh_ip")
72
+
73
+ # If we were not able to identify the container's IP, we return nil
74
+ # here and we let Vagrant core deal with it ;)
75
+ return nil unless env[:machine_ip]
76
+
77
+ {
78
+ :host => env[:machine_ip],
79
+ :port => @machine.config.ssh.guest_port
80
+ }
81
+ end
82
+
83
+ def state
84
+ state_id = nil
85
+ state_id = :not_created if !@driver.container_name
86
+ state_id = @driver.state if !state_id
87
+ state_id = :unknown if !state_id
88
+
89
+ short = state_id.to_s.gsub("_", " ")
90
+ long = I18n.t("vagrant.commands.status.#{state_id}")
91
+
92
+ Vagrant::MachineState.new(state_id, short, long)
93
+ end
94
+
95
+ def to_s
96
+ id = @machine.id ? @machine.id : "new VM"
97
+ "LXC (#{id})"
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,17 @@
1
+ module Vagrant
2
+ module LXC
3
+ class Provider
4
+ module Cap
5
+ module PublicAddress
6
+ def self.public_address(machine)
7
+ return nil if machine.state.id != :running
8
+
9
+ ssh_info = machine.ssh_info
10
+ return nil if !ssh_info
11
+ ssh_info[:host]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,104 @@
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
+ attr_reader :wrapper_path
8
+
9
+ def self.dest_path
10
+ "/usr/local/bin/vagrant-lxc-wrapper"
11
+ end
12
+
13
+ def initialize(privileged: true)
14
+ @wrapper_path = Pathname.new(SudoWrapper.dest_path).exist? && SudoWrapper.dest_path || nil
15
+ @privileged = privileged
16
+ @logger = Log4r::Logger.new("vagrant::lxc::sudo_wrapper")
17
+ end
18
+
19
+ def run(*command)
20
+ options = command.last.is_a?(Hash) ? command.last : {}
21
+
22
+ # Avoid running LXC commands with a restrictive umask.
23
+ # Otherwise disasters occur, like the container root directory
24
+ # having permissions `rwxr-x---` which prevents the `vagrant`
25
+ # user from accessing its own home directory; among other
26
+ # problems, SSH cannot then read `authorized_keys`!
27
+ old_mask = File.umask
28
+ File.umask(old_mask & 022) # allow all `r` and `x` bits
29
+
30
+ begin
31
+ if @privileged
32
+ if @wrapper_path && !options[:no_wrapper]
33
+ command.unshift @wrapper_path
34
+ execute *(['sudo'] + command)
35
+ else
36
+ execute *(['sudo', '/usr/bin/env'] + command)
37
+ end
38
+ else
39
+ execute *(['/usr/bin/env'] + command)
40
+ end
41
+ ensure
42
+ File.umask(old_mask)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ # TODO: Review code below this line, it was pretty much a copy and
49
+ # paste from VirtualBox base driver and has no tests
50
+ def execute(*command, &block)
51
+ # Get the options hash if it exists
52
+ opts = {}
53
+ opts = command.pop if command.last.is_a?(Hash)
54
+
55
+ tries = 0
56
+ tries = 3 if opts[:retryable]
57
+
58
+ sleep = opts.fetch(:sleep, 1)
59
+
60
+ # Variable to store our execution result
61
+ r = nil
62
+
63
+ retryable(:on => LXC::Errors::ExecuteError, :tries => tries, :sleep => sleep) do
64
+ # Execute the command
65
+ r = raw(*command, &block)
66
+
67
+ # If the command was a failure, then raise an exception that is
68
+ # nicely handled by Vagrant.
69
+ if r.exit_code != 0
70
+ if @interrupted
71
+ raise LXC::Errors::SubprocessInterruptError, command.inspect
72
+ else
73
+ raise LXC::Errors::ExecuteError,
74
+ command: command.inspect, stderr: r.stderr, stdout: r.stdout, exitcode: r.exit_code
75
+ end
76
+ end
77
+ end
78
+
79
+ # Return the output, making sure to replace any Windows-style
80
+ # newlines with Unix-style.
81
+ stdout = r.stdout.gsub("\r\n", "\n")
82
+ if opts[:show_stderr]
83
+ { :stdout => stdout, :stderr => r.stderr.gsub("\r\n", "\n") }
84
+ else
85
+ stdout
86
+ end
87
+ end
88
+
89
+ def raw(*command, &block)
90
+ int_callback = lambda do
91
+ @interrupted = true
92
+ @logger.info("Interrupted.")
93
+ end
94
+
95
+ # Append in the options for subprocess
96
+ command << { :notify => [:stdout, :stderr] }
97
+
98
+ Vagrant::Util::Busy.busy(int_callback) do
99
+ Vagrant::Util::Subprocess.execute(*command, &block)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,72 @@
1
+ module Vagrant
2
+ module LXC
3
+ class SyncedFolder < Vagrant.plugin("2", :synced_folder)
4
+ def usable?(machine)
5
+ # These synced folders only work if the provider is LXC
6
+ machine.provider_name == :lxc
7
+ end
8
+
9
+ def prepare(machine, folders, _opts)
10
+ machine.ui.output(I18n.t("vagrant.actions.lxc.share_folders.preparing"))
11
+ # short guestpaths first, so we don't step on ourselves
12
+ folders = folders.sort_by do |id, data|
13
+ if data[:guestpath]
14
+ data[:guestpath].length
15
+ else
16
+ # A long enough path to just do this at the end.
17
+ 10000
18
+ end
19
+ end
20
+
21
+ folders.each do |id, data|
22
+ host_path = Pathname.new(File.expand_path(data[:hostpath], machine.env.root_path))
23
+ guest_path = data[:guestpath]
24
+
25
+ machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_owner")) if data[:owner]
26
+ machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_group")) if data[:group]
27
+
28
+ if !host_path.directory? && data[:create]
29
+ # Host path doesn't exist, so let's create it.
30
+ @logger.info("Host path doesn't exist, creating: #{host_path}")
31
+
32
+ begin
33
+ host_path.mkpath
34
+ rescue Errno::EACCES
35
+ raise Vagrant::Errors::SharedFolderCreateFailed,
36
+ :path => hostpath.to_s
37
+ end
38
+ end
39
+
40
+ mount_opts = data[:mount_options]
41
+ machine.provider.driver.share_folder(host_path, guest_path, mount_opts)
42
+ # Guest path specified, so mount the folder to specified point
43
+ machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
44
+ guestpath: data[:guestpath],
45
+ hostpath: data[:hostpath],
46
+ guest_path: data[:guestpath]))
47
+ end
48
+ end
49
+
50
+ def enable(machine, folders, _opts)
51
+ # Emit an upstart event if we can
52
+ return unless machine.communicate.test("test -x /sbin/initctl")
53
+
54
+ # short guestpaths first, so we don't step on ourselves
55
+ folders = folders.sort_by do |id, data|
56
+ if data[:guestpath]
57
+ data[:guestpath].length
58
+ else
59
+ # A long enough path to just do this at the end.
60
+ 10000
61
+ end
62
+ end
63
+
64
+ folders.each do |id, data|
65
+ guest_path = data[:guestpath]
66
+ machine.communicate.sudo(
67
+ "/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}")
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ module Vagrant
2
+ module LXC
3
+ VERSION = "1.4.0"
4
+ end
5
+ end
@@ -0,0 +1,82 @@
1
+ en:
2
+ vagrant_lxc:
3
+ messages:
4
+ not_created: |-
5
+ The container hasn't been created yet.
6
+ not_running: |-
7
+ The container is not currently running.
8
+ will_not_destroy: |-
9
+ The container '%{name}' will not be destroyed, since the confirmation
10
+ was declined.
11
+ starting: |-
12
+ Starting container...
13
+ force_shutdown: |-
14
+ Forcing shutdown of container...
15
+ warn_networks: |-
16
+ Warning! The LXC provider doesn't support public networks, the settings
17
+ will be silently ignored.
18
+ warn_group: |-
19
+ Warning! The LXC provider doesn't support the :group parameter for synced
20
+ folders. It will be silently ignored.
21
+ warn_owner: |-
22
+ Warning! The LXC provider doesn't support the :owner parameter for synced
23
+ folders. It will be silently ignored.
24
+ setup_private_network: |-
25
+ Setting up private networks...
26
+ remove_bridge: |-
27
+ Removing bridge '%{name}'...
28
+
29
+ vagrant:
30
+ commands:
31
+ status:
32
+ stopped: |-
33
+ The container is currently stopped. Run `vagrant up` to bring it up again.
34
+
35
+ actions:
36
+ lxc:
37
+ compressing_rootfs: Compressing container's rootfs...
38
+
39
+ share_folders:
40
+ preparing: Setting up mount entries for shared folders...
41
+
42
+ errors:
43
+ lxc_interrupt_error: |-
44
+ Interrupted
45
+
46
+ lxc_execute_error: |-
47
+ There was an error executing %{command}
48
+
49
+ For more information on the failure, enable detailed logging by setting
50
+ the environment variable VAGRANT_LOG to DEBUG.
51
+
52
+ lxc_incompatible_box: |-
53
+ The base box you are trying to use is not compatible with the installed
54
+ vagrant-lxc version. Supported box versions are %{supported} but %{found} was found.
55
+
56
+ lxc_template_file_missing: |-
57
+ The template file used for creating the container was not found for %{name}
58
+ box.
59
+
60
+ lxc_templates_dir_missing: |-
61
+ Unable to identify lxc templates path.
62
+
63
+ Looked up under: %{paths}
64
+
65
+ lxc_linux_required: |-
66
+ The LXC provider only works on Linux. Please try to use
67
+ another provider.
68
+
69
+ lxc_not_installed: |-
70
+ The `lxc` package does not seem to be installed or `lxc-create` is not accessible on the PATH.
71
+
72
+ lxc_redir_not_installed: |-
73
+ `redir` is not installed or is not accessible on the PATH.
74
+
75
+ lxc_container_already_exists: |-
76
+ There is container on your system with the same name you've specified
77
+ on your Vagrantfile (%{name}), please choose a different one or
78
+ run `lxc-destroy --name %{name}` and try again.
79
+
80
+ lxc_command_not_supported: |-
81
+ Command (lxc-%{command}) not supported in version %{version}.
82
+ This command is available with version %{available_version}.