From 8b8bfe739baa05f9b1413000adcf812f40020bd8 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 1 Mar 2013 20:45:13 -0300 Subject: [PATCH] lxc-create: check --- lib/vagrant-lxc/actions.rb | 3 +- lib/vagrant-lxc/container.rb | 72 +++++++++++++++++++++++++++++++++++- lib/vagrant-lxc/errors.rb | 9 +++++ locales/en.yml | 5 +++ spec/unit/container_spec.rb | 30 +++++++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 lib/vagrant-lxc/errors.rb create mode 100644 spec/unit/container_spec.rb diff --git a/lib/vagrant-lxc/actions.rb b/lib/vagrant-lxc/actions.rb index 17d1a2f..dc9f6db 100644 --- a/lib/vagrant-lxc/actions.rb +++ b/lib/vagrant-lxc/actions.rb @@ -166,8 +166,7 @@ module Vagrant 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 + env[:machine].id = env[:machine].provider.container.create @app.call env end end diff --git a/lib/vagrant-lxc/container.rb b/lib/vagrant-lxc/container.rb index 3c12316..71a8190 100644 --- a/lib/vagrant-lxc/container.rb +++ b/lib/vagrant-lxc/container.rb @@ -1,14 +1,29 @@ +# FIXME: Ruby 1.8 users dont have SecureRandom +require 'securerandom' + +require 'vagrant/util/retryable' +require 'vagrant/util/subprocess' + +require "vagrant-lxc/errors" + module Vagrant module LXC class Container + # Include this so we can use `Subprocess` more easily. + include Vagrant::Util::Retryable + CONTAINER_STATE_FILE_PATH = '/tmp/vagrant-lxc-container-state-%s' def initialize(machine) @machine = machine + @logger = Log4r::Logger.new("vagrant::provider::lxc::container") end def create - puts 'TODO: Create container' + # FIXME: Ruby 1.8 users dont have SecureRandom + machine_id = SecureRandom.hex(6) + log, status = lxc(:create, {'--template' => 'ubuntu-cloud', '--name' => machine_id}, {'-S' => '/home/vagrant/.ssh/id_rsa.pub'}) + machine_id end def start @@ -32,6 +47,14 @@ module Vagrant private + def lxc(command, params, extra = {}) + params = params.map { |opt, val| "#{opt}='#{val}'" } + params << '--' if extra.any? + # Handles extra options passed to templates when using lxc-create + params << extra.map { |opt, val| "#{opt} #{val}" } + execute('sudo', "lxc-#{command}", *params.flatten) + end + def update!(state) File.open(state_file_path, 'w') { |f| f.print state } end @@ -47,6 +70,53 @@ module Vagrant def state_file_path CONTAINER_STATE_FILE_PATH % {id: @machine.id} end + + # TODO: Review code below this line, it was pretty much a copy and paste from VirtualBox base driver + def execute(*command, &block) + # Get the options hash if it exists + opts = {} + opts = command.pop if command.last.is_a?(Hash) + + tries = 0 + tries = 3 if opts[:retryable] + + # Variable to store our execution result + r = nil + + retryable(:on => LXC::Errors::ExecuteError, :tries => tries, :sleep => 1) do + # Execute the command + r = raw(*command, &block) + + # If the command was a failure, then raise an exception that is + # nicely handled by Vagrant. + if r.exit_code != 0 + if @interrupted + @logger.info("Exit code != 0, but interrupted. Ignoring.") + else + raise LXC::Errors::ExecuteError, :command => command.inspect + end + end + end + + # Return the output, making sure to replace any Windows-style + # newlines with Unix-style. + r.stdout.gsub("\r\n", "\n") + end + + # Executes a command and returns the raw result object. + def raw(*command, &block) + int_callback = lambda do + @interrupted = true + @logger.info("Interrupted.") + end + + # Append in the options for subprocess + command << { :notify => [:stdout, :stderr] } + + Vagrant::Util::Busy.busy(int_callback) do + Vagrant::Util::Subprocess.execute(*command, &block) + end + end end end end diff --git a/lib/vagrant-lxc/errors.rb b/lib/vagrant-lxc/errors.rb new file mode 100644 index 0000000..8d0057b --- /dev/null +++ b/lib/vagrant-lxc/errors.rb @@ -0,0 +1,9 @@ +module Vagrant + module LXC + module Errors + class ExecuteError < Vagrant::Errors::VagrantError + error_key(:lxc_execute_error) + end + end + end +end diff --git a/locales/en.yml b/locales/en.yml index 1495d7f..5b9b88e 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -1,3 +1,8 @@ en: vagrant: errors: + lxc_execute_error: |- + There was an error executing %{command} + + For more information on the failure, enable detailed logging by setting + the environment variable VAGRANT_LOG to DEBUG. diff --git a/spec/unit/container_spec.rb b/spec/unit/container_spec.rb new file mode 100644 index 0000000..63fafed --- /dev/null +++ b/spec/unit/container_spec.rb @@ -0,0 +1,30 @@ +require 'unit_helper' + +require 'vagrant-lxc/container' + +describe Vagrant::LXC::Container do + let(:machine) { fire_double('Vagrant::Machine') } + + subject { described_class.new(machine) } + + describe 'create' do + let(:last_command) { @last_command } + let(:new_machine_id) { 'random-machine-id' } + + before do + Vagrant::Util::Subprocess.stub(:execute) do |*cmds| + cmds.pop if cmds.last.is_a?(Hash) + @last_command = cmds.join(' ') + mock(exit_code: 0, stdout: '') + end + SecureRandom.stub(hex: new_machine_id) + subject.create + end + + it 'runs lxc-create with the right arguments' do + last_command.should include "--name='#{new_machine_id}'" + last_command.should include "--template='ubuntu-cloud'" + last_command.should =~ /\-\- \-S (\w|\/|\.)+\/id_rsa\.pub/ + end + end +end