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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 61968a830b3bc14160ec9f1da648d4d25692e4de
|
4
|
+
data.tar.gz: 9488c5e6f4b90c8f8cbdc163b919cfecfca86a05
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9055590e48fa44358ecf33105e2329b29383c6ea1dbf2612d1eb8630abcb2c320578d53af38ca32c6cbdf97a3924389fe50bc4be43a08aaeea2f7e9320d44e0a
|
7
|
+
data.tar.gz: a29840bdc11b837c7d53e50c072b8ab28d0a855a54e407c827044a394df078d84f89cbe9774fc6b439e9d5cc37fff129104d3aca028e4cb994fa4e671899129d
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.2
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## 2.0.0 (10/10/2015)
|
4
|
+
|
5
|
+
* Conversion to being a command line tool distributed through Ruby Gems.
|
6
|
+
* Basic test coverage using Specs and Feature tests.
|
7
|
+
* Maintains an environment for running builds.
|
8
|
+
* Parses, validates and combines arguments.
|
9
|
+
* Allows the building of all of the previous styles of boxes.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Nick Charlton
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# boxes
|
2
|
+
|
3
|
+
[boxes][] takes the complexity out of building custom [Vagrant][] boxes.
|
4
|
+
|
5
|
+
It's a command line tool which provides a set of templates and scripts to
|
6
|
+
combine as you need. There are also a set of pre-build boxes which are
|
7
|
+
regenerated regularly.
|
8
|
+
|
9
|
+
## Installation & Requirements
|
10
|
+
|
11
|
+
```shell
|
12
|
+
[sudo] gem install boxes
|
13
|
+
```
|
14
|
+
|
15
|
+
boxes leans on [Packer][] and [VirtualBox][], [VMware Fusion][fusion] or
|
16
|
+
[VMware Workstation][workstation] for building boxes and these will need to
|
17
|
+
available in your `$PATH`.
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
boxes is driven by the `boxes` command line tool, and works with artifacts
|
22
|
+
inside it's own working directory. You need to specify a name for the build,
|
23
|
+
a template to work with and the output provider. Something like so:
|
24
|
+
|
25
|
+
```shell
|
26
|
+
boxes build --name=trusty64-empty --template=ubuntu/trusty64 --provider=vmware
|
27
|
+
```
|
28
|
+
|
29
|
+
This will build a file called `trusty64-empty.box` in the current directory.
|
30
|
+
|
31
|
+
There's lots more to `boxes` than building simple empty Vagrant boxes like
|
32
|
+
this, which can be see in the inline help.
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
1. Fork it ( https://github.com/nickcharlton/boxes/fork )
|
37
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
38
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
39
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
40
|
+
5. Create a new Pull Request
|
41
|
+
|
42
|
+
## Author
|
43
|
+
|
44
|
+
Copyright (c) 2013 Nick Charlton <nick@nickcharlton.net>
|
45
|
+
|
46
|
+
[boxes]: http://boxes.io
|
47
|
+
[Vagrant]: http://vagrantup.com
|
48
|
+
[Packer]: https://packer.io
|
49
|
+
[VirtualBox]: https://www.virtualbox.org
|
50
|
+
[fusion]: https://www.vmware.com/products/fusion/features.html
|
51
|
+
[workstation]: https://www.vmware.com/products/workstation/features.html
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'bundler/gem_tasks'
|
10
|
+
|
11
|
+
##
|
12
|
+
# Configure the test suite.
|
13
|
+
##
|
14
|
+
require 'rspec/core'
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new
|
18
|
+
|
19
|
+
##
|
20
|
+
# Cucumber for feature testing.
|
21
|
+
##
|
22
|
+
require 'rake/clean'
|
23
|
+
require 'cucumber'
|
24
|
+
require 'cucumber/rake/task'
|
25
|
+
|
26
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
27
|
+
t.cucumber_opts = 'features --format pretty -x'
|
28
|
+
t.fork = false
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# By default, just run the tests.
|
33
|
+
##
|
34
|
+
task default: :spec
|
data/bin/boxes
ADDED
data/boxes.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'boxes/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'boxes'
|
8
|
+
spec.version = Boxes::VERSION
|
9
|
+
spec.authors = ['Nick Charlton']
|
10
|
+
spec.email = ['nick@nickcharlton.net']
|
11
|
+
|
12
|
+
spec.summary = 'A command line tool to take the complexity out of '\
|
13
|
+
'building Vagrant boxes.'
|
14
|
+
spec.description = <<-EOF
|
15
|
+
boxes takes the complexity out of building custom Vagrant boxes.
|
16
|
+
|
17
|
+
It's a command line tool which provides a set of templates and scripts to
|
18
|
+
combine as you need. There are also a set of pre-build boxes which are
|
19
|
+
regenerated regularly.'
|
20
|
+
EOF
|
21
|
+
spec.homepage = 'https://github.com/nickcharlton/boxes'
|
22
|
+
spec.license = 'MIT'
|
23
|
+
|
24
|
+
spec.files = `git ls-files`.split($RS)
|
25
|
+
spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
|
26
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)/)
|
27
|
+
spec.require_paths = ['lib']
|
28
|
+
|
29
|
+
spec.add_dependency 'claide', '~> 0.9'
|
30
|
+
spec.add_dependency 'colored', '~> 1.2'
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler', '~> 1.9'
|
33
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.3'
|
35
|
+
spec.add_development_dependency 'cucumber', '~> 1.3'
|
36
|
+
spec.add_development_dependency 'aruba', '~> 0.8'
|
37
|
+
spec.add_development_dependency 'fakefs', '~> 0.6'
|
38
|
+
spec.add_development_dependency 'pry'
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Feature: We can build boxes
|
2
|
+
|
3
|
+
Scenario: It will error without a name
|
4
|
+
When I run `boxes build --template=ubuntu/trusty64 --provider=vmware`
|
5
|
+
Then the output should contain "[!] A name is required!"
|
6
|
+
And the exit status should be 1
|
7
|
+
|
8
|
+
Scenario: It will error without a provider
|
9
|
+
When I run `boxes build --name=trusty64-standard --template=ubuntu/trusty64`
|
10
|
+
Then the output should contain "[!] A provider is required!"
|
11
|
+
And the exit status should be 1
|
12
|
+
|
13
|
+
Scenario: It will error without a template
|
14
|
+
When I run `boxes build --name=trusty64-standard --provider=vmware`
|
15
|
+
Then the output should contain "[!] A template is required!"
|
16
|
+
And the exit status should be 1
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: We can manage the boxes environment
|
2
|
+
|
3
|
+
Scenario: It shows the environment by default
|
4
|
+
When I run `boxes env`
|
5
|
+
Then the output should contain "Configuration:"
|
6
|
+
Then the output should contain "Environment Variables:"
|
7
|
+
And the exit status should be 0
|
8
|
+
|
9
|
+
Scenario: It has a show command
|
10
|
+
When I run `boxes env show`
|
11
|
+
Then the output should contain "Configuration:"
|
12
|
+
Then the output should contain "Environment Variables:"
|
13
|
+
And the exit status should be 0
|
14
|
+
|
15
|
+
Scenario: It can clean the environment
|
16
|
+
When I run `boxes env clean`
|
17
|
+
Then the directory named "~/.boxes/env" does not exist
|
18
|
+
And the exit status should be 0
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'aruba/cucumber'
|
data/lib/boxes.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
4
|
+
require 'open3'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
require 'claide'
|
8
|
+
require 'colored'
|
9
|
+
|
10
|
+
require 'boxes/version'
|
11
|
+
require 'boxes/errors'
|
12
|
+
require 'boxes/config'
|
13
|
+
require 'boxes/subprocess'
|
14
|
+
require 'boxes/environment'
|
15
|
+
require 'boxes/template'
|
16
|
+
require 'boxes/builder'
|
17
|
+
require 'boxes/command'
|
18
|
+
|
19
|
+
# Toolkit for building Vagrantboxes, VM and cloud images.
|
20
|
+
module Boxes
|
21
|
+
class << self
|
22
|
+
attr_reader :config
|
23
|
+
|
24
|
+
def config
|
25
|
+
@config ||= Config.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Boxes
|
2
|
+
# Class which drives the build process.
|
3
|
+
class Builder
|
4
|
+
include Boxes::Errors
|
5
|
+
|
6
|
+
attr_accessor :name, :template, :scripts, :provider
|
7
|
+
|
8
|
+
# Initialise a new build.
|
9
|
+
#
|
10
|
+
# @param env [Boxes::Environment] environment to operate in.
|
11
|
+
# @param args [Hash]
|
12
|
+
# @param template [String] the name of the template.
|
13
|
+
# @param scripts [Array] scripts to include in the build.
|
14
|
+
def initialize(env, args) # rubocop:disable Metrics/MethodLength
|
15
|
+
@name = args[:name] || fail(MissingArgumentError,
|
16
|
+
'The name must be specified.')
|
17
|
+
@provider = args[:provider] || fail(MissingArgumentError,
|
18
|
+
'The provider must be specified.')
|
19
|
+
template = args[:template] || fail(MissingArgumentError,
|
20
|
+
'The template must be specified.')
|
21
|
+
scripts = args.fetch(:scripts, [])
|
22
|
+
|
23
|
+
@template = Template.new(env, template)
|
24
|
+
@scripts = scripts.collect do |c|
|
25
|
+
env.available_scripts.include?(c) ? c : fail(ScriptNotFoundError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Run the build.
|
30
|
+
def run # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
31
|
+
original_directory = FileUtils.pwd
|
32
|
+
box_name = ''
|
33
|
+
|
34
|
+
# render the template
|
35
|
+
rendered_template = template.render(name: name,
|
36
|
+
provider: provider,
|
37
|
+
scripts: scripts)
|
38
|
+
|
39
|
+
# write the template to a file
|
40
|
+
File.open(Boxes.config.working_dir + "#{build_name}.json", 'w') do |f|
|
41
|
+
f.puts rendered_template
|
42
|
+
end
|
43
|
+
|
44
|
+
# execute the packer command
|
45
|
+
FileUtils.chdir(Boxes.config.working_dir)
|
46
|
+
cmd = "packer build #{build_name}.json"
|
47
|
+
status = Subprocess.run(cmd) do |stdout, stderr, _thread|
|
48
|
+
puts stdout unless stdout.nil?
|
49
|
+
puts stderr unless stderr.nil?
|
50
|
+
|
51
|
+
# catch the name of the artifact
|
52
|
+
if stdout =~ /\.box/
|
53
|
+
box_name = stdout.gsub(/[a-zA-Z0-9:\-_]*?\.box/).first
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if status.exitstatus == 0
|
58
|
+
FileUtils.mv(Boxes.config.working_dir + box_name,
|
59
|
+
"#{original_directory}/#{name}.box")
|
60
|
+
else
|
61
|
+
fail BuildRunError,
|
62
|
+
'The build didn\'t complete successfully. Check the logs.'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Clean any temporary files used during building.
|
67
|
+
def clean
|
68
|
+
FileUtils.rm("#{build_name}.json")
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def build_name
|
74
|
+
@build_name ||= "#{@name}-#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Boxes
|
2
|
+
# Class which encapsulates the command line handling.
|
3
|
+
class Command < CLAide::Command
|
4
|
+
require 'boxes/command/build'
|
5
|
+
require 'boxes/command/env'
|
6
|
+
|
7
|
+
self.abstract_command = true
|
8
|
+
self.command = 'boxes'
|
9
|
+
self.version = VERSION
|
10
|
+
self.description = 'Toolkit for building Vagrantboxes, VM and cloud images.'
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Boxes
|
2
|
+
class Command
|
3
|
+
# Command handling for the box building functionality.
|
4
|
+
class Build < Command
|
5
|
+
self.summary = 'Build boxes'
|
6
|
+
self.description = 'Builds boxes using templates and scripts.'
|
7
|
+
|
8
|
+
def self.options
|
9
|
+
[
|
10
|
+
['--name', 'The name for the build'],
|
11
|
+
['--provider=[virtualbox|vmware]',
|
12
|
+
'The provider to build the box for'],
|
13
|
+
['--template', 'Template to build the box with'],
|
14
|
+
['--scripts', 'Scripts to apply to the box']
|
15
|
+
].concat(super)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(argv)
|
19
|
+
@build = {}
|
20
|
+
@build[:name] = argv.option('name')
|
21
|
+
@build[:provider] = argv.option('provider')
|
22
|
+
@build[:template] = argv.option('template')
|
23
|
+
scripts = argv.option('scripts') || ''
|
24
|
+
@build[:scripts] = scripts.split(',')
|
25
|
+
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
super
|
31
|
+
|
32
|
+
%w(name provider template).each do |key|
|
33
|
+
help! "A #{key} is required!" if @build[key.to_sym].nil?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
env = Boxes::Environment.new
|
39
|
+
builder = Boxes::Builder.new(env, @build)
|
40
|
+
builder.run
|
41
|
+
builder.clean
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Boxes
|
2
|
+
class Command
|
3
|
+
# Command handling for the environment used for building boxes.
|
4
|
+
class Env < Command
|
5
|
+
self.abstract_command = true
|
6
|
+
self.default_subcommand = 'show'
|
7
|
+
|
8
|
+
self.summary = 'Manage the build environment'
|
9
|
+
self.description = 'Expore the environment that boxes uses for building '\
|
10
|
+
'inside of.'
|
11
|
+
|
12
|
+
# Prints out the environment and configuration.
|
13
|
+
class Show < Env
|
14
|
+
self.summary = 'Show the environment and configuration'
|
15
|
+
self.description = <<-DESC
|
16
|
+
This lists the environment variables and other parts of the
|
17
|
+
configuration that boxes uses to handle builds.
|
18
|
+
DESC
|
19
|
+
|
20
|
+
def run # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
21
|
+
puts 'Configuration:'.underline
|
22
|
+
puts ''
|
23
|
+
puts "HOME_DIR=\"#{Boxes.config.home_dir}\""
|
24
|
+
puts "WORKING_DIR=\"#{Boxes.config.working_dir}\""
|
25
|
+
puts "TEMPLATE_PATHS=\"#{Boxes.config.template_paths.join(', ')}\""
|
26
|
+
puts "SCRIPT_PATHS=\"#{Boxes.config.script_paths.join(', ')}\""
|
27
|
+
|
28
|
+
puts ''
|
29
|
+
puts 'Environment Variables:'.underline
|
30
|
+
puts ''
|
31
|
+
Boxes.config.environment_vars.each do |e|
|
32
|
+
puts "#{e.keys.join}=\"#{e.values.join}\""
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Tidies up the working environment
|
38
|
+
class Clean < Env
|
39
|
+
self.summary = 'Clean up the environment.'
|
40
|
+
self.description = 'Removes any files from the working directory.'
|
41
|
+
|
42
|
+
def run
|
43
|
+
working_dir = Boxes.config.working_dir
|
44
|
+
|
45
|
+
FileUtils.rm_rf(working_dir) if working_dir.exist?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|