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).
### 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).

View file

@ -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],

View file

@ -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

View file

@ -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)
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, config_path
@sudo_wrapper.run 'chown', 'root:root', config_path
@sudo_wrapper.run 'cp', '-f', file.path, confpath
@sudo_wrapper.run 'chown', 'root:root', confpath
end
end
end
end

View file

@ -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

View file

@ -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,12 +28,16 @@ module Vagrant
File.umask(old_mask & 022) # allow all `r` and `x` bits
begin
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 *(['/usr/bin/env'] + command)
end
ensure
File.umask(old_mask)
end