Compare commits

..

No commits in common. "master" and "0.8-stable" have entirely different histories.

87 changed files with 2764 additions and 2624 deletions

1
.gitignore vendored
View file

@ -19,7 +19,6 @@ doc/
/tags /tags
/gems.tags /gems.tags
/Gemfile.lock
.vagrant .vagrant
/cache /cache

View file

@ -1,10 +1,8 @@
language: ruby language: ruby
rvm: rvm:
- 2.2 - 1.9.3
- 2.3 - 2.0.0
- 2.4 matrix:
- 2.5 allow_failures:
install: - rvm: 2.0.0
- gem install -v 1.12.5 bundler
- bundle _1.12.5_ install --jobs=3 --retry=3
script: "bundle exec rake ci" script: "bundle exec rake ci"

View file

@ -4,11 +4,20 @@ Although the official documentation says it is only supported for VirtualBox
environments, you can use the [`vagrant package`](http://docs.vagrantup.com/v2/cli/package.html) environments, you can use the [`vagrant package`](http://docs.vagrantup.com/v2/cli/package.html)
command to export a `.box` file from an existing vagrant-lxc container. command to export a `.box` file from an existing vagrant-lxc container.
There is also a set of [bash scripts](https://github.com/fgrehm/vagrant-lxc-base-boxes) There is also a set of [bash scripts](https://github.com/fgrehm/vagrant-lxc/tree/master/boxes)
that you can use to build base boxes as needed. By default it won't include any that you can use to build base boxes as needed. By default it won't include any
provisioning tool and you can pick the ones you want by providing some environment provisioning tool and you can pick the ones you want by providing some environment
variables. Please refer to the [base boxes repository](https://github.com/fgrehm/vagrant-lxc-base-boxes) variables.
for more information.
For example:
```
git clone https://github.com/fgrehm/vagrant-lxc.git
cd vagrant-lxc/boxes
PUPPET=1 CHEF=1 sudo -E ./build-ubuntu-box.sh precise amd64
```
Will build a Ubuntu Precise x86_64 box with latest Puppet and Chef pre-installed, please refer to the scripts for more information.
## "Anatomy" of a box ## "Anatomy" of a box
@ -17,20 +26,19 @@ on knowing what makes a base box for vagrant-lxc, here's what's needed:
### Expected `.box` contents ### Expected `.box` contents
| FILE | REQUIRED? | DESCRIPTION | | FILE | DESCRIPTION |
| --- | --- | --- | | --- | --- |
| `metadata.json` | Yes | Required by Vagrant | | `lxc-template` | Script responsible for creating and setting up the container (used with `lxc-create`), a ["generic script"]() is provided along with project's source. |
| `rootfs.tar.gz` | Yes | Compressed container rootfs tarball (need to remeber to pass in `--numeric-owner` when creating it) | | `rootfs.tar.gz` | Compressed container rootfs tarball (need to remeber to pass in `--numeric-owner` when creating it) |
| `lxc-template` | No, a ["generic script"](scripts/lxc-template) is provided by the plugin if it doesn't exist on the base box | Script responsible for creating and setting up the container (used with `lxc-create`). | | `lxc.conf` | |
| `lxc-config` | No | Box specific configuration to be _appended_ to the system's generated container config file | | `metadata.json` | |
| `lxc.conf` | No | File passed in to `lxc-create -f` |
### metadata.json ### metadata.json
```json ```json
{ {
"provider": "lxc", "provider": "lxc",
"version": "1.0.0", "version": "3",
"built-on": "Sat Sep 21 21:10:00 UTC 2013", "built-on": "Sat Sep 21 21:10:00 UTC 2013",
"template-opts": { "template-opts": {
"--arch": "amd64", "--arch": "amd64",
@ -43,5 +51,5 @@ on knowing what makes a base box for vagrant-lxc, here's what's needed:
| --- | --- | --- | | --- | --- | --- |
| `provider` | Yes | Required by Vagrant | | `provider` | Yes | Required by Vagrant |
| `version` | Yes | Tracks backward incompatibilities | | `version` | Yes | Tracks backward incompatibilities |
| `built-on` | No | Date / time when the box was packaged for the first time | | `built-on` | No | Date / time when the box was packaged |
| `template-opts` | No | Extra options to be passed to the `lxc-template` script | | `template-opts` | No | Extra options to be passed to the `lxc-template` script provided with the .box package |

View file

@ -1,304 +1,4 @@
## [1.4.2](https://github.com/fgrehm/vagrant-lxc/compare/v1.4.1...v1.4.2) (Jul 17, 2018) ## [0.8.1](https://github.com/fgrehm/vagrant-lxc/compare/v0.8.0...master) (unreleased)
FIXES:
- Fix problems with `redir` 3.x command line. [[GH-467]]
## [1.4.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.4.0...v1.4.1) (Apr 30, 2018)
FEATURES:
- Add support for LXC v3.0
- Add support for `redir` 3.x command line. [[GH-460]]
[GH-460]: https://github.com/fgrehm/vagrant-lxc/issues/460
## [1.4.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.3.1...v1.4.0) (Mar 04, 2018)
FEATURES:
- Add support for unprivileged containers. [[GH-312]]
[GH-312]: https://github.com/fgrehm/vagrant-lxc/issues/312
## [1.3.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.3.0...v1.3.1) (Fev 06, 2018)
FIXES:
- Fix problems with `tmpfs` fiddling in v1.3.0. [[GH-455]]
[GH-455]: https://github.com/fgrehm/vagrant-lxc/pull/455
## [1.3.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.4...v1.3.0) (Jan 20, 2018)
FEATURES:
- lxc-template: make runnable by unprivileged users [[GH-447]]
- Use `lxc-info` instead of `lxc-attach` to retrieve container IP
- Add support for LXC v2.1+ [[GH-445]]
- Remove 2Gb limitation on `/tmp`. [[GH-406]]
OTHERS:
- Bump Vagrant requirements to v1.8+
- Bump LXC requirements to v1.0+
[GH-447]: https://github.com/fgrehm/vagrant-lxc/pull/447
[GH-445]: https://github.com/fgrehm/vagrant-lxc/pull/445
[GH-406]: https://github.com/fgrehm/vagrant-lxc/pull/406
## [1.2.4](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.3...v1.2.4) (Dec 20, 2017)
BUGFIX:
- Support alternative `lxcpath` [[GH-413]]
- Update `pipework` regexp in sudo wrapper for Vagrant 1.9+ [[GH-438]]
- Work around restrictive `umask` values [[GH-435]]
- Make `--config` in `lxc-template` optional [[GH-421]]
- Fix sudo wrapper binpath construction logic [[GH-410]]
- Fix bug causing CTRL-C on `vagrant up` to destroy the VM [[GH-449]]
[GH-413]: https://github.com/fgrehm/vagrant-lxc/pull/413
[GH-438]: https://github.com/fgrehm/vagrant-lxc/pull/438
[GH-435]: https://github.com/fgrehm/vagrant-lxc/pull/435
[GH-421]: https://github.com/fgrehm/vagrant-lxc/pull/421
[GH-410]: https://github.com/fgrehm/vagrant-lxc/pull/410
[GH-449]: https://github.com/fgrehm/vagrant-lxc/pull/449
## [1.2.3](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.2...v1.2.3) (Dec 20, 2016)
- Fix bug in Gemfile.lock
## [1.2.2](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.1...v1.2.2) (Dec 20, 2016)
BUGFIX:
- Make the timeout for fetching container IP's configurable [[GH-426]]
- Load locale file only once [[GH-423]]
- Preserve xattrs in container filesystems [[GH-411]]
- Forward port latest pipework script [[GH-408]]
- Fix handling of non-fatal lxc-stop return code [[GH-405]]
[GH-426]: https://github.com/fgrehm/vagrant-lxc/pull/426
[GH-423]: https://github.com/fgrehm/vagrant-lxc/pull/423
[GH-411]: https://github.com/fgrehm/vagrant-lxc/pull/411
[GH-408]: https://github.com/fgrehm/vagrant-lxc/pull/408
[GH-405]: https://github.com/fgrehm/vagrant-lxc/pull/405
## [1.2.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.0...v1.2.1) (Sep 24, 2015)
BUGFIX:
- Fix sudo Wrapper [[GH-393]]
[GH-393]: https://github.com/fgrehm/vagrant-lxc/pull/393
## [1.2.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.1.0...v1.2.0) (Sep 15, 2015)
FEATURES:
- Support private networking using DHCP [[GH-352]]
[GH-352]: https://github.com/fgrehm/vagrant-lxc/pull/352
IMPROVEMENTS:
- Move mountpoint creation to lxc template for lvm rootfs support [[GH-361]] / [[GH-359]]
- Mount selinux sys dir read-only [[GH-357]] / [[GH-301]]
- Use correct ruby interpreter when generating sudoers file [[GH-355]]
- Fix shebangs to be more portable [[GH-376]]
- Fix removal of lxcbr0/virbr0 when using private networking [[GH-383]]
- Improve /tmp handling by using tmpfs [[GH-362]]
[GH-301]: https://github.com/fgrehm/vagrant-lxc/issues/301
[GH-355]: https://github.com/fgrehm/vagrant-lxc/pull/355
[GH-357]: https://github.com/fgrehm/vagrant-lxc/pull/357
[GH-359]: https://github.com/fgrehm/vagrant-lxc/issues/359
[GH-361]: https://github.com/fgrehm/vagrant-lxc/pull/361
[GH-376]: https://github.com/fgrehm/vagrant-lxc/pull/376
[GH-383]: https://github.com/fgrehm/vagrant-lxc/pull/383
[GH-362]: https://github.com/fgrehm/vagrant-lxc/pull/362
## [1.1.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.1...v1.1.0) (Jan 14, 2015)
BACKWARDS INCOMPATIBILITIES:
- Support for Vagrant versions prior to 1.5 have been removed. The plugin now targets
Vagrant 1.7+ but it _might_ work on 1.5+.
FEATURES:
- New experimental support for private networking [[GH-298]] / [[GH-120]].
- Support for formatted overlayfs path [[GH-329]]
[GH-298]: https://github.com/fgrehm/vagrant-lxc/pull/298
[GH-120]: https://github.com/fgrehm/vagrant-lxc/issues/120
[GH-329]: https://github.com/fgrehm/vagrant-lxc/pull/329
IMPROVEMENTS:
- The provider will now have a higher priority over the VirtualBox provider
in case VirtualBox is installed alongside lxc dependecies.
- Show an user friendly message when trying to use the plugin on non-Linux
environments.
BUG FIXES:
- Allow backingstore options to be used along with the sudo wrapper script [[GH-310]]
- Trim automatically generated container names to 64 chars [[GH-337]]
[GH-337]: https://github.com/fgrehm/vagrant-lxc/issues/337
[GH-310]: https://github.com/fgrehm/vagrant-lxc/issues/310
## [1.0.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0...v1.0.1) (Oct 15, 2014)
IMPROVEMENTS:
- Avoid lock race condition when fetching container's IP [[GH-318]] and SSH execution [[GH-321]]
- Support for custom containers storage path by reading `lxc.lxcpath` [[GH-317]]
[GH-317]: https://github.com/fgrehm/vagrant-lxc/pull/317
[GH-318]: https://github.com/fgrehm/vagrant-lxc/pull/318
[GH-321]: https://github.com/fgrehm/vagrant-lxc/issues/321
## [1.0.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0.alpha.3...v1.0.0) (Sep 23, 2014)
DEPRECATIONS:
- Support to **all Vagrant versions prior to 1.5 are deprecated**, there is a
[small layer](lib/vagrant-backports) that ensures compatibility with versions
starting with 1.1.5 that will be removed on a future release.
- Official base boxes that were made available from http://bit.ly are no longer
supported and were removed from @fgrehm's Dropbox, please upgrade your Vagrant
and vagrant-lxc installation and use a base box from [VagrantCloud](https://vagrantcloud.com/search?provider=lxc)
BACKWARDS INCOMPATIBILITIES:
- Remove plugin version from config file name generated by the `vagrant lxc sudoers`
command. Manual removal of `/usr/local/bin/vagrant-lxc-wrapper-*` / `/etc/sudoers.d/vagrant-lxc-*`
files are required.
IMPROVEMENTS:
- `vagrant-mounted` upstart event is now emited on containers that support it [[GH-302]]
- Add support for specifying the `--strip-parameters` used by the [default template](scripts/lxc-template)
when extracting rootfs tarballs [[GH-311]]
[GH-302]: https://github.com/fgrehm/vagrant-lxc/issues/302
BUG FIXES:
- Check for outdated base boxes when starting containers [[GH-314]]
[GH-311]: https://github.com/fgrehm/vagrant-lxc/pull/311
[GH-314]: https://github.com/fgrehm/vagrant-lxc/pull/314
## [1.0.0.alpha.3](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0.alpha.2...v1.0.0.alpha.3) (Aug 9, 2014)
IMPROVEMENTS:
- Remove `lxc-shutdown` usage in favor of Vagrant's built in graceful halt
- Add fallback mechanism for platforms without `lxc-attach` support [[GH-294]]
[GH-294]: https://github.com/fgrehm/vagrant-lxc/pull/294
BUG FIXES:
- Figure out the real executable paths for whitelisted commands on the sudo
wrapper script instead of hardcoding Ubuntu paths [[GH-304]] / [[GH-305]]
- Attach to containers using the `MOUNT` namespace when attempting to fetch
container's IP [[GH-300]]
- Escape space characters for synced folders [[GH-291]]
- Use Vagrant's ruby on the sudoers file so that it works on systems that don't
have a global ruby installation [[GH-289]]
[GH-304]: https://github.com/fgrehm/vagrant-lxc/issues/304
[GH-305]: https://github.com/fgrehm/vagrant-lxc/issues/305
[GH-300]: https://github.com/fgrehm/vagrant-lxc/issues/300
[GH-291]: https://github.com/fgrehm/vagrant-lxc/issues/291
[GH-289]: https://github.com/fgrehm/vagrant-lxc/issues/289
## [1.0.0.alpha.2](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0.alpha.1...v1.0.0.alpha.2) (May 13, 2014)
BACKWARDS INCOMPATIBILITIES:
- The `sudo_wrapper` provider configuration was removed in favor of using the
secure wrapper generated by `vagrant lxc sudoers` [[GH-272]]
- Support for specifying backingstore parameters from `Vagrantfile`s for `lxc-create`
was added and it defaults to the `best` option. On older lxc versions that does not
support that value, it needs to be set to `none`.
FEATURES:
- Add support for specifying backingstore parameters from `Vagrantfile`s [[GH-277]]
IMPROVEMENTS:
- Make `dnsmasq` leases MAC address regex check case insensitive [[GH-283]]
- Use relative paths for `lxc.mount.entry` to avoid issues with `lxc-clone` [[GH-258]].
- Sort synced folders when mounting [[GH-271]]
- Privileged ports can now be forwarded with `sudo` [[GH-259]]
- The `vagrant lxc sudoers` generated sudoers configuration and wrapper script
are safer and properly whitelists the commands required by vagrant-lxc to run.
[[GH-272]] / [[GH-269]]
BUG FIXES:
- Fix `lxc-create` issues with pre 1.0.0 versions [[GH-282]]
[GH-283]: https://github.com/fgrehm/vagrant-lxc/pull/283
[GH-282]: https://github.com/fgrehm/vagrant-lxc/pull/282
[GH-269]: https://github.com/fgrehm/vagrant-lxc/issues/269
[GH-272]: https://github.com/fgrehm/vagrant-lxc/pull/272
[GH-259]: https://github.com/fgrehm/vagrant-lxc/pull/259
[GH-271]: https://github.com/fgrehm/vagrant-lxc/pull/271
[GH-277]: https://github.com/fgrehm/vagrant-lxc/pull/277
[GH-258]: https://github.com/fgrehm/vagrant-lxc/issues/258
## [1.0.0.alpha.1](https://github.com/fgrehm/vagrant-lxc/compare/v0.8.0...v1.0.0.alpha.1) (Apr 06, 2014)
DEPRECATIONS:
- Support to **all Vagrant versions prior to 1.5 are now deprecated**, there is a
[small layer](lib/vagrant-backports) that ensures compatibility with versions
starting with 1.1.5 but there is no guarantee that it will stick for too long.
- Boxes released prior to this version are now deprecated and won't be available
after the final 1.0.0 release.
- `--auth-key` argument is no longer provided to `lxc-template`. This will cause
all official base boxes prior to 09/28/2013 to break.
FEATURES:
- New `vagrant lxc sudoers` command for creating a policy for users in order to
avoid `sudo` passwords [[GH-237]] / [[GH-257]]
- Support for NFS and rsync synced folders.
- Support for synced folder mount options allowing for using read only synced
folders [[GH-193]]
[GH-237]: https://github.com/fgrehm/vagrant-lxc/issues/237
[GH-257]: https://github.com/fgrehm/vagrant-lxc/pull/257
[GH-193]: https://github.com/fgrehm/vagrant-lxc/issues/193
IMPROVEMENTS:
- `lxc-template` is now optional for base boxes and are bundled with the plugin,
allowing us to roll out updates without the need to rebuild boxes [[GH-254]]
- Set container's `utsname` to `config.vm.hostname` by default [[GH-253]]
- Added libvirt dnsmasq leases file to the lookup paths [[GH-251]]
- Improved compatibility with Vagrant 1.4 / 1.5 including the ability
to use `rsync` and `nfs` shared folders to work around synced folders
permission problems. More information can be found on the following
issues: [[GH-151]] [[GH-191]] [[GH-241]] [[GH-242]]
- Warn in case `:group` or `:owner` are specified for synced folders [[GH-196]]
- Acceptance specs are now powered by `vagrant-spec` [[GH-213]]
- Base boxes creation scripts were moved out to https://github.com/fgrehm/vagrant-lxc-base-boxes.
[GH-254]: https://github.com/fgrehm/vagrant-lxc/issues/254
[GH-196]: https://github.com/fgrehm/vagrant-lxc/issues/196
[GH-251]: https://github.com/fgrehm/vagrant-lxc/pull/251
[GH-253]: https://github.com/fgrehm/vagrant-lxc/pull/253
[GH-151]: https://github.com/fgrehm/vagrant-lxc/issues/151
[GH-213]: https://github.com/fgrehm/vagrant-lxc/issues/213
[GH-191]: https://github.com/fgrehm/vagrant-lxc/issues/191
[GH-241]: https://github.com/fgrehm/vagrant-lxc/issues/241
[GH-242]: https://github.com/fgrehm/vagrant-lxc/issues/242
## [0.8.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.7.0...v0.8.0) (Feb 26, 2014) ## [0.8.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.7.0...v0.8.0) (Feb 26, 2014)

View file

@ -1,17 +1,14 @@
### Please read before contributing ### Please read before contributing
* If you have an issue with base boxes, please create it on https://github.com/fgrehm/vagrant-lxc-base-boxes,
this repository is for the Vagrant plugin only.
* Try not to post questions in the issues tracker. I will probably answer you * Try not to post questions in the issues tracker. I will probably answer you
but I'll most likely close the issue right away and will continue the discussion but I'll most likely close the issue right away and will continue the discussion
with the issue closed. If you have any questions about the plugin, make sure with the issue closed. If you have any questions about the plugin, make sure
you go through the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki) pages you go through the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki) pages
first (specially the [Troubleshooting Section](https://github.com/fgrehm/vagrant-lxc/wiki/Troubleshooting)) first (specially the [Troubleshooting Section](https://github.com/fgrehm/vagrant-lxc/wiki/Troubleshooting))
and if you still need answers please ask a question on [Stack Overflow](http://stackoverflow.com/questions/tagged/vagrant-lxc) and if you still need answers please ask a question on [Stack Overflow](http://stackoverflow.com/questions/tagged/vagrant-lxc)
using the `vagrant` / `lxc` tag on it so that I get notified :) using the `vagrant-lxc` tag on it so that I get notified :)
* Please do a search on the issues tracker before submitting your issue to * Please do a small search on the issues tracker before submitting your issue to
check if it was already reported / fixed. check if it was already reported / fixed.
* When reporting a bug, please include **all** information that you can get * When reporting a bug, please include **all** information that you can get

27
Gemfile
View file

@ -1,23 +1,24 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gemspec
group :development do group :development do
gem 'vagrant', git: 'https://github.com/mitchellh/vagrant.git' gem 'vagrant', github: 'mitchellh/vagrant'
gem 'vagrant-cachier', github: 'fgrehm/vagrant-cachier'
gem 'vagrant-pristine', github: 'fgrehm/vagrant-pristine'
gem 'vagrant-omnibus'
gem 'guard' gem 'guard'
gem 'guard-rspec' gem 'guard-rspec'
gem 'rb-inotify' gem 'rb-inotify'
end end
group :development, :test do
gem 'rake', '~> 10.4.2'
gem 'rspec', '~> 3.5.0'
gem 'coveralls', '~> 0.7.2', require: (ENV['COVERAGE'] == 'true')
gem 'vagrant-spec', git: 'https://github.com/mitchellh/vagrant-spec.git'
end
group :plugins do group :development, :test do
acceptance = (ENV['ACCEPTANCE'] == 'true') gem 'rake'
gem 'vagrant-cachier', git: 'https://github.com/fgrehm/vagrant-cachier.git', require: !acceptance # Update https://github.com/fgrehm/vagrant-lxc/issues/111 once we are able to
gem 'vagrant-pristine', git: 'https://github.com/fgrehm/vagrant-pristine.git', require: !acceptance # upgrade to a newer release
gem 'vagrant-omnibus', require: !acceptance gem 'rspec', '~> 2.13.0'
gemspec gem 'rspec-fire', require: 'rspec/fire'
gem 'rspec-spies', require: false
gem 'coveralls', require: false
end end

120
Gemfile.lock Normal file
View file

@ -0,0 +1,120 @@
GIT
remote: git://github.com/fgrehm/vagrant-cachier.git
revision: 2faa6615466f8d518893f5ba51b493b877d2efde
specs:
vagrant-cachier (0.6.1.dev)
GIT
remote: git://github.com/fgrehm/vagrant-pristine.git
revision: 4638491786943bfbf6f115b1fc379f069963fe46
specs:
vagrant-pristine (0.3.0)
GIT
remote: git://github.com/mitchellh/vagrant.git
revision: a92e03cf4ce936243d3959b7b5603262a234a58d
specs:
vagrant (1.3.6.dev)
childprocess (~> 0.3.7)
erubis (~> 2.7.0)
i18n (~> 0.6.0)
log4r (~> 1.1.9)
net-scp (~> 1.1.0)
net-ssh (~> 2.6.6)
PATH
remote: .
specs:
vagrant-lxc (0.8.1.dev)
GEM
remote: https://rubygems.org/
specs:
celluloid (0.15.2)
timers (~> 1.1.0)
childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11)
coderay (1.0.9)
coveralls (0.7.0)
multi_json (~> 1.3)
rest-client
simplecov (>= 0.7)
term-ansicolor
thor
diff-lcs (1.2.5)
erubis (2.7.0)
ffi (1.9.3)
formatador (0.2.4)
guard (2.2.3)
formatador (>= 0.2.4)
listen (~> 2.1)
lumberjack (~> 1.0)
pry (>= 0.9.12)
thor (>= 0.18.1)
guard-rspec (3.1.0)
guard (>= 1.8)
rspec (~> 2.13)
i18n (0.6.5)
listen (2.2.0)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
log4r (1.1.10)
lumberjack (1.0.4)
method_source (0.8.2)
mime-types (2.0)
multi_json (1.8.2)
net-scp (1.1.2)
net-ssh (>= 2.6.5)
net-ssh (2.6.8)
pry (0.9.12.2)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
rake (10.1.0)
rb-fsevent (0.9.3)
rb-inotify (0.9.2)
ffi (>= 0.5.0)
rest-client (1.6.7)
mime-types (>= 1.16)
rspec (2.13.0)
rspec-core (~> 2.13.0)
rspec-expectations (~> 2.13.0)
rspec-mocks (~> 2.13.0)
rspec-core (2.13.1)
rspec-expectations (2.13.0)
diff-lcs (>= 1.1.3, < 2.0)
rspec-fire (1.3.0)
rspec (>= 2.11, < 4)
rspec-mocks (2.13.1)
rspec-spies (2.1.4)
rspec (~> 2.0)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
simplecov-html (0.7.1)
slop (3.4.6)
term-ansicolor (1.2.2)
tins (~> 0.8)
thor (0.18.1)
timers (1.1.0)
tins (0.13.0)
vagrant-omnibus (1.1.2)
PLATFORMS
ruby
DEPENDENCIES
coveralls
guard
guard-rspec
rake
rb-inotify
rspec (~> 2.13.0)
rspec-fire
rspec-spies
vagrant!
vagrant-cachier!
vagrant-lxc!
vagrant-omnibus
vagrant-pristine!

165
README.md
View file

@ -1,40 +1,47 @@
🟢 We plan to support and maintain vagrant-lxc, as well as clean it up.<br/>
🟢 Please feel free to contribute Issues and pull requests.<br/>
🟢 P.S: Thanks [Fabio Rehm](https://fabiorehm.com) for the amazing initial project.
# vagrant-lxc # vagrant-lxc
[![Build Status](https://travis-ci.org/fgrehm/vagrant-lxc.png?branch=master)](https://travis-ci.org/fgrehm/vagrant-lxc) [![Gem Version](https://badge.fury.io/rb/vagrant-lxc.png)](http://badge.fury.io/rb/vagrant-lxc) [![Code Climate](https://codeclimate.com/github/fgrehm/vagrant-lxc.png)](https://codeclimate.com/github/fgrehm/vagrant-lxc) [![Coverage Status](https://coveralls.io/repos/fgrehm/vagrant-lxc/badge.png?branch=master)](https://coveralls.io/r/fgrehm/vagrant-lxc) [![Gitter chat](https://badges.gitter.im/fgrehm/vagrant-lxc.png)](https://gitter.im/fgrehm/vagrant-lxc) [![Build Status](https://travis-ci.org/fgrehm/vagrant-lxc.png?branch=master)](https://travis-ci.org/fgrehm/vagrant-lxc) [![Gem Version](https://badge.fury.io/rb/vagrant-lxc.png)](http://badge.fury.io/rb/vagrant-lxc) [![Code Climate](https://codeclimate.com/github/fgrehm/vagrant-lxc.png)](https://codeclimate.com/github/fgrehm/vagrant-lxc) [![Coverage Status](https://coveralls.io/repos/fgrehm/vagrant-lxc/badge.png?branch=master)](https://coveralls.io/r/fgrehm/vagrant-lxc) [![Gittip](http://img.shields.io/gittip/fgrehm.svg)](https://www.gittip.com/fgrehm/)
[LXC](http://lxc.sourceforge.net/) provider for [Vagrant](http://www.vagrantup.com/) 1.9+ [LXC](http://lxc.sourceforge.net/) provider for [Vagrant](http://www.vagrantup.com/) 1.1+
This is a Vagrant plugin that allows it to control and provision Linux Containers This is a Vagrant plugin that allows it to control and provision Linux Containers
as an alternative to the built in VirtualBox provider for Linux hosts. Check out as an alternative to the built in VirtualBox provider for Linux hosts. Check out
[this blog post](http://fabiorehm.com/blog/2013/04/28/lxc-provider-for-vagrant/) [this blog post](http://fabiorehm.com/blog/2013/04/28/lxc-provider-for-vagrant/)
to see it in action. to see it in action.
## Features
## Features / Limitations
* Provides the same workflow as the Vagrant VirtualBox provider * Provides the same workflow as the Vagrant VirtualBox provider
* Port forwarding via [`redir`](https://github.com/troglobit/redir) * Port forwarding via [`redir`](http://linux.die.net/man/1/redir)
* Private networking via [`pipework`](https://github.com/jpetazzo/pipework) * Does not support public / private networks
* Assumes you have a `lxcbr0` bridge configured on your host similar to [Ubuntu's built-in](https://help.ubuntu.com/lts/serverguide/lxc.html#lxcbr0)
## Requirements ## Requirements
* [Vagrant 1.9+](http://www.vagrantup.com/downloads.html) * [Vagrant 1.1+](http://downloads.vagrantup.com/)
* lxc >=2.1 * lxc 0.7.5+
* `redir` (if you are planning to use port forwarding) * redir (if you are planning to use port forwarding)
* `brctl` (if you are planning to use private networks, on Ubuntu this means `apt-get install bridge-utils`) * A [kernel != 3.5.0-17.28](https://github.com/fgrehm/vagrant-lxc/wiki/Troubleshooting#wiki-im-unable-to-restart-containers)
The plugin is known to work better and pretty much out of the box on Ubuntu 14.04+ The plugin is known to work better and pretty much out of the box on Ubuntu 12.04+
hosts and installing the dependencies on it basically means a hosts and installing the dependencies on it basically means a `apt-get install lxc lxc-templates cgroup-lite redir`
`apt-get install lxc lxc-templates cgroup-lite redir`. For setting up other and a `apt-get update && apt-get dist-upgrade` to upgrade the kernel. For Debian
types of hosts please have a look at the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki). hosts you'll need to follow the instructions described on the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki/Usage-on-debian-hosts).
Some manual steps are required to set up a Linode machine prior to using this
plugin, please check [the wiki](https://github.com/fgrehm/vagrant-lxc/wiki/Usage-on-Linode)
for more information. Documentation on how to set things up for other distros
[are welcome](https://github.com/fgrehm/vagrant-lxc/wiki) :)
If you are on a Mac or Windows machine, you might want to have a look at [this](http://the.taoofmac.com/space/HOWTO/Vagrant) If you are on a Mac or Windows machine, you might want to have a look at [this](http://the.taoofmac.com/space/HOWTO/Vagrant)
blog post for some ideas on how to set things up or check out [this other repo](https://github.com/fgrehm/vagrant-lxc-vbox-hosts) blog post for some ideas on how to set things up or check out [this other repo](https://github.com/fgrehm/vagrant-lxc-vbox-hosts)
for a set of Vagrant VirtualBox machines ready for vagrant-lxc usage. for a set of Vagrant VirtualBox machines ready for vagrant-lxc usage.
**NOTE: Some users have been experiencing networking issues and right now you might need to
disable checksum offloading as described on [this comment](https://github.com/fgrehm/vagrant-lxc/issues/153#issuecomment-26441273)**
## Installation ## Installation
@ -43,33 +50,38 @@ vagrant plugin install vagrant-lxc
``` ```
## Quick start ## Usage
After installing, add a [base box](#base-boxes) using any name you want, for example:
``` ```
vagrant init fgrehm/precise64-lxc vagrant box add quantal64 http://bit.ly/vagrant-lxc-quantal64-2013-10-23
vagrant up --provider=lxc
``` ```
_More information about skipping the `--provider` argument can be found at the Then create a Vagrantfile that looks like the following, changing the box name
"DEFAULT PROVIDER" section of [Vagrant docs](https://docs.vagrantup.com/v2/providers/basic_usage.html)_ to the one you've just added:
## Base boxes
Base boxes provided on Atlas haven't been refreshed for a good while and shouldn't be relied on.
Your best best is to build your boxes yourself. Some scripts to build your own are available at
[hsoft/vagrant-lxc-base-boxes](https://github.com/hsoft/vagrant-lxc-base-boxes).
If you want to build your own boxes, please have a look at [`BOXES.md`](https://github.com/fgrehm/vagrant-lxc/tree/master/BOXES.md)
for more information.
## Advanced configuration
You can modify container configurations from within your Vagrantfile using the
[provider block](http://docs.vagrantup.com/v2/providers/configuration.html):
```ruby ```ruby
Vagrant.configure("2") do |config| Vagrant.configure("2") do |config|
config.vm.box = "fgrehm/trusty64-lxc" config.vm.box = "quantal64"
end
```
And finally run `vagrant up --provider=lxc`.
If you are using Vagrant 1.2+ you can also set `VAGRANT_DEFAULT_PROVIDER`
environmental variable to `lxc` in order to avoid typing `--provider=lxc` all
the time.
### Advanced configuration
If you want, you can modify container configurations from within your Vagrantfile
using the [provider block](http://docs.vagrantup.com/v2/providers/configuration.html):
```ruby
Vagrant.configure("2") do |config|
config.vm.box = "quantal64"
config.vm.provider :lxc do |lxc| config.vm.provider :lxc do |lxc|
# Same effect as 'customize ["modifyvm", :id, "--memory", "1024"]' for VirtualBox # Same effect as 'customize ["modifyvm", :id, "--memory", "1024"]' for VirtualBox
lxc.customize 'cgroup.memory.limit_in_bytes', '1024M' lxc.customize 'cgroup.memory.limit_in_bytes', '1024M'
@ -81,29 +93,7 @@ vagrant-lxc will then write out `lxc.cgroup.memory.limit_in_bytes='1024M'` to th
container config file (usually kept under `/var/lib/lxc/<container>/config`) container config file (usually kept under `/var/lib/lxc/<container>/config`)
prior to starting it. 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/quantal/man5/lxc.conf.5.html).
### 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)
by leveraging the [pipework](https://github.com/jpetazzo/pipework) project.
On its current state, there is a requirement for setting the bridge name that
will be created and will allow your machine to comunicate with the container
For example:
```ruby
Vagrant.configure("2") do |config|
config.vm.network "private_network", ip: "192.168.2.100", lxc__bridge_name: 'vlxcbr1'
end
```
Will create a new `veth` device for the container and will set up (or reuse)
a `vlxcbr1` bridge between your machine and the `veth` device. Once the last
vagrant-lxc container attached to the bridge gets `vagrant halt`ed, the plugin
will delete the bridge.
### Container naming ### Container naming
@ -113,6 +103,8 @@ for you. However, if the container name is important to you, you may use the
```ruby ```ruby
Vagrant.configure("2") do |config| Vagrant.configure("2") do |config|
config.vm.box = "quantal64"
config.vm.define "db" do |node| config.vm.define "db" do |node|
node.vm.provider :lxc do |lxc| node.vm.provider :lxc do |lxc|
lxc.container_name = :machine # Sets the container name to 'db' lxc.container_name = :machine # Sets the container name to 'db'
@ -122,52 +114,19 @@ Vagrant.configure("2") do |config|
end end
``` ```
_Please note that there is a 64 chars limit and the container name will be ### Avoiding `sudo` passwords
trimmed down to that to ensure we can always bring the container up.
### Backingstore options This plugin requires **a lot** of `sudo`ing since [user namespaces](https://wiki.ubuntu.com/UserNamespace)
are not supported on mainstream kernels. Have a look at the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki/Avoiding-'sudo'-passwords)
to find out how to work around that specially if you are running an OS with `sudo`
< 1.8.4 (like Ubuntu 12.04) as you might be affected by a bug.
Support for setting `lxc-create`'s backingstore option (`-B` and related) can be ### Base boxes
specified from the provider block and it defaults to `best`, to change it:
```ruby Please check [the wiki](https://github.com/fgrehm/vagrant-lxc/wiki/Base-boxes)
Vagrant.configure("2") do |config| for a list of [pre built](https://github.com/fgrehm/vagrant-lxc/wiki/Base-boxes#available-boxes)
config.vm.provider :lxc do |lxc| base boxes and have a look at [`BOXES.md`](https://github.com/fgrehm/vagrant-lxc/tree/master/BOXES.md)
lxc.backingstore = 'lvm' # or 'btrfs', 'overlayfs', ... for more information on building your own.
# lvm specific options
lxc.backingstore_option '--vgname', 'schroots'
lxc.backingstore_option '--fssize', '5G'
lxc.backingstore_option '--fstype', 'xfs'
end
end
```
## 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.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
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).
## More information ## More information

22
boxes/build-all.sh Executable file
View file

@ -0,0 +1,22 @@
#!/bin/bash
# set -x
set -e
# Convenience script used for building all of the base boxes available
# Ubuntu boxes
sudo -E ./build-ubuntu-box.sh precise
sudo -E ./build-ubuntu-box.sh quantal
sudo -E ./build-ubuntu-box.sh raring
sudo -E ./build-ubuntu-box.sh saucy
# Debian boxes
sudo -E ./build-debian-box.sh squeeze
sudo -E ./build-debian-box.sh wheezy
sudo -E ./build-debian-box.sh sid
for box in precise raring quantal saucy squeeze wheezy sid; do
box="vagrant-lxc-${box}-amd64-`date +%Y-%m-%d`.box"
~/bin/dropbox_uploader.sh upload output/${box} Public/
done

167
boxes/build-debian-box.sh Executable file
View file

@ -0,0 +1,167 @@
#!/bin/bash
# set -x
set -e
# Script used to build Debian base vagrant-lxc containers, currently limited to
# host's arch
#
# USAGE:
# $ cd boxes && sudo ./build-debian-box.sh DEBIAN_RELEASE
#
# To enable Chef or any other configuration management tool pass '1' to the
# corresponding env var:
# $ CHEF=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE
# $ PUPPET=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE
# $ SALT=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE
# $ BABUSHKA=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE
##################################################################################
# 0 - Initial setup and sanity checks
TODAY=$(date -u +"%Y-%m-%d")
NOW=$(date -u)
RELEASE=${1:-"wheezy"}
ARCH=$(dpkg --print-architecture) # This is what the Debian template will use under the hood
PKG=vagrant-lxc-${RELEASE}-${ARCH}-${TODAY}.box
WORKING_DIR=/tmp/vagrant-lxc-${RELEASE}
VAGRANT_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key"
ROOTFS=/var/lib/lxc/${RELEASE}-base/rootfs
# Providing '1' will enable these tools
CHEF=${CHEF:-0}
PUPPET=${PUPPET:-0}
SALT=${SALT:-0}
BABUSHKA=${BABUSHKA:-0}
# Path to files bundled with the box
CWD=`readlink -f .`
LXC_TEMPLATE=${CWD}/common/lxc-template
LXC_CONF=${CWD}/common/lxc.conf
METATADA_JSON=${CWD}/common/metadata.json
# Set up a working dir
mkdir -p $WORKING_DIR
if [ -f "${WORKING_DIR}/${PKG}" ]; then
echo "Found a box on ${WORKING_DIR}/${PKG} already!"
exit 1
fi
##################################################################################
# 1 - Create the base container
if $(lxc-ls | grep -q "${RELEASE}-base"); then
echo "Base container already exists, please remove it with \`lxc-destroy -n ${RELEASE}-base\`!"
exit 1
else
export SUITE=$RELEASE
lxc-create -n ${RELEASE}-base -t debian
fi
######################################
# 2 - Fix some known issues
# Fixes some networking issues
# See https://github.com/fgrehm/vagrant-lxc/issues/91 for more info
sed -i -e "s/\(127.0.0.1\s\+localhost\)/\1\n127.0.1.1\t${RELEASE}-base\n/g" ${ROOTFS}/etc/hosts
# Ensures that `/tmp` does not get cleared on halt
# See https://github.com/fgrehm/vagrant-lxc/issues/68 for more info
chroot $ROOTFS /usr/sbin/update-rc.d -f checkroot-bootclean.sh remove
chroot $ROOTFS /usr/sbin/update-rc.d -f mountall-bootclean.sh remove
chroot $ROOTFS /usr/sbin/update-rc.d -f mountnfs-bootclean.sh remove
# Ensure locales are properly set, based on http://linux.livejournal.com/1880366.html
sed -i "s/^# en_US/en_US/" ${ROOTFS}/etc/locale.gen
chroot $ROOTFS /usr/sbin/locale-gen
chroot $ROOTFS update-locale LANG=en_US.UTF-8
##################################################################################
# 3 - Prepare vagrant user
sudo chroot ${ROOTFS} useradd --create-home -s /bin/bash vagrant
echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd
##################################################################################
# 4 - Setup SSH access and passwordless sudo
# Configure SSH access
mkdir -p ${ROOTFS}/home/vagrant/.ssh
echo $VAGRANT_KEY > ${ROOTFS}/home/vagrant/.ssh/authorized_keys
chroot ${ROOTFS} chown -R vagrant: /home/vagrant/.ssh
chroot ${ROOTFS} apt-get install sudo -y --force-yes
chroot ${ROOTFS} adduser vagrant sudo
# Enable passwordless sudo for users under the "sudo" group
cp ${ROOTFS}/etc/sudoers{,.orig}
sed -i -e \
's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \
${ROOTFS}/etc/sudoers
##################################################################################
# 5 - Add some goodies and update packages
PACKAGES=(vim curl wget man-db bash-completion ca-certificates)
chroot ${ROOTFS} apt-get install ${PACKAGES[*]} -y --force-yes
chroot ${ROOTFS} apt-get upgrade -y --force-yes
##################################################################################
# 6 - Configuration management tools
if [ $CHEF = 1 ]; then
./common/install-chef $ROOTFS
fi
if [ $PUPPET = 1 ]; then
./common/install-puppet $ROOTFS
fi
if [ $SALT = 1 ]; then
./common/install-salt-debian $ROOTFS
fi
if [ $BABUSHKA = 1 ]; then
./common/install-babushka $ROOTFS
fi
##################################################################################
# 7 - Free up some disk space
rm -rf ${ROOTFS}/tmp/*
chroot ${ROOTFS} apt-get clean
##################################################################################
# 8 - Build box package
# Compress container's rootfs
cd $(dirname $ROOTFS)
tar --numeric-owner -czf /tmp/vagrant-lxc-${RELEASE}/rootfs.tar.gz ./rootfs/*
# Prepare package contents
cd $WORKING_DIR
cp $LXC_TEMPLATE .
cp $LXC_CONF .
cp $METATADA_JSON .
chmod +x lxc-template
sed -i "s/<TODAY>/${NOW}/" metadata.json
# Vagrant box!
tar -czf $PKG ./*
chmod +rw ${WORKING_DIR}/${PKG}
mkdir -p ${CWD}/output
mv ${WORKING_DIR}/${PKG} ${CWD}/output
# Clean up after ourselves
rm -rf ${WORKING_DIR}
echo "The base box was built successfully to ${CWD}/output/${PKG}"

View file

@ -0,0 +1,159 @@
#!/bin/bash
# set -x
set -e
# Script used to build OpenMandriva base vagrant-lxc containers, currently limited to
# host's arch
#
# USAGE:
# $ cd boxes && sudo ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH
#
# TODO: scripts for install CHEF, PUPPET, SALT, BABUSHKA
# To enable Chef or any other configuration management tool pass '1' to the
# corresponding env var:
# $ CHEF=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH
# $ PUPPET=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH
# $ SALT=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH
# $ BABUSHKA=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH
##################################################################################
# 0 - Initial setup and sanity checks
TODAY=$(date -u +"%Y-%m-%d")
NOW=$(date -u)
RELEASE=${1:-"openmandriva2013.0"}
ARCH=${2:-"x86_64"}
PKG=vagrant-lxc-${RELEASE}-${ARCH}-${TODAY}.box
WORKING_DIR=/tmp/vagrant-lxc-${RELEASE}
VAGRANT_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key"
ROOTFS=/var/lib/lxc/${RELEASE}-base/${RELEASE}-base/rootfs
# Providing '1' will enable these tools
CHEF=${CHEF:-0}
PUPPET=${PUPPET:-0}
SALT=${SALT:-0}
BABUSHKA=${BABUSHKA:-0}
# Path to files bundled with the box
CWD=`readlink -f .`
LXC_TEMPLATE=${CWD}/common/lxc-template-openmandriva
LXC_CONF=${CWD}/common/lxc.conf
METATADA_JSON=${CWD}/common/metadata.json
# Set up a working dir
mkdir -p $WORKING_DIR
if [ -f "${WORKING_DIR}/${PKG}" ]; then
echo "Found a box on ${WORKING_DIR}/${PKG} already!"
exit 1
fi
##################################################################################
# 1 - Create the base container
if $(lxc-ls | grep -q "${RELEASE}-base"); then
echo "Base container already exists, please remove it with \`lxc-destroy -n ${RELEASE}-base\`!"
exit 1
else
export SUITE=$RELEASE
lxc-create -n ${RELEASE}-base -t openmandriva -- -R ${RELEASE} --arch ${ARCH}
fi
######################################
# 2 - Fix some known issues
# Fixes some networking issues
cat /etc/resolv.conf > ${ROOTFS}/etc/resolv.conf
##################################################################################
# 3 - Prepare vagrant user
chroot ${ROOTFS} su -c 'useradd --create-home -s /bin/bash vagrant'
# echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd
chroot ${ROOTFS} su -c "echo -n 'vagrant:vagrant' | chpasswd"
##################################################################################
# 4 - Setup SSH access and passwordless sudo
# Configure SSH access
mkdir -p ${ROOTFS}/home/vagrant/.ssh
echo $VAGRANT_KEY > ${ROOTFS}/home/vagrant/.ssh/authorized_keys
chroot ${ROOTFS} chown -R vagrant: /home/vagrant/.ssh
chroot ${ROOTFS} urpmi sudo --auto
chroot ${ROOTFS} usermod -a -G wheel vagrant
# Enable passwordless sudo for users under the "sudo" group
cp ${ROOTFS}/etc/sudoers{,.orig}
sed -i 's/Defaults requiretty/\# Defaults requiretty/' ${ROOTFS}/etc/sudoers
sed -i 's/\#%wheel/\%wheel/' ${ROOTFS}/etc/sudoers
sed -i 's/\# %wheel/\%wheel/' ${ROOTFS}/etc/sudoers
# sed -i -e \
# 's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \
# ${ROOTFS}/etc/sudoers
##################################################################################
# 5 - Add some goodies and update packages
PACKAGES=(vim curl wget man bash-completion openssh-server openssh-clients tar)
chroot ${ROOTFS} urpmi ${PACKAGES[*]} --auto
chroot ${ROOTFS} urpmi.update -a
##################################################################################
# 6 - Configuration management tools
if [ $CHEF = 1 ]; then
./common/install-chef $ROOTFS
fi
if [ $PUPPET = 1 ]; then
./common/install-puppet $ROOTFS
fi
if [ $SALT = 1 ]; then
./common/install-salt $ROOTFS
fi
if [ $BABUSHKA = 1 ]; then
./common/install-babushka $ROOTFS
fi
##################################################################################
# 7 - Free up some disk space
rm -rf ${ROOTFS}/tmp/*
# chroot ${ROOTFS} urpmi clean metadata
##################################################################################
# 8 - Build box package
# Compress container's rootfs
cd $(dirname $ROOTFS)
tar --numeric-owner -czf /tmp/vagrant-lxc-${RELEASE}/rootfs.tar.gz ./rootfs/*
# Prepare package contents
cd $WORKING_DIR
cp $LXC_TEMPLATE lxc-template
cp $LXC_CONF .
cp $METATADA_JSON .
chmod +x lxc-template
sed -i "s/<TODAY>/${NOW}/" metadata.json
# Vagrant box!
tar -czf $PKG ./*
chmod +rw ${WORKING_DIR}/${PKG}
mkdir -p ${CWD}/output
mv ${WORKING_DIR}/${PKG} ${CWD}/output
# Clean up after ourselves
rm -rf ${WORKING_DIR}
echo "The base box was built successfully to ${CWD}/output/${PKG}"

151
boxes/build-ubuntu-box.sh Executable file
View file

@ -0,0 +1,151 @@
#!/bin/bash
# set -x
set -e
# Script used to build Ubuntu base vagrant-lxc containers
#
# USAGE:
# $ cd boxes && sudo ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH
#
# To enable Chef or any other configuration management tool pass '1' to the
# corresponding env var:
# $ CHEF=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH
# $ PUPPET=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH
# $ SALT=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH
# $ BABUSHKA=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH
##################################################################################
# 0 - Initial setup and sanity checks
TODAY=$(date -u +"%Y-%m-%d")
NOW=$(date -u)
RELEASE=${1:-"raring"}
ARCH=${2:-"amd64"}
PKG=vagrant-lxc-${RELEASE}-${ARCH}-${TODAY}.box
WORKING_DIR=/tmp/vagrant-lxc-${RELEASE}
VAGRANT_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key"
ROOTFS=/var/lib/lxc/${RELEASE}-base/rootfs
# Providing '1' will enable these tools
CHEF=${CHEF:-0}
PUPPET=${PUPPET:-0}
SALT=${SALT:-0}
BABUSHKA=${BABUSHKA:-0}
# Path to files bundled with the box
CWD=`readlink -f .`
LXC_TEMPLATE=${CWD}/common/lxc-template
LXC_CONF=${CWD}/common/lxc.conf
METATADA_JSON=${CWD}/common/metadata.json
# Set up a working dir
mkdir -p $WORKING_DIR
if [ -f "${WORKING_DIR}/${PKG}" ]; then
echo "Found a box on ${WORKING_DIR}/${PKG} already!"
exit 1
fi
##################################################################################
# 1 - Create the base container
if $(lxc-ls | grep -q "${RELEASE}-base"); then
echo "Base container already exists, please remove it with \`lxc-destroy -n ${RELEASE}-base\`!"
exit 1
else
lxc-create -n ${RELEASE}-base -t ubuntu -- --release ${RELEASE} --arch ${ARCH}
fi
# Fixes some networking issues
# See https://github.com/fgrehm/vagrant-lxc/issues/91 for more info
echo 'ff02::3 ip6-allhosts' >> ${ROOTFS}/etc/hosts
##################################################################################
# 2 - Prepare vagrant user
mv ${ROOTFS}/home/{ubuntu,vagrant}
chroot ${ROOTFS} usermod -l vagrant -d /home/vagrant ubuntu
chroot ${ROOTFS} groupmod -n vagrant ubuntu
echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd
##################################################################################
# 3 - Setup SSH access and passwordless sudo
# Configure SSH access
mkdir -p ${ROOTFS}/home/vagrant/.ssh
echo $VAGRANT_KEY > ${ROOTFS}/home/vagrant/.ssh/authorized_keys
chroot ${ROOTFS} chown -R vagrant: /home/vagrant/.ssh
# Enable passwordless sudo for users under the "sudo" group
cp ${ROOTFS}/etc/sudoers{,.orig}
sed -i -e \
's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \
${ROOTFS}/etc/sudoers
##################################################################################
# 4 - Add some goodies and update packages
PACKAGES=(vim curl wget man-db bash-completion)
chroot ${ROOTFS} apt-get install ${PACKAGES[*]} -y --force-yes
chroot ${ROOTFS} apt-get upgrade -y --force-yes
##################################################################################
# 5 - Configuration management tools
if [ $CHEF = 1 ]; then
./common/install-chef $ROOTFS
fi
if [ $PUPPET = 1 ]; then
./common/install-puppet $ROOTFS
fi
if [ $SALT = 1 ]; then
./common/install-salt $ROOTFS
fi
if [ $BABUSHKA = 1 ]; then
./common/install-babushka $ROOTFS
fi
##################################################################################
# 6 - Free up some disk space
rm -rf ${ROOTFS}/tmp/*
chroot ${ROOTFS} apt-get clean
##################################################################################
# 7 - Build box package
# Compress container's rootfs
cd $(dirname $ROOTFS)
tar --numeric-owner -czf /tmp/vagrant-lxc-${RELEASE}/rootfs.tar.gz ./rootfs/*
# Prepare package contents
cd $WORKING_DIR
cp $LXC_TEMPLATE .
cp $LXC_CONF .
cp $METATADA_JSON .
chmod +x lxc-template
sed -i "s/<TODAY>/${NOW}/" metadata.json
# Vagrant box!
tar -czf $PKG ./*
chmod +rw ${WORKING_DIR}/${PKG}
mkdir -p ${CWD}/output
mv ${WORKING_DIR}/${PKG} ${CWD}/output
# Clean up after ourselves
rm -rf ${WORKING_DIR}
lxc-destroy -n ${RELEASE}-base
echo "The base box was built successfully to ${CWD}/output/${PKG}"

7
boxes/common/cleanup Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
cache=`readlink -f .`
rootfs="${cache}/rootfs"
rm -rf $rootfs/tmp/*
chroot $rootfs apt-get clean

16
boxes/common/install-babushka Executable file
View file

@ -0,0 +1,16 @@
#!/bin/bash
set -e
rootfs=$1
echo "installing babushka"
cat > $rootfs/tmp/install-babushka.sh << EOF
#!/bin/sh
curl https://babushka.me/up | sudo bash
EOF
chmod +x $rootfs/tmp/install-babushka.sh
chroot $rootfs /tmp/install-babushka.sh
rm -rf $rootfs/tmp/*

15
boxes/common/install-chef Executable file
View file

@ -0,0 +1,15 @@
#!/bin/bash
set -e
rootfs=$1
echo "installing chef"
cat > $rootfs/tmp/install-chef.sh << EOF
#!/bin/sh
curl -L https://www.opscode.com/chef/install.sh -k | sudo bash
EOF
chmod +x $rootfs/tmp/install-chef.sh
chroot $rootfs /tmp/install-chef.sh
rm -rf $rootfs/tmp/*

13
boxes/common/install-puppet Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
set -e
rootfs=$1
echo "installing puppet"
wget http://apt.puppetlabs.com/puppetlabs-release-stable.deb -O "${rootfs}/tmp/puppetlabs-release-stable.deb"
chroot $rootfs dpkg -i "/tmp/puppetlabs-release-stable.deb"
chroot $rootfs apt-get update
chroot $rootfs apt-get install puppet -y --force-yes
rm -rf $rootfs/tmp/*

12
boxes/common/install-salt Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
set -e
rootfs=$1
echo "installing salt"
chroot $rootfs apt-add-repository -y ppa:saltstack/salt
chroot $rootfs apt-get update
chroot $rootfs apt-get install salt-minion -y --force-yes
rm -rf $rootfs/tmp/*

View file

@ -0,0 +1,28 @@
#!/bin/bash
set -e
rootfs=$1
echo "installing salt"
if [ $SUITE == "squeeze" ]; then
SALT_SOURCE="deb http://debian.saltstack.com/debian squeeze-saltstack main\ndeb http://backports.debian.org/debian-backports squeeze-backports main contrib non-free"
elif [ $SUITE == "sid" ]; then
SALT_SOURCE="deb http://debian.saltstack.com/debian unstable main"
else
SALT_SOURCE="deb http://debian.saltstack.com/debian wheezy-saltstack main"
fi
cat > $rootfs/tmp/install-salt << EOF
#!/bin/sh
echo "$SALT_SOURCE" > /etc/apt/sources.list.d/saltstack.list
wget -q -O- "http://debian.saltstack.com/debian-salt-team-joehealy.gpg.key" | apt-key add -
apt-get update
apt-get install -y salt-minion
apt-get clean
EOF
chroot $rootfs sh /tmp/install-salt
rm -rf $rootfs/tmp/*

226
boxes/common/lxc-template Executable file
View file

@ -0,0 +1,226 @@
#!/bin/bash
# This is a modified version of /usr/share/lxc/templates/lxc-ubuntu
# that comes with Ubuntu 13.04 changed to suit vagrant-lxc needs
#
# template script for generating ubuntu container for LXC
#
# This script consolidates and extends the existing lxc ubuntu scripts
#
# Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com>
# Copyright © 2010 Wilhelm Meier
# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
set -e
if [ -r /etc/default/lxc ]; then
. /etc/default/lxc
fi
extract_rootfs()
{
tarball=$1
arch=$2
rootfs=$3
echo "Extracting $tarball ..."
mkdir -p $rootfs
(cd $rootfs && tar xfz $tarball --strip-components=2)
return 0
}
install_ubuntu()
{
rootfs=$1
release=$2
tarball=$3
mkdir -p /var/lock/subsys/
(
flock -x 200
if [ $? -ne 0 ]; then
echo "Cache repository is busy."
return 1
fi
extract_rootfs $tarball $arch $rootfs
if [ $? -ne 0 ]; then
echo "Failed to copy rootfs"
return 1
fi
return 0
) 200>/var/lock/subsys/lxc
return $?
}
copy_configuration()
{
path=$1
rootfs=$2
name=$3
grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
# if there is exactly one veth network entry, make sure it has an
# associated hwaddr.
nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
if [ $nics -eq 1 ]; then
grep -q "^lxc.network.hwaddr" $path/config || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" $path/config
fi
if [ $? -ne 0 ]; then
echo "Failed to add configuration"
return 1
fi
return 0
}
post_process()
{
rootfs=$1
# rmdir /dev/shm for containers that have /run/shm
# I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
# get bind mounted to the host's /run/shm. So try to rmdir
# it, and in case that fails move it out of the way.
if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then
mv $rootfs/dev/shm $rootfs/dev/shm.bak
ln -s /run/shm $rootfs/dev/shm
fi
}
usage()
{
cat <<EOF
$1 -h|--help [-a|--arch] [--trim] [-d|--debug] [--rootfs <rootfs>] [-T|--tarball <rootfs-tarball>
arch: the container architecture (e.g. amd64): defaults to host arch
EOF
return 0
}
options=$(getopt -o a:b:hp:r:xn:FS:d:C -l arch:,help,path:,release:,trim,name:,flush-cache,auth-key:,debug:,tarball:,rootfs: -- "$@")
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
fi
eval set -- "$options"
release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems
if [ -f /etc/lsb-release ]; then
. /etc/lsb-release
if [ "$DISTRIB_ID" = "Ubuntu" ]; then
release=$DISTRIB_CODENAME
fi
fi
arch=$(uname -m)
# Code taken from debootstrap
if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
arch=`/usr/bin/dpkg --print-architecture`
elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
arch=`/usr/bin/udpkg --print-architecture`
else
arch=$(uname -m)
if [ "$arch" = "i686" ]; then
arch="i386"
elif [ "$arch" = "x86_64" ]; then
arch="amd64"
elif [ "$arch" = "armv7l" ]; then
arch="armel"
fi
fi
debug=0
trim_container=0
hostarch=$arch
while true
do
case "$1" in
-h|--help) usage $0 && exit 0;;
--rootfs) rootfs=$2; shift 2;;
-p|--path) path=$2; shift 2;;
-n|--name) name=$2; shift 2;;
-T|--tarball) tarball=$2; shift 2;;
-a|--arch) arch=$2; shift 2;;
-S|--auth-key) auth_key=$2; shift 2;;
-d|--debug) debug=1; shift 1;;
--) shift 1; break ;;
*) break ;;
esac
done
if [ $debug -eq 1 ]; then
set -x
fi
if [ "$arch" == "i686" ]; then
arch=i386
fi
if [ $hostarch = "i386" -a $arch = "amd64" ]; then
echo "can't create amd64 container on i386"
exit 1
fi
if [ -z "$path" ]; then
echo "'path' parameter is required"
exit 1
fi
if [ "$(id -u)" != "0" ]; then
echo "This script should be run as 'root'"
exit 1
fi
# detect rootfs
config="$path/config"
# if $rootfs exists here, it was passed in with --rootfs
if [ -z "$rootfs" ]; then
if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'`
else
rootfs=$path/rootfs
fi
fi
install_ubuntu $rootfs $release $tarball
if [ $? -ne 0 ]; then
echo "failed to install ubuntu $release"
exit 1
fi
copy_configuration $path $rootfs $name $arch
if [ $? -ne 0 ]; then
echo "failed write configuration file"
exit 1
fi
post_process $rootfs $release $trim_container
echo ""
echo "##"
echo "# The default user is 'vagrant' with password 'vagrant'!"
echo "# Use the 'sudo' command to run tasks as root in the container."
echo "##"
echo ""

View file

@ -0,0 +1,225 @@
#!/bin/bash
# This is a modified version of /usr/share/lxc/templates/lxc-openmandriva
# that comes with OpenMandriva changed to suit vagrant-lxc needs
#
# template script for generating openmandriva container for LXC
#
#
# lxc: linux Container library
# Authors:
# Alexander Khryukin <alexander@mezon.ru>
# Vokhmin Alexey V <avokhmin@gmail.com>
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
set -e
if [ -r /etc/default/lxc ]; then
. /etc/default/lxc
fi
extract_rootfs()
{
tarball=$1
arch=$2
rootfs=$3
echo "Extracting $tarball ..."
mkdir -p $(dirname $rootfs)
(cd `dirname $rootfs` && tar xfz $tarball)
return 0
}
install_openmandriva()
{
rootfs=$1
release=$2
tarball=$3
mkdir -p /var/lock/subsys/
(
flock -x 200
if [ $? -ne 0 ]; then
echo "Cache repository is busy."
return 1
fi
extract_rootfs $tarball $arch $rootfs
if [ $? -ne 0 ]; then
echo "Failed to copy rootfs"
return 1
fi
return 0
) 200>/var/lock/subsys/lxc
return $?
}
copy_configuration()
{
path=$1
rootfs=$2
name=$3
grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
# if there is exactly one veth network entry, make sure it has an
# associated hwaddr.
nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
if [ $nics -eq 1 ]; then
grep -q "^lxc.network.hwaddr" $path/config || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" $path/config
fi
if [ $? -ne 0 ]; then
echo "Failed to add configuration"
return 1
fi
return 0
}
post_process()
{
rootfs=$1
# rmdir /dev/shm for containers that have /run/shm
# I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
# get bind mounted to the host's /run/shm. So try to rmdir
# it, and in case that fails move it out of the way.
if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then
mv $rootfs/dev/shm $rootfs/dev/shm.bak
ln -s /run/shm $rootfs/dev/shm
fi
}
usage()
{
cat <<EOF
usage:
$1 -n|--name=<container_name>
[-p|--path=<path>] [-c|--clean] [-R|--release=<openmandriva2013.0/rosa2012.1/cooker/ release>]
[-4|--ipv4=<ipv4 address>] [-6|--ipv6=<ipv6 address>]
[-g|--gw=<gw address>] [-d|--dns=<dns address>]
[-P|--profile=<name of the profile>] [--rootfs=<path>]
[-A|--arch=<arch of the container>]
[-T|--tarball <tarball path>]
[-S|--auth-key <auth-key path>]
[-h|--help]
Mandatory args:
-n,--name container name, used to as an identifier for that container from now on
Optional args:
-p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case
-c,--clean clean the cache
-R,--release openmandriva2013.0/cooker/rosa2012.1 release for the new container. if the host is OpenMandriva, then it will default to the host's release.
-4,--ipv4 specify the ipv4 address to assign to the virtualized interface, eg. 192.168.1.123/24
-6,--ipv6 specify the ipv6 address to assign to the virtualized interface, eg. 2003:db8:1:0:214:1234:fe0b:3596/64
-g,--gw specify the default gw, eg. 192.168.1.1
-G,--gw6 specify the default gw, eg. 2003:db8:1:0:214:1234:fe0b:3596
-d,--dns specify the DNS server, eg. 192.168.1.2
-P,--profile Profile name is the file name in /etc/lxc/profiles contained packages name for install to cache.
-A,--arch Define what arch the container will be [i586,x86_64,armv7l,armv7hl]
---rootfs rootfs path
-h,--help print this help
EOF
return 0
}
options=$(getopt -o hp:n:P:cR:4:6:g:d:A:S:T: -l help,rootfs:,path:,name:,profile:,clean:,release:,ipv4:,ipv6:,gw:,dns:,arch:,auth-key:,tarball: -- "$@")
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
fi
eval set -- "$options"
# doesn't use
release=${release:-"cooker"}
hostarch=$(uname -m)
while true
do
case "$1" in
-h|--help) usage $0 && exit 0;;
-p|--path) path=$2; shift 2;;
--rootfs) rootfs_path=$2; shift 2;;
-n|--name) name=$2; shift 2;;
-P|--profile) profile=$2; shift 2;;
-c|--clean) clean=$2; shift 2;;
-R|--release) release=$2; shift 2;;
-T|--tarball) tarball=$2; shift 2;;
-S|--auth-key) auth_key=$2; shift 2;;
-A|--arch) arch=$2; shift 2;;
-4|--ipv4) ipv4=$2; shift 2;;
-6|--ipv6) ipv6=$2; shift 2;;
-g|--gw) gw=$2; shift 2;;
-d|--dns) dns=$2; shift 2;;
--) shift 1; break ;;
*) break ;;
esac
done
arch=${arch:-$hostarch}
if [ $hostarch = "i586" -a $arch = "x86_64" ]; then
echo "can't create x86_64 container on i586"
exit 1
fi
if [ -z "$path" ]; then
echo "'path' parameter is required"
exit 1
fi
if [ "$(id -u)" != "0" ]; then
echo "This script should be run as 'root'"
exit 1
fi
# detect rootfs
config="$path/config"
# if $rootfs exists here, it was passed in with --rootfs
if [ -z "$rootfs" ]; then
if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'`
else
rootfs=$path/rootfs
fi
fi
install_openmandriva $rootfs $release $tarball
if [ $? -ne 0 ]; then
echo "failed to install openmandriva $release"
exit 1
fi
copy_configuration $path $rootfs $name $arch
if [ $? -ne 0 ]; then
echo "failed write configuration file"
exit 1
fi
post_process $rootfs $release
echo ""
echo "##"
echo "# The default user is 'vagrant' with password 'vagrant'!"
echo "# Use the 'sudo' command to run tasks as root in the container."
echo "##"
echo ""

49
boxes/common/lxc.conf Normal file
View file

@ -0,0 +1,49 @@
lxc.network.type=veth
lxc.network.link=lxcbr0
lxc.network.flags=up
lxc.pivotdir = lxc_putold
lxc.devttydir = lxc
lxc.tty = 4
lxc.pts = 1024
lxc.arch = amd64
lxc.cap.drop = sys_module mac_admin mac_override
# When using LXC with apparmor, uncomment the next line to run unconfined:
#lxc.aa_profile = unconfined
lxc.cgroup.devices.deny = a
# Allow any mknod (but not using the node)
lxc.cgroup.devices.allow = c *:* m
lxc.cgroup.devices.allow = b *:* m
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
#lxc.cgroup.devices.allow = c 4:0 rwm
#lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
#fuse
lxc.cgroup.devices.allow = c 10:229 rwm
#tun
lxc.cgroup.devices.allow = c 10:200 rwm
#full
lxc.cgroup.devices.allow = c 1:7 rwm
#hpet
lxc.cgroup.devices.allow = c 10:228 rwm
#kvm
lxc.cgroup.devices.allow = c 10:232 rwm
# mounts point
lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
lxc.mount.entry = sysfs sys sysfs defaults 0 0

View file

@ -0,0 +1,5 @@
{
"provider": "lxc",
"version": "3",
"built-on": "<TODAY>"
}

94
development/Vagrantfile vendored Normal file
View file

@ -0,0 +1,94 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
require 'pathname'
BASE_URL = 'http://bit.ly/'
LAST_RELEASE_DATE = '2013-09-28'
LOCAL_BOXES_PATH = Pathname('../boxes/output').expand_path
def lxc_box_url(release_name)
box_name = "vagrant-lxc-#{release_name}-amd64-#{LAST_RELEASE_DATE}"
local_box_file = LOCAL_BOXES_PATH.join("#{box_name}.box")
local_box_file.exist? ?
local_box_file.to_s :
"#{BASE_URL}/#{box_name}"
end
BOXES = {
precise: {
lxc_url: lxc_box_url('precise'),
vbox_url: 'http://files.vagrantup.com/precise64.box'
},
quantal: {
lxc_url: lxc_box_url('quantal'),
vbox_url: 'https://github.com/downloads/roderik/VagrantQuantal64Box/quantal64.box'
},
raring: {
lxc_url: lxc_box_url('raring'),
vbox_url: 'http://cloud-images.ubuntu.com/vagrant/raring/current/raring-server-cloudimg-amd64-vagrant-disk1.box'
},
saucy: {
vbox_url: 'http://cloud-images.ubuntu.com/vagrant/saucy/current/saucy-server-cloudimg-amd64-vagrant-disk1.box'
},
squeeze: {
lxc_url: lxc_box_url('squeeze'),
# https://gist.github.com/henare/1964037
vbox_url: 'http://dl.dropbox.com/u/174733/debian-squeeze-64.box'
},
wheezy: {
lxc_url: lxc_box_url('wheezy'),
vbox_url: 'http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210.box'
},
sid: {
lxc_url: lxc_box_url('sid'),
}
}
Vagrant.require_plugin 'vagrant-lxc'
Vagrant.require_plugin 'vagrant-cachier'
Vagrant.require_plugin 'vagrant-pristine'
Vagrant.configure("2") do |config|
config.vm.synced_folder "../", "/vagrant", id: 'vagrant-root', nfs: true
config.cache.scope = :machine
config.cache.auto_detect = true
config.cache.enable_nfs = true
ip_suffix = 30
BOXES.each do |box_name, box_config|
config.vm.define(box_name.to_sym) do |vm_config|
vm_config.vm.network :private_network, ip: "192.168.50.#{ip_suffix += 1}"
vm_config.vm.box = "#{box_name}64"
if box_config[:vbox_url]
vm_config.vm.provider :virtualbox do |vb, vb_config|
vb_config.vm.box_url = box_config[:vbox_url]
vb_config.vm.hostname = 'vbox'
vb.customize [
"modifyvm", :id,
"--memory", '1536',
"--cpus", '2'
]
end
end
if box_config[:lxc_url]
vm_config.vm.provider :lxc do |lxc, lxc_config|
lxc_config.vm.box_url = box_config[:lxc_url]
lxc_config.vm.hostname = 'lxc-dev-box'
# Required to boot nested containers
lxc.customize 'aa_profile', 'unconfined' unless %w(squeeze wheezy sid).include? box_name.to_s
end
end
end
end
config.vm.provision :puppet do |puppet|
puppet.manifests_path = "."
puppet.manifest_file = "site.pp"
puppet.options << [ '--verbose', '--debug' ]
end
end

View file

@ -0,0 +1,37 @@
###############################################################################
# This file has the same configs as the built in /etc/default/lxc on Ubuntu,
# we only changed IPs to 10.0.254.* to avoid collision with LXC default 10.0.3.*
# which is likely to be running from the host machine
###############################################################################
# MIRROR to be used by ubuntu template at container creation:
# Leaving it undefined is fine
#MIRROR="http://archive.ubuntu.com/ubuntu"
# or
#MIRROR="http://<host-ip-addr>:3142/archive.ubuntu.com/ubuntu"
# LXC_AUTO - whether or not to start containers symlinked under
# /etc/lxc/auto
LXC_AUTO="true"
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
# containers. Set to "false" if you'll use virbr0 or another existing
# bridge, or mavlan to your host's NIC.
USE_LXC_BRIDGE="true"
# If you change the LXC_BRIDGE to something other than lxcbr1, then
# you will also need to update your /etc/lxc/lxc.conf as well as the
# configuration (/var/lib/lxc/<container>/config) for any containers
# already created using the default config to reflect the new bridge
# name.
# If you have the dnsmasq daemon installed, you'll also have to update
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.253.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.253.0/24"
LXC_DHCP_RANGE="10.0.253.2,10.0.253.254"
LXC_DHCP_MAX="253"
LXC_SHUTDOWN_TIMEOUT=120

View file

@ -0,0 +1,37 @@
###############################################################################
# This file has the same configs as the built in /etc/default/lxc on Ubuntu,
# we only changed IPs to 10.0.254.* to avoid collision with LXC default 10.0.3.*
# which is likely to be running from the host machine
###############################################################################
# MIRROR to be used by ubuntu template at container creation:
# Leaving it undefined is fine
#MIRROR="http://archive.ubuntu.com/ubuntu"
# or
#MIRROR="http://<host-ip-addr>:3142/archive.ubuntu.com/ubuntu"
# LXC_AUTO - whether or not to start containers symlinked under
# /etc/lxc/auto
LXC_AUTO="true"
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
# containers. Set to "false" if you'll use virbr0 or another existing
# bridge, or mavlan to your host's NIC.
USE_LXC_BRIDGE="true"
# If you change the LXC_BRIDGE to something other than lxcbr1, then
# you will also need to update your /etc/lxc/lxc.conf as well as the
# configuration (/var/lib/lxc/<container>/config) for any containers
# already created using the default config to reflect the new bridge
# name.
# If you have the dnsmasq daemon installed, you'll also have to update
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.251.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.251.0/24"
LXC_DHCP_RANGE="10.0.253.2,10.0.251.254"
LXC_DHCP_MAX="253"
LXC_SHUTDOWN_TIMEOUT=120

View file

@ -0,0 +1,37 @@
###############################################################################
# This file has the same configs as the built in /etc/default/lxc on Ubuntu,
# we only changed IPs to 10.0.254.* to avoid collision with LXC default 10.0.3.*
# which is likely to be running from the host machine
###############################################################################
# MIRROR to be used by ubuntu template at container creation:
# Leaving it undefined is fine
#MIRROR="http://archive.ubuntu.com/ubuntu"
# or
#MIRROR="http://<host-ip-addr>:3142/archive.ubuntu.com/ubuntu"
# LXC_AUTO - whether or not to start containers symlinked under
# /etc/lxc/auto
LXC_AUTO="true"
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
# containers. Set to "false" if you'll use virbr0 or another existing
# bridge, or mavlan to your host's NIC.
USE_LXC_BRIDGE="true"
# If you change the LXC_BRIDGE to something other than lxcbr1, then
# you will also need to update your /etc/lxc/lxc.conf as well as the
# configuration (/var/lib/lxc/<container>/config) for any containers
# already created using the default config to reflect the new bridge
# name.
# If you have the dnsmasq daemon installed, you'll also have to update
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.250.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.250.0/24"
LXC_DHCP_RANGE="10.0.253.2,10.0.250.254"
LXC_DHCP_MAX="253"
LXC_SHUTDOWN_TIMEOUT=120

View file

@ -0,0 +1,37 @@
###############################################################################
# This file has the same configs as the built in /etc/default/lxc on Ubuntu,
# we only changed IPs to 10.0.254.* to avoid collision with LXC default 10.0.3.*
# which is likely to be running from the host machine
###############################################################################
# MIRROR to be used by ubuntu template at container creation:
# Leaving it undefined is fine
#MIRROR="http://archive.ubuntu.com/ubuntu"
# or
#MIRROR="http://<host-ip-addr>:3142/archive.ubuntu.com/ubuntu"
# LXC_AUTO - whether or not to start containers symlinked under
# /etc/lxc/auto
LXC_AUTO="true"
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
# containers. Set to "false" if you'll use virbr0 or another existing
# bridge, or mavlan to your host's NIC.
USE_LXC_BRIDGE="true"
# If you change the LXC_BRIDGE to something other than lxcbr1, then
# you will also need to update your /etc/lxc/lxc.conf as well as the
# configuration (/var/lib/lxc/<container>/config) for any containers
# already created using the default config to reflect the new bridge
# name.
# If you have the dnsmasq daemon installed, you'll also have to update
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.254.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.254.0/24"
LXC_DHCP_RANGE="10.0.254.2,10.0.254.254"
LXC_DHCP_MAX="253"
LXC_SHUTDOWN_TIMEOUT=120

View file

@ -0,0 +1,37 @@
###############################################################################
# This file has the same configs as the built in /etc/default/lxc on Ubuntu,
# we only changed IPs to 10.0.254.* to avoid collision with LXC default 10.0.3.*
# which is likely to be running from the host machine
###############################################################################
# MIRROR to be used by ubuntu template at container creation:
# Leaving it undefined is fine
#MIRROR="http://archive.ubuntu.com/ubuntu"
# or
#MIRROR="http://<host-ip-addr>:3142/archive.ubuntu.com/ubuntu"
# LXC_AUTO - whether or not to start containers symlinked under
# /etc/lxc/auto
LXC_AUTO="true"
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
# containers. Set to "false" if you'll use virbr0 or another existing
# bridge, or mavlan to your host's NIC.
USE_LXC_BRIDGE="true"
# If you change the LXC_BRIDGE to something other than lxcbr1, then
# you will also need to update your /etc/lxc/lxc.conf as well as the
# configuration (/var/lib/lxc/<container>/config) for any containers
# already created using the default config to reflect the new bridge
# name.
# If you have the dnsmasq daemon installed, you'll also have to update
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.252.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.252.0/24"
LXC_DHCP_RANGE="10.0.253.2,10.0.252.254"
LXC_DHCP_MAX="253"
LXC_SHUTDOWN_TIMEOUT=120

151
development/site.pp Normal file
View file

@ -0,0 +1,151 @@
Exec { path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/', '/usr/local/bin'] }
stage { 'preinstall':
before => Stage['main']
}
class apt_get_update {
exec { 'apt-get -y update':
unless => "test -f /etc/default/lxc"
}
}
class { 'apt_get_update':
stage => preinstall
}
# Because I'm lazy ;)
exec {
'echo "alias be=\"bundle exec\"" >> /home/vagrant/.bashrc':
unless => 'grep -q "bundle exec" /home/vagrant/.bashrc';
'echo "export VAGRANT_DEFAULT_PROVIDER=lxc" >> /home/vagrant/.bashrc':
unless => 'grep -q "VAGRANT_DEFAULT_PROVIDER" /home/vagrant/.bashrc';
'echo "cd /vagrant" >> /home/vagrant/.bashrc':
unless => 'grep -q "cd /vagrant" /home/vagrant/.bashrc';
}
# Overwrite LXC default configs
exec {
'config-lxc':
# We need to do this otherwise IPs will collide with the host's lxc dhcp server.
# If we install the package prior to setting this configs the container will go crazy.
command => "cp /vagrant/development/lxc-configs/${hostname} /etc/default/lxc"
;
}
# Install dependencies
package {
[ 'libffi-dev', 'bsdtar', 'exuberant-ctags', 'ruby1.9.1-dev', 'htop', 'git',
'build-essential', 'redir', 'curl', 'vim', 'btrfs-tools', 'psmisc' ]:
ensure => 'installed'
;
'lxc':
require => Exec['config-lxc']
;
'bundler':
ensure => 'installed',
provider => 'gem'
;
}
# Upgrade kernel if needed
package {
[ 'linux-image-generic', 'linux-headers-generic' ]:
ensure => 'latest'
}
# Make sure we can create and boot nested containers
if $hostname == 'vbox' {
package { 'apparmor-utils': }
exec { 'aa-complain /usr/bin/lxc-start': }
}
# Allow gems to be installed on vagrant user home avoiding "sudo"s
# Tks to http://wiki.railsplayground.com/railsplayground/show/How+to+install+gems+and+non+root+user
file {
'/home/vagrant/gems':
ensure => directory,
owner => 'vagrant',
group => 'vagrant'
;
'/home/vagrant/.gemrc':
content => '
---
:verbose: true
gem: --no-ri --no-rdoc
:update_sources: true
:sources:
- http://gems.rubyforge.org
- http://gems.github.com
:backtrace: false
:bulk_threshold: 1000
:benchmark: false
gemhome: /home/vagrant/gems
gempath:
- /home/vagrant/gems
- /var/lib/gems/1.9.1
'
}
exec {
'set-gem-paths':
command => 'cat << EOF >> /home/vagrant/.profile
export GEM_HOME=/home/vagrant/gems
export GEM_PATH=/home/vagrant/gems:/var/lib/gems/1.9.1
export PATH=$PATH:/home/vagrant/gems/bin
EOF',
unless => 'grep -q "GEM_HOME" /home/vagrant/.profile'
}
# Bundle!
exec {
'su -l vagrant -c "cd /vagrant && bundle install"':
# We are checking for guard-rspec here but it could be any gem...
unless => 'gem list guard | grep -q rspec',
cwd => '/vagrant',
require => [
Exec['set-gem-paths'],
File['/home/vagrant/gems', '/home/vagrant/.gemrc'],
Package['bundler']
]
}
# Setup vagrant default ssh key
file {
'/home/vagrant/.ssh':
ensure => directory,
owner => 'vagrant',
group => 'vagrant'
}
exec {
'download-private-key':
command => 'wget https://raw.github.com/mitchellh/vagrant/master/keys/vagrant -O /home/vagrant/.ssh/id_rsa',
creates => '/home/vagrant/.ssh/id_rsa',
require => File['/home/vagrant/.ssh'],
user => 'vagrant'
;
'wget https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub -O /home/vagrant/.ssh/id_rsa.pub':
creates => '/home/vagrant/.ssh/id_rsa.pub',
require => File['/home/vagrant/.ssh'],
user => 'vagrant'
;
}
file {
'/home/vagrant/.ssh/id_rsa':
ensure => 'present',
mode => '0600',
require => Exec['download-private-key']
}
# Passwordless sudo wrapper script
file {
'/usr/bin/lxc-vagrant-wrapper':
ensure => 'present',
mode => '0755',
content => "#!/usr/bin/env ruby
exec ARGV.join(' ')"
}

View file

@ -1,10 +1,2 @@
require "vagrant-lxc/version" require "vagrant-lxc/version"
require "vagrant-lxc/plugin" require "vagrant-lxc/plugin"
module Vagrant
module LXC
def self.source_root
@source_root ||= Pathname.new(File.dirname(__FILE__)).join('..').expand_path
end
end
end

View file

@ -1,20 +1,30 @@
require 'vagrant-lxc/action/boot' require 'vagrant-lxc/action/boot'
require 'vagrant-lxc/action/check_created'
require 'vagrant-lxc/action/check_running'
require 'vagrant-lxc/action/clear_forwarded_ports' require 'vagrant-lxc/action/clear_forwarded_ports'
require 'vagrant-lxc/action/create' require 'vagrant-lxc/action/create'
require 'vagrant-lxc/action/created'
require 'vagrant-lxc/action/destroy' require 'vagrant-lxc/action/destroy'
require 'vagrant-lxc/action/destroy_confirm' require 'vagrant-lxc/action/destroy_confirm'
require 'vagrant-lxc/action/disconnect'
require 'vagrant-lxc/action/compress_rootfs' require 'vagrant-lxc/action/compress_rootfs'
require 'vagrant-lxc/action/fetch_ip_with_lxc_info' require 'vagrant-lxc/action/fetch_ip_with_lxc_attach'
require 'vagrant-lxc/action/fetch_ip_from_dnsmasq_leases'
require 'vagrant-lxc/action/forced_halt' require 'vagrant-lxc/action/forced_halt'
require 'vagrant-lxc/action/forward_ports' require 'vagrant-lxc/action/forward_ports'
require 'vagrant-lxc/action/gc_private_network_bridges'
require 'vagrant-lxc/action/handle_box_metadata' require 'vagrant-lxc/action/handle_box_metadata'
require 'vagrant-lxc/action/prepare_nfs_settings' require 'vagrant-lxc/action/is_running'
require 'vagrant-lxc/action/prepare_nfs_valid_ids' require 'vagrant-lxc/action/message'
require 'vagrant-lxc/action/private_networks' require 'vagrant-lxc/action/remove_temporary_files'
require 'vagrant-lxc/action/setup_package_files' require 'vagrant-lxc/action/setup_package_files'
require 'vagrant-lxc/action/share_folders'
require 'vagrant-lxc/action/warn_networks' require 'vagrant-lxc/action/warn_networks'
unless Vagrant::LXC.vagrant_1_3_or_later
require 'vagrant-lxc/action/wait_for_communicator'
Vagrant::Action::Builtin.const_set :WaitForCommunicator, Vagrant::LXC::Action::WaitForCommunicator
end
module Vagrant module Vagrant
module LXC module LXC
module Action module Action
@ -27,9 +37,9 @@ module Vagrant
# machine back up with the new configuration. # machine back up with the new configuration.
def self.action_reload def self.action_reload
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2| b.use Builtin::Call, Created do |env1, b2|
if env1[:result] if !env1[:result]
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created") b2.use Message, :not_created
next next
end end
@ -47,14 +57,10 @@ module Vagrant
b.use Builtin::Provision b.use Builtin::Provision
b.use Builtin::EnvSet, :port_collision_repair => true b.use Builtin::EnvSet, :port_collision_repair => true
b.use Builtin::HandleForwardedPortCollisions b.use Builtin::HandleForwardedPortCollisions
b.use PrepareNFSValidIds b.use ShareFolders
b.use Builtin::SyncedFolderCleanup
b.use Builtin::SyncedFolders
b.use PrepareNFSSettings
b.use Builtin::SetHostname b.use Builtin::SetHostname
b.use WarnNetworks b.use WarnNetworks
b.use ForwardPorts b.use ForwardPorts
b.use PrivateNetworks
b.use Boot b.use Boot
b.use Builtin::WaitForCommunicator b.use Builtin::WaitForCommunicator
end end
@ -64,15 +70,15 @@ module Vagrant
def self.action_provision def self.action_provision
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use Builtin::ConfigValidate
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2| b.use Builtin::Call, Created do |env1, b2|
if env1[:result] if !env1[:result]
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created") b2.use Message, :not_created
next next
end end
b2.use Builtin::Call, Builtin::IsState, :running do |env2, b3| b2.use Builtin::Call, IsRunning do |env2, b3|
if !env2[:result] if !env2[:result]
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_running") b3.use Message, :not_running
next next
end end
@ -87,8 +93,7 @@ module Vagrant
def self.action_start def self.action_start
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use Builtin::ConfigValidate
b.use Builtin::BoxCheckOutdated b.use Builtin::Call, IsRunning do |env, b2|
b.use Builtin::Call, Builtin::IsState, :running do |env, b2|
# If the VM is running, then our work here is done, exit # If the VM is running, then our work here is done, exit
next if env[:result] next if env[:result]
b2.use action_boot b2.use action_boot
@ -101,10 +106,10 @@ module Vagrant
def self.action_up def self.action_up
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use Builtin::ConfigValidate
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2| b.use Builtin::Call, Created do |env, b2|
# If the VM is NOT created yet, then do the setup steps # If the VM is NOT created yet, then do the setup steps
if env[:result] if !env[:result]
b2.use Builtin::HandleBox b2.use Builtin::HandleBoxUrl
b2.use HandleBoxMetadata b2.use HandleBoxMetadata
b2.use Create b2.use Create
end end
@ -117,18 +122,19 @@ module Vagrant
# the virtual machine, gracefully or by force. # the virtual machine, gracefully or by force.
def self.action_halt def self.action_halt
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2| b.use Builtin::Call, Created do |env, b2|
if env[:result] if env[:result]
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created") # TODO: Remove once we drop support for vagrant 1.1
next b2.use Disconnect
end b2.use ClearForwardedPorts
b2.use RemoveTemporaryFiles
b2.use ClearForwardedPorts b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
b2.use GcPrivateNetworkBridges if !env2[:result]
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3| b3.use ForcedHalt
if !env2[:result] end
b3.use ForcedHalt
end end
else
b2.use Message, :not_created
end end
end end
end end
@ -138,21 +144,24 @@ module Vagrant
# freeing the resources of the underlying virtual machine. # freeing the resources of the underlying virtual machine.
def self.action_destroy def self.action_destroy
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2| b.use Builtin::Call, Created do |env1, b2|
if env1[:result] if !env1[:result]
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created") b2.use Message, :not_created
next next
end end
# TODO: Use Vagrant's built in action once we drop support for vagrant 1.2
b2.use Builtin::Call, DestroyConfirm do |env2, b3| b2.use Builtin::Call, DestroyConfirm do |env2, b3|
if env2[:result] if env2[:result]
b3.use Builtin::ConfigValidate b3.use Builtin::ConfigValidate
b3.use Builtin::EnvSet, :force_halt => true b3.use Builtin::EnvSet, :force_halt => true
b3.use action_halt b3.use action_halt
b3.use Destroy b3.use Destroy
b3.use Builtin::ProvisionerCleanup if Vagrant::LXC.vagrant_1_3_or_later
b3.use Builtin::ProvisionerCleanup
end
else else
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.will_not_destroy") b3.use Message, :will_not_destroy
end end
end end
end end
@ -162,9 +171,9 @@ module Vagrant
# This action packages the virtual machine into a single box file. # This action packages the virtual machine into a single box file.
def self.action_package def self.action_package
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2| b.use Builtin::Call, Created do |env1, b2|
if env1[:result] if !env1[:result]
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created") b2.use Message, :not_created
next next
end end
@ -178,55 +187,29 @@ module Vagrant
# This action is called to read the IP of the container. The IP found # This action is called to read the IP of the container. The IP found
# is expected to be put into the `:machine_ip` key. # is expected to be put into the `:machine_ip` key.
def self.action_ssh_ip def self.action_fetch_ip
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Builtin::ConfigValidate do |env, b2| b.use Builtin::ConfigValidate
b2.use FetchIpWithLxcInfo b.use FetchIpWithLxcAttach
end b.use FetchIpFromDnsmasqLeases
end end
end end
# This is the action that will exec into an SSH shell. # This is the action that will exec into an SSH shell.
def self.action_ssh def self.action_ssh
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use CheckCreated
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2| b.use CheckRunning
if env[:result] b.use Builtin::SSHExec
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next
end
b2.use Builtin::Call, Builtin::IsState, :running do |env1, b3|
if !env1[:result]
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_running")
next
end
b3.use Builtin::SSHExec
end
end
end end
end end
# This is the action that will run a single SSH command. # This is the action that will run a single SSH command.
def self.action_ssh_run def self.action_ssh_run
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use CheckCreated
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2| b.use CheckRunning
if env[:result] b.use Builtin::SSHRun
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next
end
b2.use Builtin::Call, Builtin::IsState, :running do |env1, b3|
if !env1[:result]
raise Vagrant::Errors::VMNotRunningError
next
end
b3.use Builtin::SSHRun
end
end
end end
end end
end end

View file

@ -8,35 +8,13 @@ module Vagrant
def call(env) def call(env)
@env = env @env = env
driver = env[:machine].provider.driver
config = env[:machine].provider_config config = env[:machine].provider_config
utsname = env[:machine].config.vm.hostname || env[:machine].id config.customize 'utsname', env[:machine].id
if driver.supports_new_config_format
config.customize 'uts.name', utsname
else
config.customize 'utsname', utsname
end
# Fix apparmor issues when starting Ubuntu 14.04 containers
# See https://github.com/fgrehm/vagrant-lxc/issues/278 for more information
if Dir.exists?('/sys/fs/pstore')
config.customize 'mount.entry', '/sys/fs/pstore sys/fs/pstore none bind,optional 0 0'
end
# Make selinux read-only, see
# https://github.com/fgrehm/vagrant-lxc/issues/301
if Dir.exists?('/sys/fs/selinux')
config.customize 'mount.entry', '/sys/fs/selinux sys/fs/selinux none bind,ro 0 0'
end
if config.tmpfs_mount_size && !config.tmpfs_mount_size.empty?
# Make /tmp a tmpfs to prevent init scripts from nuking synced folders mounted in here
config.customize 'mount.entry', "tmpfs tmp tmpfs nodev,nosuid,size=#{config.tmpfs_mount_size} 0 0"
end
env[:ui].info I18n.t("vagrant_lxc.messages.starting") env[:ui].info I18n.t("vagrant_lxc.messages.starting")
driver.start(config.customizations) env[:machine].provider.driver.start(config.customizations)
@app.call env @app.call env
end end

View file

@ -0,0 +1,21 @@
module Vagrant
module LXC
module Action
class CheckCreated
def initialize(app, env)
@app = app
end
def call(env)
if env[:machine].state.id == :not_created
raise Vagrant::Errors::VMNotCreatedError
end
# Call the next if we have one (but we shouldn't, since this
# middleware is built to run with the Call-type middlewares)
@app.call(env)
end
end
end
end
end

View file

@ -0,0 +1,21 @@
module Vagrant
module LXC
module Action
class CheckRunning
def initialize(app, env)
@app = app
end
def call(env)
if env[:machine].state.id != :running
raise Vagrant::Errors::VMNotRunningError
end
# Call the next if we have one (but we shouldn't, since this
# middleware is built to run with the Call-type middlewares)
@app.call(env)
end
end
end
end
end

View file

@ -13,13 +13,9 @@ module Vagrant
if redir_pids.any? if redir_pids.any?
env[:ui].info I18n.t("vagrant.actions.vm.clear_forward_ports.deleting") env[:ui].info I18n.t("vagrant.actions.vm.clear_forward_ports.deleting")
redir_pids.each do |pid| redir_pids.each do |pid|
next unless is_redir_pid?(pid[0]) next unless is_redir_pid?(pid)
@logger.debug "Killing pid #{pid[0]}" @logger.debug "Killing pid #{pid}"
if pid[1] system "pkill -TERM -P #{pid}"
system "sudo pkill -TERM -P #{pid[0]}"
else
system "pkill -TERM -P #{pid[0]}"
end
end end
@logger.info "Removing redir pids files" @logger.info "Removing redir pids files"
@ -35,8 +31,7 @@ module Vagrant
def redir_pids def redir_pids
@redir_pids = Dir[@env[:machine].data_dir.join('pids').to_s + "/redir_*.pid"].map do |file| @redir_pids = Dir[@env[:machine].data_dir.join('pids').to_s + "/redir_*.pid"].map do |file|
port_number = File.basename(file).split(/[^\d]/).join File.read(file).strip.chomp
[ File.read(file).strip.chomp , Integer(port_number) <= 1024 ]
end end
end end

View file

@ -7,8 +7,7 @@ module Vagrant
end end
def call(env) def call(env)
config = env[:machine].provider_config container_name = env[:machine].provider_config.container_name
container_name = config.container_name
case container_name case container_name
when :machine when :machine
@ -16,49 +15,24 @@ module Vagrant
when String when String
# Nothing to do here, move along... # Nothing to do here, move along...
else else
container_name = generate_container_name(env) container_name = "#{env[:root_path].basename}_#{env[:machine].name}"
container_name.gsub!(/[^-a-z0-9_]/i, "")
# milliseconds + random number suffix to allow for simultaneous
# `vagrant up` of the same box in different dirs
container_name << "_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
end end
backingstore = config.backingstore env[:machine].provider.driver.create(
if backingstore.nil?
backingstore = config.privileged ? "best" : "dir"
end
driver = env[:machine].provider.driver
template_options = env[:lxc_template_opts]
if driver.supports_new_config_format
if env[:lxc_box_config]
driver.update_config_keys(env[:lxc_box_config])
end
else
template_options['--oldconfig'] = ''
end
driver.create(
container_name, container_name,
backingstore,
config.backingstore_options,
env[:lxc_template_src], env[:lxc_template_src],
env[:lxc_template_config], env[:lxc_template_config],
template_options env[:lxc_template_opts]
) )
driver.update_config_keys
env[:machine].id = container_name env[:machine].id = container_name
@app.call env @app.call env
end end
def generate_container_name(env)
container_name = "#{env[:root_path].basename}_#{env[:machine].name}"
container_name.gsub!(/[^-a-z0-9_]/i, "")
# milliseconds + random number suffix to allow for simultaneous
# `vagrant up` of the same box in different dirs
container_name << "_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
# Trim container name to 64 chars, keeping "randomness"
trim_point = container_name.size > 64 ? -64 : -(container_name.size)
container_name[trim_point..-1]
end
end end
end end
end end

View file

@ -0,0 +1,20 @@
module Vagrant
module LXC
module Action
class Created
def initialize(app, env)
@app = app
end
def call(env)
# Set the result to be true if the machine is created.
env[:result] = env[:machine].state.id != :not_created
# Call the next if we have one (but we shouldn't, since this
# middleware is built to run with the Call-type middlewares)
@app.call(env)
end
end
end
end
end

View file

@ -0,0 +1,18 @@
module Vagrant
module LXC
module Action
class Disconnect
def initialize(app, env)
@app = app
end
def call(env)
@app.call env
# FIXME: Vagrant >= 1.1.3 should not need this
# https://github.com/mitchellh/vagrant/compare/715539eac30bc9ae62ddbb6337d13f036f7b774d...ec1bae0#L2R128
env[:machine].instance_variable_set(:@communicator, nil)
end
end
end
end
end

View file

@ -0,0 +1,48 @@
module Vagrant
module LXC
module Action
class FetchIpFromDnsmasqLeases
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_from_dnsmasq_leases")
end
def call(env)
env[:machine_ip] ||= assigned_ip(env)
@app.call(env)
end
def assigned_ip(env)
mac_address = env[:machine].provider.driver.mac_address
ip = nil
10.times do
dnsmasq_leases = read_dnsmasq_leases
@logger.debug "Attempting to load ip from dnsmasq leases (mac: #{mac_address})"
@logger.debug dnsmasq_leases
if dnsmasq_leases =~ /#{Regexp.escape mac_address}\s+([0-9.]+)\s+/
ip = $1.to_s
break
else
@logger.debug 'Ip could not be parsed from dnsmasq leases file'
sleep 2
end
end
ip
end
LEASES_PATHS = %w(
/var/lib/misc/dnsmasq.*.leases
/var/lib/misc/dnsmasq.leases
/var/lib/dnsmasq/dnsmasq.leases
/var/db/dnsmasq.leases
)
def read_dnsmasq_leases
Dir["{#{LEASES_PATHS.join(',')}}"].map do |file|
File.read(file)
end.join("\n")
end
end
end
end
end

View file

@ -1,31 +1,30 @@
module Vagrant module Vagrant
module LXC module LXC
module Action module Action
class FetchIpWithLxcInfo class FetchIpWithLxcAttach
# Include this so we can use `Subprocess` more easily. # Include this so we can use `Subprocess` more easily.
include Vagrant::Util::Retryable include Vagrant::Util::Retryable
def initialize(app, env) def initialize(app, env)
@app = app @app = app
@logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_info") @logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_attach")
end end
def call(env) def call(env)
env[:machine_ip] ||= assigned_ip(env) env[:machine_ip] ||= assigned_ip(env)
rescue LXC::Errors::NamespacesNotSupported
@logger.info 'The `lxc-attach` command available does not support the --namespaces parameter, falling back to dnsmasq leases to fetch container ip'
ensure ensure
@app.call(env) @app.call(env)
end end
def assigned_ip(env) def assigned_ip(env)
config = env[:machine].provider_config
fetch_ip_tries = config.fetch_ip_tries
driver = env[:machine].provider.driver driver = env[:machine].provider.driver
ip = '' ip = ''
return config.ssh_ip_addr if not config.ssh_ip_addr.nil? retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do
retryable(:on => LXC::Errors::ExecuteError, :tries => fetch_ip_tries, :sleep => 3) do
unless ip = get_container_ip_from_ip_addr(driver) unless ip = get_container_ip_from_ip_addr(driver)
# retry # retry
raise LXC::Errors::ExecuteError, :command => "lxc-info" raise LXC::Errors::ExecuteError, :command => "lxc-attach"
end end
end end
ip ip
@ -33,8 +32,8 @@ module Vagrant
# From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385 # From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385
def get_container_ip_from_ip_addr(driver) def get_container_ip_from_ip_addr(driver)
output = driver.info '-iH' output = driver.attach '/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'eth0', namespaces: 'network'
if output =~ /^([0-9.]+)/ if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
return $1.to_s return $1.to_s
end end
end end

View file

@ -1,5 +1,3 @@
require 'open3'
module Vagrant module Vagrant
module LXC module LXC
module Action module Action
@ -69,9 +67,7 @@ module Vagrant
# TODO: Deprecate this behavior of "automagically" skipping ssh forwarded ports # TODO: Deprecate this behavior of "automagically" skipping ssh forwarded ports
if type == :forwarded_port && options[:id] != 'ssh' if type == :forwarded_port && options[:id] != 'ssh'
if options.fetch(:host_ip, '').to_s.strip.empty? options.delete(:host_ip) if options.fetch(:host_ip, '').to_s.strip.empty?
options[:host_ip] = '127.0.0.1'
end
mappings[options[:host]] = options mappings[options[:host]] = options
end end
end end
@ -80,18 +76,11 @@ module Vagrant
end end
def redirect_port(host_ip, host_port, guest_ip, guest_port) def redirect_port(host_ip, host_port, guest_ip, guest_port)
if redir_version >= 3 params = %W( --lport=#{host_port} --caddr=#{guest_ip} --cport=#{guest_port} )
params = %W( -n #{host_ip}:#{host_port} #{guest_ip}:#{guest_port} ) params.unshift "--laddr=#{host_ip}" if host_ip
else
params = %W( --lport=#{host_port} --caddr=#{guest_ip} --cport=#{guest_port} )
params.unshift "--laddr=#{host_ip}" if host_ip
end
params << '--syslog' if ENV['REDIR_LOG'] params << '--syslog' if ENV['REDIR_LOG']
if host_port < 1024 redir_cmd = "redir #{params.join(' ')} 2>/dev/null"
redir_cmd = "sudo redir #{params.join(' ')} 2>/dev/null"
else
redir_cmd = "redir #{params.join(' ')} 2>/dev/null"
end
@logger.debug "Forwarding port with `#{redir_cmd}`" @logger.debug "Forwarding port with `#{redir_cmd}`"
spawn redir_cmd spawn redir_cmd
end end
@ -105,13 +94,6 @@ module Vagrant
end end
end end
def redir_version
stdout, stderr, _ = Open3.capture3 "redir --version"
# For some weird reason redir printed version information in STDERR prior to 3.2
version = stdout.empty? ? stderr : stdout
version.split('.')[0].to_i
end
def redir_installed? def redir_installed?
system "which redir > /dev/null" system "which redir > /dev/null"
end end

View file

@ -1,47 +0,0 @@
module Vagrant
module LXC
module Action
class GcPrivateNetworkBridges
def initialize(app, env)
@app = app
end
def call(env)
was_running = env[:machine].provider.state.id == :running
# Continue execution, we need the container to be stopped
@app.call(env)
was_running = was_running && env[:machine].provider.state.id != :running
if was_running && private_network_configured?(env[:machine].config)
private_network_configured?(env[:machine].config)
remove_bridges_that_are_not_in_use(env)
end
end
def private_network_configured?(config)
config.vm.networks.find do |type, _|
type.to_sym == :private_network
end
end
def remove_bridges_that_are_not_in_use(env)
env[:machine].config.vm.networks.find do |type, config|
next if type.to_sym != :private_network
bridge = config.fetch(:lxc__bridge_name)
driver = env[:machine].provider.driver
if ! driver.bridge_is_in_use?(bridge)
env[:ui].info I18n.t("vagrant_lxc.messages.remove_bridge", name: bridge)
unless ['lxcbr0', 'virbr0'].include? bridge
driver.remove_bridge(bridge)
end
end
end
end
end
end
end
end

View file

@ -3,8 +3,7 @@ module Vagrant
module Action module Action
# Prepare arguments to be used for lxc-create # Prepare arguments to be used for lxc-create
class HandleBoxMetadata class HandleBoxMetadata
SUPPORTED_VERSIONS = ['1.0.0', '2', '3'] SUPPORTED_VERSIONS = [2, 3]
def initialize(app, env) def initialize(app, env)
@app = app @app = app
@logger = Log4r::Logger.new("vagrant::lxc::action::handle_box_metadata") @logger = Log4r::Logger.new("vagrant::lxc::action::handle_box_metadata")
@ -17,53 +16,34 @@ module Vagrant
@env[:ui].info I18n.t("vagrant.actions.vm.import.importing", @env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
:name => @env[:machine].box.name) :name => @env[:machine].box.name)
@logger.info 'Validating box contents' @logger.debug 'Validating box contents'
validate_box validate_box
@logger.info 'Setting box options on environment' @logger.debug 'Setting box options on environment'
@env[:lxc_template_src] = template_src
@env[:lxc_template_opts] = template_opts @env[:lxc_template_opts] = template_opts
@env[:lxc_template_src] = template_src
# FIXME: Remove support for pre 1.0.0 boxes
if box_version != '1.0.0'
@env[:ui].warn "WARNING: You are using a base box that has a format that has been deprecated, please upgrade to a new one."
@env[:lxc_template_opts].merge!(
'--auth-key' => Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s
)
end
if template_config_file.exist? if template_config_file.exist?
@env[:lxc_box_config] = template_config_file.to_s @env[:lxc_template_config] = template_config_file.to_s
@env[:lxc_template_opts].merge!('--config' => template_config_file.to_s)
elsif old_template_config_file.exist?
@env[:lxc_box_config] = old_template_config_file.to_s
@env[:lxc_template_config] = old_template_config_file.to_s
end end
@app.call env @app.call env
end end
def template_src def template_src
@template_src ||= @template_src ||= @box.directory.join('lxc-template').to_s
if (box_template = @box.directory.join('lxc-template')).exist?
box_template.to_s
else
Vagrant::LXC.source_root.join('scripts/lxc-template').to_s
end
end end
def template_config_file def template_config_file
@template_config_file ||= @box.directory.join('lxc-config') @template_config_file ||= @box.directory.join('lxc.conf')
end
# TODO: Remove this once we remove compatibility for < 1.0.0 boxes
def old_template_config_file
@old_template_config_file ||= @box.directory.join('lxc.conf')
end end
def template_opts def template_opts
@template_opts ||= @box.metadata.fetch('template-opts', {}).dup.merge!( @template_opts ||= @box.metadata.fetch('template-opts', {}).dup.merge!(
'--tarball' => rootfs_tarball '--tarball' => rootfs_tarball,
# TODO: Deprecate this, the rootfs should be ready for vagrant-lxc
# SSH access at this point
'--auth-key' => Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s
) )
end end
@ -72,10 +52,10 @@ module Vagrant
end end
def validate_box def validate_box
unless SUPPORTED_VERSIONS.include? box_version unless SUPPORTED_VERSIONS.include? @box.metadata.fetch('version').to_i
raise Errors::IncompatibleBox.new name: @box.name, raise Errors::IncompatibleBox.new name: @box.name,
found: box_version, found: @box.metadata.fetch('version').to_i,
supported: SUPPORTED_VERSIONS.join(', ') supported: SUPPORTED_VERSIONS.join(' and ')
end end
unless File.exists?(template_src) unless File.exists?(template_src)
@ -86,10 +66,6 @@ module Vagrant
raise Errors::RootFSTarballMissing.new name: @box.name raise Errors::RootFSTarballMissing.new name: @box.name
end end
end end
def box_version
@box.metadata.fetch('version')
end
end end
end end
end end

View file

@ -0,0 +1,19 @@
module Vagrant
module LXC
module Action
class IsRunning
def initialize(app, env)
@app = app
end
def call(env)
env[:result] = env[:machine].state.id == :running
# Call the next if we have one (but we shouldn't, since this
# middleware is built to run with the Call-type middlewares)
@app.call(env)
end
end
end
end
end

View file

@ -0,0 +1,23 @@
module Vagrant
module LXC
module Action
# XXX: Is this really needed? Should we contribute this back to Vagrant's core?
class Message
def initialize(app, env, msg_key, type = :info)
@app = app
@msg_key = msg_key
@type = type
end
def call(env)
machine = env[:machine]
message = I18n.t("vagrant_lxc.messages.#{@msg_key}", name: machine.name)
env[:ui].send @type, message
@app.call env
end
end
end
end
end

View file

@ -1,64 +0,0 @@
module Vagrant
module LXC
module Action
class PrepareNFSSettings
include Vagrant::Util::Retryable
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
end
def call(env)
@machine = env[:machine]
@app.call(env)
# if using_nfs? # TODO: && !privileged_container?
# raise Errors::NfsWithoutPrivilegedError
# end
if using_nfs?
@logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP")
add_ips_to_env!(env)
end
end
# We're using NFS if we have any synced folder with NFS configured. If
# we are not using NFS we don't need to do the extra work to
# populate these fields in the environment.
def using_nfs?
@machine.config.vm.synced_folders.any? { |_, opts| opts[:type] == :nfs }
end
# TODO:
# def privileged_container?
# @machine.provider.driver.privileged?(@machine.id)
# end
# Extracts the proper host and guest IPs for NFS mounts and stores them
# in the environment for the SyncedFolder action to use them in
# mounting.
#
# The ! indicates that this method modifies its argument.
def add_ips_to_env!(env)
provider = @machine.provider
host_ip = read_host_ip
machine_ip = provider.ssh_info[:host]
raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip
env[:nfs_host_ip] = host_ip
env[:nfs_machine_ip] = machine_ip
end
def read_host_ip
@machine.communicate.execute 'echo $SSH_CLIENT' do |buffer, output|
return output.chomp.split(' ')[0] if buffer == :stdout
end
end
end
end
end
end

View file

@ -1,19 +0,0 @@
module Vagrant
module LXC
module Action
class PrepareNFSValidIds
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
end
def call(env)
machine = env[:machine]
env[:nfs_valid_ids] = machine.provider.driver.all_containers
@app.call(env)
end
end
end
end
end

View file

@ -1,46 +0,0 @@
module Vagrant
module LXC
module Action
class PrivateNetworks
def initialize(app, env)
@app = app
end
def call(env)
@app.call(env)
if private_network_configured?(env[:machine].config)
env[:ui].output(I18n.t("vagrant_lxc.messages.setup_private_network"))
configure_private_networks(env)
end
end
def private_network_configured?(config)
config.vm.networks.find do |type, _|
type.to_sym == :private_network
end
end
def configure_private_networks(env)
env[:machine].config.vm.networks.find do |type, config|
next if type.to_sym != :private_network
container_name = env[:machine].provider.driver.container_name
address_type = config[:type]
ip = config[:ip]
bridge_ip = config.fetch(:lxc__bridge_ip) { build_bridge_ip(ip) }
bridge = config.fetch(:lxc__bridge_name)
env[:machine].provider.driver.configure_private_network(bridge, bridge_ip, container_name, address_type, ip)
end
end
def build_bridge_ip(ip)
if ip
ip.sub(/^(\d+\.\d+\.\d+)\.\d+/, '\1.254')
end
end
end
end
end
end

View file

@ -0,0 +1,23 @@
module Vagrant
module LXC
module Action
class RemoveTemporaryFiles
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::lxc::action::remove_tmp_files")
end
def call(env)
# Continue execution, we need the container to be stopped
@app.call env
if env[:machine].state.id == :stopped
@logger.debug 'Removing temporary files'
tmp_path = env[:machine].provider.driver.rootfs_path.join('tmp')
env[:machine].provider.sudo_wrapper.run('rm', '-rf', "#{tmp_path}/*")
end
end
end
end
end
end

View file

@ -43,16 +43,12 @@ module Vagrant
def copy_box_files_to_pkg_dir def copy_box_files_to_pkg_dir
box_dir = @env[:machine].box.directory box_dir = @env[:machine].box.directory
FileUtils.cp box_dir.join('lxc-template').to_s, @env['package.directory'].to_s
FileUtils.cp box_dir.join('metadata.json').to_s, @env['package.directory'].to_s FileUtils.cp box_dir.join('metadata.json').to_s, @env['package.directory'].to_s
if (template = box_dir.join('lxc-template')).exist? # TODO: Update built-on metadata.json
FileUtils.cp template.to_s, @env['package.directory'].to_s
end
if (conf = box_dir.join('lxc.conf')).exist? if (conf = box_dir.join('lxc.conf')).exist?
FileUtils.cp conf.to_s, @env['package.directory'].to_s FileUtils.cp conf.to_s, @env['package.directory'].to_s
end end
if (conf = box_dir.join('lxc-config')).exist?
FileUtils.cp conf.to_s, @env['package.directory'].to_s
end
end end
end end
end end

View file

@ -0,0 +1,67 @@
module Vagrant
module LXC
module Action
class ShareFolders
def initialize(app, env)
@app = app
end
def call(env)
@env = env
prepare_folders
add_override_configs
@app.call env
end
# This method returns an actual list of synced folders to create and their
# proper path.
def shared_folders
{}.tap do |result|
@env[:machine].config.vm.synced_folders.each do |id, data|
# Ignore disabled shared folders
next if data[:disabled]
# This to prevent overwriting the actual shared folders data
result[id] = data.dup
end
end
end
# Prepares the shared folders by verifying they exist and creating them
# if they don't.
def prepare_folders
shared_folders.each do |id, options|
hostpath = Pathname.new(options[:hostpath]).expand_path(@env[:root_path])
if !hostpath.directory? && options[:create]
# Host path doesn't exist, so let's create it.
@logger.debug("Host path doesn't exist, creating: #{hostpath}")
begin
hostpath.mkpath
rescue Errno::EACCES
raise Vagrant::Errors::SharedFolderCreateFailed,
:path => hostpath.to_s
end
end
end
end
def add_override_configs
@env[:ui].info I18n.t("vagrant.actions.lxc.share_folders.preparing")
folders = []
shared_folders.each do |id, data|
folders << {
:name => id,
:hostpath => File.expand_path(data[:hostpath], @env[:root_path]),
:guestpath => data[:guestpath]
}
@env[:ui].info(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
:guest_path => data[:guestpath]))
end
@env[:machine].provider.driver.share_folders(folders)
end
end
end
end
end

View file

@ -0,0 +1,41 @@
# This acts like a backport of Vagrant's built in action from 1.3+ for older versions
# and will probably be deprecated on 0.8+
# https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/action/builtin/wait_for_communicator.rb
module Vagrant
module LXC
module Action
class WaitForCommunicator
def initialize(app, env)
@app = app
end
def call(env)
@env = env
raise Vagrant::Errors::VMFailedToBoot if !wait_for_communicator
@app.call env
end
def wait_for_communicator
max_tries = @env[:machine].config.ssh.max_tries.to_i
max_tries.times do |i|
if @env[:machine].communicate.ready?
@env[:ui].info I18n.t("vagrant_lxc.messages.container_ready")
return true
end
# Return true so that the vm_failed_to_boot error doesn't
# get shown
return true if @env[:interrupted]
sleep 1 if !@env["vagrant.test"]
end
@env[:ui].error I18n.t("vagrant.actions.vm.boot.failed")
false
end
end
end
end
end

View file

@ -7,16 +7,16 @@ module Vagrant
end end
def call(env) def call(env)
if public_network_configured?(env[:machine].config) if public_or_private_network_configured?(env[:machine].config)
env[:ui].warn(I18n.t("vagrant_lxc.messages.warn_networks")) env[:ui].warn(I18n.t("vagrant_lxc.messages.warn_networks"))
end end
@app.call(env) @app.call(env)
end end
def public_network_configured?(config) def public_or_private_network_configured?(config)
config.vm.networks.find do |type, _| config.vm.networks.find do |type, _|
type.to_sym == :public_network [:private_network, :public_network].include?(type.to_sym)
end end
end end
end end

View file

@ -1,58 +0,0 @@
module Vagrant
module LXC
module Command
class Root < Vagrant.plugin("2", :command)
def self.synopsis
'vagrant-lxc specific commands'
end
def initialize(argv, env)
@args, @sub_command, @sub_args = split_main_and_subcommand(argv)
@subcommands = Vagrant::Registry.new.tap do |registry|
registry.register(:sudoers) do
require_relative 'sudoers'
Sudoers
end
end
super(argv, env)
end
def execute
# Print the help
return help if @args.include?("-h") || @args.include?("--help")
klazz = @subcommands.get(@sub_command.to_sym) if @sub_command
return help unless klazz
@logger.debug("Executing command: #{klazz} #{@sub_args.inspect}")
# Initialize and execute the command class
klazz.new(@sub_args, @env).execute
end
def help
opts = OptionParser.new do |opts|
opts.banner = "Usage: vagrant lxc <subcommand> [<args>]"
opts.separator ""
opts.separator "Available subcommands:"
# REFACTOR Use @subcommands.keys.sort
# https://github.com/mitchellh/vagrant/commit/4194da19c60956f6e59239c0145f772be257e79d
keys = []
@subcommands.each { |key, value| keys << key }
keys.sort.each do |key|
opts.separator " #{key}"
end
opts.separator ""
opts.separator "For help on any individual subcommand run `vagrant lxc <subcommand> -h`"
end
@env.ui.info(opts.help, :prefix => false)
end
end
end
end
end

View file

@ -1,97 +0,0 @@
require 'tempfile'
require "vagrant-lxc/driver"
require "vagrant-lxc/sudo_wrapper"
module Vagrant
module LXC
module Command
class Sudoers < Vagrant.plugin("2", :command)
def initialize(argv, env)
super
@argv
@env = env
end
def execute
options = { user: ENV['USER'] }
opts = OptionParser.new do |opts|
opts.banner = "Usage: vagrant lxc sudoers"
opts.separator ""
opts.on('-u user', '--user user', String, "The user for which to create the policy (defaults to '#{options[:user]}')") do |u|
options[:user] = u
end
end
argv = parse_options(opts)
return unless argv
wrapper_path = SudoWrapper.dest_path
wrapper = create_wrapper!
sudoers = create_sudoers!(options[:user], wrapper_path)
su_copy([
{source: wrapper, target: wrapper_path, mode: "0555"},
{source: sudoers, target: sudoers_path, mode: "0440"}
])
end
def sudoers_path
"/etc/sudoers.d/vagrant-lxc"
end
private
# This requires vagrant 1.5.2+ https://github.com/mitchellh/vagrant/commit/3371c3716278071680af9b526ba19235c79c64cb
def create_wrapper!
lxc_base_path = Driver.new("").containers_path
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
template = Vagrant::Util::TemplateRenderer.new(
'sudoers.rb',
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
:cmd_paths => build_cmd_paths_hash,
:lxc_base_path => lxc_base_path,
:pipework_regex => "#{ENV['HOME']}/\.vagrant\.d/gems/(?:\\d+?\\.\\d+?\\.\\d+?/)?gems/vagrant-lxc.+/scripts/pipework"
)
file.puts template.render
end
wrapper.close
wrapper.path
end
def create_sudoers!(user, command)
sudoers = Tempfile.new('vagrant-lxc-sudoers').tap do |file|
file.puts "# Automatically created by vagrant-lxc"
file.puts "#{user} ALL=(root) NOPASSWD: #{command}"
end
sudoers.close
sudoers.path
end
def su_copy(files)
commands = files.map { |file|
[
"rm -f #{file[:target]}",
"cp #{file[:source]} #{file[:target]}",
"chown root:root #{file[:target]}",
"chmod #{file[:mode]} #{file[:target]}"
]
}.flatten
system "echo \"#{commands.join("; ")}\" | sudo sh"
end
def build_cmd_paths_hash
{}.tap do |hash|
%w( which cat mkdir cp chown chmod rm tar chown ip ifconfig brctl ).each do |cmd|
hash[cmd] = `sudo which #{cmd}`.strip
end
hash['lxc_bin'] = Pathname(`sudo which lxc-create`.strip).parent.to_s
hash['ruby'] = Gem.ruby
end
end
end
end
end
end

View file

@ -6,41 +6,20 @@ module Vagrant
# @return [Array] # @return [Array]
attr_reader :customizations attr_reader :customizations
# A string that contains the backing store type used with lxc-create -B # A String that points to a file that acts as a wrapper for sudo commands.
attr_accessor :backingstore
# Optional arguments for the backing store, such as --fssize, --fstype, ...
# #
# @return [Array] # This allows us to have a single entry when whitelisting NOPASSWD commands
attr_accessor :backingstore_options # on /etc/sudoers
attr_accessor :sudo_wrapper
# A string to explicitly set the container name. To use the vagrant # A string to explicitly set the container name. To use the vagrant
# machine name, set this to :machine # machine name, set this to :machine
attr_accessor :container_name attr_accessor :container_name
# Size (as a string like '400M') of the tmpfs to mount at /tmp on boot.
# Set to false or nil to disable the tmpfs mount altogether. Defaults to '2G'.
attr_accessor :tmpfs_mount_size
attr_accessor :fetch_ip_tries
attr_accessor :ssh_ip_addr
# 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 @sudo_wrapper = UNSET_VALUE
@backingstore_options = []
@container_name = UNSET_VALUE @container_name = UNSET_VALUE
@tmpfs_mount_size = UNSET_VALUE
@fetch_ip_tries = UNSET_VALUE
@ssh_ip_addr = 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
@ -58,19 +37,24 @@ module Vagrant
@customizations << [key, value] @customizations << [key, value]
end end
# Stores options for backingstores like lvm, btrfs, etc def finalize!
def backingstore_option(key, value) @sudo_wrapper = nil if @sudo_wrapper == UNSET_VALUE
@backingstore_options << [key, value] @container_name = nil if @container_name == UNSET_VALUE
end end
def finalize! def validate(machine)
@container_name = nil if @container_name == UNSET_VALUE errors = []
@backingstore = nil if @backingstore == UNSET_VALUE
@existing_container_name = nil if @existing_container_name == UNSET_VALUE if @sudo_wrapper
@tmpfs_mount_size = '2G' if @tmpfs_mount_size == UNSET_VALUE hostpath = Pathname.new(@sudo_wrapper).expand_path(machine.env.root_path)
@fetch_ip_tries = 10 if @fetch_ip_tries == UNSET_VALUE if ! hostpath.file?
@ssh_ip_addr = nil if @ssh_ip_addr == UNSET_VALUE errors << I18n.t('vagrant_lxc.sudo_wrapper_not_found', path: hostpath.to_s)
@privileged = true if @privileged == UNSET_VALUE elsif ! hostpath.executable?
errors << I18n.t('vagrant_lxc.sudo_wrapper_not_executable', path: hostpath.to_s)
end
end
{ "lxc provider" => errors }
end end
end end
end end

View file

@ -3,12 +3,9 @@ require "vagrant/util/subprocess"
require "vagrant-lxc/errors" require "vagrant-lxc/errors"
require "vagrant-lxc/driver/cli" require "vagrant-lxc/driver/cli"
require "vagrant-lxc/sudo_wrapper"
require "etc" require "etc"
require "tempfile"
module Vagrant module Vagrant
module LXC module LXC
class Driver class Driver
@ -16,14 +13,16 @@ module Vagrant
# a name. # a name.
class ContainerNotFound < StandardError; end class ContainerNotFound < StandardError; end
# Default root folder where container configs are stored # Root folder where container configs are stored
CONTAINERS_PATH = '/var/lib/lxc'
attr_reader :container_name, attr_reader :container_name,
:customizations :customizations
def initialize(container_name, sudo_wrapper = nil, cli = nil, privileged: true) def initialize(container_name, sudo_wrapper, cli = nil)
@container_name = container_name @container_name = container_name
@sudo_wrapper = sudo_wrapper || SudoWrapper.new(privileged: privileged) @sudo_wrapper = sudo_wrapper
@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 = []
end end
@ -32,72 +31,45 @@ module Vagrant
raise ContainerNotFound if @container_name && ! @cli.list.include?(@container_name) raise ContainerNotFound if @container_name && ! @cli.list.include?(@container_name)
end end
# Root folder where container configs are stored
def containers_path
@containers_path ||= @cli.config('lxc.lxcpath')
end
def all_containers
@cli.list
end
def base_path def base_path
Pathname.new("#{containers_path}/#{@container_name}") Pathname.new("#{CONTAINERS_PATH}/#{@container_name}")
end
def config_path
base_path.join('config').to_s
end end
def rootfs_path def rootfs_path
pathtype, path = config_string.match(/^lxc\.rootfs(?:\.path)?\s+=\s+(.+:)?(.+)$/)[1..2] Pathname.new(config_string.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1])
case pathtype
when 'overlayfs:'
# Split on colon (:), ignoring any colon escaped by an escape character ( \ )
# Pays attention to when the escape character is itself escaped.
_, overlay_path = config_entry.split(/(?<!\\)(?:\\\\)*:/)
if overlay_path
Pathname.new(overlay_path)
else
# Malformed: fall back to prior behaviour
Pathname.new(path)
end
else
Pathname.new(path)
end
end end
def mac_address def mac_address
return @mac_address if @mac_address @mac_address ||= config_string.match(/^lxc\.network\.hwaddr\s*+=\s*+(.+)$/)[1]
if config_string =~ /^lxc\.network\.hwaddr\s*+=\s*+(.+)$/
@mac_address = $1
end
end end
def config_string def config_string
@sudo_wrapper.run('cat', config_path) @sudo_wrapper.run('cat', base_path.join('config').to_s)
end end
def create(name, backingstore, backingstore_options, template_path, config_file, template_options = {}) def create(name, template_path, config_file, template_options = {})
@cli.name = @container_name = name @cli.name = @container_name = name
@logger.debug "Creating container..." import_template(template_path) do |template_name|
@logger.debug "Creating container..."
@cli.create template_path, backingstore, backingstore_options, config_file, template_options @cli.create template_name, config_file, template_options
end
def share_folders(folders)
folders.each do |f|
share_folder(f[:hostpath], f[:guestpath], f.fetch(:mount_options, nil))
end end
end end
def share_folder(host_path, guest_path, mount_options = nil) def share_folders(folders)
guest_path = guest_path.gsub(/^\//, '').gsub(' ', '\\\040') folders.each do |folder|
mount_options = Array(mount_options || ['bind', 'create=dir']) guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, ''))
host_path = host_path.to_s.gsub(' ', '\\\040') unless guestpath.directory?
@customizations << ['mount.entry', "#{host_path} #{guest_path} none #{mount_options.join(',')} 0 0"] begin
@logger.debug("Guest path doesn't exist, creating: #{guestpath}")
@sudo_wrapper.run('mkdir', '-p', guestpath.to_s)
rescue Errno::EACCES
raise Vagrant::Errors::SharedFolderCreateFailed, :path => guestpath.to_s
end
end
@customizations << ['mount.entry', "#{folder[:hostpath]} #{guestpath} none bind 0 0"]
end
end end
def start(customizations) def start(customizations)
@ -115,6 +87,9 @@ module Vagrant
def forced_halt def forced_halt
@logger.info('Shutting down container...') @logger.info('Shutting down container...')
@cli.transition_to(:stopped) { |c| c.shutdown }
# REFACTOR: Do not use exception to control the flow
rescue CLI::TargetStateNotReached, CLI::ShutdownNotSupported
@cli.transition_to(:stopped) { |c| c.stop } @cli.transition_to(:stopped) { |c| c.stop }
end end
@ -126,103 +101,27 @@ module Vagrant
@cli.attach(*command) @cli.attach(*command)
end end
def info(*command)
@cli.info(*command)
end
def configure_private_network(bridge_name, bridge_ip, container_name, address_type, ip)
@logger.info "Configuring network interface for #{container_name} using #{ip} and bridge #{bridge_name}"
if ip
ip += '/24'
end
if ! bridge_exists?(bridge_name)
if not bridge_ip
raise "Bridge is missing and no IP was specified!"
end
@logger.info "Creating the bridge #{bridge_name}"
cmd = [
'brctl',
'addbr',
bridge_name
]
@sudo_wrapper.run(*cmd)
end
if ! bridge_has_an_ip?(bridge_name)
if not bridge_ip
raise "Bridge has no IP and none was specified!"
end
@logger.info "Adding #{bridge_ip} to the bridge #{bridge_name}"
cmd = [
'ip',
'addr',
'add',
"#{bridge_ip}/24",
'dev',
bridge_name
]
@sudo_wrapper.run(*cmd)
@sudo_wrapper.run('ip', 'link', 'set', bridge_name, 'up')
end
cmd = [
Vagrant::LXC.source_root.join('scripts/pipework').to_s,
bridge_name,
container_name,
ip ||= "dhcp"
]
@sudo_wrapper.run(*cmd)
end
def bridge_has_an_ip?(bridge_name)
@logger.info "Checking whether the bridge #{bridge_name} has an IP"
`ip -4 addr show scope global #{bridge_name}` =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
end
def bridge_exists?(bridge_name)
@logger.info "Checking whether bridge #{bridge_name} exists"
brctl_output = `ip link | egrep -q " #{bridge_name}:"`
$?.to_i == 0
end
def bridge_is_in_use?(bridge_name)
# REFACTOR: This method is **VERY** hacky
@logger.info "Checking if bridge #{bridge_name} is in use"
brctl_output = `brctl show #{bridge_name} 2>/dev/null | tail -n +2 | grep -q veth`
$?.to_i == 0
end
def remove_bridge(bridge_name)
if ['lxcbr0', 'virbr0'].include? bridge_name
@logger.info "Skipping removal of system bridge #{bridge_name}"
return
end
return unless bridge_exists?(bridge_name)
@logger.info "Removing bridge #{bridge_name}"
@sudo_wrapper.run('ip', 'link', 'set', bridge_name, 'down')
@sudo_wrapper.run('brctl', 'delbr', bridge_name)
end
def version def version
@version ||= @cli.version @version ||= @cli.version
end end
def supports_new_config_format
Gem::Version.new(version) >= Gem::Version.new('2.1.0')
end
# TODO: This needs to be reviewed and specs needs to be written # TODO: This needs to be reviewed and specs needs to be written
def compress_rootfs def compress_rootfs
# TODO: Pass in tmpdir so we can clean up from outside # TODO: Pass in tmpdir so we can clean up from outside
target_path = "#{Dir.mktmpdir}/rootfs.tar.gz" target_path = "#{Dir.mktmpdir}/rootfs.tar.gz"
@logger.info "Compressing '#{rootfs_path}' rootfs to #{target_path}" @logger.info "Compressing '#{rootfs_path}' rootfs to #{target_path}"
@sudo_wrapper.run('tar', '--numeric-owner', '-cvzf', target_path, '-C', # "vagrant package" will copy the existing lxc-template in the new box file
rootfs_path.parent.to_s, "./#{rootfs_path.basename.to_s}") # To keep this function backwards compatible with existing boxes, the path
# included in the tarball needs to have the same amount of path components (2)
# that will be stripped before extraction, hence the './.'
# TODO: This should be reviewed before 1.0
cmds = [
"cd #{base_path}",
"rm -f rootfs.tar.gz",
"tar --numeric-owner -czf #{target_path} -C #{rootfs_path} './.'"
]
@sudo_wrapper.su_c(cmds.join(' && '))
@logger.info "Changing rootfs tarball owner" @logger.info "Changing rootfs tarball owner"
user_details = Etc.getpwnam(Etc.getlogin) user_details = Etc.getpwnam(Etc.getlogin)
@ -240,16 +139,7 @@ module Vagrant
def prune_customizations def prune_customizations
# Use sed to just strip out the block of code which was inserted by Vagrant # Use sed to just strip out the block of code which was inserted by Vagrant
@logger.debug 'Prunning vagrant-lxc customizations' @logger.debug 'Prunning vagrant-lxc customizations'
contents = config_string @sudo_wrapper.su_c("sed -e '/^# VAGRANT-BEGIN/,/^# VAGRANT-END/ d' -ibak #{base_path.join('config')}")
contents.gsub! /^# VAGRANT-BEGIN(.|\s)*# VAGRANT-END\n/, ''
write_config(contents)
end
def update_config_keys(path = nil)
path = path || config_path
@cli.update_config(path)
rescue Errors::ExecuteError
# not on LXC 2.1+. Doesn't matter, ignore.
end end
protected protected
@ -259,32 +149,46 @@ module Vagrant
"lxc.#{key}=#{value}" "lxc.#{key}=#{value}"
end end
customizations.unshift '# VAGRANT-BEGIN' customizations.unshift '# VAGRANT-BEGIN'
customizations << "# VAGRANT-END\n" customizations << '# VAGRANT-END'
contents = config_string config_file = base_path.join('config').to_s
contents << customizations.join("\n") customizations.each do |line|
@sudo_wrapper.su_c("echo '#{line}' >> #{config_file}")
write_config(contents) end
end end
def write_config(contents) def import_template(path)
confpath = base_path.join('config').to_s template_name = "vagrant-tmp-#{@container_name}"
begin tmp_template_path = templates_path.join("lxc-#{template_name}").to_s
File.open(confpath, File::RDWR) do |file|
file.write contents @logger.info 'Copying LXC template into place'
end @sudo_wrapper.run('cp', path, tmp_template_path)
rescue @sudo_wrapper.run('chmod', '+x', tmp_template_path)
# 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. yield template_name
Tempfile.new('lxc-config').tap do |file| ensure
file.chmod 0644 @logger.info 'Removing LXC template'
file.write contents if tmp_template_path
file.close @sudo_wrapper.run('rm', tmp_template_path)
@sudo_wrapper.run 'cp', '-f', file.path, confpath
@sudo_wrapper.run 'chown', 'root:root', confpath
end
end end
end end
TEMPLATES_PATH_LOOKUP = %w(
/usr/share/lxc/templates
/usr/lib/lxc/templates
/usr/lib64/lxc/templates
/usr/local/lib/lxc/templates
)
def templates_path
return @templates_path if @templates_path
path = TEMPLATES_PATH_LOOKUP.find { |candidate| File.directory?(candidate) }
if !path
raise Errors::TemplatesDirMissing.new paths: TEMPLATES_PATH_LOOKUP.inspect
end
@templates_path = Pathname(path)
end
end end
end end
end end

View file

@ -10,6 +10,7 @@ module Vagrant
attr_accessor :name attr_accessor :name
class TransitionBlockNotProvided < RuntimeError; end class TransitionBlockNotProvided < RuntimeError; end
class ShutdownNotSupported < RuntimeError; end
class TargetStateNotReached < RuntimeError class TargetStateNotReached < RuntimeError
def initialize(target_state, state) def initialize(target_state, state)
msg = "Target state '#{target_state}' not reached, currently on '#{state}'" msg = "Target state '#{target_state}' not reached, currently on '#{state}'"
@ -28,24 +29,14 @@ module Vagrant
end end
def version def version
return @version if @version if run(:version) =~ /lxc version:\s+(.+)\s*$/
@version = run(:create, '--version') $1.downcase
if @version =~ /(lxc version:\s+|)(.+)\s*$/
@version = $2.downcase
else else
# TODO: Raise an user friendly error # TODO: Raise an user friendly error
raise 'Unable to parse lxc version!' raise 'Unable to parse lxc version!'
end end
end end
def config(param)
run(:config, param).gsub("\n", '')
end
def update_config(path)
run('update-config', '-c', path)
end
def state def state
if @name && run(:info, '--name', @name, retryable: true) =~ /^state:[^A-Z]+([A-Z]+)$/i if @name && run(:info, '--name', @name, retryable: true) =~ /^state:[^A-Z]+([A-Z]+)$/i
$1.downcase.to_sym $1.downcase.to_sym
@ -54,19 +45,17 @@ module Vagrant
end end
end end
def create(template, backingstore, backingstore_options, config_file, template_opts = {}) def create(template, config_file, template_opts = {})
if config_file if config_file
config_opts = ['-f', config_file] config_opts = ['-f', config_file]
end end
extra = template_opts.to_a.flatten.reject { |elem| elem.empty? } extra = template_opts.to_a.flatten
extra.unshift '--' unless extra.empty? extra.unshift '--' unless extra.empty?
run :create, run :create,
'-B', backingstore,
'--template', template, '--template', template,
'--name', @name, '--name', @name,
*(backingstore_options.to_a.flatten),
*(config_opts), *(config_opts),
*extra *extra
rescue Errors::ExecuteError => e rescue Errors::ExecuteError => e
@ -85,18 +74,17 @@ module Vagrant
run :start, '-d', '--name', @name, *Array(options) run :start, '-d', '--name', @name, *Array(options)
end end
## lxc-stop will exit 2 if machine was already stopped
# Man Page:
# 2 The specified container exists but was not running.
def stop def stop
begin attach '/sbin/halt'
run :stop, '--name', @name run :stop, '--name', @name
rescue LXC::Errors::ExecuteError => e end
if e.exitcode == 2
@logger.debug "Machine already stopped, lxc-stop returned 2" def shutdown
else if system('which lxc-shutdown > /dev/null')
raise e run :shutdown, '--name', @name
end else
# REFACTOR: Do not use exception to control the flow
raise ShutdownNotSupported
end end
end end
@ -107,23 +95,18 @@ module Vagrant
opts = cmd.pop opts = cmd.pop
namespaces = Array(opts[:namespaces]).map(&:upcase).join('|') namespaces = Array(opts[:namespaces]).map(&:upcase).join('|')
# HACK: The wrapper script should be able to handle this
if @sudo_wrapper.wrapper_path
namespaces = "'#{namespaces}'"
end
if namespaces if namespaces
extra = ['--namespaces', namespaces] if supports_attach_with_namespaces?
extra = ['--namespaces', namespaces]
else
raise LXC::Errors::NamespacesNotSupported
end
end end
end end
run :attach, '--name', @name, *((extra || []) + cmd) run :attach, '--name', @name, *((extra || []) + cmd)
end end
def info(*cmd)
run(:info, '--name', @name, *cmd)
end
def transition_to(target_state, tries = 30, timeout = 1, &block) def transition_to(target_state, tries = 30, timeout = 1, &block)
raise TransitionBlockNotProvided unless block_given? raise TransitionBlockNotProvided unless block_given?
@ -146,6 +129,14 @@ module Vagrant
def run(command, *args) def run(command, *args)
@sudo_wrapper.run("lxc-#{command}", *args) @sudo_wrapper.run("lxc-#{command}", *args)
end end
def supports_attach_with_namespaces?
unless defined?(@supports_attach_with_namespaces)
@supports_attach_with_namespaces = run(:attach, '-h', :show_stderr => true).values.join.include?('--namespaces')
end
return @supports_attach_with_namespaces
end
end end
end end
end end

View file

@ -5,28 +5,17 @@ module Vagrant
module Errors module Errors
class ExecuteError < Vagrant::Errors::VagrantError class ExecuteError < Vagrant::Errors::VagrantError
error_key(:lxc_execute_error) error_key(:lxc_execute_error)
attr_reader :stderr, :stdout, :exitcode attr_reader :stderr, :stdout
def initialize(message, *args) def initialize(message, *args)
super super
if message.is_a?(Hash) if message.is_a?(Hash)
@stderr = message[:stderr] @stderr = message[:stderr]
@stdout = message[:stdout] @stdout = message[:stdout]
@exitcode = message[:exitcode]
end end
end end
end end
# Raised when user interrupts a subprocess class NamespacesNotSupported < Vagrant::Errors::VagrantError
class SubprocessInterruptError < Vagrant::Errors::VagrantError
error_key(:lxc_interrupt_error)
def initialize(message, *args)
super
end
end
class LxcLinuxRequired < Vagrant::Errors::VagrantError
error_key(:lxc_linux_required)
end end
class LxcNotInstalled < Vagrant::Errors::VagrantError class LxcNotInstalled < Vagrant::Errors::VagrantError
@ -37,10 +26,6 @@ module Vagrant
error_key(:lxc_container_already_exists) error_key(:lxc_container_already_exists)
end end
class CommandNotSupported < Vagrant::Errors::VagrantError
error_key(:lxc_command_not_supported)
end
# Box related errors # Box related errors
class TemplateFileMissing < Vagrant::Errors::VagrantError class TemplateFileMissing < Vagrant::Errors::VagrantError
error_key(:lxc_template_file_missing) error_key(:lxc_template_file_missing)

View file

@ -1,4 +1,4 @@
require 'vagrant' require "vagrant"
module Vagrant module Vagrant
module LXC module LXC
@ -9,43 +9,23 @@ module Vagrant
LXC-based virtual machines. LXC-based virtual machines.
EOF EOF
provider(:lxc, parallel: true, priority: 7) do provider(:lxc, parallel: true) do
require_relative 'provider' require File.expand_path("../provider", __FILE__)
init!
I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
I18n.reload!
Provider Provider
end end
command "lxc" do
require_relative 'command/root'
init!
Command::Root
end
config(:lxc, :provider) do config(:lxc, :provider) do
require_relative 'config' require File.expand_path("../config", __FILE__)
init!
Config Config
end end
end
synced_folder(:lxc) do def self.vagrant_1_3_or_later
require_relative 'synced_folder' Gem::Version.new(Vagrant::VERSION) >= Gem::Version.new('1.3.0')
SyncedFolder
end
provider_capability("lxc", "public_address") do
require_relative "provider/cap/public_address"
Provider::Cap::PublicAddress
end
protected
def self.init!
return if defined?(@_init)
I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
I18n.reload!
@_init = true
end
end end
end end
end end

View file

@ -2,20 +2,13 @@ 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
class Provider < Vagrant.plugin("2", :provider) class Provider < Vagrant.plugin("2", :provider)
attr_reader :driver attr_reader :driver
def self.usable?(raise_error=false)
if !Vagrant::Util::Platform.linux?
raise Errors::LxcLinuxRequired
end
true
end
def initialize(machine) def initialize(machine)
@logger = Log4r::Logger.new("vagrant::provider::lxc") @logger = Log4r::Logger.new("vagrant::provider::lxc")
@machine = machine @machine = machine
@ -24,9 +17,17 @@ module Vagrant
machine_id_changed machine_id_changed
end end
def sudo_wrapper
@shell ||= begin
wrapper = @machine.provider_config.sudo_wrapper
wrapper = Pathname(wrapper).expand_path(@machine.env.root_path).to_s if wrapper
SudoWrapper.new(wrapper)
end
end
def ensure_lxc_installed! def ensure_lxc_installed!
begin begin
SudoWrapper.new(privileged: @machine.provider_config.privileged).run("which", "lxc-create") sudo_wrapper.run("which", "lxc-create")
rescue Vagrant::LXC::Errors::ExecuteError rescue Vagrant::LXC::Errors::ExecuteError
raise Errors::LxcNotInstalled raise Errors::LxcNotInstalled
end end
@ -39,7 +40,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, privileged: @machine.provider_config.privileged) @driver = Driver.new(id, self.sudo_wrapper)
@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
@ -62,13 +63,13 @@ module Vagrant
# Returns the SSH info for accessing the Container. # Returns the SSH info for accessing the Container.
def ssh_info def ssh_info
# If the Container is not running then we cannot possibly SSH into it, so # If the Container is not created then we cannot possibly SSH into it, so
# we return nil. # we return nil.
return nil if state.id != :running return nil if state == :not_created
# Run a custom action called "ssh_ip" which does what it says and puts # Run a custom action called "fetch_ip" which does what it says and puts
# the IP found into the `:machine_ip` key in the environment. # the IP found into the `:machine_ip` key in the environment.
env = @machine.action("ssh_ip") env = @machine.action("fetch_ip")
# If we were not able to identify the container's IP, we return nil # If we were not able to identify the container's IP, we return nil
# here and we let Vagrant core deal with it ;) # here and we let Vagrant core deal with it ;)

View file

@ -1,17 +0,0 @@
module Vagrant
module LXC
class Provider
module Cap
module PublicAddress
def self.public_address(machine)
return nil if machine.state.id != :running
ssh_info = machine.ssh_info
return nil if !ssh_info
ssh_info[:host]
end
end
end
end
end
end

View file

@ -4,43 +4,24 @@ module Vagrant
# Include this so we can use `Subprocess` more easily. # Include this so we can use `Subprocess` more easily.
include Vagrant::Util::Retryable include Vagrant::Util::Retryable
attr_reader :wrapper_path def initialize(wrapper_path = nil)
@wrapper_path = wrapper_path
def self.dest_path
"/usr/local/bin/vagrant-lxc-wrapper"
end
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") @logger = Log4r::Logger.new("vagrant::lxc::sudo_wrapper")
end end
def run(*command) def run(*command)
options = command.last.is_a?(Hash) ? command.last : {} command.unshift @wrapper_path if @wrapper_path
execute *(['sudo'] + command)
end
# Avoid running LXC commands with a restrictive umask. def su_c(command)
# Otherwise disasters occur, like the container root directory su_command = if @wrapper_path
# having permissions `rwxr-x---` which prevents the `vagrant` "#{@wrapper_path} \"#{command}\""
# user from accessing its own home directory; among other
# problems, SSH cannot then read `authorized_keys`!
old_mask = File.umask
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 else
execute *(['/usr/bin/env'] + command) "su root -c \"#{command}\""
end end
ensure @logger.debug "Running 'sudo #{su_command}'"
File.umask(old_mask) system "sudo #{su_command}"
end
end end
private private
@ -68,10 +49,10 @@ module Vagrant
# nicely handled by Vagrant. # nicely handled by Vagrant.
if r.exit_code != 0 if r.exit_code != 0
if @interrupted if @interrupted
raise LXC::Errors::SubprocessInterruptError, command.inspect @logger.info("Exit code != 0, but interrupted. Ignoring.")
else else
raise LXC::Errors::ExecuteError, raise LXC::Errors::ExecuteError,
command: command.inspect, stderr: r.stderr, stdout: r.stdout, exitcode: r.exit_code command: command.inspect, stderr: r.stderr, stdout: r.stdout
end end
end end
end end

View file

@ -1,72 +0,0 @@
module Vagrant
module LXC
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
def usable?(machine)
# These synced folders only work if the provider is LXC
machine.provider_name == :lxc
end
def prepare(machine, folders, _opts)
machine.ui.output(I18n.t("vagrant.actions.lxc.share_folders.preparing"))
# short guestpaths first, so we don't step on ourselves
folders = folders.sort_by do |id, data|
if data[:guestpath]
data[:guestpath].length
else
# A long enough path to just do this at the end.
10000
end
end
folders.each do |id, data|
host_path = Pathname.new(File.expand_path(data[:hostpath], machine.env.root_path))
guest_path = data[:guestpath]
machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_owner")) if data[:owner]
machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_group")) if data[:group]
if !host_path.directory? && data[:create]
# Host path doesn't exist, so let's create it.
@logger.info("Host path doesn't exist, creating: #{host_path}")
begin
host_path.mkpath
rescue Errno::EACCES
raise Vagrant::Errors::SharedFolderCreateFailed,
:path => hostpath.to_s
end
end
mount_opts = data[:mount_options]
machine.provider.driver.share_folder(host_path, guest_path, mount_opts)
# Guest path specified, so mount the folder to specified point
machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
guestpath: data[:guestpath],
hostpath: data[:hostpath],
guest_path: data[:guestpath]))
end
end
def enable(machine, folders, _opts)
# Emit an upstart event if we can
return unless machine.communicate.test("test -x /sbin/initctl")
# short guestpaths first, so we don't step on ourselves
folders = folders.sort_by do |id, data|
if data[:guestpath]
data[:guestpath].length
else
# A long enough path to just do this at the end.
10000
end
end
folders.each do |id, data|
guest_path = data[:guestpath]
machine.communicate.sudo(
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}")
end
end
end
end
end

View file

@ -1,5 +1,5 @@
module Vagrant module Vagrant
module LXC module LXC
VERSION = "1.4.2" VERSION = "0.8.1.dev"
end end
end end

View file

@ -12,19 +12,15 @@ en:
Starting container... Starting container...
force_shutdown: |- force_shutdown: |-
Forcing shutdown of container... Forcing shutdown of container...
# TODO: Remove the following keys after we drop support for vagrant < 1.3
waiting_for_start: |-
Waiting for container to start. This should not take long.
container_ready: |-
Container started and ready for use!
warn_networks: |- warn_networks: |-
Warning! The LXC provider doesn't support public networks, the settings Warning! The LXC provider doesn't support any of the Vagrant public / private
will be silently ignored. network configurations (ex: `config.vm.network :private_network, ip: "some-ip"`).
warn_group: |- They will be silently ignored.
Warning! The LXC provider doesn't support the :group parameter for synced
folders. It will be silently ignored.
warn_owner: |-
Warning! The LXC provider doesn't support the :owner parameter for synced
folders. It will be silently ignored.
setup_private_network: |-
Setting up private networks...
remove_bridge: |-
Removing bridge '%{name}'...
vagrant: vagrant:
commands: commands:
@ -40,9 +36,6 @@ en:
preparing: Setting up mount entries for shared folders... preparing: Setting up mount entries for shared folders...
errors: errors:
lxc_interrupt_error: |-
Interrupted
lxc_execute_error: |- lxc_execute_error: |-
There was an error executing %{command} There was an error executing %{command}
@ -62,12 +55,8 @@ en:
Looked up under: %{paths} Looked up under: %{paths}
lxc_linux_required: |-
The LXC provider only works on Linux. Please try to use
another provider.
lxc_not_installed: |- lxc_not_installed: |-
The `lxc` package does not seem to be installed or `lxc-create` is not accessible on the PATH. The `lxc` package does not seem to be installed or is not accessible on the PATH.
lxc_redir_not_installed: |- lxc_redir_not_installed: |-
`redir` is not installed or is not accessible on the PATH. `redir` is not installed or is not accessible on the PATH.
@ -76,7 +65,3 @@ en:
There is container on your system with the same name you've specified There is container on your system with the same name you've specified
on your Vagrantfile (%{name}), please choose a different one or on your Vagrantfile (%{name}), please choose a different one or
run `lxc-destroy --name %{name}` and try again. run `lxc-destroy --name %{name}` and try again.
lxc_command_not_supported: |-
Command (lxc-%{command}) not supported in version %{version}.
This command is available with version %{available_version}.

View file

@ -1,180 +0,0 @@
#!/usr/bin/env bash
# This is a modified version of /usr/share/lxc/templates/lxc-download
# that comes with ubuntu-lxc 1.0.0 stable from ppa changed to suit vagrant-lxc needs
#
# Copyright © 2014 Stéphane Graber <stgraber@ubuntu.com>
# Copyright © 2014 Fábio Rehm <fgrehm@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
# USA
set -eu
LXC_HOOK_DIR="/usr/share/lxc/hooks"
LXC_TEMPLATE_CONFIG="/usr/share/lxc/config"
LXC_MAPPED_GID=
LXC_MAPPED_UID=
LXC_NAME=
LXC_PATH=
LXC_ROOTFS=
LXC_TARBALL=
LXC_CONFIG=
LXC_USE_OLDCONFIG=
LXC_STRIP_COMPONENTS=2
usage() {
cat <<EOF
vagrant-lxc default template
Required arguments:
[ --tarball <path> ]: The full path of the rootfs tarball
Optional arguments:
[ --config ]: Configuration file to be used when building the container
[ --oldconfig ]: Use pre LXC 2.1 config format
[ -h | --help ]: This help message
LXC internal arguments (do not pass manually!):
[ --name <name> ]: The container name
[ --path <path> ]: The path to the container
[ --rootfs <rootfs> ]: The path to the container's rootfs
[ --mapped-uid <map> ]: A uid map (user namespaces)
[ --mapped-gid <map> ]: A gid map (user namespaces)
[ --strip-components <num> ]: Number of path components to strip from tarball
EOF
return 0
}
options=$(getopt -o h -l tarball:,config:,oldconfig,help:,name:,path:,rootfs:,mapped-uid:,mapped-gid:,strip-components: -- "$@")SS
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
fi
eval set -- "$options"
while true
do
case "$1" in
-h|--help) usage $0 && exit 0;;
--config) LXC_CONFIG=$2; shift 2;;
--oldconfig) LXC_USE_OLDCONFIG=1; shift 1;;
--tarball) LXC_TARBALL=$2; shift 2;;
--name) LXC_NAME=$2; shift 2;;
--path) LXC_PATH=$2; shift 2;;
--rootfs) LXC_ROOTFS=$2; shift 2;;
--mapped-uid) LXC_MAPPED_UID=$2; shift 2;;
--mapped-gid) LXC_MAPPED_GID=$2; shift 2;;
--strip-components) LXC_STRIP_COMPONENTS=$2; shift 2;;
*) break;;
esac
done
if [ -z "${LXC_NAME}" ]; then
echo "'name' parameter is required"
exit 1
fi
if [ -z "${LXC_TARBALL}" ]; then
echo "'tarball' parameter is required"
exit 1
fi
if [ -z "${LXC_PATH}" ]; then
echo "'path' parameter is required"
exit 1
fi
# if $LXC_ROOTFS exists here, it was passed in with --rootfs
if [ -z "${LXC_ROOTFS}" ]; then
config=${LXC_PATH}/config
if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
LXC_ROOTFS=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'`
else
LXC_ROOTFS=$LXC_PATH/rootfs
echo "lxc.rootfs = ${LXC_ROOTFS}" >> $config
fi
fi
# Unpack the rootfs
echo "Unpacking the rootfs"
(
flock -x 200
if [ $? -ne 0 ]; then
echo "Cache repository is busy."
exit 1
fi
mkdir -p ${LXC_ROOTFS}
(cd ${LXC_ROOTFS} && tar xfz ${LXC_TARBALL} --strip-components=${LXC_STRIP_COMPONENTS} --xattrs --xattrs-include=* || true)
if [ ! -f ${LXC_ROOTFS}/bin/true ]; then
echo "Failed to extract rootfs"
exit 1
fi
) 200>${LXC_PATH}/vagrant_lock
rm ${LXC_PATH}/vagrant_lock
mkdir -p ${LXC_ROOTFS}/dev/pts/
## Extract all the network config entries
sed -i -e "/lxc.network/{w ${LXC_PATH}/config-network" -e "d}" \
${LXC_PATH}/config
## Extract any other config entry
sed -i -e "/lxc./{w ${LXC_PATH}/config-auto" -e "d}" ${LXC_PATH}/config
## Add the container-specific config
echo "" >> ${LXC_PATH}/config
echo "##############################################" >> ${LXC_PATH}/config
echo "# Container specific configuration (automatically set)" >> ${LXC_PATH}/config
if [ -e "${LXC_PATH}/config-auto" ]; then
cat ${LXC_PATH}/config-auto >> ${LXC_PATH}/config
rm ${LXC_PATH}/config-auto
fi
if [ $LXC_USE_OLDCONFIG ]; then
echo "lxc.utsname = ${LXC_NAME}" >> ${LXC_PATH}/config
else
echo "lxc.uts.name = ${LXC_NAME}" >> ${LXC_PATH}/config
fi
## Re-add the previously removed network config
if [ -e "${LXC_PATH}/config-network" ]; then
echo "" >> ${LXC_PATH}/config
echo "##############################################" >> ${LXC_PATH}/config
echo "# Network configuration (automatically set)" >> ${LXC_PATH}/config
cat ${LXC_PATH}/config-network >> ${LXC_PATH}/config
rm ${LXC_PATH}/config-network
fi
if [ -n "${LXC_CONFIG}" ]; then
## Append the defaults
echo "" >> ${LXC_PATH}/config
echo "##############################################" >> ${LXC_PATH}/config
echo "# vagrant-lxc base box specific configuration" >> ${LXC_PATH}/config
cat ${LXC_CONFIG} >> ${LXC_PATH}/config
fi
# Empty section for lxc.customize calls from vagrantfile
echo "" >> ${LXC_PATH}/config
echo "##############################################" >> ${LXC_PATH}/config
echo "# vagrant-lxc container specific configuration" >> ${LXC_PATH}/config
exit 0

View file

@ -1,422 +0,0 @@
#!/bin/sh
# This code should (try to) follow Google's Shell Style Guide
# (https://google-styleguide.googlecode.com/svn/trunk/shell.xml)
set -e
case "$1" in
--wait)
WAIT=1
;;
esac
IFNAME=$1
# default value set further down if not set here
CONTAINER_IFNAME=
if [ "$2" = "-i" ]; then
CONTAINER_IFNAME=$3
shift 2
fi
if [ "$2" = "-l" ]; then
LOCAL_IFNAME=$3
shift 2
fi
GUESTNAME=$2
IPADDR=$3
MACADDR=$4
case "$MACADDR" in
*@*)
VLAN="${MACADDR#*@}"
VLAN="${VLAN%%@*}"
MACADDR="${MACADDR%%@*}"
;;
*)
VLAN=
;;
esac
# did they ask to generate a custom MACADDR?
# generate the unique string
case "$MACADDR" in
U:*)
macunique="${MACADDR#*:}"
# now generate a 48-bit hash string from $macunique
MACADDR=$(echo $macunique|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
;;
esac
[ "$IPADDR" ] || [ "$WAIT" ] || {
echo "Syntax:"
echo "pipework <hostinterface> [-i containerinterface] [-l localinterfacename] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan]"
echo "pipework <hostinterface> [-i containerinterface] [-l localinterfacename] <guest> dhcp [macaddr][@vlan]"
echo "pipework route <guest> <route_command>"
echo "pipework --wait [-i containerinterface]"
exit 1
}
# Succeed if the given utility is installed. Fail otherwise.
# For explanations about `which` vs `type` vs `command`, see:
# http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212
# (Thanks to @chenhanxiao for pointing this out!)
installed () {
command -v "$1" >/dev/null 2>&1
}
# Google Styleguide says error messages should go to standard error.
warn () {
echo "$@" >&2
}
die () {
status="$1"
shift
warn "$@"
exit "$status"
}
# First step: determine type of first argument (bridge, physical interface...),
# Unless "--wait" is set (then skip the whole section)
if [ -z "$WAIT" ]; then
if [ -d "/sys/class/net/$IFNAME" ]
then
if [ -d "/sys/class/net/$IFNAME/bridge" ]; then
IFTYPE=bridge
BRTYPE=linux
elif installed ovs-vsctl && ovs-vsctl list-br|grep -q "^${IFNAME}$"; then
IFTYPE=bridge
BRTYPE=openvswitch
elif [ "$(cat "/sys/class/net/$IFNAME/type")" -eq 32 ]; then # InfiniBand IPoIB interface type 32
IFTYPE=ipoib
# The IPoIB kernel module is fussy, set device name to ib0 if not overridden
CONTAINER_IFNAME=${CONTAINER_IFNAME:-ib0}
PKEY=$VLAN
else IFTYPE=phys
fi
else
case "$IFNAME" in
br*)
IFTYPE=bridge
BRTYPE=linux
;;
ovs*)
if ! installed ovs-vsctl; then
die 1 "Need OVS installed on the system to create an ovs bridge"
fi
IFTYPE=bridge
BRTYPE=openvswitch
;;
route*)
IFTYPE=route
;;
dummy*)
IFTYPE=dummy
;;
*) die 1 "I do not know how to setup interface $IFNAME." ;;
esac
fi
fi
# Set the default container interface name to eth1 if not already set
CONTAINER_IFNAME=${CONTAINER_IFNAME:-eth1}
[ "$WAIT" ] && {
while true; do
# This first method works even without `ip` or `ifconfig` installed,
# but doesn't work on older kernels (e.g. CentOS 6.X). See #128.
grep -q '^1$' "/sys/class/net/$CONTAINER_IFNAME/carrier" && break
# This method hopefully works on those older kernels.
ip link ls dev "$CONTAINER_IFNAME" && break
sleep 1
done > /dev/null 2>&1
exit 0
}
[ "$IFTYPE" = bridge ] && [ "$BRTYPE" = linux ] && [ "$VLAN" ] && {
die 1 "VLAN configuration currently unsupported for Linux bridge."
}
[ "$IFTYPE" = ipoib ] && [ "$MACADDR" ] && {
die 1 "MACADDR configuration unsupported for IPoIB interfaces."
}
# Second step: find the guest (for now, we only support LXC containers)
while read _ mnt fstype options _; do
[ "$fstype" != "cgroup" ] && continue
echo "$options" | grep -qw devices || continue
CGROUPMNT=$mnt
done < /proc/mounts
[ "$CGROUPMNT" ] || {
die 1 "Could not locate cgroup mount point."
}
# Try to find a cgroup matching exactly the provided name.
N=$(find "$CGROUPMNT" -name "$GUESTNAME" | wc -l)
case "$N" in
0)
# If we didn't find anything, try to lookup the container with Docker.
if installed docker; then
RETRIES=3
while [ "$RETRIES" -gt 0 ]; do
DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' "$GUESTNAME")
[ "$DOCKERPID" != 0 ] && break
sleep 1
RETRIES=$((RETRIES - 1))
done
[ "$DOCKERPID" = 0 ] && {
die 1 "Docker inspect returned invalid PID 0"
}
[ "$DOCKERPID" = "<no value>" ] && {
die 1 "Container $GUESTNAME not found, and unknown to Docker."
}
else
die 1 "Container $GUESTNAME not found, and Docker not installed."
fi
;;
1) true ;;
*) die 1 "Found more than one container matching $GUESTNAME." ;;
esac
# only check IPADDR if we are not in a route mode
[ "$IFTYPE" != route ] && {
case "$IPADDR" in
# Let's check first if the user asked for DHCP allocation.
dhcp|dhcp:*)
# Use Docker-specific strategy to run the DHCP client
# from the busybox image, in the network namespace of
# the container.
if ! [ "$DOCKERPID" ]; then
warn "You asked for a Docker-specific DHCP method."
warn "However, $GUESTNAME doesn't seem to be a Docker container."
warn "Try to replace 'dhcp' with another option?"
die 1 "Aborting."
fi
DHCP_CLIENT=${IPADDR%%:*}
;;
udhcpc|udhcpc:*|udhcpc-f|udhcpc-f:*|dhcpcd|dhcpcd:*|dhclient|dhclient:*|dhclient-f|dhclient-f:*)
DHCP_CLIENT=${IPADDR%%:*}
# did they ask for the client to remain?
DHCP_FOREGROUND=
[ "${DHCP_CLIENT: -2}" = '-f' ] && {
DHCP_FOREGROUND=true
}
DHCP_CLIENT=${DHCP_CLIENT%-f}
if ! installed "$DHCP_CLIENT"; then
die 1 "You asked for DHCP client $DHCP_CLIENT, but I can't find it."
fi
;;
# Alright, no DHCP? Then let's see if we have a subnet *and* gateway.
*/*@*)
GATEWAY="${IPADDR#*@}" GATEWAY="${GATEWAY%%@*}"
IPADDR="${IPADDR%%@*}"
;;
# No gateway? We need at least a subnet, anyway!
*/*) : ;;
# ... No? Then stop right here.
*)
warn "The IP address should include a netmask."
die 1 "Maybe you meant $IPADDR/24 ?"
;;
esac
}
# If a DHCP method was specified, extract the DHCP options.
if [ "$DHCP_CLIENT" ]; then
case "$IPADDR" in
*:*) DHCP_OPTIONS="${IPADDR#*:}" ;;
esac
fi
if [ "$DOCKERPID" ]; then
NSPID=$DOCKERPID
else
NSPID=$(head -n 1 "$(find "$CGROUPMNT" -name "$GUESTNAME" | head -n 1)/tasks")
[ "$NSPID" ] || {
# it is an alternative way to get the pid
NSPID=$(lxc-info -n "$GUESTNAME" | grep PID | grep -Eo '[0-9]+')
[ "$NSPID" ] || {
die 1 "Could not find a process inside container $GUESTNAME."
}
}
fi
# Check if an incompatible VLAN device already exists
[ "$IFTYPE" = phys ] && [ "$VLAN" ] && [ -d "/sys/class/net/$IFNAME.VLAN" ] && {
ip -d link show "$IFNAME.$VLAN" | grep -q "vlan.*id $VLAN" || {
die 1 "$IFNAME.VLAN already exists but is not a VLAN device for tag $VLAN"
}
}
[ ! -d /var/run/netns ] && mkdir -p /var/run/netns
rm -f "/var/run/netns/$NSPID"
ln -s "/proc/$NSPID/ns/net" "/var/run/netns/$NSPID"
# Check if we need to create a bridge.
[ "$IFTYPE" = bridge ] && [ ! -d "/sys/class/net/$IFNAME" ] && {
[ "$BRTYPE" = linux ] && {
(ip link add dev "$IFNAME" type bridge > /dev/null 2>&1) || (brctl addbr "$IFNAME")
ip link set "$IFNAME" up
}
[ "$BRTYPE" = openvswitch ] && {
ovs-vsctl add-br "$IFNAME"
}
}
[ "$IFTYPE" != "route" ] && [ "$IFTYPE" != "dummy" ] && MTU=$(ip link show "$IFNAME" | awk '{print $5}')
# If it's a bridge, we need to create a veth pair
[ "$IFTYPE" = bridge ] && {
if [ -z "$LOCAL_IFNAME" ]; then
LOCAL_IFNAME="v${CONTAINER_IFNAME}pl${NSPID}"
fi
GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}"
# Does the link already exist?
if ip link show "$LOCAL_IFNAME" >/dev/null 2>&1; then
# link exists, is it in use?
if ip link show "$LOCAL_IFNAME" up | grep -q "UP"; then
echo "Link $LOCAL_IFNAME exists and is up"
exit 1
fi
# delete the link so we can re-add it afterwards
ip link del "$LOCAL_IFNAME"
fi
ip link add name "$LOCAL_IFNAME" mtu "$MTU" type veth peer name "$GUEST_IFNAME" mtu "$MTU"
case "$BRTYPE" in
linux)
(ip link set "$LOCAL_IFNAME" master "$IFNAME" > /dev/null 2>&1) || (brctl addif "$IFNAME" "$LOCAL_IFNAME")
;;
openvswitch)
if ! ovs-vsctl list-ports "$IFNAME" | grep -q "^${LOCAL_IFNAME}$"; then
ovs-vsctl add-port "$IFNAME" "$LOCAL_IFNAME" ${VLAN:+tag="$VLAN"}
fi
;;
esac
ip link set "$LOCAL_IFNAME" up
}
# If it's a physical interface, create a macvlan subinterface
[ "$IFTYPE" = phys ] && {
[ "$VLAN" ] && {
[ ! -d "/sys/class/net/${IFNAME}.${VLAN}" ] && {
ip link add link "$IFNAME" name "$IFNAME.$VLAN" mtu "$MTU" type vlan id "$VLAN"
}
ip link set "$IFNAME" up
IFNAME=$IFNAME.$VLAN
}
GUEST_IFNAME=ph$NSPID$CONTAINER_IFNAME
ip link add link "$IFNAME" dev "$GUEST_IFNAME" mtu "$MTU" type macvlan mode bridge
ip link set "$IFNAME" up
}
# If it's an IPoIB interface, create a virtual IPoIB interface (the IPoIB
# equivalent of a macvlan device)
#
# Note: no macvlan subinterface nor Ethernet bridge can be created on top of an
# IPoIB interface. InfiniBand is not Ethernet. IPoIB is an IP layer on top of
# InfiniBand, without an intermediate Ethernet layer.
[ "$IFTYPE" = ipoib ] && {
GUEST_IFNAME="${IFNAME}.${NSPID}"
# If a partition key is provided, use it
[ "$PKEY" ] && {
GUEST_IFNAME="${IFNAME}.${PKEY}.${NSPID}"
PKEY="pkey 0x$PKEY"
}
ip link add link "$IFNAME" name "$GUEST_IFNAME" type ipoib $PKEY
ip link set "$IFNAME" up
}
# If its a dummy interface, create a dummy interface.
[ "$IFTYPE" = dummy ] && {
GUEST_IFNAME=du$NSPID$CONTAINER_IFNAME
ip link add dev "$GUEST_IFNAME" type dummy
}
# If the `route` command was specified ...
if [ "$IFTYPE" = route ]; then
# ... discard the first two arguments and pass the rest to the route command.
shift 2
ip netns exec "$NSPID" ip route "$@"
else
# Otherwise, run normally.
ip link set "$GUEST_IFNAME" netns "$NSPID"
ip netns exec "$NSPID" ip link set "$GUEST_IFNAME" name "$CONTAINER_IFNAME"
[ "$MACADDR" ] && ip netns exec "$NSPID" ip link set dev "$CONTAINER_IFNAME" address "$MACADDR"
# When using any of the DHCP methods, we start a DHCP client in the
# network namespace of the container. With the 'dhcp' method, the
# client used is taken from the Docker busybox image (therefore
# requiring no specific client installed on the host). Other methods
# use a locally installed client.
case "$DHCP_CLIENT" in
dhcp)
docker run -d --net container:$GUESTNAME --cap-add NET_ADMIN \
busybox udhcpc -i "$CONTAINER_IFNAME" -x "hostname:$GUESTNAME" \
$DHCP_OPTIONS \
>/dev/null
;;
udhcpc)
DHCP_Q="-q"
[ "$DHCP_FOREGROUND" ] && {
DHCP_OPTIONS="$DHCP_OPTIONS -f"
}
ip netns exec "$NSPID" "$DHCP_CLIENT" -qi "$CONTAINER_IFNAME" \
-x "hostname:$GUESTNAME" \
-p "/var/run/udhcpc.$GUESTNAME.pid" \
$DHCP_OPTIONS
[ ! "$DHCP_FOREGROUND" ] && {
rm "/var/run/udhcpc.$GUESTNAME.pid"
}
;;
dhclient)
ip netns exec "$NSPID" "$DHCP_CLIENT" "$CONTAINER_IFNAME" \
-pf "/var/run/dhclient.$GUESTNAME.pid" \
-lf "/etc/dhclient/dhclient.$GUESTNAME.leases" \
$DHCP_OPTIONS
# kill dhclient after get ip address to prevent device be used after container close
[ ! "$DHCP_FOREGROUND" ] && {
kill "$(cat "/var/run/dhclient.$GUESTNAME.pid")"
rm "/var/run/dhclient.$GUESTNAME.pid"
}
;;
dhcpcd)
ip netns exec "$NSPID" "$DHCP_CLIENT" -q "$CONTAINER_IFNAME" -h "$GUESTNAME"
;;
"")
if installed ipcalc; then
eval "$(ipcalc -b $IPADDR)"
ip netns exec "$NSPID" ip addr add "$IPADDR" brd "$BROADCAST" dev "$CONTAINER_IFNAME"
else
ip netns exec "$NSPID" ip addr add "$IPADDR" dev "$CONTAINER_IFNAME"
fi
[ "$GATEWAY" ] && {
ip netns exec "$NSPID" ip route delete default >/dev/null 2>&1 && true
}
ip netns exec "$NSPID" ip link set "$CONTAINER_IFNAME" up
[ "$GATEWAY" ] && {
ip netns exec "$NSPID" ip route get "$GATEWAY" >/dev/null 2>&1 || \
ip netns exec "$NSPID" ip route add "$GATEWAY/32" dev "$CONTAINER_IFNAME"
ip netns exec "$NSPID" ip route replace default via "$GATEWAY"
}
;;
esac
# Give our ARP neighbors a nudge about the new interface
if installed arping; then
IPADDR=$(echo "$IPADDR" | cut -d/ -f1)
ip netns exec "$NSPID" arping -c 1 -A -I "$CONTAINER_IFNAME" "$IPADDR" > /dev/null 2>&1 || true
else
echo "Warning: arping not found; interface may not be immediately reachable"
fi
fi
# Remove NSPID to avoid `ip netns` catch it.
rm -f "/var/run/netns/$NSPID"
# vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab :

4
spec/Vagrantfile vendored
View file

@ -15,6 +15,10 @@ Vagrant.configure("2") do |config|
config.cache.auto_detect = true config.cache.auto_detect = true
config.vm.provider :lxc do |lxc|
# lxc.sudo_wrapper = '/usr/bin/lxc-vagrant-wrapper'
end
config.vm.provision :shell, config.vm.provision :shell,
inline: 'mkdir -p /vagrant/tmp && echo -n "Provisioned" > /vagrant/tmp/provisioning' inline: 'mkdir -p /vagrant/tmp && echo -n "Provisioned" > /vagrant/tmp/provisioning'

View file

@ -0,0 +1,111 @@
require 'acceptance_helper'
describe 'Sanity check' do
after(:all) { destroy_container }
context 'running `vagrant up` from scratch' do
before(:all) do
destroy_container
vagrant_up
end
it 'creates a container' do
containers = `sudo lxc-ls`.chomp.split(/\s+/).uniq
expect(containers).to include vagrant_container_name
end
it 'starts the newly created container' do
status = `sudo lxc-info -n #{vagrant_container_name}`
expect(status).to include 'RUNNING'
end
it "is able to be SSH'ed" do
expect(vagrant_ssh('hostname')).to eq 'lxc-test-box'
end
it 'mounts shared folders with the right permissions' do
vagrant_ssh 'mkdir -p /vagrant/tmp && echo -n "Shared" > /vagrant/tmp/shared'
shared_file_contents = File.read('/vagrant/spec/tmp/shared')
expect(shared_file_contents).to eq 'Shared'
end
it 'provisions the container based on Vagrantfile configs' do
provisioned_file_contents = File.read('/vagrant/spec/tmp/provisioning')
expect(provisioned_file_contents).to eq 'Provisioned'
end
it 'forwards configured ports' do
output = `curl -s localhost:8080`.strip.chomp
expect(output).to include 'It works!'
end
end
context '`vagrant halt` on a running container' do
before(:all) do
destroy_container
vagrant_up
vagrant_ssh 'touch /tmp/{some,files}'
vagrant_halt
end
it 'shuts down the container' do
status = `sudo lxc-info -n #{vagrant_container_name}`
expect(status).to include 'STOPPED'
end
it 'clears forwarded ports' do
`curl -s localhost:8080 --connect-timeout 2`
expect($?.exitstatus).to_not eq 0
end
it 'kills redir processes' do
processes = `pgrep redir`
expect($?.exitstatus).to_not eq 0
end
xit 'removes files under `/tmp`' do
container_tmp_files = `sudo ls -l "/var/lib/lxc/#{vagrant_container_name}/rootfs/tmp"`.split("\n")
puts container_tmp_files.join("\n")
expect(container_tmp_files).to be_empty
end
end
context '`vagrant destroy`' do
before(:all) do
destroy_container
vagrant_up
@container_name = vagrant_container_name
vagrant_destroy
end
it 'destroys the underlying container' do
containers = `sudo lxc-ls`.chomp.split(/\s+/).uniq
expect(containers).to_not include @container_name
end
end
pending 'box packaging' do
before(:all) do
destroy_container
vagrant_box_remove('new-box')
vagrant_up
vagrant_package
@box_name = ENV['BOX_NAME']
# This will make
ENV["BOX_NAME"] = 'new-box'
ENV['BOX_URL'] = '/vagrant/spec/tmp/package.box'
end
after(:all) do
vagrant_box_remove('new-box')
ENV["BOX_NAME"] = @box_name
ENV['BOX_URL'] = nil
end
it 'creates a package that can be successfully brought up on a later `vagrant up`' do
vagrant_up
# Just to make sure we packaged it properly
expect(vagrant_ssh('cat /home/vagrant/original-box')).to eq @box_name
end
end
end

View file

@ -0,0 +1,76 @@
module AcceptanceExampleGroup
def self.included(base)
base.metadata[:type] = :acceptance
end
ID_FILE = "/vagrant/spec/.vagrant/machines/default/lxc/id"
def vagrant_container_name
File.read(ID_FILE).strip.chomp if File.exists?(ID_FILE)
end
def destroy_container
if name = vagrant_container_name
`sudo lxc-shutdown -n #{name} 2>/dev/null`
`sudo lxc-wait -n #{name} --state STOPPED 2>/dev/null`
`sudo lxc-destroy -n #{name} 2>/dev/null`
`rm -rf /vagrant/spec/.vagrant/`
end
`sudo killall -9 redir 2>/dev/null`
end
def with_vagrant_environment
opts = { cwd: '/vagrant/spec', ui_class: TestUI }
env = Vagrant::Environment.new(opts)
yield env
env.unload
end
def vagrant_up
with_vagrant_environment do |env|
env.cli('up', '--provider', 'lxc')
end
end
def vagrant_halt
with_vagrant_environment do |env|
env.cli('halt')
end
end
def vagrant_destroy
with_vagrant_environment do |env|
env.cli('destroy', '-f')
end
end
def vagrant_ssh(cmd)
output = nil
with_vagrant_environment do |env|
result = env.cli('ssh', '-c', cmd)
if result.to_i != 0
raise "SSH command failed: '#{cmd}'\n#{env.ui.messages.inspect}"
end
output = env.ui.messages[:info].join("\n").chomp
end
output
end
def vagrant_package
with_vagrant_environment do |env|
pkg = '/vagrant/spec/tmp/package.box'
`rm -f #{pkg}`
env.cli('package', '--output', pkg)
end
end
def vagrant_box_remove(name)
with_vagrant_environment do |env|
env.cli('box', 'list')
output = env.ui.messages[:info].join("\n").chomp
if output.include?(name)
env.cli('box', 'remove', name)
end
end
end
end

View file

@ -0,0 +1,12 @@
# Monkey patch vagrant in order to reuse the UI test object that is set on
# our Vagrant::Environments
#
require 'vagrant/machine'
Vagrant::Machine.class_eval do
alias :old_action :action
define_method :action do |action_name, extra_env = nil|
extra_env = { ui: @env.ui }.merge(extra_env || {})
old_action action_name, extra_env
end
end

View file

@ -0,0 +1,22 @@
class TestUI < Vagrant::UI::Interface
attr_reader :messages
METHODS = [:clear_line, :report_progress, :warn, :error, :info, :success]
def initialize
super
@messages = METHODS.each_with_object({}) { |m, h| h[m] = [] }
end
def ask(*args)
super
# Automated tests should not depend on user input, obviously.
raise Errors::UIExpectsTTY
end
METHODS.each do |method|
define_method(method) do |*args|#message, *opts|
@messages[method].push args[0]
end
end
end

21
spec/acceptance_helper.rb Normal file
View file

@ -0,0 +1,21 @@
require 'spec_helper'
unless ENV['USER'] == 'vagrant'
puts 'Acceptance specs are supposed to run from one of the vagrant-lxc dev machines'
exit 1
end
if defined? SimpleCov
SimpleCov.command_name 'acceptance'
end
require 'vagrant'
require 'vagrant-lxc'
Dir[File.dirname(__FILE__) + "/acceptance/support/**/*.rb"].each { |f| require f }
RSpec.configure do |config|
config.include AcceptanceExampleGroup, :type => :acceptance, :example_group => {
:file_path => /\bspec\/acceptance\//
}
end

View file

@ -10,10 +10,22 @@ require 'bundler/setup'
require 'i18n' require 'i18n'
require 'vagrant-lxc' require 'rspec-spies'
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f } Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
# If we should verify constant names, eager loads
if ENV['VERIFY_CONSTANT_NAMES']
require 'vagrant-lxc/plugin'
require 'vagrant-lxc/provider'
require 'vagrant-lxc/config'
end
require 'rspec/fire'
RSpec::Fire.configure do |config|
config.verify_constant_names = ENV['VERIFY_CONSTANT_NAMES'] == '1'
end
RSpec.configure do |config| RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true config.run_all_when_everything_filtered = true
@ -24,12 +36,4 @@ RSpec.configure do |config|
# the seed, which is printed after each run. # the seed, which is printed after each run.
# --seed 1234 # --seed 1234
config.order = 'random' config.order = 'random'
config.mock_with :rspec do |c|
c.yield_receiver_to_any_instance_implementation_blocks = true
end
config.expect_with :rspec do |c|
c.syntax = :expect
end
config.raise_errors_for_deprecations!
end end

View file

@ -24,12 +24,12 @@ describe Vagrant::LXC::Action::ClearForwardedPorts do
after { FileUtils.rm_rf data_dir.to_s } after { FileUtils.rm_rf data_dir.to_s }
it 'removes all files under pid directory' do it 'removes all files under pid directory' do
expect(Dir[pids_dir.to_s + "/redir_*.pid"]).to be_empty Dir[pids_dir.to_s + "/redir_*.pid"].should be_empty
end end
context 'with a valid redir pid' do context 'with a valid redir pid' do
it 'kills known processes' do it 'kills known processes' do
expect(subject).to have_received(:system).with("pkill -TERM -P #{pid}") subject.should have_received(:system).with("pkill -TERM -P #{pid}")
end end
end end
@ -37,7 +37,7 @@ describe Vagrant::LXC::Action::ClearForwardedPorts do
let(:pid_cmd) { 'sudo ls' } let(:pid_cmd) { 'sudo ls' }
it 'does not kill the process' do it 'does not kill the process' do
expect(subject).not_to have_received(:system).with("pkill -TERM -P #{pid}") subject.should_not have_received(:system).with("pkill -TERM -P #{pid}")
end end
end end
end end

View file

@ -1,15 +1,13 @@
require 'unit_helper' require 'unit_helper'
require 'vagrant-lxc/plugin'
require 'vagrant-lxc/provider'
require 'vagrant-lxc/action/compress_rootfs' require 'vagrant-lxc/action/compress_rootfs'
describe Vagrant::LXC::Action::CompressRootFS do describe Vagrant::LXC::Action::CompressRootFS do
let(:app) { double(:app, call: true) } let(:app) { double(:app, call: true) }
let(:env) { {machine: machine, ui: double(info: true)} } let(:env) { {machine: machine, ui: double(info: true)} }
let(:machine) { double(Vagrant::Machine, provider: provider) } let(:machine) { instance_double('Vagrant::Machine', provider: provider) }
let(:provider) { double(Vagrant::LXC::Provider, driver: driver) } let(:provider) { instance_double('Vagrant::LXC::Provider', driver: driver) }
let(:driver) { double(Vagrant::LXC::Driver, compress_rootfs: compressed_rootfs_path) } let(:driver) { instance_double('Vagrant::LXC::Driver', compress_rootfs: compressed_rootfs_path) }
let(:compressed_rootfs_path) { '/path/to/rootfs.tar.gz' } let(:compressed_rootfs_path) { '/path/to/rootfs.tar.gz' }
subject { described_class.new(app, env) } subject { described_class.new(app, env) }
@ -20,10 +18,10 @@ describe Vagrant::LXC::Action::CompressRootFS do
end end
it "asks the driver to compress container's rootfs" do it "asks the driver to compress container's rootfs" do
expect(driver).to have_received(:compress_rootfs) driver.should have_received(:compress_rootfs)
end end
it 'sets export.temp_dir on action env' do it 'sets export.temp_dir on action env' do
expect(env['package.rootfs']).to eq(compressed_rootfs_path) env['package.rootfs'].should == compressed_rootfs_path
end end
end end

View file

@ -1,15 +1,15 @@
require 'unit_helper' require 'unit_helper'
require 'tmpdir' require 'tmpdir'
require 'vagrant-lxc/provider' require 'vagrant-lxc/errors'
require 'vagrant-lxc/action/forward_ports' require 'vagrant-lxc/action/forward_ports'
describe Vagrant::LXC::Action::ForwardPorts do describe Vagrant::LXC::Action::ForwardPorts do
let(:app) { double(:app, call: true) } let(:app) { double(:app, call: true) }
let(:env) { {machine: machine, ui: double(info: true, warn: true)} } let(:env) { {machine: machine, ui: double(info: true)} }
let(:machine) { double(:machine) } let(:machine) { double(:machine) }
let!(:data_dir) { Pathname.new(Dir.mktmpdir) } let!(:data_dir) { Pathname.new(Dir.mktmpdir) }
let(:provider) { double(Vagrant::LXC::Provider, ssh_info: {host: container_ip}) } let(:provider) { instance_double('Vagrant::LXC::Provider', ssh_info: {host: container_ip}) }
let(:host_ip) { '127.0.0.1' } let(:host_ip) { '127.0.0.1' }
let(:host_port) { 8080 } let(:host_port) { 8080 }
let(:guest_port) { 80 } let(:guest_port) { 80 }
@ -24,7 +24,6 @@ describe Vagrant::LXC::Action::ForwardPorts do
machine.stub_chain(:config, :vm, :networks).and_return(networks) machine.stub_chain(:config, :vm, :networks).and_return(networks)
machine.stub(provider: provider, data_dir: data_dir) machine.stub(provider: provider, data_dir: data_dir)
subject.stub(redir_version: 3)
subject.stub(exec: true) subject.stub(exec: true)
subject.stub(spawn: pid) subject.stub(spawn: pid)
end end
@ -34,26 +33,26 @@ describe Vagrant::LXC::Action::ForwardPorts do
it 'forwards ports using redir' do it 'forwards ports using redir' do
subject.stub(system: true) subject.stub(system: true)
subject.call(env) subject.call(env)
expect(subject).to have_received(:spawn).with( subject.should have_received(:spawn).with(
"redir -n #{host_ip}:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null" "redir --laddr=#{host_ip} --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
) )
end end
it 'Uses 127.0.0.1 as default if host_ip is nil' do it 'skips --laddr parameter if host_ip is nil' do
forward_conf.delete(:host_ip) forward_conf.delete(:host_ip)
subject.stub(system: true) subject.stub(system: true)
subject.call(env) subject.call(env)
expect(subject).to have_received(:spawn).with( subject.should have_received(:spawn).with(
"redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null" "redir --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
) )
end end
it 'Uses 127.0.0.1 by default if host_ip is a blank string' do it 'skips --laddr parameter if host_ip is a blank string' do
forward_conf[:host_ip] = ' ' forward_conf[:host_ip] = ' '
subject.stub(system: true) subject.stub(system: true)
subject.call(env) subject.call(env)
expect(subject).to have_received(:spawn).with( subject.should have_received(:spawn).with(
"redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null" "redir --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
) )
end end
@ -61,57 +60,18 @@ describe Vagrant::LXC::Action::ForwardPorts do
subject.stub(system: true) subject.stub(system: true)
subject.call(env) subject.call(env)
pid_file = data_dir.join('pids', "redir_#{host_port}.pid").read pid_file = data_dir.join('pids', "redir_#{host_port}.pid").read
expect(pid_file).to eq(pid) pid_file.should == pid
end end
it 'allows disabling a previously forwarded port' do it 'allows disabling a previously forwarded port' do
forward_conf[:disabled] = true forward_conf[:disabled] = true
subject.stub(system: true) subject.stub(system: true)
subject.call(env) subject.call(env)
expect(subject).not_to have_received(:spawn) subject.should_not have_received(:spawn)
end
it 'uses redir 2.x command line interface' do
subject.stub(system: true)
subject.stub(redir_version: 2)
subject.call(env)
expect(subject).to have_received(:spawn).with(
"redir --laddr=#{host_ip} --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
)
end end
it 'raises RedirNotInstalled error if `redir` is not installed' do it 'raises RedirNotInstalled error if `redir` is not installed' do
subject.stub(system: false) subject.stub(system: false)
expect { subject.call(env) }.to raise_error(Vagrant::LXC::Errors::RedirNotInstalled) lambda { subject.call(env) }.should raise_error(Vagrant::LXC::Errors::RedirNotInstalled)
end
context 'when a privileged port is used' do
let(:host_port) { 80 }
it 'forwards ports using redir' do
subject.stub(system: true)
subject.call(env)
expect(subject).to have_received(:spawn).with(
"sudo redir -n #{host_ip}:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
)
end
it 'Uses 127.0.0.1 by default if host_ip is nil' do
forward_conf.delete(:host_ip)
subject.stub(system: true)
subject.call(env)
expect(subject).to have_received(:spawn).with(
"sudo redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
)
end
it 'Uses 127.0.0.1 by default if host_ip is a blank string' do
forward_conf[:host_ip] = ' '
subject.stub(system: true)
subject.call(env)
expect(subject).to have_received(:spawn).with(
"sudo redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
)
end
end end
end end

View file

@ -6,7 +6,7 @@ require 'vagrant-lxc/action/handle_box_metadata'
describe Vagrant::LXC::Action::HandleBoxMetadata do describe Vagrant::LXC::Action::HandleBoxMetadata do
let(:app) { double(:app, call: true) } let(:app) { double(:app, call: true) }
let(:env) { {machine: machine, ui: double(info: true, warn: true)} } let(:env) { {machine: machine, ui: double(info: true)} }
let(:machine) { double(:machine, box: box) } let(:machine) { double(:machine, box: box) }
let(:box) { double(:box, name: 'box-name', metadata: metadata, directory: box_directory) } let(:box) { double(:box, name: 'box-name', metadata: metadata, directory: box_directory) }
let(:box_directory) { Pathname.new('/path/to/box') } let(:box_directory) { Pathname.new('/path/to/box') }
@ -16,111 +16,55 @@ describe Vagrant::LXC::Action::HandleBoxMetadata do
subject { described_class.new(app, env) } subject { described_class.new(app, env) }
context 'with 1.0.0 box' do context 'with valid contents' do
let(:version) { '1.0.0' }
before do before do
File.stub(exists?: true) File.stub(exists?: true)
# REFACTOR: This is pretty bad
subject.stub_chain(:template_config_file, :exist?).and_return(true)
subject.stub_chain(:template_config_file, :to_s).and_return(box_directory.join('lxc-config').to_s)
subject.call(env) subject.call(env)
end end
it 'sets the tarball argument for the template' do it 'sets the tarball argument for the template' do
expect(env[:lxc_template_opts]).to include( env[:lxc_template_opts].should include(
'--tarball' => box_directory.join('rootfs.tar.gz').to_s
)
end
it 'sets the template --config parameter' do
expect(env[:lxc_template_opts]).to include(
'--config' => box_directory.join('lxc-config').to_s
)
end
it 'does not set the auth key argument for the template' do
expect(env[:lxc_template_opts]).not_to include(
'--auth-key' => vagrant_key
)
end
it 'sets the template options from metadata on env hash' do
expect(env[:lxc_template_opts]).to include(metadata['template-opts'])
end
xit 'sets the template source path on env hash' do
expect(env[:lxc_template_src]).to eq(box_directory.join('lxc-template').to_s)
end
it 'does not warn about deprecation' do
expect(env[:ui]).not_to have_received(:warn)
end
end
context 'with valid pre 1.0.0 box' do
before do
File.stub(exists?: true)
# REFACTOR: This is pretty bad
subject.stub_chain(:old_template_config_file, :exist?).and_return(true)
subject.stub_chain(:old_template_config_file, :to_s).and_return(box_directory.join('lxc.conf').to_s)
subject.call(env)
end
it 'sets the tarball argument for the template' do
expect(env[:lxc_template_opts]).to include(
'--tarball' => box_directory.join('rootfs.tar.gz').to_s '--tarball' => box_directory.join('rootfs.tar.gz').to_s
) )
end end
it 'sets the auth key argument for the template' do it 'sets the auth key argument for the template' do
expect(env[:lxc_template_opts]).to include( env[:lxc_template_opts].should include(
'--auth-key' => vagrant_key '--auth-key' => vagrant_key
) )
end end
it 'sets the lxc config file parameter' do
expect(env[:lxc_template_config]).to eq(box_directory.join('lxc.conf').to_s)
end
it 'sets the template options from metadata on env hash' do it 'sets the template options from metadata on env hash' do
expect(env[:lxc_template_opts]).to include(metadata['template-opts']) env[:lxc_template_opts].should include(metadata['template-opts'])
end end
xit 'sets the template source path on env hash' do it 'sets the template source path on env hash' do
expect(env[:lxc_template_src]).to eq(box_directory.join('lxc-template').to_s) env[:lxc_template_src].should == box_directory.join('lxc-template').to_s
end
it 'warns about deprecation' do
expect(env[:ui]).to have_received(:warn)
end end
end end
describe 'with invalid contents' do describe 'with invalid contents' do
before { File.stub(exists?: true) } before { File.stub(exists?: true) }
it 'validates box versions' do it 'raises an error if the version is != 2' do
%w( 2 3 1.0.0 ).each do |v|
metadata['version'] = v
expect { subject.call(env) }.to_not raise_error
end
metadata['version'] = '1' metadata['version'] = '1'
expect { subject.call(env) }.to raise_error expect {
subject.call(env)
}.to raise_error(Vagrant::LXC::Errors::IncompatibleBox)
end end
it 'raises an error if the rootfs tarball cant be found' do it 'raises an error if the rootfs tarball cant be found' do
allow(File).to receive(:exists?).with(box_directory.join('rootfs.tar.gz').to_s).and_return(false) File.stub(:exists?).with(box_directory.join('rootfs.tar.gz').to_s).and_return(false)
expect { expect {
subject.call(env) subject.call(env)
}.to raise_error(Vagrant::LXC::Errors::RootFSTarballMissing) }.to raise_error(Vagrant::LXC::Errors::RootFSTarballMissing)
end end
it 'does not raise an error if the lxc-template script cant be found' do it 'raises an error if the lxc-template script cant be found' do
allow(File).to receive(:exists?).with(box_directory.join('lxc-template').to_s).and_return(false) File.stub(:exists?).with(box_directory.join('lxc-template').to_s).and_return(false)
expect { expect {
subject.call(env) subject.call(env)
}.to_not raise_error }.to raise_error(Vagrant::LXC::Errors::TemplateFileMissing)
end end
end end
end end

View file

@ -5,16 +5,16 @@ require 'vagrant-lxc/action/setup_package_files'
describe Vagrant::LXC::Action::SetupPackageFiles do describe Vagrant::LXC::Action::SetupPackageFiles do
let(:app) { double(:app, call: true) } let(:app) { double(:app, call: true) }
let(:env) { {machine: machine, tmp_path: tmp_path, ui: double(info: true), 'package.rootfs' => rootfs_path} } let(:env) { {machine: machine, tmp_path: tmp_path, ui: double(info: true), 'package.rootfs' => rootfs_path} }
let(:machine) { double(Vagrant::Machine, box: box) } let(:machine) { instance_double('Vagrant::Machine', box: box) }
let!(:tmp_path) { Pathname.new(Dir.mktmpdir) } let!(:tmp_path) { Pathname.new(Dir.mktmpdir) }
let(:box) { double(Vagrant::Box, directory: tmp_path.join('box')) } let(:box) { instance_double('Vagrant::Box', directory: tmp_path.join('box')) }
let(:rootfs_path) { tmp_path.join('rootfs-amd64.tar.gz') } let(:rootfs_path) { tmp_path.join('rootfs-amd64.tar.gz') }
subject { described_class.new(app, env) } subject { described_class.new(app, env) }
before do before do
box.directory.mkdir box.directory.mkdir
files = %w( lxc-template metadata.json lxc.conf lxc-config ).map { |f| box.directory.join(f) } files = %w( lxc-template metadata.json lxc.conf ).map { |f| box.directory.join(f) }
(files + [rootfs_path]).each do |file| (files + [rootfs_path]).each do |file|
file.open('w') { |f| f.puts file.to_s } file.open('w') { |f| f.puts file.to_s }
end end
@ -30,34 +30,20 @@ describe Vagrant::LXC::Action::SetupPackageFiles do
before { subject.call(env) } before { subject.call(env) }
it 'copies box lxc-template to package directory' do it 'copies box lxc-template to package directory' do
expect(env['package.directory'].join('lxc-template')).to be_file env['package.directory'].join('lxc-template').should be_file
end end
it 'copies metadata.json to package directory' do it 'copies metadata.json to package directory' do
expect(env['package.directory'].join('metadata.json')).to be_file env['package.directory'].join('metadata.json').should be_file
end end
it 'copies box lxc.conf to package directory' do it 'copies box lxc.conf to package directory' do
expect(env['package.directory'].join('lxc-template')).to be_file env['package.directory'].join('lxc-template').should be_file
end
it 'copies box lxc-config to package directory' do
expect(env['package.directory'].join('lxc-config')).to be_file
end end
it 'moves the compressed rootfs to package directory' do it 'moves the compressed rootfs to package directory' do
expect(env['package.directory'].join(rootfs_path.basename)).to be_file env['package.directory'].join(rootfs_path.basename).should be_file
expect(env['package.rootfs']).not_to be_file env['package.rootfs'].should_not be_file
end
end
context 'when lxc-template file is not present' do
before do
box.directory.join('lxc-template').delete
end
it 'does not blow up' do
expect { subject.call(env) }.to_not raise_error
end end
end end
@ -70,14 +56,4 @@ describe Vagrant::LXC::Action::SetupPackageFiles do
expect { subject.call(env) }.to_not raise_error expect { subject.call(env) }.to_not raise_error
end end
end end
context 'when lxc-config file is not present' do
before do
box.directory.join('lxc-config').delete
end
it 'does not blow up' do
expect { subject.call(env) }.to_not raise_error
end
end
end end

View file

@ -1,10 +1,9 @@
require 'unit_helper' require 'unit_helper'
require 'vagrant-lxc/sudo_wrapper'
require 'vagrant-lxc/driver/cli' require 'vagrant-lxc/driver/cli'
describe Vagrant::LXC::Driver::CLI do describe Vagrant::LXC::Driver::CLI do
let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true, wrapper_path: nil) } let(:sudo_wrapper) { instance_double('Vagrant::LXC::SudoWrapper', run: true) }
subject { described_class.new(sudo_wrapper) } subject { described_class.new(sudo_wrapper) }
@ -13,73 +12,51 @@ describe Vagrant::LXC::Driver::CLI do
let(:result) { @result } let(:result) { @result }
before do before do
allow(subject).to receive(:run).with(:ls).and_return(lxc_ls_out) subject.stub(:run).with(:ls).and_return(lxc_ls_out)
@result = subject.list @result = subject.list
end end
it 'grabs previously created containers from lxc-ls output' do it 'grabs previously created containers from lxc-ls output' do
expect(result).to be_an Enumerable result.should be_an Enumerable
expect(result).to include 'a-container' result.should include 'a-container'
expect(result).to include 'dup-container' result.should include 'dup-container'
end end
it 'removes duplicates from lxc-ls output' do it 'removes duplicates from lxc-ls output' do
expect(result.uniq).to eq(result) result.uniq.should == result
end end
end end
describe 'version' do describe 'version' do
let(:lxc_version_out) { "lxc version: 0.x.y-rc1\n" }
before do before do
allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out) subject.stub(:run).with(:version).and_return(lxc_version_out)
end end
describe 'lxc version after 1.x.x' do it 'parses the version from the output' do
let(:lxc_version_out) { "1.0.0\n" } subject.version.should == '0.x.y-rc1'
it 'parses the version from the output' do
expect(subject.version).to eq('1.0.0')
end
end
end
describe 'config' do
before do
allow(subject).to receive(:run).with(:config, 'lxc.lxcpath').and_return(lxc_config_out)
allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
end
describe 'lxc version after 1.x.x'do
let(:lxc_config_out) { "/var/lib/lxc\n" }
let(:lxc_version_out) { "1.0.0\n" }
it 'parser the lxc.lxcpath value' do
expect(subject.config('lxc.lxcpath')).not_to end_with("\n")
end
end end
end end
describe 'create' do describe 'create' do
let(:template) { 'quantal-64' } let(:template) { 'quantal-64' }
let(:name) { 'quantal-container' } let(:name) { 'quantal-container' }
let(:backingstore) { 'btrfs' } let(:config_file) { 'config' }
let(:backingstore_opts) { [['--dir', '/tmp/foo'], ['--foo', 'bar']] } let(:template_args) { { '--extra-param' => 'param', '--other' => 'value' } }
let(:config_file) { 'config' }
let(:template_args) { { '--extra-param' => 'param', '--other' => 'value' } }
subject { described_class.new(sudo_wrapper, name) } subject { described_class.new(sudo_wrapper, name) }
before do before do
allow(subject).to receive(:run) { |*args| @run_args = args } subject.stub(:run) { |*args| @run_args = args }
end end
it 'issues a lxc-create with provided template, container name and hash of arguments' do it 'issues a lxc-create with provided template, container name and hash of arguments' do
subject.create(template, backingstore, backingstore_opts, config_file, template_args) subject.create(template, config_file, template_args)
expect(subject).to have_received(:run).with( subject.should have_received(:run).with(
:create, :create,
'-B', backingstore,
'--template', template, '--template', template,
'--name', name, '--name', name,
*(backingstore_opts.flatten),
'-f', config_file, '-f', config_file,
'--', '--',
'--extra-param', 'param', '--extra-param', 'param',
@ -88,9 +65,9 @@ describe Vagrant::LXC::Driver::CLI do
end end
it 'wraps a low level error into something more meaningful in case the container already exists' do it 'wraps a low level error into something more meaningful in case the container already exists' do
allow(subject).to receive(:run) { raise Vagrant::LXC::Errors::ExecuteError, stderr: 'alreAdy Exists' } subject.stub(:run) { raise Vagrant::LXC::Errors::ExecuteError, stderr: 'alreAdy Exists' }
expect { expect {
subject.create(template, backingstore, backingstore_opts, config_file, template_args) subject.create(template, config_file, template_args)
}.to raise_error(Vagrant::LXC::Errors::ContainerAlreadyExists) }.to raise_error(Vagrant::LXC::Errors::ContainerAlreadyExists)
end end
end end
@ -101,12 +78,12 @@ describe Vagrant::LXC::Driver::CLI do
subject { described_class.new(sudo_wrapper, name) } subject { described_class.new(sudo_wrapper, name) }
before do before do
allow(subject).to receive(:run) subject.stub(:run)
subject.destroy subject.destroy
end end
it 'issues a lxc-destroy with container name' do it 'issues a lxc-destroy with container name' do
expect(subject).to have_received(:run).with(:destroy, '--name', name) subject.should have_received(:run).with(:destroy, '--name', name)
end end
end end
@ -115,12 +92,12 @@ describe Vagrant::LXC::Driver::CLI do
subject { described_class.new(sudo_wrapper, name) } subject { described_class.new(sudo_wrapper, name) }
before do before do
allow(subject).to receive(:run) subject.stub(:run)
end end
it 'starts container on the background' do it 'starts container on the background' do
subject.start subject.start
expect(subject).to have_received(:run).with( subject.should have_received(:run).with(
:start, :start,
'-d', '-d',
'--name', name '--name', name
@ -128,17 +105,23 @@ describe Vagrant::LXC::Driver::CLI do
end end
end end
describe 'stop' do describe 'shutdown' do
let(:name) { 'a-running-container' } let(:name) { 'a-running-container' }
subject { described_class.new(sudo_wrapper, name) } subject { described_class.new(sudo_wrapper, name) }
before do before do
allow(subject).to receive(:run) subject.stub(system: true)
subject.stop subject.stub(:run)
end end
it 'issues a lxc-stop with provided container name' do it 'issues a lxc-shutdown with provided container name' do
expect(subject).to have_received(:run).with(:stop, '--name', name) subject.shutdown
subject.should have_received(:run).with(:shutdown, '--name', name)
end
it 'raises a ShutdownNotSupported in case it is not supported' do
subject.stub(:system).with('which lxc-shutdown > /dev/null').and_return(false)
expect { subject.shutdown }.to raise_error(described_class::ShutdownNotSupported)
end end
end end
@ -147,21 +130,21 @@ describe Vagrant::LXC::Driver::CLI do
subject { described_class.new(sudo_wrapper, name) } subject { described_class.new(sudo_wrapper, name) }
before do before do
allow(subject).to receive(:run).and_return("state: STOPPED\npid: 2") subject.stub(:run).and_return("state: STOPPED\npid: 2")
end end
it 'calls lxc-info with the right arguments' do it 'calls lxc-info with the right arguments' do
subject.state subject.state
expect(subject).to have_received(:run).with(:info, '--name', name, retryable: true) subject.should have_received(:run).with(:info, '--name', name, retryable: true)
end end
it 'maps the output of lxc-info status out to a symbol' do it 'maps the output of lxc-info status out to a symbol' do
expect(subject.state).to eq(:stopped) subject.state.should == :stopped
end end
it 'is not case sensitive' do it 'is not case sensitive' do
allow(subject).to receive(:run).and_return("StatE: STarTED\npid: 2") subject.stub(:run).and_return("StatE: STarTED\npid: 2")
expect(subject.state).to eq(:started) subject.state.should == :started
end end
end end
@ -177,25 +160,35 @@ describe Vagrant::LXC::Driver::CLI do
it 'calls lxc-attach with specified command' do it 'calls lxc-attach with specified command' do
subject.attach(*command) subject.attach(*command)
expect(subject).to have_received(:run).with(:attach, '--name', name, '--', *command) subject.should have_received(:run).with(:attach, '--name', name, '--', *command)
end end
it 'supports a "namespaces" parameter' do it 'supports a "namespaces" parameter' do
allow(subject).to receive(:run).with(:attach, '-h', :show_stderr => true).and_return({:stdout => '', :stderr => '--namespaces'}) subject.stub(:run).with(:attach, '-h', :show_stderr => true).and_return({:stdout => '', :stderr => '--namespaces'})
subject.attach *(command + [{namespaces: ['network', 'mount']}]) subject.attach *(command + [{namespaces: ['network', 'mount']}])
expect(subject).to have_received(:run).with(:attach, '--name', name, '--namespaces', 'NETWORK|MOUNT', '--', *command) subject.should have_received(:run).with(:attach, '--name', name, '--namespaces', 'NETWORK|MOUNT', '--', *command)
end
it 'raises a NamespacesNotSupported error if not supported' do
subject.stub(:run).with(:attach, '-h', :show_stderr => true).and_return({:stdout => '', :stderr => 'not supported'})
expect {
subject.attach *(command + [{namespaces: ['network', 'mount']}])
}.to raise_error(Vagrant::LXC::Errors::NamespacesNotSupported)
end end
end end
describe 'transition block' do describe 'transition block' do
let(:name) { 'a-running-container' }
subject { described_class.new(name) }
before do before do
subject.stub(run: true, sleep: true, state: :stopped) subject.stub(run: true, sleep: true, state: :stopped)
end end
it 'yields a cli object' do it 'yields a cli object' do
allow(subject).to receive(:shutdown) subject.stub(:shutdown)
subject.transition_to(:stopped) { |c| c.shutdown } subject.transition_to(:stopped) { |c| c.shutdown }
expect(subject).to have_received(:shutdown) subject.should have_received(:shutdown)
end end
it 'throws an exception if block is not provided' do it 'throws an exception if block is not provided' do
@ -204,6 +197,6 @@ describe Vagrant::LXC::Driver::CLI do
}.to raise_error(described_class::TransitionBlockNotProvided) }.to raise_error(described_class::TransitionBlockNotProvided)
end end
skip 'waits for the expected container state' pending 'waits for the expected container state'
end end
end end

View file

@ -1,15 +1,15 @@
require 'unit_helper' require 'unit_helper'
require 'vagrant'
require 'vagrant-lxc/driver' require 'vagrant-lxc/driver'
require 'vagrant-lxc/driver/cli' require 'vagrant-lxc/driver/cli'
require 'vagrant-lxc/sudo_wrapper'
describe Vagrant::LXC::Driver do describe Vagrant::LXC::Driver do
describe 'container name validation' do describe 'container name validation' do
let(:unknown_container) { described_class.new('unknown', nil, cli) } let(:unknown_container) { described_class.new('unknown', nil, cli) }
let(:valid_container) { described_class.new('valid', nil, cli) } let(:valid_container) { described_class.new('valid', nil, cli) }
let(:new_container) { described_class.new(nil, nil) } let(:new_container) { described_class.new(nil, nil) }
let(:cli) { double(Vagrant::LXC::Driver::CLI, list: ['valid']) } let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', list: ['valid']) }
it 'raises a ContainerNotFound error if an unknown container name gets provided' do it 'raises a ContainerNotFound error if an unknown container name gets provided' do
expect { expect {
@ -31,32 +31,28 @@ describe Vagrant::LXC::Driver do
end end
describe 'creation' do describe 'creation' do
let(:name) { 'container-name' } let(:name) { 'container-name' }
let(:backingstore) { 'btrfs' } let(:template_name) { 'auto-assigned-template-id' }
let(:backingstore_opts) { [['--dir', '/tmp/foo'], ['--foo', 'bar']] } let(:template_path) { '/path/to/lxc-template-from-box' }
let(:template_name) { 'auto-assigned-template-id' } let(:template_opts) { {'--some' => 'random-option'} }
let(:template_path) { '/path/to/lxc-template-from-box' } let(:config_file) { '/path/to/lxc-config-from-box' }
let(:template_opts) { {'--some' => 'random-option'} } let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' }
let(:config_file) { '/path/to/lxc-config-from-box' } let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', :create => true, :name= => true) }
let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' }
let(:cli) { double(Vagrant::LXC::Driver::CLI, :create => true, :name= => true) }
subject { described_class.new(nil, nil, cli) } subject { described_class.new(nil, nil, cli) }
before do before do
allow(subject).to receive(:import_template).and_yield(template_name) subject.stub(:import_template).and_yield(template_name)
subject.create name, backingstore, backingstore_opts, template_path, config_file, template_opts subject.create name, template_path, config_file, template_opts
end end
it 'sets the cli object container name' do it 'sets the cli object container name' do
expect(cli).to have_received(:name=).with(name) cli.should have_received(:name=).with(name)
end end
it 'creates container with the right arguments' do it 'creates container with the right arguments' do
expect(cli).to have_received(:create).with( cli.should have_received(:create).with(
template_path, template_name,
backingstore,
backingstore_opts,
config_file, config_file,
template_opts template_opts
) )
@ -64,32 +60,26 @@ describe Vagrant::LXC::Driver do
end end
describe 'destruction' do describe 'destruction' do
let(:cli) { double(Vagrant::LXC::Driver::CLI, destroy: true) } let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', destroy: true) }
subject { described_class.new('name', nil, cli) } subject { described_class.new('name', nil, cli) }
before { subject.destroy } before { subject.destroy }
it 'delegates to cli object' do it 'delegates to cli object' do
expect(cli).to have_received(:destroy) cli.should have_received(:destroy)
end end
end end
describe 'start' do describe 'start' do
let(:customizations) { [['a', '1'], ['b', '2']] } let(:customizations) { [['a', '1'], ['b', '2']] }
let(:internal_customization) { ['internal', 'customization'] } let(:internal_customization) { ['internal', 'customization'] }
let(:cli) { double(Vagrant::LXC::Driver::CLI, start: true) } let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', start: true) }
let(:sudo) { double(Vagrant::LXC::SudoWrapper) } let(:sudo) { instance_double('Vagrant::LXC::SudoWrapper', su_c: true) }
subject { described_class.new('name', sudo, cli) } subject { described_class.new('name', sudo, cli) }
before do before do
sudo.should_receive(:run).with('cat', '/var/lib/lxc/name/config').exactly(2).times.
and_return('# CONFIGURATION')
sudo.should_receive(:run).twice.with('cp', '-f', %r{/(run|tmp)/.*}, '/var/lib/lxc/name/config')
sudo.should_receive(:run).twice.with('chown', 'root:root', '/var/lib/lxc/name/config')
expect(cli).to receive(:config).with("lxc.lxcpath").and_return("/var/lib/lxc")
subject.customizations << internal_customization subject.customizations << internal_customization
subject.start(customizations) subject.start(customizations)
end end
@ -99,159 +89,78 @@ describe Vagrant::LXC::Driver do
it 'writes configurations to config file' it 'writes configurations to config file'
it 'starts container with configured customizations' do it 'starts container with configured customizations' do
expect(cli).to have_received(:start) cli.should have_received(:start)
end end
end end
describe 'halt' do describe 'halt' do
let(:cli) { double(Vagrant::LXC::Driver::CLI, stop: true) } let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', shutdown: true) }
subject { described_class.new('name', nil, cli) } subject { described_class.new('name', nil, cli) }
before do before do
allow(cli).to receive(:transition_to).and_yield(cli) cli.stub(:transition_to).and_yield(cli)
end end
it 'delegates to cli stop' do it 'delegates to cli shutdown' do
expect(cli).to receive(:stop) cli.should_receive(:shutdown)
subject.forced_halt subject.forced_halt
end end
it 'expects a transition to running state to take place' do it 'expects a transition to running state to take place' do
expect(cli).to receive(:transition_to).with(:stopped) cli.should_receive(:transition_to).with(:stopped)
subject.forced_halt subject.forced_halt
end end
it 'attempts to force the container to stop in case a shutdown doesnt work' do it 'attempts to force the container to stop in case a shutdown doesnt work' do
allow(cli).to receive(:shutdown).and_raise(Vagrant::LXC::Driver::CLI::TargetStateNotReached.new :target, :source) cli.stub(:shutdown).and_raise(Vagrant::LXC::Driver::CLI::TargetStateNotReached.new :target, :source)
expect(cli).to receive(:transition_to).with(:stopped) cli.should_receive(:transition_to).with(:stopped).twice
expect(cli).to receive(:stop) cli.should_receive(:stop)
subject.forced_halt
end
it 'attempts to force the container to stop in case lxc-shutdown is not supported' do
cli.stub(:shutdown).and_raise(Vagrant::LXC::Driver::CLI::ShutdownNotSupported)
cli.should_receive(:transition_to).with(:stopped).twice
cli.should_receive(:stop)
subject.forced_halt subject.forced_halt
end end
end end
describe 'state' do describe 'state' do
let(:cli_state) { :something } let(:cli_state) { :something }
let(:cli) { double(Vagrant::LXC::Driver::CLI, state: cli_state) } let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', state: cli_state) }
subject { described_class.new('name', nil, cli) } subject { described_class.new('name', nil, cli) }
it 'delegates to cli' do it 'delegates to cli' do
expect(subject.state).to eq(cli_state) subject.state.should == cli_state
end
end
describe 'containers_path' do
let(:cli) { double(Vagrant::LXC::Driver::CLI, config: cli_config_value) }
subject { described_class.new('name', nil, cli) }
describe 'lxc version after 1.x.x' do
let(:cli_config_value) { '/etc/lxc' }
it 'delegates to cli' do
expect(subject.containers_path).to eq(cli_config_value)
end
end end
end end
describe 'folder sharing' do describe 'folder sharing' do
let(:shared_folder) { {guestpath: '/vagrant', hostpath: '/path/to/host/dir'} } let(:shared_folder) { {guestpath: '/vagrant', hostpath: '/path/to/host/dir'} }
let(:ro_rw_folder) { {guestpath: '/vagrant/ro_rw', hostpath: '/path/to/host/dir', mount_options: ['ro', 'rw']} } let(:folders) { [shared_folder] }
let(:with_space_folder) { {guestpath: '/tmp/with space', hostpath: '/path/with space'} }
let(:folders) { [shared_folder, ro_rw_folder, with_space_folder] }
let(:expected_guest_path) { "vagrant" }
let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true) }
let(:rootfs_path) { Pathname('/path/to/rootfs') } let(:rootfs_path) { Pathname('/path/to/rootfs') }
let(:expected_guest_path) { "#{rootfs_path}/vagrant" }
let(:sudo_wrapper) { instance_double('Vagrant::LXC::SudoWrapper', run: true) }
subject { described_class.new('name', sudo_wrapper) } subject { described_class.new('name', sudo_wrapper) }
describe "with fixed rootfs" do before do
before do subject.stub(rootfs_path: rootfs_path, system: true)
subject.stub(rootfs_path: Pathname('/path/to/rootfs'), system: true) subject.share_folders(folders)
subject.share_folders(folders)
end
it 'adds a mount.entry to its local customizations' do
expect(subject.customizations).to include [
'mount.entry',
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
]
end
it 'supports additional mount options' do
expect(subject.customizations).to include [
'mount.entry',
"#{ro_rw_folder[:hostpath]} vagrant/ro_rw none ro,rw 0 0"
]
end
it 'supports directories with spaces' do
expect(subject.customizations).to include [
'mount.entry',
"/path/with\\040space tmp/with\\040space none bind,create=dir 0 0"
]
end
end end
describe "with directory-based LXC config" do it "creates guest folder under container's rootfs" do
let(:config_string) { sudo_wrapper.should have_received(:run).with("mkdir", "-p", expected_guest_path)
<<-ENDCONFIG.gsub(/^\s+/, '')
# Blah blah comment
lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
lxc.mount.entry = sysfs sys sysfs defaults 0 0
lxc.tty.max = 4
lxc.pty.max = 1024
lxc.rootfs.path = #{rootfs_path}
# VAGRANT-BEGIN
lxc.network.type=veth
lxc.network.name=eth1
# VAGRANT-END
ENDCONFIG
}
before do
subject { described_class.new('name', sudo_wrapper) }
subject.stub(config_string: config_string)
subject.share_folders(folders)
end
it 'adds a mount.entry to its local customizations' do
expect(subject.customizations).to include [
'mount.entry',
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
]
end
end end
describe "with overlayfs-based LXC config" do it 'adds a mount.entry to its local customizations' do
let(:config_string) { subject.customizations.should include [
<<-ENDCONFIG.gsub(/^\s+/, '') 'mount.entry',
# Blah blah comment "#{shared_folder[:hostpath]} #{expected_guest_path} none bind 0 0"
lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0 ]
lxc.mount.entry = sysfs sys sysfs defaults 0 0
lxc.tty.max = 4
lxc.pty.max = 1024
lxc.rootfs.path = overlayfs:/path/to/master/directory:#{rootfs_path}
# VAGRANT-BEGIN
lxc.network.type=veth
lxc.network.name=eth1
# VAGRANT-END
ENDCONFIG
}
before do
subject { described_class.new('name', sudo_wrapper) }
subject.stub(config_string: config_string)
subject.share_folders(folders)
end
it 'adds a mount.entry to its local customizations' do
expect(subject.customizations).to include [
'mount.entry',
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
]
end
end end
end end
end end

View file

@ -2,23 +2,23 @@ module UnitExampleGroup
def self.included(base) def self.included(base)
base.metadata[:type] = :unit base.metadata[:type] = :unit
base.before do base.before do
allow_any_instance_of(Object).to receive(:system) { |instance, *args, &block| Object.any_instance.stub(:system) { |*args, &block|
UnitExampleGroup.prevent_system_calls(*args, &block) UnitExampleGroup.prevent_system_calls(*args, &block)
} }
allow_any_instance_of(Object).to receive(:`) { |instance, *args, &block| Object.any_instance.stub(:`) { |*args, &block|
UnitExampleGroup.prevent_system_calls(*args, &block) UnitExampleGroup.prevent_system_calls(*args, &block)
} }
allow_any_instance_of(Object).to receive(:exec) { |instance, *args, &block| Object.any_instance.stub(:exec) { |*args, &block|
UnitExampleGroup.prevent_system_calls(*args, &block) UnitExampleGroup.prevent_system_calls(*args, &block)
} }
allow_any_instance_of(Object).to receive(:fork) { |instance, *args, &block| Object.any_instance.stub(:fork) { |*args, &block|
UnitExampleGroup.prevent_system_calls(*args, &block) UnitExampleGroup.prevent_system_calls(*args, &block)
} }
allow_any_instance_of(Object).to receive(:spawn) { |instance, *args, &block| Object.any_instance.stub(:spawn) { |*args, &block|
UnitExampleGroup.prevent_system_calls(*args, &block) UnitExampleGroup.prevent_system_calls(*args, &block)
} }
require 'vagrant/util/subprocess' require 'vagrant/util/subprocess'
allow(Vagrant::Util::Subprocess).to receive(:execute) { |*args, &block| Vagrant::Util::Subprocess.stub(:execute) { |*args, &block|
UnitExampleGroup.prevent_system_calls(*args, &block) UnitExampleGroup.prevent_system_calls(*args, &block)
} }
end end

View file

@ -7,11 +7,9 @@ if defined? SimpleCov
end end
RSpec.configure do |config| RSpec.configure do |config|
config.include RSpec::Fire
config.include UnitExampleGroup, :type => :unit, :example_group => { config.include UnitExampleGroup, :type => :unit, :example_group => {
:file_path => /\bspec\/unit\// :file_path => /\bspec\/unit\//
} }
config.mock_with :rspec do |c|
c.yield_receiver_to_any_instance_implementation_blocks = true
end
end end

View file

@ -3,7 +3,7 @@ begin
require 'coveralls/rake/task' require 'coveralls/rake/task'
desc 'Run all specs' desc 'Run all specs'
task :spec => ['spec:set_coverage', 'spec:unit', 'spec:acceptance'] task :spec => ['spec:unit', 'spec:acceptance']
desc 'Default task which runs all specs with code coverage enabled' desc 'Default task which runs all specs with code coverage enabled'
task :default => ['spec:set_coverage', 'spec:unit'] task :default => ['spec:set_coverage', 'spec:unit']
@ -17,24 +17,17 @@ namespace :spec do
ENV['COVERAGE'] = 'true' ENV['COVERAGE'] = 'true'
end end
desc 'Run acceptance specs using vagrant-spec' def types
task :acceptance do dirs = Dir['./spec/**/*_spec.rb'].map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }.uniq
components = %w( Hash[dirs.map { |d| [d.split('/').last, d] }]
basic
network/forwarded_port
synced_folder
synced_folder/nfs
synced_folder/rsync
provisioner/shell
provisioner/puppet
provisioner/chef-solo
package
).map{|s| "provider/lxc/#{s}" }
sh "export ACCEPTANCE=true && bundle exec vagrant-spec test --components=#{components.join(' ')}"
end end
types.each do |type, dir|
desc "Run the code examples in #{dir}"
RSpec::Core::RakeTask.new(type) do |t|
# Tells rspec-fire to verify if constants used really exist
ENV['VERIFY_CONSTANT_NAMES'] = '1'
desc "Run unit specs with rspec" t.pattern = "./#{dir}/**/*_spec.rb"
RSpec::Core::RakeTask.new(:unit) do |t| end
t.pattern = "./unit/**/*_spec.rb"
end end
end end

View file

@ -1,129 +0,0 @@
#!<%= cmd_paths['ruby'] %>
# Automatically created by vagrant-lxc
class Whitelist
class << self
def add(command, *args)
list[command] ||= []
list[command] << args
end
def add_regex(regex, *args)
regex_list << [regex, [args]]
end
def list
@list ||= {}
end
def regex_list
@regex_list ||= []
end
def allowed(command)
list[command] || allowed_regex(command) || []
end
def allowed_regex(command)
found = regex_list.find { |r| r[0] =~ command }
return found[1] if found
end
def run!(argv)
begin
command, args = `which #{argv.shift}`.chomp, argv || []
check!(command, args)
system "#{command} #{args.join(" ")}"
exit_code = $?.to_i
exit_code = 1 if exit_code == 256
exit exit_code
rescue => e
STDERR.puts e.message
exit 1
end
end
private
def check!(command, args)
allowed(command).each do |checks|
return if valid_args?(args, checks)
end
raise_invalid(command, args)
end
def valid_args?(args, checks)
return false unless valid_length?(args, checks)
check = nil
args.each_with_index do |provided, i|
check = checks[i] unless check == '**'
return false unless match?(provided, check)
end
true
end
def valid_length?(args, checks)
args.length == checks.length || checks.last == '**'
end
def match?(arg, check)
check == '**' || check.is_a?(Regexp) && !!check.match(arg) || arg == check
end
def raise_invalid(command, args)
raise "Invalid arguments for command #{command}, " <<
"provided args: #{args.inspect}"
end
end
end
base = "<%= lxc_base_path %>"
base_path = %r{\A#{base}/.*\z}
##
# Commands from provider.rb
# - Check lxc is installed
Whitelist.add '<%= cmd_paths['which'] %>', /\Alxc-\w+\z/
##
# Commands from driver.rb
# - Container config file
Whitelist.add '<%= cmd_paths['cat'] %>', base_path
# - Shared folders
Whitelist.add '<%= cmd_paths['mkdir'] %>', '-p', base_path
# - Container config customizations and pruning
Whitelist.add '<%= cmd_paths['cp'] %>', '-f', %r{/tmp/.*}, base_path
Whitelist.add '<%= cmd_paths['chown'] %>', 'root:root', base_path
# - Packaging
Whitelist.add '<%= cmd_paths['tar'] %>', '--numeric-owner', '-cvzf', %r{/tmp/.*/rootfs.tar.gz}, '-C', base_path, './rootfs'
Whitelist.add '<%= cmd_paths['chown'] %>', /\A\d+:\d+\z/, %r{\A/tmp/.*/rootfs\.tar\.gz\z}
# - Private network script and commands
Whitelist.add '<%= cmd_paths['ip'] %>', 'addr', 'add', /(\d+|\.)+\/24/, 'dev', /.+/
Whitelist.add '<%= cmd_paths['ip'] %>', 'link', 'set', /.+/, /(up|down)/
Whitelist.add '<%= cmd_paths['brctl'] %>', /(addbr|delbr)/, /.+/
Whitelist.add_regex %r{<%= pipework_regex %>}, '**'
##
# Commands from driver/cli.rb
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-version'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-ls'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-info', '--name', /.*/
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-info', '--name', /.*/, '-iH'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-create', '-B', /.*/, '--template', /.*/, '--name', /.*/, '**'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-create', '--version'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-destroy', '--name', /.*/
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-start', '-d', '--name', /.*/, '**'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-stop', '--name', /.*/
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-shutdown', '--name', /.*/
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-attach', '--name', /.*/, '**'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-attach', '-h'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-config', 'lxc.lxcpath'
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-update-config', '-c', /.*/
##
# Commands from driver/action/remove_temporary_files.rb
Whitelist.add '<%= cmd_paths['rm'] %>', '-rf', %r{\A#{base}/.*/rootfs/tmp/.*}
# Watch out for stones
Whitelist.run!(ARGV)

View file

@ -1,24 +0,0 @@
# FIXME: Figure out why this doesn't work
if ENV['COVERAGE'] == 'true'
require 'simplecov'
require 'coveralls'
SimpleCov.start { add_filter '/spec/' }
SimpleCov.command_name 'acceptance'
end
if ENV['BOX_PATH'] == nil
latest = ENV.fetch('LATEST_BOXES','2014-03-21')
release = ENV.fetch('RELEASE', 'acceptance')
local_path ="#{File.expand_path("../", __FILE__)}/boxes/output/#{latest}/vagrant-lxc-#{release}-amd64.box"
if File.exists?(local_path)
ENV['BOX_PATH'] = local_path
else
raise 'Set $BOX_PATH to the latest released boxes'
end
end
Vagrant::Spec::Acceptance.configure do |c|
c.component_paths << "spec/acceptance"
c.provider 'lxc', box: ENV['BOX_PATH'], features: ['!suspend']
end