boxes 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/scripts/vmtools.sh
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
##
|
4
|
+
# Configure the relevant VM tools for this builder.
|
5
|
+
##
|
6
|
+
|
7
|
+
case $PACKER_BUILDER_TYPE in
|
8
|
+
'virtualbox-iso')
|
9
|
+
echo "Installing VirtualBox Guest Additions..."
|
10
|
+
apt-get -qy install dkms
|
11
|
+
mount -o loop /home/vagrant/VBoxGuestAdditions.iso /mnt
|
12
|
+
sh /mnt/VBoxLinuxAdditions.run
|
13
|
+
umount /mnt
|
14
|
+
|
15
|
+
rm -f /home/vagrant/VBoxGuestAdditions.iso
|
16
|
+
;;
|
17
|
+
'vmware-iso')
|
18
|
+
echo "Installing VMware Tools..."
|
19
|
+
mkdir -p /mnt/cdrom
|
20
|
+
mount -o loop /home/vagrant/linux.iso /mnt/cdrom
|
21
|
+
|
22
|
+
cd /tmp
|
23
|
+
tar -zxpf /mnt/cdrom/VMwareTools-*.tar.gz -C /tmp/
|
24
|
+
/tmp/vmware-tools-distrib/vmware-install.pl -d
|
25
|
+
|
26
|
+
umount /mnt/cdrom
|
27
|
+
rm -f /home/vagrant/linux.iso
|
28
|
+
;;
|
29
|
+
*)
|
30
|
+
printf "Nothing to do for the %s builder type.\n" $PACKER_BUILDER_TYPE
|
31
|
+
;;
|
32
|
+
esac
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Boxes::Builder do
|
4
|
+
let(:env) { Boxes::Environment.new }
|
5
|
+
|
6
|
+
describe '#initialize' do
|
7
|
+
it 'unpacks the arguments for the build' do
|
8
|
+
build = Boxes::Builder.new(env, name: 'build-name',
|
9
|
+
provider: 'vmware',
|
10
|
+
template: 'ubuntu/trusty64',
|
11
|
+
scripts: ['ruby.sh'])
|
12
|
+
|
13
|
+
expect(build.template.name).to eq 'ubuntu/trusty64'
|
14
|
+
expect(build.scripts).to include('ruby.sh')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'requires a name' do
|
18
|
+
expect do
|
19
|
+
Boxes::Builder.new(env, provider: 'vmware', template: 'ubuntu/trusty64')
|
20
|
+
end.to raise_error(Boxes::Errors::MissingArgumentError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'requires a provider' do
|
24
|
+
expect do
|
25
|
+
Boxes::Builder.new(env, name: 'build-name', template: 'ubuntu/trusty64')
|
26
|
+
end.to raise_error(Boxes::Errors::MissingArgumentError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'requires a template' do
|
30
|
+
expect do
|
31
|
+
Boxes::Builder.new(env, name: 'build-name', provider: 'vmware')
|
32
|
+
end.to raise_error(Boxes::Errors::MissingArgumentError)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'throws an exception on unknown templates' do
|
36
|
+
expect do
|
37
|
+
Boxes::Builder.new(env, name: 'build-name',
|
38
|
+
provider: 'vmware',
|
39
|
+
template: 'nope/nope')
|
40
|
+
end.to raise_error(Boxes::Errors::TemplateNotFoundError)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'throws an exception on unknown scripts' do
|
44
|
+
expect do
|
45
|
+
Boxes::Builder.new(env, name: 'build-name',
|
46
|
+
provider: 'vmware',
|
47
|
+
template: 'ubuntu/trusty64',
|
48
|
+
scripts: ['nope.sh'])
|
49
|
+
end.to raise_error(Boxes::Errors::ScriptNotFoundError)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Boxes::Config do
|
4
|
+
let(:config) { Boxes::Config.new }
|
5
|
+
|
6
|
+
context 'with no ENV modification' do
|
7
|
+
it 'tries to load a user config file if one exists' do
|
8
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
9
|
+
allow(YAML).to receive(:load_file).and_return({})
|
10
|
+
|
11
|
+
config
|
12
|
+
|
13
|
+
config_path = Pathname.new('~/.boxes/config.yml').expand_path
|
14
|
+
expect(YAML).to have_received(:load_file).with(config_path)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'has a set of default config values' do
|
18
|
+
expect(described_class::DEFAULTS).to be_a(Hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has a home directory' do
|
22
|
+
expect(config.home_dir).to eq Pathname.new('~/.boxes').expand_path
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has a working directory' do
|
26
|
+
expect(config.working_dir).to eq Pathname.new('~/.boxes/tmp').expand_path
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'has an array of template paths' do
|
30
|
+
expect(config.template_paths).to be_a Array
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'supports adding additional template paths' do
|
34
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
35
|
+
allow(YAML).to receive(:load_file).and_return(
|
36
|
+
template_paths: ['~/user_templates'])
|
37
|
+
|
38
|
+
default_templates = Boxes::Config::DEFAULTS[:template_paths]
|
39
|
+
|
40
|
+
expect(config.template_paths).to include('~/user_templates')
|
41
|
+
expect(config.template_paths).to include(default_templates.first)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not duplicate template path values' do
|
45
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
46
|
+
|
47
|
+
default_templates = Boxes::Config::DEFAULTS[:template_paths]
|
48
|
+
|
49
|
+
allow(YAML).to receive(:load_file).and_return(
|
50
|
+
template_paths: default_templates)
|
51
|
+
|
52
|
+
expect(config.template_paths).to include(default_templates.first)
|
53
|
+
expect(config.template_paths.count).to eq default_templates.count
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'has an array of script paths' do
|
57
|
+
expect(config.script_paths).to be_a Array
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'supports adding additional script paths' do
|
61
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
62
|
+
allow(YAML).to receive(:load_file).and_return(
|
63
|
+
script_paths: ['~/user_scripts'])
|
64
|
+
|
65
|
+
default_scripts = Boxes::Config::DEFAULTS[:script_paths]
|
66
|
+
|
67
|
+
expect(config.script_paths).to include('~/user_scripts')
|
68
|
+
expect(config.script_paths).to include(default_scripts.first)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'does not duplicate script path values' do
|
72
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
73
|
+
|
74
|
+
default_scripts = Boxes::Config::DEFAULTS[:script_paths]
|
75
|
+
|
76
|
+
allow(YAML).to receive(:load_file).and_return(
|
77
|
+
script_paths: default_scripts)
|
78
|
+
|
79
|
+
expect(config.script_paths).to include(default_scripts.first)
|
80
|
+
expect(config.script_paths.count).to eq default_scripts.count
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'has an array of environment variables' do
|
84
|
+
expect(config.environment_vars).to be_a Array
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'supports adding additional environment variables' do
|
88
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
89
|
+
allow(YAML).to receive(:load_file).and_return(
|
90
|
+
environment_vars: [{ 'CUSTOM_VAR' => 'TRUE' }])
|
91
|
+
|
92
|
+
default_env_vars = Boxes::Config::DEFAULTS[:environment_vars]
|
93
|
+
|
94
|
+
expect(config.environment_vars).to include('CUSTOM_VAR' => 'TRUE')
|
95
|
+
expect(config.environment_vars).to include(default_env_vars.first)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'does not duplicate environment variable values' do
|
99
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
100
|
+
|
101
|
+
default_env_vars = Boxes::Config::DEFAULTS[:environment_vars]
|
102
|
+
|
103
|
+
allow(YAML).to receive(:load_file).and_return(
|
104
|
+
environment_vars: default_env_vars)
|
105
|
+
|
106
|
+
expect(config.environment_vars).to include(default_env_vars.first)
|
107
|
+
expect(config.environment_vars.count).to eq default_env_vars.count
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'with ENV modification' do
|
112
|
+
it 'tries to load a different user config file' do
|
113
|
+
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
|
114
|
+
allow(YAML).to receive(:load_file).and_return({})
|
115
|
+
|
116
|
+
ENV['BOXES_HOME_DIR'] = '/something'
|
117
|
+
|
118
|
+
config
|
119
|
+
|
120
|
+
config_path = Pathname.new('/something/config.yml').expand_path
|
121
|
+
expect(YAML).to have_received(:load_file).with(config_path)
|
122
|
+
|
123
|
+
ENV.delete 'BOXES_HOME_DIR'
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'can change the home directory' do
|
127
|
+
ENV['BOXES_HOME_DIR'] = '/something'
|
128
|
+
|
129
|
+
expect(config.home_dir).to eq Pathname.new('/something')
|
130
|
+
|
131
|
+
ENV.delete 'BOXES_HOME_DIR'
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'can change the working directory' do
|
135
|
+
ENV['BOXES_WORKING_DIR'] = '/something'
|
136
|
+
|
137
|
+
expect(config.working_dir).to eq Pathname.new('/something')
|
138
|
+
|
139
|
+
ENV.delete 'BOXES_WORKING_DIR'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Boxes::Environment do
|
4
|
+
include FakeFS::SpecHelpers
|
5
|
+
|
6
|
+
let(:env) { Boxes::Environment.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
current_directory = File.expand_path('../../..', __FILE__)
|
10
|
+
|
11
|
+
FileUtils.mkdir_p(current_directory + '/templates')
|
12
|
+
FileUtils.mkdir_p(current_directory + '/templates/ubuntu')
|
13
|
+
FileUtils.touch(current_directory + '/templates/ubuntu/trusty64.erb')
|
14
|
+
FileUtils.touch(current_directory + '/templates/ubuntu/preseed.cfg')
|
15
|
+
|
16
|
+
FileUtils.mkdir_p(current_directory + '/scripts')
|
17
|
+
FileUtils.touch(current_directory + '/scripts/postinstall.sh')
|
18
|
+
FileUtils.touch(current_directory + '/scripts/purge.sh')
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#initialize' do
|
22
|
+
it 'successfully builds up a working tree' do
|
23
|
+
working_dir = Boxes.config.working_dir
|
24
|
+
test_template = working_dir + 'templates/ubuntu/trusty64.erb'
|
25
|
+
test_script = working_dir + 'scripts/postinstall.sh'
|
26
|
+
|
27
|
+
env
|
28
|
+
|
29
|
+
[working_dir,
|
30
|
+
working_dir + 'templates',
|
31
|
+
working_dir + 'scripts'].each do |e|
|
32
|
+
expect(File.directory?(e)).to be_truthy
|
33
|
+
end
|
34
|
+
|
35
|
+
expect(File.exist?(test_template)).to be_truthy
|
36
|
+
expect(File.exist?(test_script)).to be_truthy
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#available_templates' do
|
41
|
+
it 'lists available templates' do
|
42
|
+
expect(env.available_templates).to be_a(Array)
|
43
|
+
expect(env.available_templates).to include('ubuntu/trusty64')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'doesn\'t include hidden templates' do
|
47
|
+
expect(env.available_templates).not_to include('ubuntu/preseed.cfg')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#hidden_templates' do
|
52
|
+
it 'lists hidden templates' do
|
53
|
+
expect(env.hidden_templates).to include('ubuntu/preseed.cfg')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#available_scripts' do
|
58
|
+
it 'lists available scripts' do
|
59
|
+
expect(env.available_scripts).to be_a(Array)
|
60
|
+
expect(env.available_scripts).to include('postinstall.sh')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'doesn\'t include hidden scripts' do
|
64
|
+
expect(env.available_scripts).not_to include('purge.sh')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#hidden_scripts' do
|
69
|
+
it 'lists hidden scripts' do
|
70
|
+
expect(env.hidden_scripts).to include('purge.sh')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Boxes::Subprocess do
|
4
|
+
let(:command) do
|
5
|
+
File.expand_path 'spec/support/subprocess_command.rb'
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'runs a command and yields a block' do
|
9
|
+
expect { |b| Boxes::Subprocess.run(command, &b) }.to yield_control
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'runs a command and returns stdout' do
|
13
|
+
total_stdout = ''
|
14
|
+
Boxes::Subprocess.run(command) do |stdout, _stderr, _thread|
|
15
|
+
total_stdout << stdout
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(total_stdout).to eq "A happy output.\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'runs a command and returns stderr' do
|
22
|
+
total_stderr = ''
|
23
|
+
Boxes::Subprocess.run(command) do |_stdout, stderr, _thread|
|
24
|
+
total_stderr << stderr
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(total_stderr).to eq "An unhappy output.\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns a status code' do
|
31
|
+
status = Boxes::Subprocess.run(command) { |_stdout, _stderr, _thread| }
|
32
|
+
|
33
|
+
expect(status.exitstatus).to eq 5
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Boxes::Template do
|
4
|
+
include FakeFS::SpecHelpers
|
5
|
+
|
6
|
+
let(:env) { Boxes::Environment.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
current_directory = File.expand_path('../../..', __FILE__)
|
10
|
+
|
11
|
+
FileUtils.mkdir_p(current_directory + '/templates')
|
12
|
+
FileUtils.mkdir_p(current_directory + '/templates/ubuntu')
|
13
|
+
|
14
|
+
mock_template = <<-EOF
|
15
|
+
<% @scripts.each do |s| %>
|
16
|
+
<%= s %>
|
17
|
+
<% end %>
|
18
|
+
EOF
|
19
|
+
|
20
|
+
File.open(current_directory + '/templates/ubuntu/trusty64.erb', 'w') do |f|
|
21
|
+
f.puts mock_template
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#initialize' do
|
26
|
+
it 'can read in a known template' do
|
27
|
+
template = described_class.new(env, 'ubuntu/trusty64')
|
28
|
+
|
29
|
+
expect(template.template).to be_a(String)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'throws an exception if the template is missing' do
|
33
|
+
expect do
|
34
|
+
described_class.new(env, 'nope/nope')
|
35
|
+
end.to raise_error(Boxes::Errors::TemplateNotFoundError)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'stores the template name' do
|
39
|
+
template = described_class.new(env, 'ubuntu/trusty64')
|
40
|
+
|
41
|
+
expect(template.name).to eq 'ubuntu/trusty64'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#render' do
|
46
|
+
it 'renders a template with a set of variables' do
|
47
|
+
template = described_class.new(env, 'ubuntu/trusty64')
|
48
|
+
rendered = template.render(scripts: ['ruby.sh'])
|
49
|
+
|
50
|
+
expect(rendered).to include('ruby.sh')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Based upon: https://help.ubuntu.com/12.04/installation-guide/example-preseed.txt
|
3
|
+
#
|
4
|
+
|
5
|
+
# localisation
|
6
|
+
d-i debian-installer/locale string en_US.utf8
|
7
|
+
d-i console-keymaps-at/keymap select us
|
8
|
+
|
9
|
+
# networking
|
10
|
+
d-i netcfg/choose_interface select auto
|
11
|
+
d-i netcfg/get_hostname string unassigned-hostname
|
12
|
+
d-i netcfg/get_domain string unassigned-domain
|
13
|
+
d-i netcfg/wireless_wep string
|
14
|
+
|
15
|
+
# apt mirrors
|
16
|
+
d-i mirror/country string manual
|
17
|
+
d-i mirror/http/hostname string http.us.debian.org
|
18
|
+
d-i mirror/http/directory string /debian
|
19
|
+
d-i mirror/http/proxy string
|
20
|
+
|
21
|
+
# clock and time zone
|
22
|
+
d-i clock-setup/utc boolean true
|
23
|
+
d-i time/zone string GMT
|
24
|
+
d-i clock-setup/ntp boolean true
|
25
|
+
|
26
|
+
# partitioning
|
27
|
+
d-i partman-auto/method string lvm
|
28
|
+
d-i partman-lvm/device_remove_lvm boolean true
|
29
|
+
d-i partman-md/device_remove_md boolean true
|
30
|
+
d-i partman-lvm/confirm boolean true
|
31
|
+
d-i partman-lvm/confirm_nooverwrite boolean true
|
32
|
+
|
33
|
+
#d-i partman-auto-lvm/guided_size string max
|
34
|
+
d-i partman-auto/choose_recipe select atomic
|
35
|
+
d-i partman-partitioning/confirm_write_new_label boolean true
|
36
|
+
d-i partman/choose_partition select finish
|
37
|
+
d-i partman/confirm boolean true
|
38
|
+
d-i partman/confirm_nooverwrite boolean true
|
39
|
+
|
40
|
+
# users
|
41
|
+
d-i passwd/root-login boolean false
|
42
|
+
d-i passwd/user-fullname string Vagrant User
|
43
|
+
d-i passwd/username string vagrant
|
44
|
+
d-i passwd/user-password password vagrant
|
45
|
+
d-i passwd/user-password-again password vagrant
|
46
|
+
d-i user-setup/allow-password-weak boolean true
|
47
|
+
d-i user-setup/encrypt-home boolean false
|
48
|
+
|
49
|
+
# packages
|
50
|
+
tasksel tasksel/first multiselect standard
|
51
|
+
#d-i pkgsel/install-language-support boolean false
|
52
|
+
d-i pkgsel/include string openssh-server nfs-common curl ntp acpid sudo bzip2 rsync git
|
53
|
+
d-i pkgsel/upgrade select full-upgrade
|
54
|
+
d-i pkgsel/update-policy select none
|
55
|
+
d-i popularity-contest/participate boolean false
|
56
|
+
postfix postfix/main_mailer_type select No configuration
|
57
|
+
|
58
|
+
# boot loader
|
59
|
+
d-i grub-installer/only_debian boolean true
|
60
|
+
|
61
|
+
# hide the shutdown notice
|
62
|
+
d-i finish-install/reboot_in_progress note
|
63
|
+
|
64
|
+
# advanced options
|
65
|
+
|
66
|
+
# ensure the default VirtualBox additions doesn't install
|
67
|
+
d-i preseed/early_command string sed -i \
|
68
|
+
'/in-target/idiscover(){/sbin/discover|grep -v VirtualBox;}' \
|
69
|
+
/usr/lib/pre-pkgsel.d/20install-hwpackages
|