From 04cdd1f3dbbb096cce89ac4234b4a07501e13afe Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 5 Apr 2013 03:10:38 -0300 Subject: [PATCH] Improved box metadata handling and container creation --- lib/vagrant-lxc/action/create.rb | 16 ++++-- lib/vagrant-lxc/action/handle_box_metadata.rb | 30 +++++------ lib/vagrant-lxc/driver.rb | 51 ++++++++++++------- spec/unit/action/handle_box_metadata_spec.rb | 33 +++++++----- spec/unit/driver_spec.rb | 30 +++++------ 5 files changed, 91 insertions(+), 69 deletions(-) diff --git a/lib/vagrant-lxc/action/create.rb b/lib/vagrant-lxc/action/create.rb index 0a0ec8d..0bce830 100644 --- a/lib/vagrant-lxc/action/create.rb +++ b/lib/vagrant-lxc/action/create.rb @@ -7,12 +7,18 @@ module Vagrant end def call(env) - base_name = env[:root_path].basename.to_s - base_name.gsub!(/[^-a-z0-9_]/i, "") + container_name = env[:root_path].basename.to_s + container_name.gsub!(/[^-a-z0-9_]/i, "") + container_name << "-#{Time.now.to_i}" + + env[:machine].provider.driver.create( + container_name, + env[:lxc_template_src], + env[:lxc_template_opts] + ) + + env[:machine].id = container_name - machine_id = env[:machine].provider.driver.create(base_name, env[:machine].box.metadata) - env[:machine].id = machine_id - env[:just_created] = true @app.call env end end diff --git a/lib/vagrant-lxc/action/handle_box_metadata.rb b/lib/vagrant-lxc/action/handle_box_metadata.rb index 9047a35..fb9f9dd 100644 --- a/lib/vagrant-lxc/action/handle_box_metadata.rb +++ b/lib/vagrant-lxc/action/handle_box_metadata.rb @@ -3,9 +3,6 @@ module Vagrant module Action # Prepare arguments to be used for lxc-create class HandleBoxMetadata - LXC_TEMPLATES_PATH = Pathname.new("/usr/share/lxc/templates") - TEMP_PREFIX = "vagrant-lxc-rootfs-temp-" - def initialize(app, env) @app = app @logger = Log4r::Logger.new("vagrant::lxc::action::handle_box_metadata") @@ -15,26 +12,27 @@ module Vagrant env[:ui].info I18n.t("vagrant.actions.vm.import.importing", :name => env[:machine].box.name) - rootfs_cache = Dir.mktmpdir(TEMP_PREFIX) - box = env[:machine].box - template_name = "vagrant-#{box.name}" + box = env[:machine].box - # Prepends "lxc-" to the template file so that `lxc-create` is able to find it - lxc_template_src = box.directory.join('lxc-template').to_s - unless File.exists?(lxc_template_src) + template_src = box.directory.join('lxc-template').to_s + unless File.exists?(template_src) raise Errors::TemplateFileMissing.new name: box.name end - dest = LXC_TEMPLATES_PATH.join("lxc-#{template_name}").to_s - @logger.debug('Copying LXC template into place') - system(%Q[sudo su root -c "cp #{lxc_template_src} #{dest}"]) + + # TODO: Validate box version @logger.debug('Merging metadata with template name and rootfs tarball') - box.metadata.merge!( - 'template-name' => template_name, - 'rootfs-tarball' => box.directory.join('rootfs.tar.gz') + + template_opts = box.metadata.fetch('template-opts', {}).dup + template_opts.merge!( + '--tarball' => box.directory.join('rootfs.tar.gz').to_s, + '--auth-key' => Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s ) - @app.call(env) + env[:lxc_template_opts] = template_opts + env[:lxc_template_src] = template_src + + @app.call env end end end diff --git a/lib/vagrant-lxc/driver.rb b/lib/vagrant-lxc/driver.rb index 1087185..bccb09e 100644 --- a/lib/vagrant-lxc/driver.rb +++ b/lib/vagrant-lxc/driver.rb @@ -1,5 +1,3 @@ -require 'securerandom' - require "vagrant/util/retryable" require "vagrant/util/subprocess" @@ -9,9 +7,6 @@ require "vagrant-lxc/driver/cli" module Vagrant module LXC class Driver - # Root folder where containers are stored - CONTAINERS_PATH = '/var/lib/lxc' - # Include this so we can use `Subprocess` more easily. include Vagrant::Util::Retryable @@ -39,20 +34,13 @@ module Vagrant Pathname.new(base_path.join('config').read.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1]) end - def create(base_name, metadata = {}) - @logger.debug('Creating container using lxc-create...') + def create(name, template_path, template_options = {}) + @cli.name = @name = name - @name = "#{base_name}-#{SecureRandom.hex(6)}" - public_key = Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s - meta_opts = metadata.fetch('template-opts', {}).merge( - '--auth-key' => public_key, - '--tarball' => metadata.fetch('rootfs-tarball').to_s - ) - - @cli.name = @name - @cli.create(metadata.fetch('template-name'), meta_opts) - - @name + import_template(template_path) do |template_name| + @logger.debug "Creating container..." + @cli.create template_name, template_options + end end def share_folders(folders, config) @@ -136,6 +124,33 @@ module Vagrant return $1.to_s end end + + protected + + LXC_TEMPLATES_PATH = Pathname.new("/usr/share/lxc/templates") + + # Root folder where container configs are stored + CONTAINERS_PATH = '/var/lib/lxc' + + def base_path + Pathname.new("#{CONTAINERS_PATH}/#{@name}") + end + + def rootfs_path + Pathname.new(base_path.join('config').read.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1]) + end + + def import_template(path) + template_name = "vagrant-tmp-#{@name}" + tmp_template_path = LXC_TEMPLATES_PATH.join("lxc-#{template_name}").to_s + + @logger.debug 'Copying LXC template into place' + system(%Q[sudo su root -c "cp #{path} #{tmp_template_path}"]) + + yield template_name + ensure + system(%Q[sudo su root -c "rm #{tmp_template_path}"]) + end end end end diff --git a/spec/unit/action/handle_box_metadata_spec.rb b/spec/unit/action/handle_box_metadata_spec.rb index 4721e7f..a656d5b 100644 --- a/spec/unit/action/handle_box_metadata_spec.rb +++ b/spec/unit/action/handle_box_metadata_spec.rb @@ -1,36 +1,41 @@ require 'unit_helper' +require 'vagrant' require 'vagrant-lxc/action/handle_box_metadata' describe Vagrant::LXC::Action::HandleBoxMetadata do - let(:metadata) { {'template-opts' => {'--foo' => 'bar'}} } - let(:box) { mock(:box, name: 'box-name', metadata: metadata, directory: box_directory) } - let(:box_directory) { Pathname.new('/path/to/box') } - let(:machine) { mock(:machine, box: box) } let(:app) { mock(:app, call: true) } let(:env) { {machine: machine, ui: stub(info: true)} } + let(:machine) { mock(:machine, box: box) } + let(:box) { mock(:box, name: 'box-name', metadata: metadata, directory: box_directory) } + let(:box_directory) { Pathname.new('/path/to/box') } + let(:metadata) { {'template-opts' => {'--foo' => 'bar'}} } + let(:vagrant_key) { Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s } subject { described_class.new(app, env) } before do File.stub(exists?: true) - subject.stub(:system) subject.call(env) end - it 'sets the rootfs-tarball path on metadata hash' do - metadata['rootfs-tarball'].should == box_directory.join('rootfs.tar.gz') + it 'sets the tarball argument for the template' do + env[:lxc_template_opts].should include( + '--tarball' => box_directory.join('rootfs.tar.gz').to_s + ) end - it 'prepends vagrant and box name to template-name' do - metadata['template-name'].should == "vagrant-#{box.name}" + it 'sets the auth key argument for the template' do + env[:lxc_template_opts].should include( + '--auth-key' => vagrant_key + ) end - it 'copies box template file to the right folder' do - src = box_directory.join('lxc-template').to_s - dest = "/usr/share/lxc/templates/lxc-#{metadata['template-name']}" + it 'sets the template options from metadata on env hash' do + env[:lxc_template_opts].should include(metadata['template-opts']) + end - subject.should have_received(:system). - with("sudo su root -c \"cp #{src} #{dest}\"") + it 'sets the template source path on env hash' do + env[:lxc_template_src].should == box_directory.join('lxc-template').to_s end end diff --git a/spec/unit/driver_spec.rb b/spec/unit/driver_spec.rb index 30d6495..9eb5e6d 100644 --- a/spec/unit/driver_spec.rb +++ b/spec/unit/driver_spec.rb @@ -4,9 +4,6 @@ require 'vagrant' require 'vagrant-lxc/driver' describe Vagrant::LXC::Driver do - let(:name) { nil } - subject { described_class.new(name) } - describe 'container name validation' do let(:unknown_container) { described_class.new('unknown', cli) } let(:valid_container) { described_class.new('valid', cli) } @@ -33,27 +30,28 @@ describe Vagrant::LXC::Driver do end describe 'creation' do - let(:base_name) { 'container-name' } - let(:suffix) { 'random-suffix' } - let(:template_name) { 'template-name' } - let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' } - let(:public_key_path) { Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s } - let(:cli) { fire_double('Vagrant::LXC::Driver::CLI', :create => true, :name= => true) } + let(:name) { 'container-name' } + let(:template_name) { 'auto-assigned-template-id' } + let(:template_path) { '/path/to/lxc-template-from-box' } + let(:template_opts) { {'--some' => 'random-option'} } + let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' } + let(:cli) { fire_double('Vagrant::LXC::Driver::CLI', :create => true, :name= => true) } - subject { described_class.new(name, cli) } + subject { described_class.new(nil, cli) } before do - SecureRandom.stub(hex: suffix) - subject.create base_name, 'template-name' => template_name, 'rootfs-tarball' => rootfs_tarball, 'template-opts' => { '--foo' => 'bar'} + subject.stub(:import_template).and_yield(template_name) + subject.create name, template_path, template_opts + end + + it 'sets the cli object container name' do + cli.should have_received(:name=).with(name) end it 'creates container with the right arguments' do - cli.should have_received(:name=).with("#{base_name}-#{suffix}") cli.should have_received(:create).with( template_name, - '--auth-key' => public_key_path, - '--tarball' => rootfs_tarball, - '--foo' => 'bar' + template_opts ) end end