Add support for unprivileged containers

fixes #312

I've also remove the "EXPERIMENTAL" flag to bridge support in the README.
It's been there long enough.
This commit is contained in:
Virgil Dupras 2018-02-17 21:53:16 -05:00
parent 9e215ae1a1
commit 530a899467
6 changed files with 57 additions and 28 deletions

View file

@ -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). 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 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) [Private Networks](https://docs.vagrantup.com/v2/networking/private_network.html)
@ -137,25 +137,29 @@ Vagrant.configure("2") do |config|
end end
``` ```
For old versions of lxc (like 0.7.5 shipped with Ubuntu 12.04 by default) that ## Unprivileged containers support
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 Since v1.4.0, `vagrant-lxc` gained support for unprivileged containers. For now, since it's a new
`~/.vagrant.d/Vagrantfile` using the same `provider` block: 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 ```ruby
Vagrant.configure("2") do |config| Vagrant.configure("2") do |config|
config.vm.provider :lxc do |lxc| config.vm.provider :lxc do |lxc|
lxc.backingstore = 'none' lxc.privileged = false
end end
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 ## Avoiding `sudo` passwords
This plugin requires **a lot** of `sudo`ing since [unprivileged containers](https://github.com/fgrehm/vagrant-lxc/issues/312) If you're not using unprivileged containers, this plugin requires **a lot** of `sudo`ing To work
are not supported yet. To work around that, you can use the `vagrant lxc sudoers` around that, you can use the `vagrant lxc sudoers` command which will create a file under
command which will create a file under `/etc/sudoers.d/vagrant-lxc` whitelisting `/etc/sudoers.d/vagrant-lxc` whitelisting all commands required by `vagrant-lxc` to run.
all commands required by `vagrant-lxc` to run.
If you are interested on what will be generated by that command, please check If you are interested on what will be generated by that command, please check
[this code](lib/vagrant-lxc/command/sudoers.rb). [this code](lib/vagrant-lxc/command/sudoers.rb).

View file

@ -19,10 +19,14 @@ module Vagrant
container_name = generate_container_name(env) container_name = generate_container_name(env)
end end
backingstore = config.backingstore
if backingstore.nil?
backingstore = config.privileged ? "best" : "dir"
end
driver = env[:machine].provider.driver driver = env[:machine].provider.driver
driver.create( driver.create(
container_name, container_name,
config.backingstore, backingstore,
config.backingstore_options, config.backingstore_options,
env[:lxc_template_src], env[:lxc_template_src],
env[:lxc_template_config], env[:lxc_template_config],

View file

@ -24,6 +24,12 @@ module Vagrant
attr_accessor :fetch_ip_tries 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 def initialize
@customizations = [] @customizations = []
@backingstore = UNSET_VALUE @backingstore = UNSET_VALUE
@ -31,6 +37,7 @@ module Vagrant
@container_name = UNSET_VALUE @container_name = UNSET_VALUE
@tmpfs_mount_size = UNSET_VALUE @tmpfs_mount_size = UNSET_VALUE
@fetch_ip_tries = UNSET_VALUE @fetch_ip_tries = UNSET_VALUE
@privileged = UNSET_VALUE
end end
# Customize the container by calling `lxc-start` with the given # Customize the container by calling `lxc-start` with the given
@ -55,10 +62,11 @@ module Vagrant
def finalize! def finalize!
@container_name = nil if @container_name == UNSET_VALUE @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 @existing_container_name = nil if @existing_container_name == UNSET_VALUE
@tmpfs_mount_size = '2G' if @tmpfs_mount_size == UNSET_VALUE @tmpfs_mount_size = '2G' if @tmpfs_mount_size == UNSET_VALUE
@fetch_ip_tries = 10 if @fetch_ip_tries == UNSET_VALUE @fetch_ip_tries = 10 if @fetch_ip_tries == UNSET_VALUE
@privileged = true if @privileged == UNSET_VALUE
end end
end end
end end

View file

@ -20,9 +20,9 @@ module Vagrant
attr_reader :container_name, attr_reader :container_name,
:customizations :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 @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) @cli = cli || CLI.new(@sudo_wrapper, container_name)
@logger = Log4r::Logger.new("vagrant::provider::lxc::driver") @logger = Log4r::Logger.new("vagrant::provider::lxc::driver")
@customizations = [] @customizations = []
@ -266,12 +266,21 @@ module Vagrant
end end
def write_config(contents) def write_config(contents)
Tempfile.new('lxc-config').tap do |file| confpath = base_path.join('config').to_s
file.chmod 0644 begin
file.write contents File.open(confpath, File::RDWR) do |file|
file.close file.write contents
@sudo_wrapper.run 'cp', '-f', file.path, config_path end
@sudo_wrapper.run 'chown', 'root:root', config_path 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 end
end end

View file

@ -2,7 +2,6 @@ require "log4r"
require "vagrant-lxc/action" require "vagrant-lxc/action"
require "vagrant-lxc/driver" require "vagrant-lxc/driver"
require "vagrant-lxc/sudo_wrapper"
module Vagrant module Vagrant
module LXC module LXC
@ -27,7 +26,7 @@ module Vagrant
def ensure_lxc_installed! def ensure_lxc_installed!
begin begin
SudoWrapper.new().run("which", "lxc-create") SudoWrapper.new(privileged: @machine.provider_config.privileged).run("which", "lxc-create")
rescue Vagrant::LXC::Errors::ExecuteError rescue Vagrant::LXC::Errors::ExecuteError
raise Errors::LxcNotInstalled raise Errors::LxcNotInstalled
end end
@ -40,7 +39,7 @@ module Vagrant
begin begin
@logger.debug("Instantiating the container for: #{id.inspect}") @logger.debug("Instantiating the container for: #{id.inspect}")
@driver = Driver.new(id) @driver = Driver.new(id, privileged: @machine.provider_config.privileged)
@driver.validate! @driver.validate!
rescue Driver::ContainerNotFound rescue Driver::ContainerNotFound
# The container doesn't exist, so we probably have a stale # The container doesn't exist, so we probably have a stale

View file

@ -10,8 +10,9 @@ module Vagrant
"/usr/local/bin/vagrant-lxc-wrapper" "/usr/local/bin/vagrant-lxc-wrapper"
end end
def initialize() def initialize(privileged: true)
@wrapper_path = Pathname.new(SudoWrapper.dest_path).exist? && SudoWrapper.dest_path || nil @wrapper_path = Pathname.new(SudoWrapper.dest_path).exist? && SudoWrapper.dest_path || nil
@privileged = privileged
@logger = Log4r::Logger.new("vagrant::lxc::sudo_wrapper") @logger = Log4r::Logger.new("vagrant::lxc::sudo_wrapper")
end end
@ -27,11 +28,15 @@ module Vagrant
File.umask(old_mask & 022) # allow all `r` and `x` bits File.umask(old_mask & 022) # allow all `r` and `x` bits
begin begin
if @wrapper_path && !options[:no_wrapper] if @privileged
command.unshift @wrapper_path if @wrapper_path && !options[:no_wrapper]
execute *(['sudo'] + command) command.unshift @wrapper_path
execute *(['sudo'] + command)
else
execute *(['sudo', '/usr/bin/env'] + command)
end
else else
execute *(['sudo', '/usr/bin/env'] + command) execute *(['/usr/bin/env'] + command)
end end
ensure ensure
File.umask(old_mask) File.umask(old_mask)