Compare commits
170 commits
1.0-stable
...
master
Author | SHA1 | Date | |
---|---|---|---|
a47660a1e5 | |||
3575d65ffb | |||
|
938a29ed96 | ||
|
ff58ecd5f2 | ||
|
df6b78c4ed | ||
|
4d53acb9fb | ||
|
b88d50fb68 | ||
4e3306ed74 | |||
|
c167ac7f83 | ||
|
a112b072aa | ||
|
f750bf406c | ||
|
2a5510b34c | ||
|
a1aa60ded5 | ||
|
61c921ac6f | ||
|
437b5e7a2e | ||
|
2c2630a788 | ||
|
5a1f6ab2cb | ||
|
f71de429a1 | ||
|
50cbe5a0d6 | ||
|
44eefd81fb | ||
|
a84f8b59bf | ||
|
c1dd7baf2a | ||
|
8a1e1863a7 | ||
|
b812a6934a | ||
|
8cfe577b17 | ||
|
dd24cdc3d6 | ||
|
208edd49e5 | ||
|
484b868100 | ||
|
b5f2a9006c | ||
|
2e20f96fec | ||
|
d3409ace2a | ||
|
530a899467 | ||
|
9e215ae1a1 | ||
|
8fa42b1ab4 | ||
|
2ae84fcc51 | ||
|
582e3b368a | ||
|
6738febaa2 | ||
|
49ebf3488e | ||
|
bd42317ec2 | ||
|
1c27047f4b | ||
|
fef11bf7ef | ||
|
c74ddbf2fc | ||
|
2b08ae199f | ||
|
aa777653f4 | ||
|
7e1eb1d373 | ||
|
4ff412e2d2 | ||
|
bd4aa8167c | ||
|
2423464cdb | ||
|
0b5087f72e | ||
|
c8801ba8b2 | ||
|
97b5882262 | ||
|
6eb7ec1a2e | ||
|
fe7d638b35 | ||
|
f8a78e520b | ||
|
dbf2dfb8ff | ||
|
d3788f55f3 | ||
|
f224fc5ea5 | ||
|
1c64ea1b2c | ||
|
b96ba86f72 | ||
|
8b93206c18 | ||
|
e4c566ebc9 | ||
|
d35ee4aed0 | ||
|
03c23d7df8 | ||
|
10c53c54d7 | ||
|
2ce460bc30 | ||
|
553f1b5ed0 | ||
|
1f805f6deb | ||
|
43aa9bfb3e | ||
|
851f58d42a | ||
|
fdb7222965 | ||
|
4fd0635204 | ||
|
ae18c05b2b | ||
|
6d8580a294 | ||
|
cac4910296 | ||
|
2d63603d85 | ||
|
a68a1de21f | ||
|
671bd55cea | ||
|
1c2208a30e | ||
|
0cdd4d352c | ||
|
62535b6465 | ||
|
932a7808be | ||
|
9dd12bfcdf | ||
|
6dcf584b25 | ||
|
544c061e65 | ||
|
848383e081 | ||
|
d4e5122c6c | ||
|
aa5fb7a932 | ||
|
81d70d26d3 | ||
|
4c969a6ae7 | ||
|
1fb64dbbdf | ||
|
d11b6f2dc7 | ||
|
ad39aa9645 | ||
|
050c160de2 | ||
|
3d924985dd | ||
|
95bfdfd54d | ||
|
25d10cd3bc | ||
|
86381bfeee | ||
|
7c778dfb4d | ||
|
9e5637a9fe | ||
|
3257bd25bb | ||
|
06bbc7a5ef | ||
|
6136ebb966 | ||
|
9b70f3daab | ||
|
2accd886fa | ||
|
993e430ccc | ||
|
ea99d13f76 | ||
|
fddd8cc257 | ||
|
611a86ce84 | ||
|
e5a55d1020 | ||
|
64f561073c | ||
|
0c353598f8 | ||
|
78ef85aa97 | ||
|
366a98a052 | ||
|
40ced9d3d1 | ||
|
bbff802b5d | ||
|
eb503e42fd | ||
|
5329e8837e | ||
|
d2c032a073 | ||
|
7eb3be37de | ||
|
31bb4eadf9 | ||
|
5fb0bcbcbc | ||
|
eba671c54d | ||
|
4b78c04a47 | ||
|
9c67e13fb8 | ||
|
5cd32c76df | ||
|
2b91983cae | ||
|
64240323f0 | ||
|
6718fed241 | ||
|
81f2c13541 | ||
|
c3508870fd | ||
|
fb661300e7 | ||
|
bb21906ec4 | ||
|
0365ad4a17 | ||
|
fd22ccc073 | ||
|
52cca8e7f6 | ||
|
55bbadef6f | ||
|
f52df5df14 | ||
|
8cb0afeb39 | ||
|
8ccafecd9e | ||
|
497f750248 | ||
|
caa3c53a8f | ||
|
7d017ada1e | ||
|
05fdb3e000 | ||
|
5da3fc8be5 | ||
|
c9cd671a32 | ||
|
3b45b92d1a | ||
|
156bc015c8 | ||
|
fb23e606cc | ||
|
ef06ea622e | ||
|
7a09375ae7 | ||
|
f4b738ebd9 | ||
|
555499d04a | ||
|
447d0dfc42 | ||
|
bf3a9a5039 | ||
|
28bdbe371d | ||
|
758703ea6b | ||
|
01d53a783c | ||
|
8b37056294 | ||
|
2a667b88b6 | ||
|
2a48f366d4 | ||
|
92685472ec | ||
|
67523019aa | ||
|
fe532525c8 | ||
|
188a1eb089 | ||
|
89f3e98679 | ||
|
a3252c3593 | ||
|
5232f2c7b1 | ||
|
d22d6588f8 | ||
|
0bd071f95d | ||
|
044322d70f |
44 changed files with 1284 additions and 917 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -19,6 +19,7 @@ doc/
|
||||||
|
|
||||||
/tags
|
/tags
|
||||||
/gems.tags
|
/gems.tags
|
||||||
|
/Gemfile.lock
|
||||||
|
|
||||||
.vagrant
|
.vagrant
|
||||||
/cache
|
/cache
|
||||||
|
|
12
.travis.yml
12
.travis.yml
|
@ -1,8 +1,10 @@
|
||||||
language: ruby
|
language: ruby
|
||||||
rvm:
|
rvm:
|
||||||
- 2.0.0
|
- 2.2
|
||||||
- 2.1.1
|
- 2.3
|
||||||
matrix:
|
- 2.4
|
||||||
allow_failures:
|
- 2.5
|
||||||
- rvm: 2.1.1
|
install:
|
||||||
|
- 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"
|
||||||
|
|
145
CHANGELOG.md
145
CHANGELOG.md
|
@ -1,3 +1,148 @@
|
||||||
|
## [1.4.2](https://github.com/fgrehm/vagrant-lxc/compare/v1.4.1...v1.4.2) (Jul 17, 2018)
|
||||||
|
|
||||||
|
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)
|
## [1.0.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0...v1.0.1) (Oct 15, 2014)
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
|
6
Gemfile
6
Gemfile
|
@ -8,9 +8,9 @@ group :development do
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'rake'
|
gem 'rake', '~> 10.4.2'
|
||||||
gem 'rspec', '2.99.0'
|
gem 'rspec', '~> 3.5.0'
|
||||||
gem 'coveralls', require: (ENV['COVERAGE'] == 'true')
|
gem 'coveralls', '~> 0.7.2', require: (ENV['COVERAGE'] == 'true')
|
||||||
gem 'vagrant-spec', git: 'https://github.com/mitchellh/vagrant-spec.git'
|
gem 'vagrant-spec', git: 'https://github.com/mitchellh/vagrant-spec.git'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
175
Gemfile.lock
175
Gemfile.lock
|
@ -1,175 +0,0 @@
|
||||||
GIT
|
|
||||||
remote: https://github.com/fgrehm/vagrant-cachier.git
|
|
||||||
revision: 6f275353b82ab57ada04c79f6fb2befce0395c77
|
|
||||||
specs:
|
|
||||||
vagrant-cachier (0.7.2)
|
|
||||||
|
|
||||||
GIT
|
|
||||||
remote: https://github.com/fgrehm/vagrant-pristine.git
|
|
||||||
revision: 503dbc47848c81d0fbfa6840491856f518d244a1
|
|
||||||
specs:
|
|
||||||
vagrant-pristine (0.3.0)
|
|
||||||
|
|
||||||
GIT
|
|
||||||
remote: https://github.com/mitchellh/vagrant-spec.git
|
|
||||||
revision: c0dafc996165bf1628b672dd533f1858ff66fe4a
|
|
||||||
specs:
|
|
||||||
vagrant-spec (0.0.1)
|
|
||||||
childprocess (~> 0.5.0)
|
|
||||||
log4r (~> 1.1.9)
|
|
||||||
rspec (~> 2.14)
|
|
||||||
thor (~> 0.18.1)
|
|
||||||
|
|
||||||
GIT
|
|
||||||
remote: https://github.com/mitchellh/vagrant.git
|
|
||||||
revision: 0a5f6bb77e6a61b56c96057de94f5f8c6868e27c
|
|
||||||
specs:
|
|
||||||
vagrant (1.6.4.dev)
|
|
||||||
bundler (>= 1.5.2, < 1.7.0)
|
|
||||||
childprocess (~> 0.5.0)
|
|
||||||
erubis (~> 2.7.0)
|
|
||||||
i18n (~> 0.6.0)
|
|
||||||
listen (~> 2.7.1)
|
|
||||||
log4r (~> 1.1.9, < 1.1.11)
|
|
||||||
net-scp (~> 1.1.0)
|
|
||||||
net-ssh (>= 2.6.6, < 2.10.0)
|
|
||||||
rb-kqueue (~> 0.2.0)
|
|
||||||
wdm (~> 0.1.0)
|
|
||||||
winrm (~> 1.1.3)
|
|
||||||
|
|
||||||
PATH
|
|
||||||
remote: .
|
|
||||||
specs:
|
|
||||||
vagrant-lxc (1.0.1)
|
|
||||||
|
|
||||||
GEM
|
|
||||||
remote: https://rubygems.org/
|
|
||||||
specs:
|
|
||||||
akami (1.2.2)
|
|
||||||
gyoku (>= 0.4.0)
|
|
||||||
nokogiri
|
|
||||||
builder (3.2.2)
|
|
||||||
celluloid (0.15.2)
|
|
||||||
timers (~> 1.1.0)
|
|
||||||
childprocess (0.5.3)
|
|
||||||
ffi (~> 1.0, >= 1.0.11)
|
|
||||||
coderay (1.1.0)
|
|
||||||
coveralls (0.7.0)
|
|
||||||
multi_json (~> 1.3)
|
|
||||||
rest-client
|
|
||||||
simplecov (>= 0.7)
|
|
||||||
term-ansicolor
|
|
||||||
thor
|
|
||||||
diff-lcs (1.2.5)
|
|
||||||
docile (1.1.3)
|
|
||||||
erubis (2.7.0)
|
|
||||||
ffi (1.9.3)
|
|
||||||
formatador (0.2.5)
|
|
||||||
gssapi (1.0.3)
|
|
||||||
ffi (>= 1.0.1)
|
|
||||||
guard (2.6.1)
|
|
||||||
formatador (>= 0.2.4)
|
|
||||||
listen (~> 2.7)
|
|
||||||
lumberjack (~> 1.0)
|
|
||||||
pry (>= 0.9.12)
|
|
||||||
thor (>= 0.18.1)
|
|
||||||
guard-rspec (4.2.9)
|
|
||||||
guard (~> 2.1)
|
|
||||||
rspec (>= 2.14, < 4.0)
|
|
||||||
gyoku (1.1.1)
|
|
||||||
builder (>= 2.1.2)
|
|
||||||
httpclient (2.4.0)
|
|
||||||
httpi (0.9.7)
|
|
||||||
rack
|
|
||||||
i18n (0.6.9)
|
|
||||||
listen (2.7.7)
|
|
||||||
celluloid (>= 0.15.2)
|
|
||||||
rb-fsevent (>= 0.9.3)
|
|
||||||
rb-inotify (>= 0.9)
|
|
||||||
little-plugger (1.1.3)
|
|
||||||
log4r (1.1.10)
|
|
||||||
logging (1.8.2)
|
|
||||||
little-plugger (>= 1.1.3)
|
|
||||||
multi_json (>= 1.8.4)
|
|
||||||
lumberjack (1.0.6)
|
|
||||||
method_source (0.8.2)
|
|
||||||
mime-types (2.3)
|
|
||||||
mini_portile (0.6.0)
|
|
||||||
multi_json (1.10.1)
|
|
||||||
net-scp (1.1.2)
|
|
||||||
net-ssh (>= 2.6.5)
|
|
||||||
net-ssh (2.9.1)
|
|
||||||
nokogiri (1.6.2.1)
|
|
||||||
mini_portile (= 0.6.0)
|
|
||||||
nori (1.1.5)
|
|
||||||
pry (0.9.12.6)
|
|
||||||
coderay (~> 1.0)
|
|
||||||
method_source (~> 0.8)
|
|
||||||
slop (~> 3.4)
|
|
||||||
rack (1.5.2)
|
|
||||||
rake (10.3.2)
|
|
||||||
rb-fsevent (0.9.4)
|
|
||||||
rb-inotify (0.9.5)
|
|
||||||
ffi (>= 0.5.0)
|
|
||||||
rb-kqueue (0.2.3)
|
|
||||||
ffi (>= 0.5.0)
|
|
||||||
rest-client (1.6.7)
|
|
||||||
mime-types (>= 1.16)
|
|
||||||
rspec (2.99.0)
|
|
||||||
rspec-core (~> 2.99.0)
|
|
||||||
rspec-expectations (~> 2.99.0)
|
|
||||||
rspec-mocks (~> 2.99.0)
|
|
||||||
rspec-core (2.99.0)
|
|
||||||
rspec-expectations (2.99.0)
|
|
||||||
diff-lcs (>= 1.1.3, < 2.0)
|
|
||||||
rspec-mocks (2.99.0)
|
|
||||||
rubyntlm (0.1.1)
|
|
||||||
savon (0.9.5)
|
|
||||||
akami (~> 1.0)
|
|
||||||
builder (>= 2.1.2)
|
|
||||||
gyoku (>= 0.4.0)
|
|
||||||
httpi (~> 0.9)
|
|
||||||
nokogiri (>= 1.4.0)
|
|
||||||
nori (~> 1.0)
|
|
||||||
wasabi (~> 1.0)
|
|
||||||
simplecov (0.8.2)
|
|
||||||
docile (~> 1.1.0)
|
|
||||||
multi_json
|
|
||||||
simplecov-html (~> 0.8.0)
|
|
||||||
simplecov-html (0.8.0)
|
|
||||||
slop (3.5.0)
|
|
||||||
term-ansicolor (1.3.0)
|
|
||||||
tins (~> 1.0)
|
|
||||||
thor (0.18.1)
|
|
||||||
timers (1.1.0)
|
|
||||||
tins (1.3.0)
|
|
||||||
uuidtools (2.1.4)
|
|
||||||
vagrant-omnibus (1.4.1)
|
|
||||||
wasabi (1.0.0)
|
|
||||||
nokogiri (>= 1.4.0)
|
|
||||||
wdm (0.1.0)
|
|
||||||
winrm (1.1.3)
|
|
||||||
gssapi (~> 1.0.0)
|
|
||||||
httpclient (~> 2.2, >= 2.2.0.2)
|
|
||||||
logging (~> 1.6, >= 1.6.1)
|
|
||||||
nokogiri (~> 1.5)
|
|
||||||
rubyntlm (~> 0.1.1)
|
|
||||||
savon (= 0.9.5)
|
|
||||||
uuidtools (~> 2.1.2)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
ruby
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
coveralls
|
|
||||||
guard
|
|
||||||
guard-rspec
|
|
||||||
rake
|
|
||||||
rb-inotify
|
|
||||||
rspec (= 2.99.0)
|
|
||||||
vagrant!
|
|
||||||
vagrant-cachier!
|
|
||||||
vagrant-lxc!
|
|
||||||
vagrant-omnibus
|
|
||||||
vagrant-pristine!
|
|
||||||
vagrant-spec!
|
|
99
README.md
99
README.md
|
@ -1,41 +1,40 @@
|
||||||
|
🟢 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) [![Gittip](http://img.shields.io/gittip/fgrehm.svg)](https://www.gittip.com/fgrehm/) [![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) [![Gitter chat](https://badges.gitter.im/fgrehm/vagrant-lxc.png)](https://gitter.im/fgrehm/vagrant-lxc)
|
||||||
|
|
||||||
[LXC](http://lxc.sourceforge.net/) provider for [Vagrant](http://www.vagrantup.com/) 1.1+
|
[LXC](http://lxc.sourceforge.net/) provider for [Vagrant](http://www.vagrantup.com/) 1.9+
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
* Provides the same workflow as the Vagrant VirtualBox provider
|
* Provides the same workflow as the Vagrant VirtualBox provider
|
||||||
* Port forwarding via [`redir`](http://linux.die.net/man/1/redir)
|
* Port forwarding via [`redir`](https://github.com/troglobit/redir)
|
||||||
|
* Private networking via [`pipework`](https://github.com/jpetazzo/pipework)
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
* [Vagrant 1.1+](http://www.vagrantup.com/downloads.html)
|
* [Vagrant 1.9+](http://www.vagrantup.com/downloads.html)
|
||||||
* lxc 0.7.5+
|
* lxc >=2.1
|
||||||
* `redir` (if you are planning to use port forwarding)
|
* `redir` (if you are planning to use port forwarding)
|
||||||
* A [kernel != 3.5.0-17.28](https://github.com/fgrehm/vagrant-lxc/wiki/Troubleshooting#wiki-im-unable-to-restart-containers)
|
* `brctl` (if you are planning to use private networks, on Ubuntu this means `apt-get install bridge-utils`)
|
||||||
|
|
||||||
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 14.04+
|
||||||
hosts and installing the dependencies on it basically means a `apt-get install lxc lxc-templates cgroup-lite redir`
|
hosts and installing the dependencies on it basically means a
|
||||||
and a `apt-get update && apt-get dist-upgrade` to upgrade the kernel. For Debian
|
`apt-get install lxc lxc-templates cgroup-lite redir`. For setting up other
|
||||||
hosts you'll need to follow the instructions described on the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki/Usage-on-debian-hosts)
|
types of hosts please have a look at the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki).
|
||||||
and old lxc versions (like 0.7.5 shipped with Ubuntu 12.04 by default) might require
|
|
||||||
[additional configurations to work](#backingstore-options).
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
@ -51,27 +50,26 @@ vagrant init fgrehm/precise64-lxc
|
||||||
vagrant up --provider=lxc
|
vagrant up --provider=lxc
|
||||||
```
|
```
|
||||||
|
|
||||||
_Set the `VAGRANT_DEFAULT_PROVIDER` environmental variable to `lxc` in order to
|
_More information about skipping the `--provider` argument can be found at the
|
||||||
avoid typing `--provider=lxc` all the time._
|
"DEFAULT PROVIDER" section of [Vagrant docs](https://docs.vagrantup.com/v2/providers/basic_usage.html)_
|
||||||
|
|
||||||
|
|
||||||
## Base boxes
|
## Base boxes
|
||||||
|
|
||||||
Base boxes can be found on [VagrantCloud](https://vagrantcloud.com/search?provider=lxc)
|
Base boxes provided on Atlas haven't been refreshed for a good while and shouldn't be relied on.
|
||||||
and some scripts to build your own are available at [fgrehm/vagrant-lxc-base-boxes](https://github.com/fgrehm/vagrant-lxc-base-boxes).
|
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)
|
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.
|
for more information.
|
||||||
|
|
||||||
|
|
||||||
## Advanced configuration
|
## Advanced configuration
|
||||||
|
|
||||||
If you want, you can modify container configurations from within your Vagrantfile
|
You can modify container configurations from within your Vagrantfile using the
|
||||||
using the [provider block](http://docs.vagrantup.com/v2/providers/configuration.html):
|
[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 = "quantal64"
|
config.vm.box = "fgrehm/trusty64-lxc"
|
||||||
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'
|
||||||
|
@ -85,6 +83,28 @@ prior to starting it.
|
||||||
|
|
||||||
For other configuration options, please check the [lxc.conf manpages](http://manpages.ubuntu.com/manpages/precise/man5/lxc.conf.5.html).
|
For other configuration options, please check the [lxc.conf manpages](http://manpages.ubuntu.com/manpages/precise/man5/lxc.conf.5.html).
|
||||||
|
|
||||||
|
### Private Networks
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
By default vagrant-lxc will attempt to generate a unique container name
|
By default vagrant-lxc will attempt to generate a unique container name
|
||||||
|
@ -102,6 +122,9 @@ Vagrant.configure("2") do |config|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
_Please note that there is a 64 chars limit and the container name will be
|
||||||
|
trimmed down to that to ensure we can always bring the container up.
|
||||||
|
|
||||||
### Backingstore options
|
### Backingstore options
|
||||||
|
|
||||||
Support for setting `lxc-create`'s backingstore option (`-B` and related) can be
|
Support for setting `lxc-create`'s backingstore option (`-B` and related) can be
|
||||||
|
@ -110,7 +133,7 @@ specified from the provider block and it defaults to `best`, to change it:
|
||||||
```ruby
|
```ruby
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.provider :lxc do |lxc|
|
config.vm.provider :lxc do |lxc|
|
||||||
lxc.backingstore = 'lvm' # or 'btrfs',...
|
lxc.backingstore = 'lvm' # or 'btrfs', 'overlayfs', ...
|
||||||
# lvm specific options
|
# lvm specific options
|
||||||
lxc.backingstore_option '--vgname', 'schroots'
|
lxc.backingstore_option '--vgname', 'schroots'
|
||||||
lxc.backingstore_option '--fssize', '5G'
|
lxc.backingstore_option '--fssize', '5G'
|
||||||
|
@ -119,31 +142,33 @@ Vagrant.configure("2") do |config|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
For old versions of lxc (like 0.7.5 shipped with Ubuntu 12.04 by default) that
|
## Unprivileged containers support
|
||||||
does not support `best` for the backingstore option, changing it to `none` is
|
|
||||||
required and a default for all Vagrant environments can be set from your
|
Since v1.4.0, `vagrant-lxc` gained support for unprivileged containers. For now, since it's a new
|
||||||
`~/.vagrant.d/Vagrantfile` using the same `provider` block:
|
feature, privileged containers are still the default, but you can have your `Vagrantfile` use
|
||||||
|
unprivileged containers with the `privileged` flag (which defaults to `true`). Example:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.provider :lxc do |lxc|
|
config.vm.provider :lxc do |lxc|
|
||||||
lxc.backingstore = 'none'
|
lxc.privileged = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### Avoiding `sudo` passwords
|
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/).
|
||||||
|
|
||||||
This plugin requires **a lot** of `sudo`ing since [user namespaces](https://wiki.ubuntu.com/UserNamespace)
|
## Avoiding `sudo` passwords
|
||||||
are not supported on mainstream kernels. To work around that, you can use the
|
|
||||||
`vagrant lxc sudoers` command which will create a file under `/etc/sudoers.d/vagrant-lxc-<VERSION>`
|
If you're not using unprivileged containers, this plugin requires **a lot** of `sudo`ing To work
|
||||||
whitelisting all commands required by `vagrant-lxc` to run.
|
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
|
If you are interested on what will be generated by that command, please check
|
||||||
[this code](lib/vagrant-lxc/command/sudoers.rb).
|
[this code](lib/vagrant-lxc/command/sudoers.rb).
|
||||||
|
|
||||||
_vagrant-lxc < 1.0.0 users, please check this [Wiki page](https://github.com/fgrehm/vagrant-lxc/wiki/Avoiding-%27sudo%27-passwords)_
|
|
||||||
|
|
||||||
|
|
||||||
## More information
|
## More information
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
# vagrant-backports
|
|
||||||
|
|
||||||
<!--
|
|
||||||
[![Build Status](https://travis-ci.org/fgrehm/vagrant-backports.png?branch=master)](https://travis-ci.org/fgrehm/vagrant-backports) [![Gem Version](https://badge.fury.io/rb/vagrant-backports.png)](http://badge.fury.io/rb/vagrant-backports) [![Code Climate](https://codeclimate.com/github/fgrehm/vagrant-backports.png)](https://codeclimate.com/github/fgrehm/vagrant-backports) [![Coverage Status](https://coveralls.io/repos/fgrehm/vagrant-backports/badge.png?branch=master)](https://coveralls.io/r/fgrehm/vagrant-backports) [![Gittip](http://img.shields.io/gittip/fgrehm.svg)](https://www.gittip.com/fgrehm/)
|
|
||||||
-->
|
|
||||||
|
|
||||||
A _"hypothetical"_ gem that helps Vagrant plugin developers to stay sane when
|
|
||||||
keeping up with Vagrant improvements by backporting parts of its recent versions
|
|
||||||
functionality.
|
|
||||||
|
|
||||||
More information will be provided if there is enough interest on having this
|
|
||||||
extracted as a separate gem.
|
|
|
@ -1 +0,0 @@
|
||||||
Vagrant::Action::Builtin.const_set :HandleBox, Vagrant::Action::Builtin::HandleBoxUrl
|
|
|
@ -1,34 +0,0 @@
|
||||||
module Vagrant
|
|
||||||
module Backports
|
|
||||||
module Action
|
|
||||||
# This middleware is meant to be used with Call and can check if
|
|
||||||
# a machine is in the given state ID.
|
|
||||||
class IsState
|
|
||||||
# Note: Any of the arguments can be arrays as well.
|
|
||||||
#
|
|
||||||
# @param [Symbol] target_state The target state ID that means that
|
|
||||||
# the machine was properly shut down.
|
|
||||||
# @param [Symbol] source_state The source state ID that the machine
|
|
||||||
# must be in to be shut down.
|
|
||||||
def initialize(app, env, check, **opts)
|
|
||||||
@app = app
|
|
||||||
@logger = Log4r::Logger.new("vagrant::action::builtin::is_state")
|
|
||||||
@check = check
|
|
||||||
@invert = !!opts[:invert]
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
@logger.debug("Checking if machine state is '#{@check}'")
|
|
||||||
state = env[:machine].state.id
|
|
||||||
@logger.debug("-- Machine state: #{state}")
|
|
||||||
|
|
||||||
env[:result] = @check == state
|
|
||||||
env[:result] = !env[:result] if @invert
|
|
||||||
@app.call(env)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Vagrant::Action::Builtin.const_set :IsState, Vagrant::Backports::Action::IsState
|
|
|
@ -1,20 +0,0 @@
|
||||||
module Vagrant
|
|
||||||
module Backports
|
|
||||||
module Action
|
|
||||||
# This middleware simply outputs a message to the UI.
|
|
||||||
class Message
|
|
||||||
def initialize(app, env, message, **opts)
|
|
||||||
@app = app
|
|
||||||
@message = message
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
env[:ui].info(@message)
|
|
||||||
@app.call(env)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Vagrant::Action::Builtin.const_set :Message, Vagrant::Backports::Action::Message
|
|
|
@ -1,42 +0,0 @@
|
||||||
# This acts like a backport of Vagrant's built in action from 1.3+ for previous version
|
|
||||||
# https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/action/builtin/wait_for_communicator.rb
|
|
||||||
module Vagrant
|
|
||||||
module Backports
|
|
||||||
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 'Machine booted and 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
|
|
||||||
|
|
||||||
Vagrant::Action::Builtin.const_set :WaitForCommunicator, Vagrant::Backports::Action::WaitForCommunicator
|
|
|
@ -1,12 +0,0 @@
|
||||||
module Vagrant
|
|
||||||
module UI
|
|
||||||
class Interface
|
|
||||||
def output(*args)
|
|
||||||
info(*args)
|
|
||||||
end
|
|
||||||
def detail(*args)
|
|
||||||
info(*args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,27 +0,0 @@
|
||||||
module Vagrant
|
|
||||||
module Backports
|
|
||||||
class << self
|
|
||||||
def vagrant_1_2_or_later?
|
|
||||||
greater_than?('1.2.0')
|
|
||||||
end
|
|
||||||
|
|
||||||
def vagrant_1_3_or_later?
|
|
||||||
greater_than?('1.3.0')
|
|
||||||
end
|
|
||||||
|
|
||||||
def vagrant_1_4_or_later?
|
|
||||||
greater_than?('1.4.0')
|
|
||||||
end
|
|
||||||
|
|
||||||
def vagrant_1_5_or_later?
|
|
||||||
greater_than?('1.5.0')
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def greater_than?(version)
|
|
||||||
Gem::Version.new(Vagrant::VERSION) >= Gem::Version.new(version)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -6,9 +6,5 @@ module Vagrant
|
||||||
def self.source_root
|
def self.source_root
|
||||||
@source_root ||= Pathname.new(File.dirname(__FILE__)).join('..').expand_path
|
@source_root ||= Pathname.new(File.dirname(__FILE__)).join('..').expand_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.sudo_wrapper_path
|
|
||||||
"/usr/local/bin/vagrant-lxc-wrapper"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,27 +4,17 @@ require 'vagrant-lxc/action/create'
|
||||||
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/compress_rootfs'
|
require 'vagrant-lxc/action/compress_rootfs'
|
||||||
require 'vagrant-lxc/action/fetch_ip_with_lxc_attach'
|
require 'vagrant-lxc/action/fetch_ip_with_lxc_info'
|
||||||
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/prepare_nfs_settings'
|
||||||
require 'vagrant-lxc/action/prepare_nfs_valid_ids'
|
require 'vagrant-lxc/action/prepare_nfs_valid_ids'
|
||||||
require 'vagrant-lxc/action/remove_temporary_files'
|
require 'vagrant-lxc/action/private_networks'
|
||||||
require 'vagrant-lxc/action/setup_package_files'
|
require 'vagrant-lxc/action/setup_package_files'
|
||||||
require 'vagrant-lxc/action/warn_networks'
|
require 'vagrant-lxc/action/warn_networks'
|
||||||
|
|
||||||
unless Vagrant::Backports.vagrant_1_3_or_later?
|
|
||||||
require 'vagrant-backports/action/wait_for_communicator'
|
|
||||||
end
|
|
||||||
unless Vagrant::Backports.vagrant_1_5_or_later?
|
|
||||||
require 'vagrant-backports/ui'
|
|
||||||
require 'vagrant-backports/action/handle_box'
|
|
||||||
require 'vagrant-backports/action/message'
|
|
||||||
require 'vagrant-backports/action/is_state'
|
|
||||||
end
|
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
module Action
|
module Action
|
||||||
|
@ -57,18 +47,14 @@ 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
|
||||||
if Vagrant::Backports.vagrant_1_4_or_later?
|
|
||||||
b.use PrepareNFSValidIds
|
b.use PrepareNFSValidIds
|
||||||
b.use Builtin::SyncedFolderCleanup
|
b.use Builtin::SyncedFolderCleanup
|
||||||
b.use Builtin::SyncedFolders
|
b.use Builtin::SyncedFolders
|
||||||
b.use PrepareNFSSettings
|
b.use PrepareNFSSettings
|
||||||
else
|
|
||||||
require 'vagrant-lxc/backports/action/share_folders'
|
|
||||||
b.use ShareFolders
|
|
||||||
end
|
|
||||||
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
|
||||||
|
@ -138,7 +124,7 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
b2.use ClearForwardedPorts
|
b2.use ClearForwardedPorts
|
||||||
b2.use RemoveTemporaryFiles
|
b2.use GcPrivateNetworkBridges
|
||||||
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
|
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
|
||||||
if !env2[:result]
|
if !env2[:result]
|
||||||
b3.use ForcedHalt
|
b3.use ForcedHalt
|
||||||
|
@ -158,16 +144,13 @@ module Vagrant
|
||||||
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
|
||||||
if Vagrant::Backports.vagrant_1_3_or_later?
|
|
||||||
b3.use Builtin::ProvisionerCleanup
|
b3.use Builtin::ProvisionerCleanup
|
||||||
end
|
|
||||||
else
|
else
|
||||||
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.will_not_destroy")
|
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.will_not_destroy")
|
||||||
end
|
end
|
||||||
|
@ -198,8 +181,7 @@ module Vagrant
|
||||||
def self.action_ssh_ip
|
def self.action_ssh_ip
|
||||||
Builder.new.tap do |b|
|
Builder.new.tap do |b|
|
||||||
b.use Builtin::Call, Builtin::ConfigValidate do |env, b2|
|
b.use Builtin::Call, Builtin::ConfigValidate do |env, b2|
|
||||||
b2.use FetchIpWithLxcAttach if env[:machine].provider.driver.supports_attach?
|
b2.use FetchIpWithLxcInfo
|
||||||
b2.use FetchIpFromDnsmasqLeases
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,11 +8,15 @@ 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
|
utsname = env[:machine].config.vm.hostname || env[:machine].id
|
||||||
|
if driver.supports_new_config_format
|
||||||
|
config.customize 'uts.name', utsname
|
||||||
|
else
|
||||||
config.customize 'utsname', utsname
|
config.customize 'utsname', utsname
|
||||||
|
end
|
||||||
|
|
||||||
# Fix apparmor issues when starting Ubuntu 14.04 containers
|
# Fix apparmor issues when starting Ubuntu 14.04 containers
|
||||||
# See https://github.com/fgrehm/vagrant-lxc/issues/278 for more information
|
# See https://github.com/fgrehm/vagrant-lxc/issues/278 for more information
|
||||||
|
@ -20,8 +24,19 @@ module Vagrant
|
||||||
config.customize 'mount.entry', '/sys/fs/pstore sys/fs/pstore none bind,optional 0 0'
|
config.customize 'mount.entry', '/sys/fs/pstore sys/fs/pstore none bind,optional 0 0'
|
||||||
end
|
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")
|
||||||
env[:machine].provider.driver.start(config.customizations)
|
driver.start(config.customizations)
|
||||||
|
|
||||||
@app.call env
|
@app.call env
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,26 +16,49 @@ module Vagrant
|
||||||
when String
|
when String
|
||||||
# Nothing to do here, move along...
|
# Nothing to do here, move along...
|
||||||
else
|
else
|
||||||
container_name = "#{env[:root_path].basename}_#{env[:machine].name}"
|
container_name = generate_container_name(env)
|
||||||
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
|
||||||
|
|
||||||
env[:machine].provider.driver.create(
|
backingstore = config.backingstore
|
||||||
|
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,
|
||||||
config.backingstore,
|
backingstore,
|
||||||
config.backingstore_options,
|
config.backingstore_options,
|
||||||
env[:lxc_template_src],
|
env[:lxc_template_src],
|
||||||
env[:lxc_template_config],
|
env[:lxc_template_config],
|
||||||
env[:lxc_template_opts]
|
template_options
|
||||||
)
|
)
|
||||||
|
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
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
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.to_s}\s+([0-9.]+)\s+/i
|
|
||||||
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
|
|
||||||
/var/lib/libvirt/dnsmasq/*.leases
|
|
||||||
)
|
|
||||||
|
|
||||||
def read_dnsmasq_leases
|
|
||||||
Dir["{#{LEASES_PATHS.join(',')}}"].map do |file|
|
|
||||||
File.read(file)
|
|
||||||
end.join("\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,30 +1,31 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
module Action
|
module Action
|
||||||
class FetchIpWithLxcAttach
|
class FetchIpWithLxcInfo
|
||||||
# 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_attach")
|
@logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_info")
|
||||||
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 = ''
|
||||||
retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do
|
return config.ssh_ip_addr if not config.ssh_ip_addr.nil?
|
||||||
|
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-attach"
|
raise LXC::Errors::ExecuteError, :command => "lxc-info"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ip
|
ip
|
||||||
|
@ -32,8 +33,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.attach '/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'eth0', namespaces: ['network', 'mount']
|
output = driver.info '-iH'
|
||||||
if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
|
if output =~ /^([0-9.]+)/
|
||||||
return $1.to_s
|
return $1.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'open3'
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
module Action
|
module Action
|
||||||
|
@ -67,7 +69,9 @@ 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'
|
||||||
options.delete(:host_ip) if options.fetch(:host_ip, '').to_s.strip.empty?
|
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
|
||||||
|
@ -76,8 +80,12 @@ 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( -n #{host_ip}:#{host_port} #{guest_ip}:#{guest_port} )
|
||||||
|
else
|
||||||
params = %W( --lport=#{host_port} --caddr=#{guest_ip} --cport=#{guest_port} )
|
params = %W( --lport=#{host_port} --caddr=#{guest_ip} --cport=#{guest_port} )
|
||||||
params.unshift "--laddr=#{host_ip}" if host_ip
|
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
|
if host_port < 1024
|
||||||
redir_cmd = "sudo redir #{params.join(' ')} 2>/dev/null"
|
redir_cmd = "sudo redir #{params.join(' ')} 2>/dev/null"
|
||||||
|
@ -97,6 +105,13 @@ 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
|
||||||
|
|
47
lib/vagrant-lxc/action/gc_private_network_bridges.rb
Normal file
47
lib/vagrant-lxc/action/gc_private_network_bridges.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
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
|
|
@ -33,8 +33,10 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
if template_config_file.exist?
|
if template_config_file.exist?
|
||||||
|
@env[:lxc_box_config] = template_config_file.to_s
|
||||||
@env[:lxc_template_opts].merge!('--config' => template_config_file.to_s)
|
@env[:lxc_template_opts].merge!('--config' => template_config_file.to_s)
|
||||||
elsif old_template_config_file.exist?
|
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
|
@env[:lxc_template_config] = old_template_config_file.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
46
lib/vagrant-lxc/action/private_networks.rb
Normal file
46
lib/vagrant-lxc/action/private_networks.rb
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
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
|
|
@ -1,23 +0,0 @@
|
||||||
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
|
|
|
@ -7,16 +7,16 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
if public_or_private_network_configured?(env[:machine].config)
|
if public_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_or_private_network_configured?(config)
|
def public_network_configured?(config)
|
||||||
config.vm.networks.find do |type, _|
|
config.vm.networks.find do |type, _|
|
||||||
[:private_network, :public_network].include?(type.to_sym)
|
type.to_sym == :public_network
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
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
|
|
|
@ -1,5 +1,8 @@
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
|
||||||
|
require "vagrant-lxc/driver"
|
||||||
|
require "vagrant-lxc/sudo_wrapper"
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
module Command
|
module Command
|
||||||
|
@ -25,7 +28,7 @@ module Vagrant
|
||||||
argv = parse_options(opts)
|
argv = parse_options(opts)
|
||||||
return unless argv
|
return unless argv
|
||||||
|
|
||||||
wrapper_path = Vagrant::LXC.sudo_wrapper_path
|
wrapper_path = SudoWrapper.dest_path
|
||||||
wrapper = create_wrapper!
|
wrapper = create_wrapper!
|
||||||
sudoers = create_sudoers!(options[:user], wrapper_path)
|
sudoers = create_sudoers!(options[:user], wrapper_path)
|
||||||
|
|
||||||
|
@ -43,11 +46,14 @@ module Vagrant
|
||||||
|
|
||||||
# This requires vagrant 1.5.2+ https://github.com/mitchellh/vagrant/commit/3371c3716278071680af9b526ba19235c79c64cb
|
# This requires vagrant 1.5.2+ https://github.com/mitchellh/vagrant/commit/3371c3716278071680af9b526ba19235c79c64cb
|
||||||
def create_wrapper!
|
def create_wrapper!
|
||||||
|
lxc_base_path = Driver.new("").containers_path
|
||||||
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
|
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
|
||||||
template = Vagrant::Util::TemplateRenderer.new(
|
template = Vagrant::Util::TemplateRenderer.new(
|
||||||
'sudoers.rb',
|
'sudoers.rb',
|
||||||
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
|
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
|
||||||
:cmd_paths => build_cmd_paths_hash
|
: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
|
file.puts template.render
|
||||||
end
|
end
|
||||||
|
@ -78,10 +84,11 @@ module Vagrant
|
||||||
|
|
||||||
def build_cmd_paths_hash
|
def build_cmd_paths_hash
|
||||||
{}.tap do |hash|
|
{}.tap do |hash|
|
||||||
%w( which cat mkdir cp chown chmod rm tar chown ).each do |cmd|
|
%w( which cat mkdir cp chown chmod rm tar chown ip ifconfig brctl ).each do |cmd|
|
||||||
hash[cmd] = `which #{cmd}`.strip
|
hash[cmd] = `sudo which #{cmd}`.strip
|
||||||
end
|
end
|
||||||
hash['lxc_bin'] = Pathname(`which lxc-create`.strip).parent.to_s
|
hash['lxc_bin'] = Pathname(`sudo which lxc-create`.strip).parent.to_s
|
||||||
|
hash['ruby'] = Gem.ruby
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,12 +18,29 @@ module 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
|
@backingstore = UNSET_VALUE
|
||||||
@backingstore_options = []
|
@backingstore_options = []
|
||||||
@sudo_wrapper = UNSET_VALUE
|
|
||||||
@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
|
||||||
|
@ -47,10 +64,13 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
def finalize!
|
def finalize!
|
||||||
@sudo_wrapper = nil if @sudo_wrapper == UNSET_VALUE
|
|
||||||
@container_name = nil if @container_name == UNSET_VALUE
|
@container_name = nil if @container_name == UNSET_VALUE
|
||||||
@backingstore = "best" if @backingstore == UNSET_VALUE
|
@backingstore = nil if @backingstore == UNSET_VALUE
|
||||||
@existing_container_name = nil if @existing_container_name == UNSET_VALUE
|
@existing_container_name = nil if @existing_container_name == UNSET_VALUE
|
||||||
|
@tmpfs_mount_size = '2G' if @tmpfs_mount_size == UNSET_VALUE
|
||||||
|
@fetch_ip_tries = 10 if @fetch_ip_tries == UNSET_VALUE
|
||||||
|
@ssh_ip_addr = nil if @ssh_ip_addr == UNSET_VALUE
|
||||||
|
@privileged = true if @privileged == UNSET_VALUE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,9 +3,12 @@ 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
|
||||||
|
@ -14,15 +17,13 @@ module Vagrant
|
||||||
class ContainerNotFound < StandardError; end
|
class ContainerNotFound < StandardError; end
|
||||||
|
|
||||||
# Default root folder where container configs are stored
|
# Default root folder where container configs are stored
|
||||||
DEFAULT_CONTAINERS_PATH = '/var/lib/lxc'
|
|
||||||
|
|
||||||
attr_reader :container_name,
|
attr_reader :container_name,
|
||||||
:customizations
|
:customizations
|
||||||
|
|
||||||
def initialize(container_name, sudo_wrapper, cli = nil)
|
def initialize(container_name, sudo_wrapper = nil, cli = nil, privileged: true)
|
||||||
@container_name = container_name
|
@container_name = container_name
|
||||||
@sudo_wrapper = sudo_wrapper
|
@sudo_wrapper = sudo_wrapper || SudoWrapper.new(privileged: privileged)
|
||||||
@cli = cli || CLI.new(sudo_wrapper, container_name)
|
@cli = cli || CLI.new(@sudo_wrapper, container_name)
|
||||||
@logger = Log4r::Logger.new("vagrant::provider::lxc::driver")
|
@logger = Log4r::Logger.new("vagrant::provider::lxc::driver")
|
||||||
@customizations = []
|
@customizations = []
|
||||||
end
|
end
|
||||||
|
@ -33,7 +34,7 @@ module Vagrant
|
||||||
|
|
||||||
# Root folder where container configs are stored
|
# Root folder where container configs are stored
|
||||||
def containers_path
|
def containers_path
|
||||||
@containers_path ||= @cli.support_config_command? ? @cli.config('lxc.lxcpath') : DEFAULT_CONTAINERS_PATH
|
@containers_path ||= @cli.config('lxc.lxcpath')
|
||||||
end
|
end
|
||||||
|
|
||||||
def all_containers
|
def all_containers
|
||||||
|
@ -44,8 +45,26 @@ module Vagrant
|
||||||
Pathname.new("#{containers_path}/#{@container_name}")
|
Pathname.new("#{containers_path}/#{@container_name}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def config_path
|
||||||
|
base_path.join('config').to_s
|
||||||
|
end
|
||||||
|
|
||||||
def rootfs_path
|
def rootfs_path
|
||||||
Pathname.new(config_string.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1])
|
pathtype, path = config_string.match(/^lxc\.rootfs(?:\.path)?\s+=\s+(.+:)?(.+)$/)[1..2]
|
||||||
|
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
|
||||||
|
@ -57,40 +76,27 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
def config_string
|
def config_string
|
||||||
@sudo_wrapper.run('cat', base_path.join('config').to_s)
|
@sudo_wrapper.run('cat', config_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create(name, backingstore, backingstore_options, template_path, config_file, template_options = {})
|
def create(name, backingstore, backingstore_options, template_path, config_file, template_options = {})
|
||||||
@cli.name = @container_name = name
|
@cli.name = @container_name = name
|
||||||
|
|
||||||
import_template(template_path) do |template_name|
|
|
||||||
@logger.debug "Creating container..."
|
@logger.debug "Creating container..."
|
||||||
@cli.create template_name, backingstore, backingstore_options, config_file, template_options
|
|
||||||
end
|
@cli.create template_path, backingstore, backingstore_options, config_file, template_options
|
||||||
end
|
end
|
||||||
|
|
||||||
def share_folders(folders)
|
def share_folders(folders)
|
||||||
folders.each do |f|
|
folders.each do |f|
|
||||||
share_folder(f[:hostpath], f[:guestpath], f.fetch(:mount_options, 'bind'))
|
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_folder(host_path, guest_path, mount_options = nil)
|
||||||
guest_path = guest_path.gsub(/^\//, '')
|
guest_path = guest_path.gsub(/^\//, '').gsub(' ', '\\\040')
|
||||||
guest_full_path = rootfs_path.join(guest_path)
|
mount_options = Array(mount_options || ['bind', 'create=dir'])
|
||||||
|
|
||||||
unless guest_full_path.directory?
|
|
||||||
begin
|
|
||||||
@logger.debug("Guest path doesn't exist, creating: #{guest_full_path}")
|
|
||||||
@sudo_wrapper.run('mkdir', '-p', guest_full_path.to_s)
|
|
||||||
rescue Errno::EACCES
|
|
||||||
raise Vagrant::Errors::SharedFolderCreateFailed, :path => guest_path.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
mount_options = Array(mount_options || ['bind'])
|
|
||||||
host_path = host_path.to_s.gsub(' ', '\\\040')
|
host_path = host_path.to_s.gsub(' ', '\\\040')
|
||||||
guest_path = guest_path.gsub(' ', '\\\040')
|
|
||||||
@customizations << ['mount.entry', "#{host_path} #{guest_path} none #{mount_options.join(',')} 0 0"]
|
@customizations << ['mount.entry', "#{host_path} #{guest_path} none #{mount_options.join(',')} 0 0"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -116,18 +122,99 @@ module Vagrant
|
||||||
@cli.destroy
|
@cli.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def supports_attach?
|
|
||||||
@cli.supports_attach?
|
|
||||||
end
|
|
||||||
|
|
||||||
def attach(*command)
|
def attach(*command)
|
||||||
@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
|
||||||
|
@ -158,6 +245,13 @@ module Vagrant
|
||||||
write_config(contents)
|
write_config(contents)
|
||||||
end
|
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
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def write_customizations(customizations)
|
def write_customizations(customizations)
|
||||||
|
@ -174,46 +268,22 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_config(contents)
|
def write_config(contents)
|
||||||
|
confpath = base_path.join('config').to_s
|
||||||
|
begin
|
||||||
|
File.open(confpath, File::RDWR) do |file|
|
||||||
|
file.write contents
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
# We don't have permissions to write in the conf file. That's probably because it's a
|
||||||
|
# privileged container. Work around that through sudo_wrapper.
|
||||||
Tempfile.new('lxc-config').tap do |file|
|
Tempfile.new('lxc-config').tap do |file|
|
||||||
file.chmod 0644
|
file.chmod 0644
|
||||||
file.write contents
|
file.write contents
|
||||||
file.close
|
file.close
|
||||||
@sudo_wrapper.run 'cp', '-f', file.path, base_path.join('config').to_s
|
@sudo_wrapper.run 'cp', '-f', file.path, confpath
|
||||||
@sudo_wrapper.run 'chown', 'root:root', base_path.join('config').to_s
|
@sudo_wrapper.run 'chown', 'root:root', confpath
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_template(path)
|
|
||||||
template_name = "vagrant-tmp-#{@container_name}"
|
|
||||||
tmp_template_path = templates_path.join("lxc-#{template_name}").to_s
|
|
||||||
|
|
||||||
@logger.info 'Copying LXC template into place'
|
|
||||||
@sudo_wrapper.run('cp', path, tmp_template_path)
|
|
||||||
@sudo_wrapper.run('chmod', '+x', tmp_template_path)
|
|
||||||
|
|
||||||
yield template_name
|
|
||||||
ensure
|
|
||||||
@logger.info 'Removing LXC template'
|
|
||||||
if tmp_template_path
|
|
||||||
@sudo_wrapper.run('rm', tmp_template_path)
|
|
||||||
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
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Vagrant
|
||||||
|
|
||||||
def version
|
def version
|
||||||
return @version if @version
|
return @version if @version
|
||||||
@version = support_version_command? ? run(:version) : run(:create, '--version')
|
@version = run(:create, '--version')
|
||||||
if @version =~ /(lxc version:\s+|)(.+)\s*$/
|
if @version =~ /(lxc version:\s+|)(.+)\s*$/
|
||||||
@version = $2.downcase
|
@version = $2.downcase
|
||||||
else
|
else
|
||||||
|
@ -39,11 +39,11 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
def config(param)
|
def config(param)
|
||||||
if support_config_command?
|
|
||||||
run(:config, param).gsub("\n", '')
|
run(:config, param).gsub("\n", '')
|
||||||
else
|
|
||||||
raise Errors::CommandNotSupported, name: 'config', available_version: '> 1.x.x', version: version
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_config(path)
|
||||||
|
run('update-config', '-c', path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def state
|
def state
|
||||||
|
@ -59,14 +59,14 @@ module Vagrant
|
||||||
config_opts = ['-f', config_file]
|
config_opts = ['-f', config_file]
|
||||||
end
|
end
|
||||||
|
|
||||||
extra = template_opts.to_a.flatten
|
extra = template_opts.to_a.flatten.reject { |elem| elem.empty? }
|
||||||
extra.unshift '--' unless extra.empty?
|
extra.unshift '--' unless extra.empty?
|
||||||
|
|
||||||
run :create,
|
run :create,
|
||||||
'-B', backingstore,
|
'-B', backingstore,
|
||||||
*(backingstore_options.to_a.flatten),
|
|
||||||
'--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,9 +85,19 @@ 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
|
||||||
attach '/sbin/halt' if supports_attach?
|
begin
|
||||||
run :stop, '--name', @name
|
run :stop, '--name', @name
|
||||||
|
rescue LXC::Errors::ExecuteError => e
|
||||||
|
if e.exitcode == 2
|
||||||
|
@logger.debug "Machine already stopped, lxc-stop returned 2"
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach(*cmd)
|
def attach(*cmd)
|
||||||
|
@ -103,17 +113,17 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
if namespaces
|
if namespaces
|
||||||
if supports_attach_with_namespaces?
|
|
||||||
extra = ['--namespaces', 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?
|
||||||
|
|
||||||
|
@ -131,42 +141,11 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def supports_attach?
|
|
||||||
unless defined?(@supports_attach)
|
|
||||||
begin
|
|
||||||
@supports_attach = true
|
|
||||||
run(:attach, '--name', @name, '--', '/bin/true')
|
|
||||||
rescue LXC::Errors::ExecuteError
|
|
||||||
@supports_attach = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return @supports_attach
|
|
||||||
end
|
|
||||||
|
|
||||||
def support_config_command?
|
|
||||||
version[0].to_i >= 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def support_version_command?
|
|
||||||
@sudo_wrapper.run('which', 'lxc-version').strip.chomp != ''
|
|
||||||
rescue Vagrant::LXC::Errors::ExecuteError
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -5,17 +5,28 @@ 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
|
attr_reader :stderr, :stdout, :exitcode
|
||||||
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
|
||||||
|
|
||||||
class NamespacesNotSupported < Vagrant::Errors::VagrantError
|
# Raised when user interrupts a subprocess
|
||||||
|
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
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
require 'vagrant'
|
require 'vagrant'
|
||||||
require 'vagrant-backports/utils'
|
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
|
@ -10,40 +9,43 @@ module Vagrant
|
||||||
LXC-based virtual machines.
|
LXC-based virtual machines.
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
extra = []
|
provider(:lxc, parallel: true, priority: 7) do
|
||||||
extra << {parallel: true} if Vagrant::Backports.vagrant_1_2_or_later?
|
require_relative 'provider'
|
||||||
provider(:lxc, *extra) do
|
init!
|
||||||
require File.expand_path("../provider", __FILE__)
|
|
||||||
|
|
||||||
I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
|
|
||||||
I18n.reload!
|
|
||||||
|
|
||||||
Provider
|
Provider
|
||||||
end
|
end
|
||||||
|
|
||||||
command "lxc" do
|
command "lxc" do
|
||||||
require_relative 'command/root'
|
require_relative 'command/root'
|
||||||
|
init!
|
||||||
Command::Root
|
Command::Root
|
||||||
end
|
end
|
||||||
|
|
||||||
config(:lxc, :provider) do
|
config(:lxc, :provider) do
|
||||||
require File.expand_path("../config", __FILE__)
|
require_relative 'config'
|
||||||
|
init!
|
||||||
Config
|
Config
|
||||||
end
|
end
|
||||||
|
|
||||||
if Vagrant::Backports.vagrant_1_4_or_later?
|
|
||||||
synced_folder(:lxc) do
|
synced_folder(:lxc) do
|
||||||
require File.expand_path("../synced_folder", __FILE__)
|
require_relative 'synced_folder'
|
||||||
SyncedFolder
|
SyncedFolder
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if Vagrant::Backports.vagrant_1_5_or_later?
|
|
||||||
provider_capability("lxc", "public_address") do
|
provider_capability("lxc", "public_address") do
|
||||||
require_relative "provider/cap/public_address"
|
require_relative "provider/cap/public_address"
|
||||||
Provider::Cap::PublicAddress
|
Provider::Cap::PublicAddress
|
||||||
end
|
end
|
||||||
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
|
||||||
|
|
|
@ -2,13 +2,20 @@ 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
|
||||||
|
@ -17,18 +24,9 @@ module Vagrant
|
||||||
machine_id_changed
|
machine_id_changed
|
||||||
end
|
end
|
||||||
|
|
||||||
def sudo_wrapper
|
|
||||||
@shell ||= begin
|
|
||||||
wrapper = Pathname.new(LXC.sudo_wrapper_path).exist? &&
|
|
||||||
LXC.sudo_wrapper_path || nil
|
|
||||||
@logger.debug("Found sudo wrapper : #{wrapper}") if wrapper
|
|
||||||
SudoWrapper.new(wrapper)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_lxc_installed!
|
def ensure_lxc_installed!
|
||||||
begin
|
begin
|
||||||
sudo_wrapper.run("which", "lxc-create")
|
SudoWrapper.new(privileged: @machine.provider_config.privileged).run("which", "lxc-create")
|
||||||
rescue Vagrant::LXC::Errors::ExecuteError
|
rescue Vagrant::LXC::Errors::ExecuteError
|
||||||
raise Errors::LxcNotInstalled
|
raise Errors::LxcNotInstalled
|
||||||
end
|
end
|
||||||
|
@ -41,7 +39,7 @@ module Vagrant
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@logger.debug("Instantiating the container for: #{id.inspect}")
|
@logger.debug("Instantiating the container for: #{id.inspect}")
|
||||||
@driver = Driver.new(id, self.sudo_wrapper)
|
@driver = Driver.new(id, privileged: @machine.provider_config.privileged)
|
||||||
@driver.validate!
|
@driver.validate!
|
||||||
rescue Driver::ContainerNotFound
|
rescue Driver::ContainerNotFound
|
||||||
# The container doesn't exist, so we probably have a stale
|
# The container doesn't exist, so we probably have a stale
|
||||||
|
|
|
@ -6,15 +6,41 @@ module Vagrant
|
||||||
|
|
||||||
attr_reader :wrapper_path
|
attr_reader :wrapper_path
|
||||||
|
|
||||||
def initialize(wrapper_path = nil)
|
def self.dest_path
|
||||||
@wrapper_path = wrapper_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 : {}
|
options = command.last.is_a?(Hash) ? command.last : {}
|
||||||
command.unshift @wrapper_path if @wrapper_path && !options[:no_wrapper]
|
|
||||||
|
# Avoid running LXC commands with a restrictive umask.
|
||||||
|
# Otherwise disasters occur, like the container root directory
|
||||||
|
# having permissions `rwxr-x---` which prevents the `vagrant`
|
||||||
|
# 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)
|
execute *(['sudo'] + command)
|
||||||
|
else
|
||||||
|
execute *(['sudo', '/usr/bin/env'] + command)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
execute *(['/usr/bin/env'] + command)
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
File.umask(old_mask)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -42,10 +68,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
|
||||||
@logger.info("Exit code != 0, but interrupted. Ignoring.")
|
raise LXC::Errors::SubprocessInterruptError, command.inspect
|
||||||
else
|
else
|
||||||
raise LXC::Errors::ExecuteError,
|
raise LXC::Errors::ExecuteError,
|
||||||
command: command.inspect, stderr: r.stderr, stdout: r.stdout
|
command: command.inspect, stderr: r.stderr, stdout: r.stdout, exitcode: r.exit_code
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
VERSION = "1.0.1"
|
VERSION = "1.4.2"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,15 +13,18 @@ en:
|
||||||
force_shutdown: |-
|
force_shutdown: |-
|
||||||
Forcing shutdown of container...
|
Forcing shutdown of container...
|
||||||
warn_networks: |-
|
warn_networks: |-
|
||||||
Warning! The LXC provider doesn't support any of the Vagrant public / private
|
Warning! The LXC provider doesn't support public networks, the settings
|
||||||
network configurations (ex: `config.vm.network :private_network, ip: "some-ip"`).
|
will be silently ignored.
|
||||||
They will be silently ignored.
|
|
||||||
warn_group: |-
|
warn_group: |-
|
||||||
Warning! The LXC provider doesn't support the :group parameter for synced
|
Warning! The LXC provider doesn't support the :group parameter for synced
|
||||||
folders. It will be silently ignored.
|
folders. It will be silently ignored.
|
||||||
warn_owner: |-
|
warn_owner: |-
|
||||||
Warning! The LXC provider doesn't support the :owner parameter for synced
|
Warning! The LXC provider doesn't support the :owner parameter for synced
|
||||||
folders. It will be silently ignored.
|
folders. It will be silently ignored.
|
||||||
|
setup_private_network: |-
|
||||||
|
Setting up private networks...
|
||||||
|
remove_bridge: |-
|
||||||
|
Removing bridge '%{name}'...
|
||||||
|
|
||||||
vagrant:
|
vagrant:
|
||||||
commands:
|
commands:
|
||||||
|
@ -37,6 +40,9 @@ 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}
|
||||||
|
|
||||||
|
@ -56,8 +62,12 @@ 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 is not accessible on the PATH.
|
The `lxc` package does not seem to be installed or `lxc-create` 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.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# This is a modified version of /usr/share/lxc/templates/lxc-download
|
# 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
|
# that comes with ubuntu-lxc 1.0.0 stable from ppa changed to suit vagrant-lxc needs
|
||||||
|
@ -33,8 +33,10 @@ LXC_PATH=
|
||||||
LXC_ROOTFS=
|
LXC_ROOTFS=
|
||||||
LXC_TARBALL=
|
LXC_TARBALL=
|
||||||
LXC_CONFIG=
|
LXC_CONFIG=
|
||||||
|
LXC_USE_OLDCONFIG=
|
||||||
LXC_STRIP_COMPONENTS=2
|
LXC_STRIP_COMPONENTS=2
|
||||||
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
vagrant-lxc default template
|
vagrant-lxc default template
|
||||||
|
@ -44,6 +46,7 @@ Required arguments:
|
||||||
|
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
[ --config ]: Configuration file to be used when building the container
|
[ --config ]: Configuration file to be used when building the container
|
||||||
|
[ --oldconfig ]: Use pre LXC 2.1 config format
|
||||||
[ -h | --help ]: This help message
|
[ -h | --help ]: This help message
|
||||||
|
|
||||||
LXC internal arguments (do not pass manually!):
|
LXC internal arguments (do not pass manually!):
|
||||||
|
@ -57,7 +60,7 @@ EOF
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
options=$(getopt -o h -l tarball:,config:,help:,name:,path:,rootfs:,mapped-uid:,mapped-gid:,strip-components: -- "$@")SS
|
options=$(getopt -o h -l tarball:,config:,oldconfig,help:,name:,path:,rootfs:,mapped-uid:,mapped-gid:,strip-components: -- "$@")SS
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
usage $(basename $0)
|
usage $(basename $0)
|
||||||
|
@ -70,6 +73,7 @@ do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-h|--help) usage $0 && exit 0;;
|
-h|--help) usage $0 && exit 0;;
|
||||||
--config) LXC_CONFIG=$2; shift 2;;
|
--config) LXC_CONFIG=$2; shift 2;;
|
||||||
|
--oldconfig) LXC_USE_OLDCONFIG=1; shift 1;;
|
||||||
--tarball) LXC_TARBALL=$2; shift 2;;
|
--tarball) LXC_TARBALL=$2; shift 2;;
|
||||||
--name) LXC_NAME=$2; shift 2;;
|
--name) LXC_NAME=$2; shift 2;;
|
||||||
--path) LXC_PATH=$2; shift 2;;
|
--path) LXC_PATH=$2; shift 2;;
|
||||||
|
@ -96,11 +100,6 @@ if [ -z "${LXC_PATH}" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "${LXC_CONFIG}" ]; then
|
|
||||||
echo "'config' parameter is required"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if $LXC_ROOTFS exists here, it was passed in with --rootfs
|
# if $LXC_ROOTFS exists here, it was passed in with --rootfs
|
||||||
if [ -z "${LXC_ROOTFS}" ]; then
|
if [ -z "${LXC_ROOTFS}" ]; then
|
||||||
config=${LXC_PATH}/config
|
config=${LXC_PATH}/config
|
||||||
|
@ -115,7 +114,6 @@ fi
|
||||||
# Unpack the rootfs
|
# Unpack the rootfs
|
||||||
echo "Unpacking the rootfs"
|
echo "Unpacking the rootfs"
|
||||||
|
|
||||||
mkdir -p /var/lock/subsys
|
|
||||||
(
|
(
|
||||||
flock -x 200
|
flock -x 200
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
|
@ -124,13 +122,14 @@ mkdir -p /var/lock/subsys
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p ${LXC_ROOTFS}
|
mkdir -p ${LXC_ROOTFS}
|
||||||
(cd ${LXC_ROOTFS} && tar xfz ${LXC_TARBALL} --strip-components=${LXC_STRIP_COMPONENTS})
|
(cd ${LXC_ROOTFS} && tar xfz ${LXC_TARBALL} --strip-components=${LXC_STRIP_COMPONENTS} --xattrs --xattrs-include=* || true)
|
||||||
if [ $? -ne 0 ]; then
|
if [ ! -f ${LXC_ROOTFS}/bin/true ]; then
|
||||||
echo "Failed to extract rootfs"
|
echo "Failed to extract rootfs"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
) 200>/var/lock/subsys/lxc
|
) 200>${LXC_PATH}/vagrant_lock
|
||||||
|
rm ${LXC_PATH}/vagrant_lock
|
||||||
|
|
||||||
mkdir -p ${LXC_ROOTFS}/dev/pts/
|
mkdir -p ${LXC_ROOTFS}/dev/pts/
|
||||||
|
|
||||||
|
@ -149,7 +148,12 @@ if [ -e "${LXC_PATH}/config-auto" ]; then
|
||||||
cat ${LXC_PATH}/config-auto >> ${LXC_PATH}/config
|
cat ${LXC_PATH}/config-auto >> ${LXC_PATH}/config
|
||||||
rm ${LXC_PATH}/config-auto
|
rm ${LXC_PATH}/config-auto
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ $LXC_USE_OLDCONFIG ]; then
|
||||||
echo "lxc.utsname = ${LXC_NAME}" >> ${LXC_PATH}/config
|
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
|
## Re-add the previously removed network config
|
||||||
if [ -e "${LXC_PATH}/config-network" ]; then
|
if [ -e "${LXC_PATH}/config-network" ]; then
|
||||||
|
@ -160,11 +164,13 @@ if [ -e "${LXC_PATH}/config-network" ]; then
|
||||||
rm ${LXC_PATH}/config-network
|
rm ${LXC_PATH}/config-network
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "${LXC_CONFIG}" ]; then
|
||||||
## Append the defaults
|
## Append the defaults
|
||||||
echo "" >> ${LXC_PATH}/config
|
echo "" >> ${LXC_PATH}/config
|
||||||
echo "##############################################" >> ${LXC_PATH}/config
|
echo "##############################################" >> ${LXC_PATH}/config
|
||||||
echo "# vagrant-lxc base box specific configuration" >> ${LXC_PATH}/config
|
echo "# vagrant-lxc base box specific configuration" >> ${LXC_PATH}/config
|
||||||
cat ${LXC_CONFIG} >> ${LXC_PATH}/config
|
cat ${LXC_CONFIG} >> ${LXC_PATH}/config
|
||||||
|
fi
|
||||||
|
|
||||||
# Empty section for lxc.customize calls from vagrantfile
|
# Empty section for lxc.customize calls from vagrantfile
|
||||||
echo "" >> ${LXC_PATH}/config
|
echo "" >> ${LXC_PATH}/config
|
||||||
|
|
422
scripts/pipework
Executable file
422
scripts/pipework
Executable file
|
@ -0,0 +1,422 @@
|
||||||
|
#!/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
4
spec/Vagrantfile
vendored
|
@ -15,10 +15,6 @@ 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'
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ 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,25 +35,25 @@ describe Vagrant::LXC::Action::ForwardPorts do
|
||||||
subject.stub(system: true)
|
subject.stub(system: true)
|
||||||
subject.call(env)
|
subject.call(env)
|
||||||
expect(subject).to have_received(:spawn).with(
|
expect(subject).to have_received(:spawn).with(
|
||||||
"redir --laddr=#{host_ip} --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
|
"redir -n #{host_ip}:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'skips --laddr parameter if host_ip is nil' do
|
it 'Uses 127.0.0.1 as default 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(
|
expect(subject).to have_received(:spawn).with(
|
||||||
"redir --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
|
"redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'skips --laddr parameter if host_ip is a blank string' do
|
it 'Uses 127.0.0.1 by default 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(
|
expect(subject).to have_received(:spawn).with(
|
||||||
"redir --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
|
"redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -70,6 +71,15 @@ describe Vagrant::LXC::Action::ForwardPorts do
|
||||||
expect(subject).not_to have_received(:spawn)
|
expect(subject).not_to have_received(:spawn)
|
||||||
end
|
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
|
||||||
|
|
||||||
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)
|
expect { subject.call(env) }.to raise_error(Vagrant::LXC::Errors::RedirNotInstalled)
|
||||||
|
@ -82,25 +92,25 @@ describe Vagrant::LXC::Action::ForwardPorts do
|
||||||
subject.stub(system: true)
|
subject.stub(system: true)
|
||||||
subject.call(env)
|
subject.call(env)
|
||||||
expect(subject).to have_received(:spawn).with(
|
expect(subject).to have_received(:spawn).with(
|
||||||
"sudo redir --laddr=#{host_ip} --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
|
"sudo redir -n #{host_ip}:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'skips --laddr parameter if host_ip is nil' do
|
it 'Uses 127.0.0.1 by default 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(
|
expect(subject).to have_received(:spawn).with(
|
||||||
"sudo redir --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
|
"sudo redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'skips --laddr parameter if host_ip is a blank string' do
|
it 'Uses 127.0.0.1 by default 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(
|
expect(subject).to have_received(:spawn).with(
|
||||||
"sudo redir --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
|
"sudo redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,16 +30,7 @@ describe Vagrant::LXC::Driver::CLI do
|
||||||
|
|
||||||
describe 'version' do
|
describe 'version' do
|
||||||
before do
|
before do
|
||||||
allow(subject).to receive(:support_version_command?).and_return(true)
|
allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
|
||||||
allow(subject).to receive(:run).with(:version).and_return(lxc_version_out)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'lxc version before 1.x.x' do
|
|
||||||
let(:lxc_version_out) { "lxc version: 0.x.y-rc1\n" }
|
|
||||||
|
|
||||||
it 'parses the version from the output' do
|
|
||||||
expect(subject.version).to eq('0.x.y-rc1')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'lxc version after 1.x.x' do
|
describe 'lxc version after 1.x.x' do
|
||||||
|
@ -53,24 +44,11 @@ describe Vagrant::LXC::Driver::CLI do
|
||||||
|
|
||||||
describe 'config' do
|
describe 'config' do
|
||||||
before do
|
before do
|
||||||
allow(subject).to receive(:support_version_command?).and_return(support_version_command?)
|
|
||||||
allow(subject).to receive(:run).with(:config, 'lxc.lxcpath').and_return(lxc_config_out)
|
allow(subject).to receive(:run).with(:config, 'lxc.lxcpath').and_return(lxc_config_out)
|
||||||
allow(subject).to receive(:run).with(:version).and_return(lxc_version_out)
|
|
||||||
allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
|
allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'lxc version before 1.x.x' do
|
describe 'lxc version after 1.x.x'do
|
||||||
let(:support_version_command?) { true }
|
|
||||||
let(:lxc_config_out) { "/var/lib/lxc\n" }
|
|
||||||
let(:lxc_version_out) { "lxc version: 0.x.y-rc1\n" }
|
|
||||||
|
|
||||||
it 'not supported' do
|
|
||||||
expect{subject.config('lxc.lxcpath')}.to raise_error(Vagrant::LXC::Errors::CommandNotSupported)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'lxc version before after 1.x.x'do
|
|
||||||
let(:support_version_command?) { false }
|
|
||||||
let(:lxc_config_out) { "/var/lib/lxc\n" }
|
let(:lxc_config_out) { "/var/lib/lxc\n" }
|
||||||
let(:lxc_version_out) { "1.0.0\n" }
|
let(:lxc_version_out) { "1.0.0\n" }
|
||||||
|
|
||||||
|
@ -99,9 +77,9 @@ describe Vagrant::LXC::Driver::CLI do
|
||||||
expect(subject).to have_received(:run).with(
|
expect(subject).to have_received(:run).with(
|
||||||
:create,
|
:create,
|
||||||
'-B', backingstore,
|
'-B', backingstore,
|
||||||
*(backingstore_opts.flatten),
|
|
||||||
'--template', template,
|
'--template', template,
|
||||||
'--name', name,
|
'--name', name,
|
||||||
|
*(backingstore_opts.flatten),
|
||||||
'-f', config_file,
|
'-f', config_file,
|
||||||
'--',
|
'--',
|
||||||
'--extra-param', 'param',
|
'--extra-param', 'param',
|
||||||
|
@ -156,39 +134,14 @@ describe Vagrant::LXC::Driver::CLI do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(subject).to receive(:run)
|
allow(subject).to receive(:run)
|
||||||
end
|
|
||||||
|
|
||||||
context 'lxc-attach is supported' do
|
|
||||||
before do
|
|
||||||
subject.stub(attach: true, supports_attach?: true)
|
|
||||||
subject.stop
|
subject.stop
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'runs a /sbin/halt within the container' do
|
|
||||||
expect(subject).to have_received(:attach).with('/sbin/halt')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'issues a lxc-stop with provided container name' do
|
it 'issues a lxc-stop with provided container name' do
|
||||||
expect(subject).to have_received(:run).with(:stop, '--name', name)
|
expect(subject).to have_received(:run).with(:stop, '--name', name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'lxc-attach is not supported' do
|
|
||||||
before do
|
|
||||||
subject.stub(attach: false, supports_attach?: false)
|
|
||||||
subject.stop
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'runs a /sbin/halt within the container' do
|
|
||||||
expect(subject).to_not have_received(:attach)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'issues a lxc-stop with provided container name' do
|
|
||||||
expect(subject).to have_received(:run).with(:stop, '--name', name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'state' do
|
describe 'state' do
|
||||||
let(:name) { 'a-container' }
|
let(:name) { 'a-container' }
|
||||||
subject { described_class.new(sudo_wrapper, name) }
|
subject { described_class.new(sudo_wrapper, name) }
|
||||||
|
@ -232,13 +185,6 @@ describe Vagrant::LXC::Driver::CLI do
|
||||||
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)
|
expect(subject).to have_received(:run).with(:attach, '--name', name, '--namespaces', 'NETWORK|MOUNT', '--', *command)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises a NamespacesNotSupported error if not supported' do
|
|
||||||
allow(subject).to receive(: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
|
||||||
|
|
||||||
describe 'transition block' do
|
describe 'transition block' do
|
||||||
|
@ -260,33 +206,4 @@ describe Vagrant::LXC::Driver::CLI do
|
||||||
|
|
||||||
skip 'waits for the expected container state'
|
skip 'waits for the expected container state'
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'check for whether lxc-attach is supported' do
|
|
||||||
let(:name) { 'a-running-container' }
|
|
||||||
subject { described_class.new(sudo_wrapper, name) }
|
|
||||||
|
|
||||||
context 'lxc-attach is present on system' do
|
|
||||||
before { subject.stub(run: true) }
|
|
||||||
|
|
||||||
it 'returns true if `lxc-attach --name CNAME -- /bin/true` works' do
|
|
||||||
expect(subject.supports_attach?).to be_truthy
|
|
||||||
expect(subject).to have_received(:run).with(
|
|
||||||
:attach, '--name', name, '--', '/bin/true'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'lxc-attach is not present on system' do
|
|
||||||
before do
|
|
||||||
allow(subject).to receive(:run).and_raise(Vagrant::LXC::Errors::ExecuteError.new('msg'))
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns true if `lxc-attach --name CNAME -- /bin/true` works' do
|
|
||||||
expect(subject.supports_attach?).to be_falsy
|
|
||||||
expect(subject).to have_received(:run).with(
|
|
||||||
:attach, '--name', name, '--', '/bin/true'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,7 +54,7 @@ describe Vagrant::LXC::Driver do
|
||||||
|
|
||||||
it 'creates container with the right arguments' do
|
it 'creates container with the right arguments' do
|
||||||
expect(cli).to have_received(:create).with(
|
expect(cli).to have_received(:create).with(
|
||||||
template_name,
|
template_path,
|
||||||
backingstore,
|
backingstore,
|
||||||
backingstore_opts,
|
backingstore_opts,
|
||||||
config_file,
|
config_file,
|
||||||
|
@ -75,21 +75,10 @@ describe Vagrant::LXC::Driver do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'supports_attach?' do
|
|
||||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, supports_attach?: true) }
|
|
||||||
|
|
||||||
subject { described_class.new('name', nil, cli) }
|
|
||||||
|
|
||||||
it 'delegates to cli object' do
|
|
||||||
expect(subject.supports_attach?).to be_truthy
|
|
||||||
expect(cli).to have_received(:supports_attach?)
|
|
||||||
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, support_config_command?: false) }
|
let(:cli) { double(Vagrant::LXC::Driver::CLI, start: true) }
|
||||||
let(:sudo) { double(Vagrant::LXC::SudoWrapper) }
|
let(:sudo) { double(Vagrant::LXC::SudoWrapper) }
|
||||||
|
|
||||||
subject { described_class.new('name', sudo, cli) }
|
subject { described_class.new('name', sudo, cli) }
|
||||||
|
@ -97,8 +86,9 @@ describe Vagrant::LXC::Driver do
|
||||||
before do
|
before do
|
||||||
sudo.should_receive(:run).with('cat', '/var/lib/lxc/name/config').exactly(2).times.
|
sudo.should_receive(:run).with('cat', '/var/lib/lxc/name/config').exactly(2).times.
|
||||||
and_return('# CONFIGURATION')
|
and_return('# CONFIGURATION')
|
||||||
sudo.should_receive(:run).twice.with('cp', '-f', %r{/tmp/.*}, '/var/lib/lxc/name/config')
|
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')
|
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)
|
||||||
|
@ -152,21 +142,11 @@ describe Vagrant::LXC::Driver do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'containers_path' do
|
describe 'containers_path' do
|
||||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, config: cli_config_value, support_config_command?: cli_support_config_command_value) }
|
let(:cli) { double(Vagrant::LXC::Driver::CLI, config: cli_config_value) }
|
||||||
|
|
||||||
subject { described_class.new('name', nil, cli) }
|
subject { described_class.new('name', nil, cli) }
|
||||||
|
|
||||||
describe 'lxc version before 1.x.x' do
|
|
||||||
let(:cli_support_config_command_value) { false }
|
|
||||||
let(:cli_config_value) { '/var/lib/lxc' }
|
|
||||||
|
|
||||||
it 'delegates to cli' do
|
|
||||||
expect(subject.containers_path).to eq(cli_config_value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'lxc version after 1.x.x' do
|
describe 'lxc version after 1.x.x' do
|
||||||
let(:cli_support_config_command_value) { true }
|
|
||||||
let(:cli_config_value) { '/etc/lxc' }
|
let(:cli_config_value) { '/etc/lxc' }
|
||||||
|
|
||||||
it 'delegates to cli' do
|
it 'delegates to cli' do
|
||||||
|
@ -180,25 +160,22 @@ describe Vagrant::LXC::Driver do
|
||||||
let(:ro_rw_folder) { {guestpath: '/vagrant/ro_rw', hostpath: '/path/to/host/dir', mount_options: ['ro', 'rw']} }
|
let(:ro_rw_folder) { {guestpath: '/vagrant/ro_rw', hostpath: '/path/to/host/dir', mount_options: ['ro', 'rw']} }
|
||||||
let(:with_space_folder) { {guestpath: '/tmp/with space', hostpath: '/path/with space'} }
|
let(:with_space_folder) { {guestpath: '/tmp/with space', hostpath: '/path/with space'} }
|
||||||
let(:folders) { [shared_folder, ro_rw_folder, with_space_folder] }
|
let(:folders) { [shared_folder, ro_rw_folder, with_space_folder] }
|
||||||
let(:rootfs_path) { Pathname('/path/to/rootfs') }
|
|
||||||
let(:expected_guest_path) { "vagrant" }
|
let(:expected_guest_path) { "vagrant" }
|
||||||
let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true) }
|
let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true) }
|
||||||
|
let(:rootfs_path) { Pathname('/path/to/rootfs') }
|
||||||
|
|
||||||
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
|
end
|
||||||
|
|
||||||
it "creates guest folder under container's rootfs" do
|
|
||||||
expect(sudo_wrapper).to have_received(:run).with("mkdir", "-p", "#{rootfs_path}/#{expected_guest_path}")
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'adds a mount.entry to its local customizations' do
|
it 'adds a mount.entry to its local customizations' do
|
||||||
expect(subject.customizations).to include [
|
expect(subject.customizations).to include [
|
||||||
'mount.entry',
|
'mount.entry',
|
||||||
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind 0 0"
|
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -212,8 +189,69 @@ describe Vagrant::LXC::Driver do
|
||||||
it 'supports directories with spaces' do
|
it 'supports directories with spaces' do
|
||||||
expect(subject.customizations).to include [
|
expect(subject.customizations).to include [
|
||||||
'mount.entry',
|
'mount.entry',
|
||||||
"/path/with\\040space tmp/with\\040space none bind 0 0"
|
"/path/with\\040space tmp/with\\040space none bind,create=dir 0 0"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with directory-based LXC config" do
|
||||||
|
let(:config_string) {
|
||||||
|
<<-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
|
||||||
|
|
||||||
|
describe "with overlayfs-based LXC config" do
|
||||||
|
let(:config_string) {
|
||||||
|
<<-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 = 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
|
||||||
|
|
|
@ -1,28 +1,44 @@
|
||||||
#!/opt/vagrant/embedded/bin/ruby
|
#!<%= cmd_paths['ruby'] %>
|
||||||
# Automatically created by vagrant-lxc
|
# Automatically created by vagrant-lxc
|
||||||
|
|
||||||
class Whitelist
|
class Whitelist
|
||||||
class << self
|
class << self
|
||||||
def add(command, *args)
|
def add(command, *args)
|
||||||
|
list[command] ||= []
|
||||||
list[command] << args
|
list[command] << args
|
||||||
end
|
end
|
||||||
|
|
||||||
def list
|
def add_regex(regex, *args)
|
||||||
@list ||= Hash.new do |key, hsh|
|
regex_list << [regex, [args]]
|
||||||
key[hsh] = []
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def list
|
||||||
|
@list ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def regex_list
|
||||||
|
@regex_list ||= []
|
||||||
end
|
end
|
||||||
|
|
||||||
def allowed(command)
|
def allowed(command)
|
||||||
list[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
|
end
|
||||||
|
|
||||||
def run!(argv)
|
def run!(argv)
|
||||||
begin
|
begin
|
||||||
command, args = `which #{argv.shift}`.chomp, argv || []
|
command, args = `which #{argv.shift}`.chomp, argv || []
|
||||||
check!(command, args)
|
check!(command, args)
|
||||||
puts `#{command} #{args.join(" ")}`
|
system "#{command} #{args.join(" ")}"
|
||||||
exit $?.to_i
|
|
||||||
|
exit_code = $?.to_i
|
||||||
|
exit_code = 1 if exit_code == 256
|
||||||
|
|
||||||
|
exit exit_code
|
||||||
rescue => e
|
rescue => e
|
||||||
STDERR.puts e.message
|
STDERR.puts e.message
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -62,9 +78,8 @@ class Whitelist
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
base = "/var/lib/lxc"
|
base = "<%= lxc_base_path %>"
|
||||||
base_path = %r{\A#{base}/.*\z}
|
base_path = %r{\A#{base}/.*\z}
|
||||||
templates_path = %r{\A/usr/(share|lib|lib64|local/lib)/lxc/templates/.*\z}
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Commands from provider.rb
|
# Commands from provider.rb
|
||||||
|
@ -80,20 +95,21 @@ Whitelist.add '<%= cmd_paths['mkdir'] %>', '-p', base_path
|
||||||
# - Container config customizations and pruning
|
# - Container config customizations and pruning
|
||||||
Whitelist.add '<%= cmd_paths['cp'] %>', '-f', %r{/tmp/.*}, base_path
|
Whitelist.add '<%= cmd_paths['cp'] %>', '-f', %r{/tmp/.*}, base_path
|
||||||
Whitelist.add '<%= cmd_paths['chown'] %>', 'root:root', base_path
|
Whitelist.add '<%= cmd_paths['chown'] %>', 'root:root', base_path
|
||||||
# - Template import
|
|
||||||
Whitelist.add '<%= cmd_paths['cp'] %>', %r{\A.*\z}, templates_path
|
|
||||||
Whitelist.add '<%= cmd_paths['chmod'] %>', '+x', templates_path
|
|
||||||
# - Template removal
|
|
||||||
Whitelist.add '<%= cmd_paths['rm'] %>', templates_path
|
|
||||||
# - Packaging
|
# - Packaging
|
||||||
Whitelist.add '<%= cmd_paths['tar'] %>', '--numeric-owner', '-cvzf', %r{/tmp/.*/rootfs.tar.gz}, '-C', base_path, './rootfs'
|
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}
|
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
|
# Commands from driver/cli.rb
|
||||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-version'
|
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-version'
|
||||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-ls'
|
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', /.*/
|
||||||
|
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', '-B', /.*/, '--template', /.*/, '--name', /.*/, '**'
|
||||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-create', '--version'
|
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-destroy', '--name', /.*/
|
||||||
|
@ -103,6 +119,7 @@ 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', '--name', /.*/, '**'
|
||||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-attach', '-h'
|
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-config', 'lxc.lxcpath'
|
||||||
|
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-update-config', '-c', /.*/
|
||||||
|
|
||||||
##
|
##
|
||||||
# Commands from driver/action/remove_temporary_files.rb
|
# Commands from driver/action/remove_temporary_files.rb
|
||||||
|
|
Loading…
Reference in a new issue