boxes 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,4 @@
1
+ # Versions and other declarations.
2
+ module Boxes
3
+ VERSION = '2.0.0'
4
+ end
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+
3
+ case $(lsb_release -is) in
4
+ 'ubuntu')
5
+ apt-add-repository ppa:ansible/ansible
6
+ apt-get -qy update
7
+ apt-get -qy install ansible
8
+ ;;
9
+ *)
10
+ easy_install pip
11
+ pip install ansible
12
+ ;;
13
+ esac
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