boxes 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +51 -0
- data/Rakefile +34 -0
- data/bin/boxes +6 -0
- data/boxes.gemspec +39 -0
- data/features/boxes.feature +8 -0
- data/features/build.feature +16 -0
- data/features/env.feature +18 -0
- data/features/support/env.rb +1 -0
- data/lib/boxes.rb +28 -0
- data/lib/boxes/builder.rb +77 -0
- data/lib/boxes/command.rb +12 -0
- data/lib/boxes/command/build.rb +45 -0
- data/lib/boxes/command/env.rb +50 -0
- data/lib/boxes/config.rb +73 -0
- data/lib/boxes/environment.rb +74 -0
- data/lib/boxes/errors.rb +19 -0
- data/lib/boxes/subprocess.rb +39 -0
- data/lib/boxes/template.rb +50 -0
- data/lib/boxes/version.rb +4 -0
- data/scripts/ansible.sh +13 -0
- data/scripts/chef.sh +28 -0
- data/scripts/postinstall.sh +42 -0
- data/scripts/puppet.sh +14 -0
- data/scripts/purge.sh +60 -0
- data/scripts/ruby.sh +41 -0
- data/scripts/vmtools.sh +32 -0
- data/spec/boxes/builder_spec.rb +52 -0
- data/spec/boxes/config_spec.rb +142 -0
- data/spec/boxes/environment_spec.rb +73 -0
- data/spec/boxes/subprocess_spec.rb +35 -0
- data/spec/boxes/template_spec.rb +53 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/subprocess_command.rb +7 -0
- data/templates/debian/preseed.cfg +69 -0
- data/templates/debian/wheezy64.erb +59 -0
- data/templates/ubuntu/precise64.erb +59 -0
- data/templates/ubuntu/preseed.cfg +61 -0
- data/templates/ubuntu/trusty64.erb +59 -0
- metadata +230 -0
data/lib/boxes/config.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module Boxes
|
2
|
+
# Stores the configuration for Boxes.
|
3
|
+
class Config
|
4
|
+
# The default settings for the configuration.
|
5
|
+
DEFAULTS = {
|
6
|
+
environment_vars: [
|
7
|
+
{ 'PACKER_CACHE_DIR' => (
|
8
|
+
Pathname.new(ENV['BOXES_HOME_DIR'] || '~/.boxes'
|
9
|
+
).expand_path + 'packer_cache') }
|
10
|
+
],
|
11
|
+
template_paths: [
|
12
|
+
# the gem install directory
|
13
|
+
File.expand_path('../../../templates', __FILE__)
|
14
|
+
],
|
15
|
+
script_paths: [
|
16
|
+
# the gem install directory
|
17
|
+
File.expand_path('../../../scripts', __FILE__)
|
18
|
+
]
|
19
|
+
}
|
20
|
+
|
21
|
+
# The directory which boxes works out of.
|
22
|
+
def home_dir
|
23
|
+
@home_dir ||= Pathname.new(
|
24
|
+
ENV['BOXES_HOME_DIR'] || '~/.boxes').expand_path
|
25
|
+
end
|
26
|
+
|
27
|
+
# The directory inside the `home_dir` which boxes runs builds inside of.
|
28
|
+
def working_dir
|
29
|
+
@working_dir ||= Pathname.new(
|
30
|
+
ENV['BOXES_WORKING_DIR'] || home_dir + 'tmp').expand_path
|
31
|
+
end
|
32
|
+
|
33
|
+
# Paths known to boxes for discovering templates.
|
34
|
+
attr_accessor :template_paths
|
35
|
+
|
36
|
+
# Paths known to boxes for discovering scripts.
|
37
|
+
attr_accessor :script_paths
|
38
|
+
|
39
|
+
# A Hash of environment variables Boxes sets in the run environment.
|
40
|
+
attr_accessor :environment_vars
|
41
|
+
|
42
|
+
def initialize
|
43
|
+
configure_with(DEFAULTS)
|
44
|
+
|
45
|
+
return unless user_settings_file.exist?
|
46
|
+
|
47
|
+
user_settings = YAML.load_file(user_settings_file)
|
48
|
+
configure_with(user_settings)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def user_settings_file
|
54
|
+
home_dir + 'config.yml'
|
55
|
+
end
|
56
|
+
|
57
|
+
def configure_with(opts = {}) # rubocop:disable Metrics/MethodLength
|
58
|
+
opts.each do |k, v|
|
59
|
+
next unless respond_to?("#{k}=")
|
60
|
+
|
61
|
+
if v.class == Array
|
62
|
+
v.each do |e|
|
63
|
+
set = Set.new(send("#{k}".to_sym))
|
64
|
+
set << e
|
65
|
+
send("#{k}=".to_sym, set.to_a)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
send("#{k}=".to_sym, v)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Boxes
|
2
|
+
# For creating and managing the environment which boxes uses.
|
3
|
+
class Environment
|
4
|
+
def initialize
|
5
|
+
FileUtils.mkdir_p(Boxes.config.working_dir)
|
6
|
+
|
7
|
+
copy_templates
|
8
|
+
copy_scripts
|
9
|
+
end
|
10
|
+
|
11
|
+
def available_templates
|
12
|
+
t = Dir.glob("#{Boxes.config.working_dir}/templates/*/**")
|
13
|
+
a = t.collect { |c| c.include?('preseed.cfg') ? next : c }.compact
|
14
|
+
|
15
|
+
a.collect do |c|
|
16
|
+
c = c.gsub(Boxes.config.working_dir.to_s + '/templates/', '')
|
17
|
+
c.gsub('.erb', '')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def hidden_templates
|
22
|
+
t = Dir.glob("#{Boxes.config.working_dir}/templates/*/**")
|
23
|
+
a = t.collect { |c| c.include?('preseed.cfg') ? c : next }.compact
|
24
|
+
|
25
|
+
a.collect do |c|
|
26
|
+
c.gsub(Boxes.config.working_dir.to_s + '/templates/', '')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def available_scripts
|
31
|
+
t = Dir.glob("#{Boxes.config.working_dir}/scripts/*")
|
32
|
+
a = t.collect { |c| c.include?('purge.sh') ? next : c }.compact
|
33
|
+
|
34
|
+
a.collect do |c|
|
35
|
+
c.gsub(Boxes.config.working_dir.to_s + '/scripts/', '')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def hidden_scripts
|
40
|
+
t = Dir.glob("#{Boxes.config.working_dir}/scripts/*")
|
41
|
+
a = t.collect { |c| c.include?('purge.sh') ? c : next }.compact
|
42
|
+
|
43
|
+
a.collect do |c|
|
44
|
+
c.gsub(Boxes.config.working_dir.to_s + '/scripts/', '')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def copy_templates
|
51
|
+
templates_dir = Boxes.config.working_dir + 'templates'
|
52
|
+
|
53
|
+
FileUtils.mkdir_p(templates_dir)
|
54
|
+
|
55
|
+
Boxes.config.template_paths.each do |template_path|
|
56
|
+
Dir.glob("#{template_path}/*").each do |src_template|
|
57
|
+
FileUtils.cp_r(src_template, templates_dir)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def copy_scripts
|
63
|
+
scripts_dir = Boxes.config.working_dir + 'scripts'
|
64
|
+
|
65
|
+
FileUtils.mkdir_p(Boxes.config.working_dir + 'scripts')
|
66
|
+
|
67
|
+
Boxes.config.script_paths.each do |script_path|
|
68
|
+
Dir.glob("#{script_path}/*").each do |src_script|
|
69
|
+
FileUtils.cp_r(src_script, scripts_dir)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/boxes/errors.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Boxes
|
2
|
+
# A collection of errors which can be raised by boxes.
|
3
|
+
module Errors
|
4
|
+
# Base error class for all other errors.
|
5
|
+
class BoxesError < StandardError; end
|
6
|
+
|
7
|
+
# Raised when a template is missing.
|
8
|
+
class TemplateNotFoundError < BoxesError; end
|
9
|
+
|
10
|
+
# Raised when a script is missing.
|
11
|
+
class ScriptNotFoundError < BoxesError; end
|
12
|
+
|
13
|
+
# Raised when an expected argument is missing.
|
14
|
+
class MissingArgumentError < BoxesError; end
|
15
|
+
|
16
|
+
# Raised when a build fails.
|
17
|
+
class BuildRunError < BoxesError; end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Boxes
|
2
|
+
# Standardise handling the stdout and stderr from Open3.
|
3
|
+
#
|
4
|
+
# @example Print the values returned to stdout and stderr
|
5
|
+
# Boxes::Utils::Subprocess.run 'ls' do |stdout, stderr, thread|
|
6
|
+
# puts stdout unless stdout == nil
|
7
|
+
# puts stderr unless stderr == nil
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
class Subprocess
|
11
|
+
# Create a new subprocess with a command, with a block for the response.
|
12
|
+
#
|
13
|
+
# @param cmd [String] the command to run
|
14
|
+
# @yield [stdout, stderr, thread] Gives the stdout, stderr and process
|
15
|
+
# thread to the block.
|
16
|
+
def self.run(command) # rubocop:disable Metrics/MethodLength
|
17
|
+
# see: http://stackoverflow.com/a/1162850/83386
|
18
|
+
Open3.popen3(command) do |_stdin, stdout, stderr, thread|
|
19
|
+
# read each stream from a new thread
|
20
|
+
{ out: stdout, err: stderr }.each do |key, stream|
|
21
|
+
Thread.new do
|
22
|
+
stream.each_line do |line|
|
23
|
+
# yield the block depending on the stream
|
24
|
+
if key == :out
|
25
|
+
yield line, nil, thread if block_given?
|
26
|
+
else
|
27
|
+
yield nil, line, thread if block_given?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
thread.join # don't exit until the external process is done
|
34
|
+
|
35
|
+
thread.value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Boxes
|
2
|
+
# Representations of Packer templates.
|
3
|
+
class Template
|
4
|
+
include Boxes::Errors
|
5
|
+
|
6
|
+
attr_reader :name, :template
|
7
|
+
|
8
|
+
# Load a template with a given name.
|
9
|
+
#
|
10
|
+
# @param env [Boxes::Environment] the environment to source templates.
|
11
|
+
# @param name [String] the name of the template.
|
12
|
+
#
|
13
|
+
# @return [Boxes::Template] a template instance.
|
14
|
+
def initialize(env, name)
|
15
|
+
fail(TemplateNotFoundError) unless env.available_templates.include?(name)
|
16
|
+
|
17
|
+
@name = name
|
18
|
+
@template = ''
|
19
|
+
File.open(Boxes.config.working_dir + "templates/#{name}.erb") do |f|
|
20
|
+
@template << f.read
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Render the template.
|
25
|
+
#
|
26
|
+
# @param args [Hash] the values to set.
|
27
|
+
#
|
28
|
+
# @return [String] the rendered template.
|
29
|
+
def render(args)
|
30
|
+
ERB.new(template, nil, '-').result(ERBContext.new(args).get_binding)
|
31
|
+
end
|
32
|
+
|
33
|
+
# A context to render inside, to avoid polluting other classes.
|
34
|
+
class ERBContext
|
35
|
+
# Create a new context with a given hash of values.
|
36
|
+
#
|
37
|
+
# @params args [Hash] the values to substitute.
|
38
|
+
def initialize(args = {})
|
39
|
+
args.each_pair do |k, v|
|
40
|
+
instance_variable_set('@' + k.to_s, v)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# The binding which is passed to ERB.
|
45
|
+
def get_binding # rubocop:disable Style/AccessorMethodName
|
46
|
+
binding
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/scripts/ansible.sh
ADDED
data/scripts/chef.sh
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Get the Chef package version through their metadata service.
|
4
|
+
platform=$(lsb_release -si | tr '[:upper:]' '[:lower:]')
|
5
|
+
release=$(lsb_release -sr)
|
6
|
+
version_url="https://www.opscode.com/chef/metadata?v=&prerelease=false&nightlies=false&p=$platform&pv=$release&m=x86_64"
|
7
|
+
current_version=$(curl -s "$version_url")
|
8
|
+
|
9
|
+
version_url=$(echo "$current_version" | awk '/url/{print $2}')
|
10
|
+
version_sha=$(echo "$current_version" | awk '/sha256/{print $2}')
|
11
|
+
|
12
|
+
# fetch chef
|
13
|
+
curl $version_url -o chef.deb
|
14
|
+
|
15
|
+
# check the file
|
16
|
+
echo "$version_sha chef.deb" > '/tmp/chef-checksum'
|
17
|
+
shasum -a 256 -c '/tmp/chef-checksum'
|
18
|
+
if [ $? -ne 0 ]; then
|
19
|
+
echo "Downloaded Chef package failed to checksum."
|
20
|
+
exit 1
|
21
|
+
fi
|
22
|
+
|
23
|
+
# install
|
24
|
+
dpkg -i chef.deb
|
25
|
+
|
26
|
+
# cleanup
|
27
|
+
rm chef.deb
|
28
|
+
rm /tmp/chef-checksum
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# postinstall.sh based upon Mitchell's old basebox example
|
2
|
+
|
3
|
+
# mark the build time
|
4
|
+
date > /etc/vagrant_box_build_time
|
5
|
+
|
6
|
+
# update the apt cache and packages
|
7
|
+
case $(lsb_release -cs) in
|
8
|
+
'precise')
|
9
|
+
apt-get clean
|
10
|
+
rm -rf /var/lib/apt/lists/*
|
11
|
+
apt-get clean
|
12
|
+
;;
|
13
|
+
*)
|
14
|
+
;;
|
15
|
+
esac
|
16
|
+
|
17
|
+
apt-get -qy update
|
18
|
+
apt-get -qy upgrade
|
19
|
+
|
20
|
+
# install some oft used packages
|
21
|
+
apt-get -qy install linux-headers-$(uname -r) build-essential
|
22
|
+
apt-get -qy install zlib1g-dev libssl-dev
|
23
|
+
apt-get -qy install python-software-properties python-setuptools python-dev
|
24
|
+
apt-get -qy install ruby1.9.3
|
25
|
+
|
26
|
+
# configure password-less sudo
|
27
|
+
usermod -a -G sudo vagrant
|
28
|
+
echo "%vagrant ALL=NOPASSWD:ALL" > /tmp/vagrant
|
29
|
+
mv /tmp/vagrant /etc/sudoers.d/vagrant
|
30
|
+
chmod 0440 /etc/sudoers.d/vagrant
|
31
|
+
|
32
|
+
# install the vagrant-provided ssh keys
|
33
|
+
mkdir -pm 700 /home/vagrant/.ssh
|
34
|
+
curl -Lo /home/vagrant/.ssh/authorized_keys \
|
35
|
+
'https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub'
|
36
|
+
chmod 0600 /home/vagrant/.ssh/authorized_keys
|
37
|
+
chown -R vagrant:vagrant /home/vagrant/.ssh
|
38
|
+
|
39
|
+
# clean up any artifacts
|
40
|
+
rm -f /home/vagrant/shutdown.sh
|
41
|
+
|
42
|
+
exit
|
data/scripts/puppet.sh
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# see: http://docs.puppetlabs.com/guides/puppetlabs_package_repositories.html
|
4
|
+
|
5
|
+
# determine the os release
|
6
|
+
os_release=$(lsb_release -cs)
|
7
|
+
|
8
|
+
# configure the puppet package sources
|
9
|
+
wget http://apt.puppetlabs.com/puppetlabs-release-$os_release.deb
|
10
|
+
dpkg -i puppetlabs-release-$os_release.deb
|
11
|
+
apt-get -q update
|
12
|
+
|
13
|
+
# install puppet
|
14
|
+
apt-get install -qy puppet
|
data/scripts/purge.sh
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
##
|
4
|
+
# Purge unnecessary data from the image to keep it small.
|
5
|
+
#
|
6
|
+
# Based on: https://gist.github.com/adrienbrault/3775253
|
7
|
+
##
|
8
|
+
|
9
|
+
# tidy up DCHP leases
|
10
|
+
echo "Cleaning up dhcp..."
|
11
|
+
rm /var/lib/dhcp/*
|
12
|
+
|
13
|
+
# make sure Udev doesn't block our network
|
14
|
+
# http://6.ptmc.org/?p=164
|
15
|
+
echo "Cleaning up udev..."
|
16
|
+
rm /etc/udev/rules.d/70-persistent-net.rules
|
17
|
+
mkdir /etc/udev/rules.d/70-persistent-net.rules
|
18
|
+
rm -rf /dev/.udev/
|
19
|
+
rm /lib/udev/rules.d/75-persistent-net-generator.rules
|
20
|
+
|
21
|
+
# clean up apt
|
22
|
+
echo "Cleaning up apt..."
|
23
|
+
apt-get -qy autoremove
|
24
|
+
apt-get clean -qy
|
25
|
+
apt-get autoclean -qy
|
26
|
+
|
27
|
+
# nuke the bash history
|
28
|
+
echo "Removing bash history..."
|
29
|
+
unset HISTFILE
|
30
|
+
rm -f /root/.bash_history
|
31
|
+
rm -f /home/vagrant/.bash_history
|
32
|
+
|
33
|
+
# clean up the logs
|
34
|
+
echo "Cleaning up logs..."
|
35
|
+
find /var/log -type f | while read f; do echo -ne '' > $f; done;
|
36
|
+
|
37
|
+
# zero any and all free space
|
38
|
+
echo "Cleaning free space..."
|
39
|
+
dd if=/dev/zero of=/EMPTY bs=1M
|
40
|
+
rm -f /EMPTY
|
41
|
+
|
42
|
+
# whiteout root
|
43
|
+
echo "Cleaning up /..."
|
44
|
+
#count=`df --sync -kP / | tail -n1 | awk -F ' ' '{print $4}'`;
|
45
|
+
dd if=/dev/zero of=/tmp/whitespace bs=1024;
|
46
|
+
rm /tmp/whitespace;
|
47
|
+
|
48
|
+
# whiteout /boot
|
49
|
+
echo "Cleaning up /boot..."
|
50
|
+
#count=`df --sync -kP /boot | tail -n1 | awk -F ' ' '{print $4}'`;
|
51
|
+
dd if=/dev/zero of=/boot/whitespace bs=1024;
|
52
|
+
rm /boot/whitespace;
|
53
|
+
|
54
|
+
# whiteout the swap
|
55
|
+
echo "Cleaning up swap partitions..."
|
56
|
+
swappart=`cat /proc/swaps | tail -n1 | awk -F ' ' '{print $1}'`
|
57
|
+
swapoff $swappart;
|
58
|
+
dd if=/dev/zero of=$swappart;
|
59
|
+
mkswap $swappart;
|
60
|
+
swapon $swappart;
|
data/scripts/ruby.sh
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# this installs chruby, ruby-install and a selection of rubies and is used in
|
4
|
+
# the 'ruby' special box type.
|
5
|
+
|
6
|
+
chruby_version=0.3.9
|
7
|
+
rubyinstall_version=0.5.0
|
8
|
+
|
9
|
+
# install chruby
|
10
|
+
wget -O chruby-$chruby_version.tar.gz https://github.com/postmodern/chruby/archive/v$chruby_version.tar.gz
|
11
|
+
tar -xzvf chruby-$chruby_version.tar.gz
|
12
|
+
cd chruby-$chruby_version/
|
13
|
+
make install
|
14
|
+
|
15
|
+
# configure system-wide
|
16
|
+
cat << 'EOF' > /etc/profile.d/chruby.sh
|
17
|
+
if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then
|
18
|
+
source /usr/local/share/chruby/chruby.sh
|
19
|
+
source /usr/local/share/chruby/auto.sh
|
20
|
+
fi
|
21
|
+
EOF
|
22
|
+
|
23
|
+
# install ruby-install
|
24
|
+
wget -O ruby-install-$rubyinstall_version.tar.gz https://github.com/postmodern/ruby-install/archive/v$rubyinstall_version.tar.gz
|
25
|
+
tar -xzvf ruby-install-$rubyinstall_version.tar.gz
|
26
|
+
cd ruby-install-$rubyinstall_version/
|
27
|
+
make install
|
28
|
+
|
29
|
+
# install a set of recent MRI Rubies.
|
30
|
+
ruby-install ruby 2.1.5
|
31
|
+
ruby-install ruby 2.2.0
|
32
|
+
ruby-install ruby 2.2.1
|
33
|
+
ruby-install ruby 2.2.2
|
34
|
+
|
35
|
+
# update gems and install bundler
|
36
|
+
source /usr/local/share/chruby/chruby.sh
|
37
|
+
for ruby in `chruby`; do
|
38
|
+
chruby-exec $ruby -- gem install bundler
|
39
|
+
done
|
40
|
+
|
41
|
+
exit
|