diff --git a/README.md b/README.md index 88bacb1..d190f28 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ prior to starting it. For other configuration options, please check the [lxc.conf manpages](http://manpages.ubuntu.com/manpages/precise/man5/lxc.conf.5.html). -### Private Networks [EXPERIMENTAL] +### Private Networks Starting with vagrant-lxc 1.1.0, there is some rudimentary support for configuring [Private Networks](https://docs.vagrantup.com/v2/networking/private_network.html) @@ -137,25 +137,29 @@ Vagrant.configure("2") do |config| end ``` -For old versions of lxc (like 0.7.5 shipped with Ubuntu 12.04 by default) that -does not support `best` for the backingstore option, changing it to `none` is -required and a default for all Vagrant environments can be set from your -`~/.vagrant.d/Vagrantfile` using the same `provider` block: +## Unprivileged containers support + +Since v1.4.0, `vagrant-lxc` gained support for unprivileged containers. For now, since it's a new +feature, privileged containers are still the default, but you can have your `Vagrantfile` use +unprivileged containers with the `privileged` flag (which defaults to `true`). Example: ```ruby Vagrant.configure("2") do |config| config.vm.provider :lxc do |lxc| - lxc.backingstore = 'none' + lxc.privileged = false end end ``` +For unprivileged containers to work with `vagrant-lxc`, you need a properly configured system. On +some distros, it can be somewhat of a challenge. Your journey to configuring your system can start +with [Stéphane Graber's blog post about it](https://stgraber.org/2014/01/17/lxc-1-0-unprivileged-containers/). + ## Avoiding `sudo` passwords -This plugin requires **a lot** of `sudo`ing since [unprivileged containers](https://github.com/fgrehm/vagrant-lxc/issues/312) -are not supported yet. To work around that, you can use the `vagrant lxc sudoers` -command which will create a file under `/etc/sudoers.d/vagrant-lxc` whitelisting -all commands required by `vagrant-lxc` to run. +If you're not using unprivileged containers, this plugin requires **a lot** of `sudo`ing To work +around that, you can use the `vagrant lxc sudoers` command which will create a file under +`/etc/sudoers.d/vagrant-lxc` whitelisting all commands required by `vagrant-lxc` to run. If you are interested on what will be generated by that command, please check [this code](lib/vagrant-lxc/command/sudoers.rb). diff --git a/lib/vagrant-lxc/action/create.rb b/lib/vagrant-lxc/action/create.rb index fa46623..f1c5740 100644 --- a/lib/vagrant-lxc/action/create.rb +++ b/lib/vagrant-lxc/action/create.rb @@ -19,10 +19,14 @@ module Vagrant container_name = generate_container_name(env) end + backingstore = config.backingstore + if backingstore.nil? + backingstore = config.privileged ? "best" : "dir" + end driver = env[:machine].provider.driver driver.create( container_name, - config.backingstore, + backingstore, config.backingstore_options, env[:lxc_template_src], env[:lxc_template_config], diff --git a/lib/vagrant-lxc/config.rb b/lib/vagrant-lxc/config.rb index 2c45b73..0a117c3 100644 --- a/lib/vagrant-lxc/config.rb +++ b/lib/vagrant-lxc/config.rb @@ -24,6 +24,12 @@ module Vagrant attr_accessor :fetch_ip_tries + # Whether the container needs to be privileged. Defaults to true (unprivileged containers + # is a very new feature in vagrant-lxc). If false, will try creating an unprivileged + # container. If it can't, will revert to the old "sudo wrapper" method to create a privileged + # container. + attr_accessor :privileged + def initialize @customizations = [] @backingstore = UNSET_VALUE @@ -31,6 +37,7 @@ module Vagrant @container_name = UNSET_VALUE @tmpfs_mount_size = UNSET_VALUE @fetch_ip_tries = UNSET_VALUE + @privileged = UNSET_VALUE end # Customize the container by calling `lxc-start` with the given @@ -55,10 +62,11 @@ module Vagrant def finalize! @container_name = nil if @container_name == UNSET_VALUE - @backingstore = "best" if @backingstore == UNSET_VALUE + @backingstore = nil if @backingstore == UNSET_VALUE @existing_container_name = nil if @existing_container_name == UNSET_VALUE @tmpfs_mount_size = '2G' if @tmpfs_mount_size == UNSET_VALUE @fetch_ip_tries = 10 if @fetch_ip_tries == UNSET_VALUE + @privileged = true if @privileged == UNSET_VALUE end end end diff --git a/lib/vagrant-lxc/driver.rb b/lib/vagrant-lxc/driver.rb index 5cf13d1..4124dc9 100644 --- a/lib/vagrant-lxc/driver.rb +++ b/lib/vagrant-lxc/driver.rb @@ -20,9 +20,9 @@ module Vagrant attr_reader :container_name, :customizations - def initialize(container_name, sudo_wrapper = nil, cli = nil) + def initialize(container_name, sudo_wrapper = nil, cli = nil, privileged: true) @container_name = container_name - @sudo_wrapper = sudo_wrapper || SudoWrapper.new() + @sudo_wrapper = sudo_wrapper || SudoWrapper.new(privileged: privileged) @cli = cli || CLI.new(@sudo_wrapper, container_name) @logger = Log4r::Logger.new("vagrant::provider::lxc::driver") @customizations = [] @@ -266,12 +266,21 @@ module Vagrant end def write_config(contents) - Tempfile.new('lxc-config').tap do |file| - file.chmod 0644 - file.write contents - file.close - @sudo_wrapper.run 'cp', '-f', file.path, config_path - @sudo_wrapper.run 'chown', 'root:root', config_path + confpath = base_path.join('config').to_s + begin + File.open(confpath, File::RDWR) do |file| + file.write contents + end + rescue + # We don't have permissions to write in the conf file. That's probably because it's a + # privileged container. Work around that through sudo_wrapper. + Tempfile.new('lxc-config').tap do |file| + file.chmod 0644 + file.write contents + file.close + @sudo_wrapper.run 'cp', '-f', file.path, confpath + @sudo_wrapper.run 'chown', 'root:root', confpath + end end end end diff --git a/lib/vagrant-lxc/provider.rb b/lib/vagrant-lxc/provider.rb index 52c82ff..85c9925 100644 --- a/lib/vagrant-lxc/provider.rb +++ b/lib/vagrant-lxc/provider.rb @@ -2,7 +2,6 @@ require "log4r" require "vagrant-lxc/action" require "vagrant-lxc/driver" -require "vagrant-lxc/sudo_wrapper" module Vagrant module LXC @@ -27,7 +26,7 @@ module Vagrant def ensure_lxc_installed! begin - SudoWrapper.new().run("which", "lxc-create") + SudoWrapper.new(privileged: @machine.provider_config.privileged).run("which", "lxc-create") rescue Vagrant::LXC::Errors::ExecuteError raise Errors::LxcNotInstalled end @@ -40,7 +39,7 @@ module Vagrant begin @logger.debug("Instantiating the container for: #{id.inspect}") - @driver = Driver.new(id) + @driver = Driver.new(id, privileged: @machine.provider_config.privileged) @driver.validate! rescue Driver::ContainerNotFound # The container doesn't exist, so we probably have a stale diff --git a/lib/vagrant-lxc/sudo_wrapper.rb b/lib/vagrant-lxc/sudo_wrapper.rb index 67b9409..910d6ff 100644 --- a/lib/vagrant-lxc/sudo_wrapper.rb +++ b/lib/vagrant-lxc/sudo_wrapper.rb @@ -10,8 +10,9 @@ module Vagrant "/usr/local/bin/vagrant-lxc-wrapper" end - def initialize() + def initialize(privileged: true) @wrapper_path = Pathname.new(SudoWrapper.dest_path).exist? && SudoWrapper.dest_path || nil + @privileged = privileged @logger = Log4r::Logger.new("vagrant::lxc::sudo_wrapper") end @@ -27,11 +28,15 @@ module Vagrant File.umask(old_mask & 022) # allow all `r` and `x` bits begin - if @wrapper_path && !options[:no_wrapper] - command.unshift @wrapper_path - execute *(['sudo'] + command) + if @privileged + if @wrapper_path && !options[:no_wrapper] + command.unshift @wrapper_path + execute *(['sudo'] + command) + else + execute *(['sudo', '/usr/bin/env'] + command) + end else - execute *(['sudo', '/usr/bin/env'] + command) + execute *(['/usr/bin/env'] + command) end ensure File.umask(old_mask)