Merge pull request #249 from fgrehm/vagrant-1.5

Support for Vagrant 1.5
This commit is contained in:
Fabio Rehm 2014-03-13 01:03:06 -03:00
commit f20f6aaa40
45 changed files with 550 additions and 559 deletions

View file

@ -1,8 +1,8 @@
language: ruby language: ruby
rvm: rvm:
- 1.9.3
- 2.0.0 - 2.0.0
- 2.1.1
matrix: matrix:
allow_failures: allow_failures:
- rvm: 2.0.0 - rvm: 2.1.1
script: "bundle exec rake ci" script: "bundle exec rake ci"

View file

@ -52,5 +52,5 @@ on knowing what makes a base box for vagrant-lxc, here's what's needed:
| --- | --- | --- | | --- | --- | --- |
| `provider` | Yes | Required by Vagrant | | `provider` | Yes | Required by Vagrant |
| `version` | Yes | Tracks backward incompatibilities | | `version` | Yes | Tracks backward incompatibilities |
| `built-on` | No | Date / time when the box was packaged | | `built-on` | No | Date / time when the box was packaged for the first time |
| `template-opts` | No | Extra options to be passed to the `lxc-template` script provided with the .box package | | `template-opts` | No | Extra options to be passed to the `lxc-template` script provided with the .box package |

View file

@ -1,4 +1,4 @@
## [0.8.1](https://github.com/fgrehm/vagrant-lxc/compare/v0.8.0...master) (unreleased) ## [1.0.0.beta1](https://github.com/fgrehm/vagrant-lxc/compare/v0.8.0...master) (unreleased)
DEPRECATIONS: DEPRECATIONS:

23
Gemfile
View file

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

View file

@ -1,40 +1,54 @@
GIT GIT
remote: git://github.com/fgrehm/vagrant-cachier.git remote: https://github.com/fgrehm/vagrant-cachier.git
revision: 2faa6615466f8d518893f5ba51b493b877d2efde revision: 2df1e319408a7e6f1c6e75d48e36591199e98527
specs: specs:
vagrant-cachier (0.6.1.dev) vagrant-cachier (0.6.1.dev)
GIT GIT
remote: git://github.com/fgrehm/vagrant-pristine.git remote: https://github.com/fgrehm/vagrant-pristine.git
revision: 4638491786943bfbf6f115b1fc379f069963fe46 revision: 503dbc47848c81d0fbfa6840491856f518d244a1
specs: specs:
vagrant-pristine (0.3.0) vagrant-pristine (0.3.0)
GIT GIT
remote: git://github.com/mitchellh/vagrant.git remote: https://github.com/mitchellh/vagrant-spec.git
revision: a92e03cf4ce936243d3959b7b5603262a234a58d revision: aae28ee57071cdd121ca782c6e0709a5c650a4be
specs: specs:
vagrant (1.3.6.dev) vagrant-spec (0.0.1)
childprocess (~> 0.3.7) childprocess (~> 0.5.0)
log4r (~> 1.1.9)
rspec (~> 2.14)
thor (~> 0.18.1)
GIT
remote: https://github.com/mitchellh/vagrant.git
revision: 56dd0e8531e1810fc3ceb17411eeded711794f59
specs:
vagrant (1.5.1.dev)
bundler (~> 1.5.2)
childprocess (~> 0.5.0)
erubis (~> 2.7.0) erubis (~> 2.7.0)
i18n (~> 0.6.0) i18n (~> 0.6.0)
log4r (~> 1.1.9) listen (~> 2.4.0)
log4r (~> 1.1.9, < 1.1.11)
net-scp (~> 1.1.0) net-scp (~> 1.1.0)
net-ssh (~> 2.6.6) net-ssh (>= 2.6.6, < 2.8.0)
rb-kqueue (~> 0.2.0)
wdm (~> 0.1.0)
PATH PATH
remote: . remote: .
specs: specs:
vagrant-lxc (0.8.1.dev) vagrant-lxc (1.0.0.beta1.dev)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
celluloid (0.15.2) celluloid (0.15.2)
timers (~> 1.1.0) timers (~> 1.1.0)
childprocess (0.3.9) childprocess (0.5.1)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
coderay (1.0.9) coderay (1.1.0)
coveralls (0.7.0) coveralls (0.7.0)
multi_json (~> 1.3) multi_json (~> 1.3)
rest-client rest-client
@ -42,64 +56,65 @@ GEM
term-ansicolor term-ansicolor
thor thor
diff-lcs (1.2.5) diff-lcs (1.2.5)
docile (1.1.3)
erubis (2.7.0) erubis (2.7.0)
ffi (1.9.3) ffi (1.9.3)
formatador (0.2.4) formatador (0.2.4)
guard (2.2.3) guard (2.4.0)
formatador (>= 0.2.4) formatador (>= 0.2.4)
listen (~> 2.1) listen (~> 2.1)
lumberjack (~> 1.0) lumberjack (~> 1.0)
pry (>= 0.9.12) pry (>= 0.9.12)
thor (>= 0.18.1) thor (>= 0.18.1)
guard-rspec (3.1.0) guard-rspec (4.2.8)
guard (>= 1.8) guard (~> 2.1)
rspec (~> 2.13) rspec (>= 2.14, < 4.0)
i18n (0.6.5) i18n (0.6.9)
listen (2.2.0) listen (2.4.1)
celluloid (>= 0.15.2) celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3) rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9) rb-inotify (>= 0.9)
log4r (1.1.10) log4r (1.1.10)
lumberjack (1.0.4) lumberjack (1.0.4)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.0) mime-types (2.1)
multi_json (1.8.2) multi_json (1.9.0)
net-scp (1.1.2) net-scp (1.1.2)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
net-ssh (2.6.8) net-ssh (2.7.0)
pry (0.9.12.2) pry (0.9.12.6)
coderay (~> 1.0.5) coderay (~> 1.0)
method_source (~> 0.8) method_source (~> 0.8)
slop (~> 3.4) slop (~> 3.4)
rake (10.1.0) rake (10.1.1)
rb-fsevent (0.9.3) rb-fsevent (0.9.4)
rb-inotify (0.9.2) rb-inotify (0.9.3)
ffi (>= 0.5.0)
rb-kqueue (0.2.2)
ffi (>= 0.5.0) ffi (>= 0.5.0)
rest-client (1.6.7) rest-client (1.6.7)
mime-types (>= 1.16) mime-types (>= 1.16)
rspec (2.13.0) rspec (2.99.0.beta2)
rspec-core (~> 2.13.0) rspec-core (= 2.99.0.beta2)
rspec-expectations (~> 2.13.0) rspec-expectations (= 2.99.0.beta2)
rspec-mocks (~> 2.13.0) rspec-mocks (= 2.99.0.beta2)
rspec-core (2.13.1) rspec-core (2.99.0.beta2)
rspec-expectations (2.13.0) rspec-expectations (2.99.0.beta2)
diff-lcs (>= 1.1.3, < 2.0) diff-lcs (>= 1.1.3, < 2.0)
rspec-fire (1.3.0) rspec-mocks (2.99.0.beta2)
rspec (>= 2.11, < 4) simplecov (0.8.2)
rspec-mocks (2.13.1) docile (~> 1.1.0)
rspec-spies (2.1.4) multi_json
rspec (~> 2.0) simplecov-html (~> 0.8.0)
simplecov (0.7.1) simplecov-html (0.8.0)
multi_json (~> 1.0) slop (3.5.0)
simplecov-html (~> 0.7.1) term-ansicolor (1.3.0)
simplecov-html (0.7.1) tins (~> 1.0)
slop (3.4.6)
term-ansicolor (1.2.2)
tins (~> 0.8)
thor (0.18.1) thor (0.18.1)
timers (1.1.0) timers (1.1.0)
tins (0.13.0) tins (1.0.0)
vagrant-omnibus (1.1.2) vagrant-omnibus (1.3.1)
wdm (0.1.0)
PLATFORMS PLATFORMS
ruby ruby
@ -110,11 +125,10 @@ DEPENDENCIES
guard-rspec guard-rspec
rake rake
rb-inotify rb-inotify
rspec (~> 2.13.0) rspec (= 2.99.0.beta2)
rspec-fire
rspec-spies
vagrant! vagrant!
vagrant-cachier! vagrant-cachier!
vagrant-lxc! vagrant-lxc!
vagrant-omnibus vagrant-omnibus
vagrant-pristine! vagrant-pristine!
vagrant-spec!

View file

@ -9,14 +9,18 @@ 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.
**NOTICE:** The master branch is targetting an initial beta for 1.0.0, for the
latest stable version of the plugin, please check the [0.8-stable](https://github.com/fgrehm/vagrant-lxc/tree/0.8-stable)
branch.
## Features / Limitations
## 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`](http://linux.die.net/man/1/redir)
* Does not support public / private networks
* Assumes you have a `lxcbr0` bridge configured on your host similar to [Ubuntu's built-in](https://help.ubuntu.com/lts/serverguide/lxc.html#lxcbr0)
As of now, it does not support public / private networks, but [private networks](https://github.com/fgrehm/vagrant-lxc/issues/120)
will be coming along _soon_.
## Requirements ## Requirements

View file

@ -0,0 +1,12 @@
# 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.

View file

@ -0,0 +1 @@
Vagrant::Action::Builtin.const_set :HandleBox, Vagrant::Action::Builtin::HandleBoxUrl

View file

@ -0,0 +1,34 @@
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

View file

@ -0,0 +1,20 @@
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

View file

@ -1,8 +1,7 @@
# This acts like a backport of Vagrant's built in action from 1.3+ for older versions # This acts like a backport of Vagrant's built in action from 1.3+ for previous version
# and will probably be deprecated on 0.8+
# https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/action/builtin/wait_for_communicator.rb # https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/action/builtin/wait_for_communicator.rb
module Vagrant module Vagrant
module LXC module Backports
module Action module Action
class WaitForCommunicator class WaitForCommunicator
def initialize(app, env) def initialize(app, env)
@ -21,7 +20,7 @@ module Vagrant
max_tries = @env[:machine].config.ssh.max_tries.to_i max_tries = @env[:machine].config.ssh.max_tries.to_i
max_tries.times do |i| max_tries.times do |i|
if @env[:machine].communicate.ready? if @env[:machine].communicate.ready?
@env[:ui].info I18n.t("vagrant_lxc.messages.container_ready") @env[:ui].info 'Machine booted and ready!'
return true return true
end end
@ -39,3 +38,5 @@ module Vagrant
end end
end end
end end
Vagrant::Action::Builtin.const_set :WaitForCommunicator, Vagrant::Backports::Action::WaitForCommunicator

View file

@ -0,0 +1,12 @@
module Vagrant
module UI
class Interface
def output(*args)
info(*args)
end
def detail(*args)
info(*args)
end
end
end
end

View file

@ -0,0 +1,27 @@
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

View file

@ -1,28 +1,28 @@
require 'vagrant-lxc/action/boot' require 'vagrant-lxc/action/boot'
require 'vagrant-lxc/action/check_created'
require 'vagrant-lxc/action/check_running'
require 'vagrant-lxc/action/clear_forwarded_ports' require 'vagrant-lxc/action/clear_forwarded_ports'
require 'vagrant-lxc/action/create' require 'vagrant-lxc/action/create'
require 'vagrant-lxc/action/created'
require 'vagrant-lxc/action/destroy' require 'vagrant-lxc/action/destroy'
require 'vagrant-lxc/action/destroy_confirm' require 'vagrant-lxc/action/destroy_confirm'
require 'vagrant-lxc/action/disconnect'
require 'vagrant-lxc/action/compress_rootfs' require 'vagrant-lxc/action/compress_rootfs'
require 'vagrant-lxc/action/fetch_ip_with_lxc_attach' require 'vagrant-lxc/action/fetch_ip_with_lxc_attach'
require 'vagrant-lxc/action/fetch_ip_from_dnsmasq_leases' 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/handle_box_metadata' require 'vagrant-lxc/action/handle_box_metadata'
require 'vagrant-lxc/action/is_running' require 'vagrant-lxc/action/prepare_nfs_settings'
require 'vagrant-lxc/action/message' require 'vagrant-lxc/action/prepare_nfs_valid_ids'
require 'vagrant-lxc/action/remove_temporary_files' require 'vagrant-lxc/action/remove_temporary_files'
require 'vagrant-lxc/action/setup_package_files' require 'vagrant-lxc/action/setup_package_files'
require 'vagrant-lxc/action/share_folders'
require 'vagrant-lxc/action/warn_networks' require 'vagrant-lxc/action/warn_networks'
unless Vagrant::LXC.vagrant_1_3_or_later unless Vagrant::Backports.vagrant_1_3_or_later?
require 'vagrant-lxc/action/wait_for_communicator' require 'vagrant-backports/action/wait_for_communicator'
Vagrant::Action::Builtin.const_set :WaitForCommunicator, Vagrant::LXC::Action::WaitForCommunicator 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 end
module Vagrant module Vagrant
@ -37,9 +37,9 @@ module Vagrant
# machine back up with the new configuration. # machine back up with the new configuration.
def self.action_reload def self.action_reload
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Created do |env1, b2| b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
if !env1[:result] if env1[:result]
b2.use Message, :not_created b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next next
end end
@ -57,7 +57,15 @@ 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 Builtin::SyncedFolderCleanup
b.use Builtin::SyncedFolders
b.use PrepareNFSSettings
else
require 'vagrant-lxc/backports/action/share_folders'
b.use ShareFolders b.use ShareFolders
end
b.use Builtin::SetHostname b.use Builtin::SetHostname
b.use WarnNetworks b.use WarnNetworks
b.use ForwardPorts b.use ForwardPorts
@ -70,15 +78,15 @@ module Vagrant
def self.action_provision def self.action_provision
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use Builtin::ConfigValidate
b.use Builtin::Call, Created do |env1, b2| b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
if !env1[:result] if env1[:result]
b2.use Message, :not_created b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next next
end end
b2.use Builtin::Call, IsRunning do |env2, b3| b2.use Builtin::Call, Builtin::IsState, :running do |env2, b3|
if !env2[:result] if !env2[:result]
b3.use Message, :not_running b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_running")
next next
end end
@ -93,7 +101,7 @@ module Vagrant
def self.action_start def self.action_start
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use Builtin::ConfigValidate
b.use Builtin::Call, IsRunning do |env, b2| b.use Builtin::Call, Builtin::IsState, :running do |env, b2|
# If the VM is running, then our work here is done, exit # If the VM is running, then our work here is done, exit
next if env[:result] next if env[:result]
b2.use action_boot b2.use action_boot
@ -106,10 +114,10 @@ module Vagrant
def self.action_up def self.action_up
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::ConfigValidate b.use Builtin::ConfigValidate
b.use Builtin::Call, Created do |env, b2| b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
# If the VM is NOT created yet, then do the setup steps # If the VM is NOT created yet, then do the setup steps
if !env[:result] if env[:result]
b2.use Builtin::HandleBoxUrl b2.use Builtin::HandleBox
b2.use HandleBoxMetadata b2.use HandleBoxMetadata
b2.use Create b2.use Create
end end
@ -122,10 +130,12 @@ module Vagrant
# the virtual machine, gracefully or by force. # the virtual machine, gracefully or by force.
def self.action_halt def self.action_halt
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Created do |env, b2| b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
if env[:result] if env[:result]
# TODO: Remove once we drop support for vagrant 1.1 b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
b2.use Disconnect next
end
b2.use ClearForwardedPorts b2.use ClearForwardedPorts
b2.use RemoveTemporaryFiles b2.use RemoveTemporaryFiles
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3| b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
@ -133,9 +143,6 @@ module Vagrant
b3.use ForcedHalt b3.use ForcedHalt
end end
end end
else
b2.use Message, :not_created
end
end end
end end
end end
@ -144,9 +151,9 @@ module Vagrant
# freeing the resources of the underlying virtual machine. # freeing the resources of the underlying virtual machine.
def self.action_destroy def self.action_destroy
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Created do |env1, b2| b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
if !env1[:result] if env1[:result]
b2.use Message, :not_created b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next next
end end
@ -157,11 +164,11 @@ module Vagrant
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::LXC.vagrant_1_3_or_later if Vagrant::Backports.vagrant_1_3_or_later?
b3.use Builtin::ProvisionerCleanup b3.use Builtin::ProvisionerCleanup
end end
else else
b3.use Message, :will_not_destroy b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.will_not_destroy")
end end
end end
end end
@ -171,9 +178,9 @@ module Vagrant
# This action packages the virtual machine into a single box file. # This action packages the virtual machine into a single box file.
def self.action_package def self.action_package
Builder.new.tap do |b| Builder.new.tap do |b|
b.use Builtin::Call, Created do |env1, b2| b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
if !env1[:result] if env1[:result]
b2.use Message, :not_created b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next next
end end
@ -198,18 +205,44 @@ module Vagrant
# This is the action that will exec into an SSH shell. # This is the action that will exec into an SSH shell.
def self.action_ssh def self.action_ssh
Builder.new.tap do |b| Builder.new.tap do |b|
b.use CheckCreated b.use Builtin::ConfigValidate
b.use CheckRunning b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
b.use Builtin::SSHExec if env[:result]
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next
end
b2.use Builtin::Call, Builtin::IsState, :running do |env1, b3|
if !env1[:result]
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_running")
next
end
b3.use BuiltIn::SSHExec
end
end
end end
end end
# This is the action that will run a single SSH command. # This is the action that will run a single SSH command.
def self.action_ssh_run def self.action_ssh_run
Builder.new.tap do |b| Builder.new.tap do |b|
b.use CheckCreated b.use Builtin::ConfigValidate
b.use CheckRunning b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
b.use Builtin::SSHRun if env[:result]
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
next
end
b2.use Builtin::Call, Builtin::IsState, :running do |env1, b3|
if !env1[:result]
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_running")
next
end
b3.use Builtin::SSHRun
end
end
end end
end end
end end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -31,6 +31,10 @@ module Vagrant
raise ContainerNotFound if @container_name && ! @cli.list.include?(@container_name) raise ContainerNotFound if @container_name && ! @cli.list.include?(@container_name)
end end
def all_containers
@cli.list
end
def base_path def base_path
Pathname.new("#{CONTAINERS_PATH}/#{@container_name}") Pathname.new("#{CONTAINERS_PATH}/#{@container_name}")
end end
@ -58,20 +62,24 @@ module Vagrant
def share_folders(folders) def share_folders(folders)
folders.each do |folder| folders.each do |folder|
guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, '')) share_folder(folder[:hostpath], folder[:guestpath])
unless guestpath.directory?
begin
@logger.debug("Guest path doesn't exist, creating: #{guestpath}")
@sudo_wrapper.run('mkdir', '-p', guestpath.to_s)
rescue Errno::EACCES
raise Vagrant::Errors::SharedFolderCreateFailed, :path => guestpath.to_s
end end
end end
@customizations << ['mount.entry', "#{folder[:hostpath]} #{guestpath} none bind 0 0"] def share_folder(host_path, guest_path)
guest_path = rootfs_path.join(guest_path.gsub(/^\//, ''))
unless guest_path.directory?
begin
@logger.debug("Guest path doesn't exist, creating: #{guest_path}")
@sudo_wrapper.run('mkdir', '-p', guest_path.to_s)
rescue Errno::EACCES
raise Vagrant::Errors::SharedFolderCreateFailed, :path => guest_path.to_s
end end
end end
@customizations << ['mount.entry', "#{host_path} #{guest_path} none bind 0 0"]
end
def start(customizations) def start(customizations)
@logger.info('Starting container...') @logger.info('Starting container...')
@ -87,6 +95,7 @@ module Vagrant
def forced_halt def forced_halt
@logger.info('Shutting down container...') @logger.info('Shutting down container...')
# TODO: Remove `lxc-shutdown` usage, graceful halt is enough
@cli.transition_to(:stopped) { |c| c.shutdown } @cli.transition_to(:stopped) { |c| c.shutdown }
# REFACTOR: Do not use exception to control the flow # REFACTOR: Do not use exception to control the flow
rescue CLI::TargetStateNotReached, CLI::ShutdownNotSupported rescue CLI::TargetStateNotReached, CLI::ShutdownNotSupported

View file

@ -1,4 +1,5 @@
require "vagrant" require 'vagrant'
require 'vagrant-backports/utils'
module Vagrant module Vagrant
module LXC module LXC
@ -9,7 +10,9 @@ module Vagrant
LXC-based virtual machines. LXC-based virtual machines.
EOF EOF
provider(:lxc, parallel: true) do extra = []
extra << {parallel: true} if Vagrant::Backports.vagrant_1_2_or_later?
provider(:lxc, *extra) do
require File.expand_path("../provider", __FILE__) require File.expand_path("../provider", __FILE__)
I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml') I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
@ -22,10 +25,20 @@ module Vagrant
require File.expand_path("../config", __FILE__) require File.expand_path("../config", __FILE__)
Config Config
end end
if Vagrant::Backports.vagrant_1_4_or_later?
synced_folder(:lxc) do
require File.expand_path("../synced_folder", __FILE__)
SyncedFolder
end
end end
def self.vagrant_1_3_or_later if Vagrant::Backports.vagrant_1_5_or_later?
Gem::Version.new(Vagrant::VERSION) >= Gem::Version.new('1.3.0') provider_capability("lxc", "public_address") do
require_relative "provider/cap/public_address"
Provider::Cap::PublicAddress
end
end
end end
end end
end end

View file

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

View file

@ -0,0 +1,38 @@
module Vagrant
module LXC
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
def usable?(machine)
# These synced folders only work if the provider is LXC
machine.provider_name == :lxc
end
def prepare(machine, folders, _opts)
machine.ui.output(I18n.t("vagrant.actions.lxc.share_folders.preparing"))
folders.each do |id, data|
host_path = Pathname.new(File.expand_path(data[:hostpath], machine.env.root_path))
guest_path = data[:guestpath]
if !host_path.directory? && data[:create]
# Host path doesn't exist, so let's create it.
@logger.info("Host path doesn't exist, creating: #{host_path}")
begin
host_path.mkpath
rescue Errno::EACCES
raise Vagrant::Errors::SharedFolderCreateFailed,
:path => hostpath.to_s
end
end
machine.provider.driver.share_folder(host_path, guest_path)
# Guest path specified, so mount the folder to specified point
machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
guestpath: data[:guestpath],
hostpath: data[:hostpath],
guest_path: data[:guestpath]))
end
end
end
end
end

View file

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

View file

@ -12,11 +12,6 @@ en:
Starting container... Starting container...
force_shutdown: |- force_shutdown: |-
Forcing shutdown of container... Forcing shutdown of container...
# TODO: Remove the following keys after we drop support for vagrant < 1.3
waiting_for_start: |-
Waiting for container to start. This should not take long.
container_ready: |-
Container started and ready for use!
warn_networks: |- warn_networks: |-
Warning! The LXC provider doesn't support any of the Vagrant public / private Warning! The LXC provider doesn't support any of the Vagrant public / private
network configurations (ex: `config.vm.network :private_network, ip: "some-ip"`). network configurations (ex: `config.vm.network :private_network, ip: "some-ip"`).

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,22 +10,10 @@ require 'bundler/setup'
require 'i18n' require 'i18n'
require 'rspec-spies' require 'vagrant-lxc/plugin'
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f } Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
# If we should verify constant names, eager loads
if ENV['VERIFY_CONSTANT_NAMES']
require 'vagrant-lxc/plugin'
require 'vagrant-lxc/provider'
require 'vagrant-lxc/config'
end
require 'rspec/fire'
RSpec::Fire.configure do |config|
config.verify_constant_names = ENV['VERIFY_CONSTANT_NAMES'] == '1'
end
RSpec.configure do |config| RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true config.run_all_when_everything_filtered = true

View file

@ -1,13 +1,15 @@
require 'unit_helper' require 'unit_helper'
require 'vagrant-lxc/plugin'
require 'vagrant-lxc/provider'
require 'vagrant-lxc/action/compress_rootfs' require 'vagrant-lxc/action/compress_rootfs'
describe Vagrant::LXC::Action::CompressRootFS do describe Vagrant::LXC::Action::CompressRootFS do
let(:app) { double(:app, call: true) } let(:app) { double(:app, call: true) }
let(:env) { {machine: machine, ui: double(info: true)} } let(:env) { {machine: machine, ui: double(info: true)} }
let(:machine) { instance_double('Vagrant::Machine', provider: provider) } let(:machine) { double(Vagrant::Machine, provider: provider) }
let(:provider) { instance_double('Vagrant::LXC::Provider', driver: driver) } let(:provider) { double(Vagrant::LXC::Provider, driver: driver) }
let(:driver) { instance_double('Vagrant::LXC::Driver', compress_rootfs: compressed_rootfs_path) } let(:driver) { double(Vagrant::LXC::Driver, compress_rootfs: compressed_rootfs_path) }
let(:compressed_rootfs_path) { '/path/to/rootfs.tar.gz' } let(:compressed_rootfs_path) { '/path/to/rootfs.tar.gz' }
subject { described_class.new(app, env) } subject { described_class.new(app, env) }

View file

@ -1,7 +1,7 @@
require 'unit_helper' require 'unit_helper'
require 'tmpdir' require 'tmpdir'
require 'vagrant-lxc/errors' require 'vagrant-lxc/provider'
require 'vagrant-lxc/action/forward_ports' require 'vagrant-lxc/action/forward_ports'
describe Vagrant::LXC::Action::ForwardPorts do describe Vagrant::LXC::Action::ForwardPorts do
@ -9,7 +9,7 @@ describe Vagrant::LXC::Action::ForwardPorts do
let(:env) { {machine: machine, ui: double(info: true)} } let(:env) { {machine: machine, ui: double(info: true)} }
let(:machine) { double(:machine) } let(:machine) { double(:machine) }
let!(:data_dir) { Pathname.new(Dir.mktmpdir) } let!(:data_dir) { Pathname.new(Dir.mktmpdir) }
let(:provider) { instance_double('Vagrant::LXC::Provider', ssh_info: {host: container_ip}) } let(:provider) { double(Vagrant::LXC::Provider, ssh_info: {host: container_ip}) }
let(:host_ip) { '127.0.0.1' } let(:host_ip) { '127.0.0.1' }
let(:host_port) { 8080 } let(:host_port) { 8080 }
let(:guest_port) { 80 } let(:guest_port) { 80 }

View file

@ -102,15 +102,11 @@ describe Vagrant::LXC::Action::HandleBoxMetadata do
it 'validates box versions' do it 'validates box versions' do
%w( 2 3 1.0.0 ).each do |v| %w( 2 3 1.0.0 ).each do |v|
metadata['version'] = v metadata['version'] = v
expect { expect { subject.call(env) }.to_not raise_error
subject.call(env)
}.to_not raise_error(Vagrant::LXC::Errors::IncompatibleBox)
end end
metadata['version'] = '1' metadata['version'] = '1'
expect { expect { subject.call(env) }.to raise_error
subject.call(env)
}.to raise_error(Vagrant::LXC::Errors::IncompatibleBox)
end end
it 'raises an error if the rootfs tarball cant be found' do it 'raises an error if the rootfs tarball cant be found' do

View file

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

View file

@ -1,9 +1,10 @@
require 'unit_helper' require 'unit_helper'
require 'vagrant-lxc/sudo_wrapper'
require 'vagrant-lxc/driver/cli' require 'vagrant-lxc/driver/cli'
describe Vagrant::LXC::Driver::CLI do describe Vagrant::LXC::Driver::CLI do
let(:sudo_wrapper) { instance_double('Vagrant::LXC::SudoWrapper', run: true) } let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true) }
subject { described_class.new(sudo_wrapper) } subject { described_class.new(sudo_wrapper) }
@ -197,6 +198,6 @@ describe Vagrant::LXC::Driver::CLI do
}.to raise_error(described_class::TransitionBlockNotProvided) }.to raise_error(described_class::TransitionBlockNotProvided)
end end
pending 'waits for the expected container state' skip 'waits for the expected container state'
end end
end end

View file

@ -1,15 +1,15 @@
require 'unit_helper' require 'unit_helper'
require 'vagrant'
require 'vagrant-lxc/driver' require 'vagrant-lxc/driver'
require 'vagrant-lxc/driver/cli' require 'vagrant-lxc/driver/cli'
require 'vagrant-lxc/sudo_wrapper'
describe Vagrant::LXC::Driver do describe Vagrant::LXC::Driver do
describe 'container name validation' do describe 'container name validation' do
let(:unknown_container) { described_class.new('unknown', nil, cli) } let(:unknown_container) { described_class.new('unknown', nil, cli) }
let(:valid_container) { described_class.new('valid', nil, cli) } let(:valid_container) { described_class.new('valid', nil, cli) }
let(:new_container) { described_class.new(nil, nil) } let(:new_container) { described_class.new(nil, nil) }
let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', list: ['valid']) } let(:cli) { double(Vagrant::LXC::Driver::CLI, list: ['valid']) }
it 'raises a ContainerNotFound error if an unknown container name gets provided' do it 'raises a ContainerNotFound error if an unknown container name gets provided' do
expect { expect {
@ -37,7 +37,7 @@ describe Vagrant::LXC::Driver do
let(:template_opts) { {'--some' => 'random-option'} } let(:template_opts) { {'--some' => 'random-option'} }
let(:config_file) { '/path/to/lxc-config-from-box' } let(:config_file) { '/path/to/lxc-config-from-box' }
let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' } let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' }
let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', :create => true, :name= => true) } let(:cli) { double(Vagrant::LXC::Driver::CLI, :create => true, :name= => true) }
subject { described_class.new(nil, nil, cli) } subject { described_class.new(nil, nil, cli) }
@ -60,7 +60,7 @@ describe Vagrant::LXC::Driver do
end end
describe 'destruction' do describe 'destruction' do
let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', destroy: true) } let(:cli) { double(Vagrant::LXC::Driver::CLI, destroy: true) }
subject { described_class.new('name', nil, cli) } subject { described_class.new('name', nil, cli) }
@ -74,8 +74,8 @@ describe Vagrant::LXC::Driver do
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) { instance_double('Vagrant::LXC::Driver::CLI', start: true) } let(:cli) { double(Vagrant::LXC::Driver::CLI, start: true) }
let(:sudo) { instance_double('Vagrant::LXC::SudoWrapper', su_c: true) } let(:sudo) { double(Vagrant::LXC::SudoWrapper, su_c: true) }
subject { described_class.new('name', sudo, cli) } subject { described_class.new('name', sudo, cli) }
@ -94,7 +94,7 @@ describe Vagrant::LXC::Driver do
end end
describe 'halt' do describe 'halt' do
let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', shutdown: true) } let(:cli) { double(Vagrant::LXC::Driver::CLI, shutdown: true) }
subject { described_class.new('name', nil, cli) } subject { described_class.new('name', nil, cli) }
@ -129,7 +129,7 @@ describe Vagrant::LXC::Driver do
describe 'state' do describe 'state' do
let(:cli_state) { :something } let(:cli_state) { :something }
let(:cli) { instance_double('Vagrant::LXC::Driver::CLI', state: cli_state) } let(:cli) { double(Vagrant::LXC::Driver::CLI, state: cli_state) }
subject { described_class.new('name', nil, cli) } subject { described_class.new('name', nil, cli) }
@ -143,7 +143,7 @@ describe Vagrant::LXC::Driver do
let(:folders) { [shared_folder] } let(:folders) { [shared_folder] }
let(:rootfs_path) { Pathname('/path/to/rootfs') } let(:rootfs_path) { Pathname('/path/to/rootfs') }
let(:expected_guest_path) { "#{rootfs_path}/vagrant" } let(:expected_guest_path) { "#{rootfs_path}/vagrant" }
let(:sudo_wrapper) { instance_double('Vagrant::LXC::SudoWrapper', run: true) } let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true) }
subject { described_class.new('name', sudo_wrapper) } subject { described_class.new('name', sudo_wrapper) }

View file

@ -7,8 +7,6 @@ if defined? SimpleCov
end end
RSpec.configure do |config| RSpec.configure do |config|
config.include RSpec::Fire
config.include UnitExampleGroup, :type => :unit, :example_group => { config.include UnitExampleGroup, :type => :unit, :example_group => {
:file_path => /\bspec\/unit\// :file_path => /\bspec\/unit\//
} }

View file

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

33
vagrant-spec.config.rb Normal file
View file

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