Merge pull request #4 from fgrehm/box-packaging

Box packaging
This commit is contained in:
Fabio Rehm 2013-03-30 15:29:58 -07:00
commit aa69226e44
11 changed files with 202 additions and 6 deletions

View file

@ -78,8 +78,10 @@ EOF
rm -f $rootfs/etc/init/tty{5,6}.conf
fi
chroot $rootfs useradd --create-home -s /bin/bash vagrant
echo "vagrant:vagrant" | chroot $rootfs chpasswd
if ! (grep -q vagrant $rootfs/etc/passwd); then
chroot $rootfs useradd --create-home -s /bin/bash vagrant
echo "vagrant:vagrant" | chroot $rootfs chpasswd
fi
return 0
}

View file

@ -1,6 +1,6 @@
{
"provider": "lxc",
"vagrant-lxc-version": "0.0.1",
"provider": "lxc",
"version": "1",
"template-opts": {
"--arch": "amd64",

View file

@ -10,11 +10,13 @@ require 'vagrant-lxc/action/create'
require 'vagrant-lxc/action/created'
require 'vagrant-lxc/action/destroy'
require 'vagrant-lxc/action/disconnect'
require 'vagrant-lxc/action/compress_rootfs'
require 'vagrant-lxc/action/forced_halt'
require 'vagrant-lxc/action/forward_ports'
require 'vagrant-lxc/action/handle_box_metadata'
require 'vagrant-lxc/action/is_running'
require 'vagrant-lxc/action/network'
require 'vagrant-lxc/action/setup_package_files'
require 'vagrant-lxc/action/share_folders'
module Vagrant
@ -173,6 +175,25 @@ module Vagrant
end
end
# This action packages the virtual machine into a single box file.
def self.action_package
Vagrant::Action::Builder.new.tap do |b|
# b.use CheckDependencies
b.use Vagrant::Action::Builtin::Call, Created do |env1, b2|
if !env1[:result]
# TODO: Implement our own MessageNotCreated
b2.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotCreated
next
end
b2.use action_halt
b2.use CompressRootFS
b2.use SetupPackageFiles
b2.use Vagrant::Action::General::Package
end
end
end
# This is the action that will exec into an SSH shell.
def self.action_ssh
Vagrant::Action::Builder.new.tap do |b|

View file

@ -0,0 +1,30 @@
require "fileutils"
module Vagrant
module LXC
module Action
class CompressRootFS
def initialize(app, env)
@app = app
end
def call(env)
raise Vagrant::Errors::VMPowerOffToPackage if env[:machine].provider.state.id != :stopped
env[:ui].info I18n.t("vagrant.actions.lxc.compressing_rootfs")
@rootfs = env['package.rootfs'] = env[:machine].provider.container.compress_rootfs
@app.call env
recover # called to remove the rootfs tarball
end
def recover(*)
if @rootfs && File.exist?(@rootfs)
FileUtils.rm_rf(File.dirname @rootfs)
end
end
end
end
end
end

View file

@ -29,7 +29,8 @@ module Vagrant
system(%Q[sudo su root -c "cp #{lxc_template_src} #{dest}"])
@logger.debug('Extracting rootfs')
system(%Q[sudo su root -c "cd #{box.directory} && tar xfz rootfs.tar.gz -C #{rootfs_cache}"])
# TODO: Ideally the compressed rootfs should not output errors...
system(%Q[sudo su root -c "cd #{box.directory} && tar xfz rootfs.tar.gz -C #{rootfs_cache} 2>/dev/null"])
box.metadata.merge!(
'template-name' => template_name,

View file

@ -0,0 +1,52 @@
require 'fileutils'
module Vagrant
module LXC
module Action
class SetupPackageFiles
def initialize(app, env)
@app = app
env["package.include"] ||= []
env["package.vagrantfile"] ||= nil
end
def call(env)
@env = env
create_package_temp_dir
move_rootfs_to_pkg_dir
copy_box_files_to_pkg_dir
@app.call env
recover # called to cleanup temp directory
end
def recover(*)
if @temp_dir && File.exist?(@temp_dir)
FileUtils.rm_rf(@temp_dir)
end
end
private
def create_package_temp_dir
@env[:ui].info I18n.t("vagrant.actions.vm.export.create_dir")
@temp_dir = @env["package.directory"] = @env[:tmp_path].join("container-export-#{Time.now.to_i.to_s}")
FileUtils.mkpath(@temp_dir)
end
def move_rootfs_to_pkg_dir
FileUtils.mv @env['package.rootfs'].to_s, @env['package.directory'].to_s
end
def copy_box_files_to_pkg_dir
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('metadata.json').to_s, @env['package.directory'].to_s
end
end
end
end
end

View file

@ -93,6 +93,26 @@ module Vagrant
@cli.destroy
end
# TODO: This needs to be reviewed and specs needs to be written
def compress_rootfs
# TODO: Our template should not depend on container's arch
arch = base_path.join('config').read.match(/^lxc\.arch\s+=\s+(.+)$/)[1]
rootfs_dirname = File.dirname rootfs_path
basename = rootfs_path.to_s.gsub(/^#{Regexp.escape rootfs_dirname}\//, '')
# TODO: Pass in tmpdir so we can clean up from outside
target_path = "#{Dir.mktmpdir}/rootfs.tar.gz"
Dir.chdir base_path do
@logger.info "Compressing '#{rootfs_path}' rootfs to #{target_path}"
system "sudo rm -f rootfs.tar.gz && sudo bsdtar -s /#{basename}/rootfs-#{arch}/ --numeric-owner -czf #{target_path} #{basename}/* 2>/dev/null"
@logger.info "Changing rootfs tarbal owner"
system "sudo chown #{ENV['USER']}:#{ENV['USER']} #{target_path}"
end
target_path
end
def state
if @name
@cli.state

View file

@ -2,6 +2,8 @@ en:
vagrant:
actions:
lxc:
compressing_rootfs: Compressing container's rootfs...
share_folders:
preparing: Setting up mount entries for shared folders...

View file

@ -0,0 +1,27 @@
require 'unit_helper'
require 'vagrant-lxc/action/compress_rootfs'
describe Vagrant::LXC::Action::CompressRootFS do
let(:app) { mock(:app, call: true) }
let(:env) { {machine: machine, ui: stub(info: true)} }
let(:machine) { fire_double('Vagrant::Machine', provider: provider) }
let(:provider) { fire_double('Vagrant::LXC::Provider', container: container) }
let(:container) { fire_double('Vagrant::LXC::Container', compress_rootfs: compressed_rootfs_path) }
let(:compressed_rootfs_path) { '/path/to/rootfs.tar.gz' }
subject { described_class.new(app, env) }
before do
provider.stub_chain(:state, :id).and_return(:stopped)
subject.call(env)
end
it 'asks the container to compress its rootfs' do
container.should have_received(:compress_rootfs)
end
it 'sets export.temp_dir on action env' do
env['package.rootfs'].should == compressed_rootfs_path
end
end

View file

@ -39,6 +39,6 @@ describe Vagrant::LXC::Action::HandleBoxMetadata do
it 'extracts rootfs into a tmp folder' do
subject.should have_received(:system).
with(%Q[sudo su root -c "cd #{box_directory} && tar xfz rootfs.tar.gz -C #{tmpdir}"])
with(%Q[sudo su root -c "cd #{box_directory} && tar xfz rootfs.tar.gz -C #{tmpdir} 2>/dev/null"])
end
end

View file

@ -0,0 +1,41 @@
require 'unit_helper'
require 'vagrant-lxc/action/setup_package_files'
describe Vagrant::LXC::Action::SetupPackageFiles do
let(:app) { mock(:app, call: true) }
let(:env) { {machine: machine, tmp_path: tmp_path, ui: stub(info: true), 'package.rootfs' => rootfs_path} }
let(:machine) { fire_double('Vagrant::Machine', box: box) }
let!(:tmp_path) { Pathname.new(Dir.mktmpdir) }
let(:box) { fire_double('Vagrant::Box', directory: tmp_path.join('box')) }
let(:rootfs_path) { tmp_path.join('rootfs-amd64.tar.gz') }
subject { described_class.new(app, env) }
before do
box.directory.mkdir
[box.directory.join('lxc-template'), box.directory.join('metadata.json'), rootfs_path].each do |file|
file.open('w') { |f| f.puts file.to_s }
end
subject.stub(recover: true) # Prevents files from being removed on specs
subject.call(env)
end
after do
FileUtils.rm_rf(tmp_path.to_s)
end
it 'copies box lxc-template to package directory' do
env['package.directory'].join('lxc-template').should be_file
end
it 'copies metadata.json to package directory' do
env['package.directory'].join('metadata.json').should be_file
end
it 'moves the compressed rootfs to package directory' do
env['package.directory'].join(rootfs_path.basename).should be_file
env['package.rootfs'].should_not be_file
end
end