diff --git a/.gitignore b/.gitignore index 6d588d6..af66537 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,9 @@ tmp _yardoc doc/ +/gems.tags + .vagrant /cache + +/dummy-ubuntu-cloudimg.box diff --git a/.gitmodules b/.gitmodules index 02032a4..bef6aa9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "vagrant-1.1"] - path = vagrant-1.1 +[submodule "vagrant"] + path = vagrant url = git://github.com/mitchellh/vagrant.git diff --git a/Gemfile b/Gemfile index f9b870d..b3f0dd4 100644 --- a/Gemfile +++ b/Gemfile @@ -7,11 +7,16 @@ end gemspec -gem 'vagrant', github: 'mitchellh/vagrant' +gem 'vagrant', path: './vagrant' gem 'rake' gem 'net-ssh' gem 'rspec' +gem 'rspec-fire', require: 'rspec/fire' +gem 'rspec-spies', require: false +gem 'simplecov', require: false gem 'guard' gem 'guard-rspec' +gem 'guard-bundler' +gem 'guard-ctags-bundler' gem 'rb-inotify' gem 'log4r' diff --git a/Gemfile.lock b/Gemfile.lock index 9bc9f8b..8f9673d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,10 @@ -GIT - remote: git://github.com/mitchellh/vagrant.git - revision: 803269f7291719715011c5c76d66e20101f7af50 +PATH + remote: . + specs: + vagrant-lxc (0.0.1) + +PATH + remote: ./vagrant specs: vagrant (1.1.0.dev) childprocess (~> 0.3.7) @@ -11,11 +15,6 @@ GIT net-scp (~> 1.0.4) net-ssh (~> 2.2.2) -PATH - remote: . - specs: - vagrant-lxc (0.0.1) - GEM remote: https://rubygems.org/ specs: @@ -31,15 +30,21 @@ GEM pry (>= 0.9.10) terminal-table (>= 1.4.3) thor (>= 0.14.6) + guard-bundler (1.0.0) + bundler (~> 1.0) + guard (~> 1.1) + guard-ctags-bundler (0.1.6) + guard (>= 1.1) guard-rspec (2.4.1) guard (>= 1.1) rspec (~> 2.11) - i18n (0.6.1) + i18n (0.6.2) json (1.6.8) listen (0.7.3) log4r (1.1.10) lumberjack (1.0.2) method_source (0.8.1) + multi_json (1.6.1) net-scp (1.0.4) net-ssh (>= 1.99.1) net-ssh (2.2.2) @@ -57,7 +62,15 @@ GEM rspec-core (2.13.0) rspec-expectations (2.13.0) diff-lcs (>= 1.1.3, < 2.0) + rspec-fire (1.1.3) + rspec (~> 2.11) rspec-mocks (2.13.0) + rspec-spies (2.1.3) + rspec (~> 2.0) + simplecov (0.7.1) + multi_json (~> 1.0) + simplecov-html (~> 0.7.1) + simplecov-html (0.7.1) slop (3.4.3) terminal-table (1.4.5) thor (0.17.0) @@ -67,11 +80,16 @@ PLATFORMS DEPENDENCIES guard + guard-bundler + guard-ctags-bundler guard-rspec log4r net-ssh rake rb-inotify rspec + rspec-fire + rspec-spies + simplecov vagrant! vagrant-lxc! diff --git a/Guardfile b/Guardfile index a148482..190fdc0 100644 --- a/Guardfile +++ b/Guardfile @@ -3,8 +3,34 @@ raise 'You should start guard from the dev box!' unless ENV['USER'] == 'vagrant' +guard 'bundler' do + watch('Gemfile') + watch(/^.+\.gemspec/) +end + +guard 'ctags-bundler', :src_path => ["lib"] do + watch(/^(lib|spec\/support)\/.*\.rb$/) + watch('Gemfile.lock') +end + guard 'rspec' do watch(%r{^spec/.+_spec\.rb$}) - watch('spec/spec_helper.rb') { 'spec' } - watch('lib/provider') { 'spec' } + watch(%r{^lib/vagrant-lxc/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" } + watch('spec/unit_helper.rb') { "spec/unit" } + watch('spec/spec_helper.rb') { "spec/" } + + # Rails example + watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } + watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } + watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] } + watch(%r{^spec/support/(.+)\.rb$}) { "spec" } + watch('config/routes.rb') { "spec/routing" } + watch('app/controllers/application_controller.rb') { "spec/controllers" } + + # Capybara features specs + watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" } + + # Turnip features and steps + watch(%r{^spec/acceptance/(.+)\.feature$}) + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' } end diff --git a/README.md b/README.md index ff2b707..91717c6 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,7 @@ # vagrant-lxc -Highly experimental, soon to come, Linux Containers support for the unreleased Vagrant 1.1 - - -## WARNING - -Please keep in mind that this is not even alpha software and things might go wrong. -Although I'm brave enough to use it on my physical machine, its recommended that you -try it out on the Vagrant dev box ;) - - -## Development - -On your host: - -```terminal -./setup-vagrant-dev-box -vagrant ssh -``` - -*NOTE: This takes around 12 minutes on a 15mb connection after the [base vagrant box](https://github.com/fgrehm/vagrant-lxc/blob/master/Vagrantfile#L5-L6) -and ubuntu [lxc cloud img](https://github.com/fgrehm/vagrant-lxc/blob/master/setup-vagrant-dev-box#L8-L9) -have been downloaded* - -On the guest machine: - -```terminal -mkdir /tmp/vagrant-lxc -cp /vagrant/config.yml.sample /tmp/vagrant-lxc/config.yml -cd /tmp/vagrant-lxc -/vagrant/lib/provider up -/vagrant/lib/provider ssh -``` - - -## Troubleshooting - -If your container / dev box start acting weird, run `vagrant reload` to see if -things get back to normal. - -In case `vagrant reload` doesn't work, restore the VirtualBox snapshot that was -created automagically right after `./setup-vagrant-dev-box` finished by running -the same script again and selecting the `[r]estore snapshot` option when asked. +Highly experimental, soon to come, Linux Containers support for the unreleased +Vagrant 1.1. More information coming out soon... ## Contributing diff --git a/Rakefile b/Rakefile index eea5261..8247fb1 100644 --- a/Rakefile +++ b/Rakefile @@ -2,4 +2,8 @@ raise 'This Rakefile is meant to be used from the dev box' unless ENV['USER'] == Dir['./tasks/**/*.rake'].each { |f| load f } -task :default => :spec +begin + require 'rspec/core/rake_task' + RSpec::Core::RakeTask.new(:spec) + task :default => :coverage +rescue LoadError; end diff --git a/dev/Gemfile b/dev/Gemfile index c572628..5ad4b27 100644 --- a/dev/Gemfile +++ b/dev/Gemfile @@ -5,5 +5,5 @@ end source "https://rubygems.org" -gem 'vagrant', github: 'mitchellh/vagrant' +gem 'vagrant', path: '../vagrant' gem 'vagrant-lxc', path: '../' diff --git a/dev/Gemfile.lock b/dev/Gemfile.lock index 5c5c3d0..a7505a6 100644 --- a/dev/Gemfile.lock +++ b/dev/Gemfile.lock @@ -1,6 +1,10 @@ -GIT - remote: git://github.com/mitchellh/vagrant.git - revision: 803269f7291719715011c5c76d66e20101f7af50 +PATH + remote: ../ + specs: + vagrant-lxc (0.0.1) + +PATH + remote: ../vagrant specs: vagrant (1.1.0.dev) childprocess (~> 0.3.7) @@ -11,11 +15,6 @@ GIT net-scp (~> 1.0.4) net-ssh (~> 2.2.2) -PATH - remote: ../ - specs: - vagrant-lxc (0.0.1) - GEM remote: https://rubygems.org/ specs: diff --git a/dummy-box-files/metadata.json b/dummy-box-files/metadata.json new file mode 100644 index 0000000..959aa0e --- /dev/null +++ b/dummy-box-files/metadata.json @@ -0,0 +1 @@ +{"provider":"lxc"} diff --git a/lib/vagrant-lxc.rb b/lib/vagrant-lxc.rb index e5bc235..405c1ce 100644 --- a/lib/vagrant-lxc.rb +++ b/lib/vagrant-lxc.rb @@ -1,7 +1,8 @@ require "vagrant-lxc/version" +require "vagrant-lxc/plugin" + module Vagrant module LXC - # Your code goes here... end end diff --git a/lib/vagrant-lxc/actions.rb b/lib/vagrant-lxc/actions.rb new file mode 100644 index 0000000..17d1a2f --- /dev/null +++ b/lib/vagrant-lxc/actions.rb @@ -0,0 +1,214 @@ +# TODO: Split action classes into their own files + +module Vagrant + module LXC + module Actions + # This action is responsible for reloading the machine, which + # brings it down, sucks in new configuration, and brings the + # machine back up with the new configuration. + def self.action_reload + Vagrant::Action::Builder.new.tap do |b| + b.use CheckLXC + b.use Vagrant::Action::Builtin::Call, Created do |env1, b2| + if !env1[:result] + b2.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotCreated + next + end + + b2.use Vagrant::Action::Builtin::ConfigValidate + b2.use action_halt + b2.use action_start + end + end + end + + # We could do this here as VirtualBox does, but at least for now its better + # to be explicit and have the full constant name in order to easily spot + # what we implemented and what is builtin on Vagrant. + # + # include Vagrant::Action::Builtin + + # This action boots the VM, assuming the VM is in a state that requires + # a bootup (i.e. not saved). + def self.action_boot + Vagrant::Action::Builder.new.tap do |b| + b.use ClearForwardedPorts + b.use Vagrant::Action::Builtin::Provision + b.use Vagrant::Action::Builtin::EnvSet, :port_collision_repair => true + b.use PrepareForwardedPortCollisionParams + b.use ClearSharedFolders + b.use ShareFolders + b.use Network + b.use ForwardPorts + b.use HostName + b.use SaneDefaults + b.use Customize + b.use Boot + end + end + + # This action starts a container, assuming it is already created and exists. + # A precondition of this action is that the container exists. + def self.action_start + Vagrant::Action::Builder.new.tap do |b| + b.use CheckLXC + b.use Vagrant::Action::Builtin::ConfigValidate + b.use Vagrant::Action::Builtin::Call, IsRunning do |env, b2| + # If the VM is running, then our work here is done, exit + next if env[:result] + # TODO: Check if has been saved / frozen and resume + b2.use action_boot + end + end + end + + # This action brings the machine up from nothing, including creating the + # container, configuring metadata, and booting. + def self.action_up + Vagrant::Action::Builder.new.tap do |b| + b.use CheckLXC + b.use Vagrant::Action::Builtin::ConfigValidate + b.use Vagrant::Action::Builtin::Call, Created do |env, b2| + # If the VM is NOT created yet, then do the setup steps + if !env[:result] + b2.use Create + # We'll probably have other actions down here... + end + end + b.use action_start + end + end + + # This is the action that is primarily responsible for halting + # the virtual machine, gracefully or by force. + def self.action_halt + Vagrant::Action::Builder.new.tap do |b| + b.use CheckLXC + b.use Vagrant::Action::Builtin::Call, Created do |env, b2| + if env[:result] + # TODO: If is paused, should resume and then halt + # TODO: If could not gracefully halt, force it + # TODO: b2.use Vagrant::Action::Builtin::GracefulHalt, :poweroff, :running + unless env[:machine].state.off? + puts 'TODO: Halt container using Vagrant::Action::Builtin::GracefulHalt' + env[:machine].provider.container.halt + end + else + b2.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotCreated + end + end + end + end + + # This is the action that is primarily responsible for completely + # freeing the resources of the underlying virtual machine. + def self.action_destroy + Vagrant::Action::Builder.new.tap do |b| + b.use CheckLXC + b.use Vagrant::Action::Builtin::Call, Created do |env1, b2| + if !env1[:result] + b2.use MessageNotCreated + next + end + + # TODO: Implement our own DestroyConfirm or propose a builtin action for Vagrant core + b2.use Vagrant::Action::Builtin::Call, VagrantPlugins::ProviderVirtualBox::Action::DestroyConfirm do |env2, b3| + if env2[:result] + b3.use Vagrant::Action::Builtin::ConfigValidate + b3.use Vagrant::Action::Builtin::EnvSet, :force_halt => true + b3.use action_halt + b3.use Destroy + # TODO: VirtualBox provider has a CleanMachineFolder action, do we need something similar? + # TODO: VirtualBox provider has a DestroyUnusedNetworkInterfaces action, do we need something similar? + else + # TODO: Implement our own DestroyConfirm or propose a builtin action for Vagrant core + b3.use VagrantPlugins::ProviderVirtualBox::Action::MessageWillNotDestroy + end + end + end + end + end + + + class BaseAction + def initialize(app, env) + @app = app + end + + def call(env) + puts "TODO: Implement #{self.class.name}" + @app.call(env) + end + end + + class Created < BaseAction + def call(env) + # Set the result to be true if the machine is created. + env[:result] = env[:machine].state.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 + + class IsRunning < BaseAction + def call(env) + # Set the result to be true if the machine is created. + env[:result] = env[:machine].state.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 + + class Create < BaseAction + def call(env) + puts "TODO: Create container" + env[:machine].id = 'TODO-set-a-proper-machine-id' unless env[:machine].id + env[:machine].provider.container.create + @app.call env + end + end + + class Destroy < BaseAction + def call(env) + env[:machine].id = nil + env[:machine].provider.container.destroy + @app.call env + end + end + + class Boot < BaseAction + def call(env) + env[:machine].provider.container.start + @app.call env + end + end + + # TODO: Check if our requirements are met. + class CheckLXC < BaseAction; end + + # TODO: Implement folder sharing with "mount" + class ShareFolders < BaseAction; end + + # TODO: Sets up all networking for the container instance. This includes + # host only networks, bridged networking, forwarded ports, etc. + class Network < BaseAction; end + + # TODO: Implement port forwarding with rinetd + class ForwardPorts < BaseAction; end + + # TODO: Find out which defaults are sane for LXC ;) + class SaneDefaults < BaseAction; end + + # TODO: Find out if the actions below will be needed + class ClearForwardedPorts < BaseAction; end + class PrepareForwardedPortCollisionParams < BaseAction; end + class ClearSharedFolders < BaseAction; end + class HostName < BaseAction; end + class Customize < BaseAction; end + end + end +end diff --git a/lib/vagrant-lxc/config.rb b/lib/vagrant-lxc/config.rb new file mode 100644 index 0000000..732f9e2 --- /dev/null +++ b/lib/vagrant-lxc/config.rb @@ -0,0 +1,6 @@ +module Vagrant + module LXC + class Config < Vagrant.plugin("2", :config) + end + end +end diff --git a/lib/vagrant-lxc/container.rb b/lib/vagrant-lxc/container.rb new file mode 100644 index 0000000..3c12316 --- /dev/null +++ b/lib/vagrant-lxc/container.rb @@ -0,0 +1,52 @@ +module Vagrant + module LXC + class Container + CONTAINER_STATE_FILE_PATH = '/tmp/vagrant-lxc-container-state-%s' + + def initialize(machine) + @machine = machine + end + + def create + puts 'TODO: Create container' + end + + def start + puts 'TODO: Start container' + update!(:running) + end + + def halt + update!(:poweroff) + end + + def destroy + puts "TODO: Destroy container" + File.delete(state_file_path) if state_file_path + end + + def state + # TODO: Grab the real machine state here + read_state_from_file + end + + private + + def update!(state) + File.open(state_file_path, 'w') { |f| f.print state } + end + + def read_state_from_file + if File.exists?(state_file_path) + File.read(state_file_path).to_sym + elsif @machine.id + :unknown + end + end + + def state_file_path + CONTAINER_STATE_FILE_PATH % {id: @machine.id} + end + end + end +end diff --git a/lib/vagrant-lxc/machine_state.rb b/lib/vagrant-lxc/machine_state.rb new file mode 100644 index 0000000..a3bbc0d --- /dev/null +++ b/lib/vagrant-lxc/machine_state.rb @@ -0,0 +1,25 @@ +module Vagrant + module LXC + class MachineState < Vagrant::MachineState + CREATED_STATES = %w( running poweroff ).map!(&:to_sym) + + def initialize(state_id) + short = state_id.to_s.gsub("_", " ") + long = I18n.t("vagrant.commands.status.#{state_id}") + super(state_id, short, long) + end + + def created? + CREATED_STATES.include?(self.id) + end + + def off? + self.id == :poweroff + end + + def running? + self.id == :running + end + end + end +end diff --git a/lib/vagrant-lxc/plugin.rb b/lib/vagrant-lxc/plugin.rb new file mode 100644 index 0000000..178450f --- /dev/null +++ b/lib/vagrant-lxc/plugin.rb @@ -0,0 +1,23 @@ +require "vagrant" + +module Vagrant + module LXC + class Plugin < Vagrant.plugin("2") + name "Linux Containers (LXC) provider" + description <<-EOF + The LXC provider allows Vagrant to manage and control + LXC-based virtual machines. + EOF + + provider(:lxc) do + require File.expand_path("../provider", __FILE__) + Provider + end + + config(:lxc, :provider) do + require File.expand_path("../config", __FILE__) + Config + end + end + end +end diff --git a/lib/vagrant-lxc/provider.rb b/lib/vagrant-lxc/provider.rb new file mode 100644 index 0000000..9f49caf --- /dev/null +++ b/lib/vagrant-lxc/provider.rb @@ -0,0 +1,40 @@ +require "vagrant-lxc/actions" +require "vagrant-lxc/container" +require "vagrant-lxc/machine_state" + +require "log4r" + +module Vagrant + module LXC + # DISCUSS: VirtualBox provider has a #machine_id_changed, do we need to handle it as well? + class Provider < Vagrant.plugin("2", :provider) + attr_reader :container + + def initialize(machine) + @logger = Log4r::Logger.new("vagrant::provider::lxc") + @machine = machine + @container = Container.new(@machine) + end + + # @see Vagrant::Plugin::V1::Provider#action + def action(name) + # Attempt to get the action method from the Action class if it + # exists, otherwise return nil to show that we don't support the + # given action. + action_method = "action_#{name}" + # TODO: Rename to singular + return LXC::Actions.send(action_method) if LXC::Actions.respond_to?(action_method) + nil + end + + def state + LXC::MachineState.new(@container.state) + end + + def to_s + id = @machine.id ? @machine.id : "new VM" + "LXC (#{id})" + end + end + end +end diff --git a/setup-vagrant-dev-box b/setup-vagrant-dev-box index 8c190c5..76db20b 100755 --- a/setup-vagrant-dev-box +++ b/setup-vagrant-dev-box @@ -58,6 +58,9 @@ end # Cache development dependencies `mkdir -p cache` +# Fetches vagrant submodule +`git submodule update --init` + # Cache container image between vagrant box destructions download "#{IMAGE_ROOT}/#{IMAGE_NAME}", IMAGE_NAME @@ -75,7 +78,7 @@ vagrant_ssh 'sudo sed -i -e "s/be.archive/br.archive/g" /etc/apt/sources.list' vagrant_ssh "sudo apt-get update && sudo apt-get upgrade -y" # Install dependencies -vagrant_ssh "sudo apt-get install lxc rinetd libffi-dev libffi-ruby ruby1.9.1-dev htop git virtualbox virtualbox-ose-dkms linux-headers-generic linux-headers-3.5.0-17-generic -y && sudo gem install bundler --no-ri --no-rdoc -v 1.2.5" +vagrant_ssh "sudo apt-get install lxc rinetd libffi-dev bsdtar exuberant-ctags libffi-ruby ruby1.9.1-dev htop git virtualbox virtualbox-ose-dkms linux-headers-generic linux-headers-3.5.0-17-generic -y && sudo gem install bundler --no-ri --no-rdoc -v 1.2.5" vagrant_ssh "sudo dkms install virtualbox/4.1.18" vagrant_ssh "sudo service virtualbox start" @@ -117,9 +120,8 @@ vagrant_ssh 'sudo chown vagrant:vagrant /etc/rinetd.conf' vagrant_ssh 'cd /vagrant && bundle && cd /vagrant/dev && bundle' # Setup vagrant default ssh key -# FIXME: This is wrong -vagrant_keys_path = '~/gems/bundler/gems/vagrant-803269f72917/keys' -vagrant_ssh "cd /vagrant && mkdir -p ~/.ssh && cp #{vagrant_keys_path}/vagrant ~/.ssh/id_rsa && cp #{vagrant_keys_path}/vagrant.pub ~/.ssh/id_rsa.pub && chmod 600 ~/.ssh/id_rsa" +vagrant_keys_path = '/vagrant/vagrant/keys' +vagrant_ssh "mkdir -p ~/.ssh && cd /vagrant && cp #{vagrant_keys_path}/vagrant ~/.ssh/id_rsa && cp #{vagrant_keys_path}/vagrant.pub ~/.ssh/id_rsa.pub && chmod 600 ~/.ssh/id_rsa" # Setup lxc cache vagrant_ssh "sudo mkdir -p /var/cache/lxc/cloud-quantal && sudo cp /vagrant/cache/#{IMAGE_NAME} /var/cache/lxc/cloud-quantal/#{IMAGE_NAME}" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3380bd3..c525fdf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,59 +1,28 @@ -require 'rubygems' +if ENV['COVERAGE'] + require 'simplecov' + SimpleCov.start do + # This can probably go away once we stop using vagrant as submodule + add_filter { |source_file| source_file.filename =~ /\/vagrant\/plugins\// } + add_filter { |source_file| source_file.filename =~ /\/vagrant\/lib\/vagrant(\/|\.rb)/ } + end +end require 'bundler/setup' Bundler.require -require 'yaml' -require 'shellwords' +require 'rspec-spies' -`mkdir -p tmp` - -module TestHelpers - def provider_up - `cd tmp && ../lib/provider up -o /vagrant/tmp/logger.log` - end - - def destroy_container! - `cd tmp && ../lib/provider destroy -o /vagrant/tmp/logger.log` - `rm -f tmp/config.yml` - end - - def restore_rinetd_conf! - `sudo cp /vagrant/cache/rinetd.conf /etc/rinetd.conf` - `sudo service rinetd restart` - end - - def configure_box_with(opts) - opts = opts.dup - opts.keys.each do |key| - opts[key.to_s] = opts.delete(key) - end - File.open('./tmp/config.yml', 'w') { |f| f.puts YAML::dump(opts) } - end - - def provider_ssh(options) - options = options.map { |opt, val| "-#{opt} #{Shellwords.escape val}" } - options = options.join(' ') - `cd tmp && ../lib/provider ssh #{options}` - end -end +Dir[File.dirname(__FILE__) + "/spec/support/**/*.rb"].each { |f| require f } RSpec.configure do |config| config.treat_symbols_as_metadata_keys_with_true_values = true config.run_all_when_everything_filtered = true config.filter_run :focus - config.include TestHelpers - # Run specs in random order to surface order dependencies. If you find an # order dependency and want to debug it, you can fix the order by providing # the seed, which is printed after each run. # --seed 1234 config.order = 'random' - - config.after :all do - destroy_container! - restore_rinetd_conf! - end end diff --git a/spec/unit/machine_state_spec.rb b/spec/unit/machine_state_spec.rb new file mode 100644 index 0000000..9865372 --- /dev/null +++ b/spec/unit/machine_state_spec.rb @@ -0,0 +1,39 @@ +require 'unit_helper' + +require 'vagrant-lxc/machine_state' + +describe Vagrant::LXC::MachineState do + describe 'short description' do + subject { described_class.new(:not_created) } + + it 'is a humanized version of state id' do + subject.short_description.should == 'not created' + end + end + + describe 'long description' do + subject { described_class.new(:short_name) } + before { I18n.stub(t: 'some really long description') } + + it 'is a localized version of the state id' do + subject.long_description.should == 'some really long description' + I18n.should have_received(:t).with('vagrant.commands.status.short_name') + end + end + + context 'when state id is :running' do + subject { described_class.new(:running) } + + it { should be_created } + it { should be_running } + it { should_not be_off } + end + + context 'when state id is :poweroff' do + subject { described_class.new(:poweroff) } + + it { should be_created } + it { should be_off } + it { should_not be_running } + end +end diff --git a/spec/unit_helper.rb b/spec/unit_helper.rb new file mode 100644 index 0000000..f3b8d6c --- /dev/null +++ b/spec/unit_helper.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +RSpec.configure do |config| + config.include RSpec::Fire +end diff --git a/lib/provider b/spike/provider similarity index 100% rename from lib/provider rename to spike/provider diff --git a/spike/spec/spec_helper.rb b/spike/spec/spec_helper.rb new file mode 100644 index 0000000..3380bd3 --- /dev/null +++ b/spike/spec/spec_helper.rb @@ -0,0 +1,59 @@ +require 'rubygems' + +require 'bundler/setup' + +Bundler.require + +require 'yaml' +require 'shellwords' + +`mkdir -p tmp` + +module TestHelpers + def provider_up + `cd tmp && ../lib/provider up -o /vagrant/tmp/logger.log` + end + + def destroy_container! + `cd tmp && ../lib/provider destroy -o /vagrant/tmp/logger.log` + `rm -f tmp/config.yml` + end + + def restore_rinetd_conf! + `sudo cp /vagrant/cache/rinetd.conf /etc/rinetd.conf` + `sudo service rinetd restart` + end + + def configure_box_with(opts) + opts = opts.dup + opts.keys.each do |key| + opts[key.to_s] = opts.delete(key) + end + File.open('./tmp/config.yml', 'w') { |f| f.puts YAML::dump(opts) } + end + + def provider_ssh(options) + options = options.map { |opt, val| "-#{opt} #{Shellwords.escape val}" } + options = options.join(' ') + `cd tmp && ../lib/provider ssh #{options}` + end +end + +RSpec.configure do |config| + config.treat_symbols_as_metadata_keys_with_true_values = true + config.run_all_when_everything_filtered = true + config.filter_run :focus + + config.include TestHelpers + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = 'random' + + config.after :all do + destroy_container! + restore_rinetd_conf! + end +end diff --git a/spec/vagrant_ssh_spec.rb b/spike/vagrant_ssh_spec.rb similarity index 100% rename from spec/vagrant_ssh_spec.rb rename to spike/vagrant_ssh_spec.rb diff --git a/spec/vagrant_up_spec.rb b/spike/vagrant_up_spec.rb similarity index 100% rename from spec/vagrant_up_spec.rb rename to spike/vagrant_up_spec.rb diff --git a/tasks/coverage.rake b/tasks/coverage.rake new file mode 100644 index 0000000..8dc9835 --- /dev/null +++ b/tasks/coverage.rake @@ -0,0 +1,5 @@ +desc 'Run specs with code coverage enabled' +task :coverage do + ENV['COVERAGE'] = 'true' + Rake::Task["spec"].execute +end diff --git a/tasks/package_dummy_box.rake b/tasks/package_dummy_box.rake new file mode 100644 index 0000000..02bcec4 --- /dev/null +++ b/tasks/package_dummy_box.rake @@ -0,0 +1,4 @@ +desc 'Packages a dummy Vagrant box to be used during development' +task :package_dummy_box do + sh 'cd dummy-box-files/ && tar -czf ../dummy-ubuntu-cloudimg.box ./*' +end diff --git a/tasks/spec.rake b/tasks/spec.rake deleted file mode 100644 index b72e1cf..0000000 --- a/tasks/spec.rake +++ /dev/null @@ -1,4 +0,0 @@ -if ENV['USER'] == 'vagrant' - require 'rspec/core/rake_task' - RSpec::Core::RakeTask.new(:spec) -end diff --git a/vagrant b/vagrant new file mode 160000 index 0000000..68aa9c8 --- /dev/null +++ b/vagrant @@ -0,0 +1 @@ +Subproject commit 68aa9c8acf386cd1926dc432a98ddf21ca4ad0e9