racker 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +17 -0
- data/LICENSE +22 -0
- data/NOTICE +8 -0
- data/README.md +215 -0
- data/Rakefile +38 -0
- data/bin/racker +40 -0
- data/lib/racker.rb +6 -0
- data/lib/racker/builders/amazon.rb +25 -0
- data/lib/racker/builders/builder.rb +25 -0
- data/lib/racker/builders/digitalocean.rb +27 -0
- data/lib/racker/builders/docker.rb +25 -0
- data/lib/racker/builders/google.rb +27 -0
- data/lib/racker/builders/openstack.rb +27 -0
- data/lib/racker/builders/qemu.rb +25 -0
- data/lib/racker/builders/virtualbox.rb +25 -0
- data/lib/racker/builders/vmware.rb +25 -0
- data/lib/racker/cli.rb +99 -0
- data/lib/racker/processor.rb +101 -0
- data/lib/racker/smash/deep_merge_modified.rb +210 -0
- data/lib/racker/smash/mash.rb +225 -0
- data/lib/racker/smash/smash.rb +58 -0
- data/lib/racker/template.rb +84 -0
- data/lib/racker/version.rb +21 -0
- data/spec/rcov.opts +2 -0
- metadata +330 -0
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
## 0.1.0 (2014-02-23)
|
2
|
+
|
3
|
+
* Initial public release
|
4
|
+
|
5
|
+
## 0.0.3 (Internal)
|
6
|
+
|
7
|
+
* Adding support for outstanding builders (digitalocean,docker,google,openstack and qemu)
|
8
|
+
* Added more robust logging support
|
9
|
+
|
10
|
+
## 0.0.2 (Internal)
|
11
|
+
|
12
|
+
* Removed ability to name post-processors due to packer template change.
|
13
|
+
|
14
|
+
## 0.0.1 (Internal)
|
15
|
+
|
16
|
+
* Initial private release
|
17
|
+
* Supports Amazon, Virtualbox and VMWare builders
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2013-2014 Anthony Spring (<tony@porkchopsandpaintchips.com>)
|
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/NOTICE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Racker NOTICE
|
2
|
+
===========
|
3
|
+
|
4
|
+
Racker incorporates code modified from Chef (https://github.com/opscode/chef), which is Copyright (c) 2008-2014 Chef Software, Inc.
|
5
|
+
|
6
|
+
Racker incorporates code modified from deep_merge (http://trac.misuse.org/science/wiki/DeepMerge), which is Copyright (c) 2008 Steve Midgley
|
7
|
+
|
8
|
+
Racker incorporates code modified from Vagrant (https://github.com/mitchellh/vagrant) which is Copyright (c) 2010-2014 Mitchell Hashimoto
|
data/README.md
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
# Racker
|
2
|
+
|
3
|
+
* Website: http://github.com/aspring/racker
|
4
|
+
|
5
|
+
Racker is an opinionated Ruby DSL for generating Packer(www.packer.io) templates.
|
6
|
+
|
7
|
+
Racker is able to take multiple Racker templates, merge them together, and generate a single Packer template. This process allows for deep merging Packer configuration pieces to give the user a more granular approach for creating and organizing templates, not currently possible with the Packer template format.
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
* Allows for building Packer templates from DRY modular templates
|
12
|
+
* Allows for commenting sections of the template
|
13
|
+
* Supports use of knockouts when merging
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
$ gem install racker
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
To generate a Packer template from a Racker template, run:
|
21
|
+
|
22
|
+
$ racker rackertemplate1.rb packertemplate.json
|
23
|
+
|
24
|
+
To generate a Packer template from multiple Racker templates, run:
|
25
|
+
|
26
|
+
$ racker rackertemplate1.rb rackertemplate2.rb packertemplate.json
|
27
|
+
|
28
|
+
To merge multiple templates you can keep adding Racker templates:
|
29
|
+
|
30
|
+
$ racker rackertemplate1.rb rackertemplate2.rb rackertemplate3.rb packertemplate.json
|
31
|
+
|
32
|
+
The output of the previous command will be the template 1 deep merged with template2, the result of this merge is deep merged with template 3 then output as a packer template.
|
33
|
+
|
34
|
+
## Racker Template Syntax
|
35
|
+
The goal of Racker is to provide a template structure that allows for allowing full control of the template merging process to achieve the desired Packer template.
|
36
|
+
|
37
|
+
In order to do this Racker takes an opinionated stance on the following:
|
38
|
+
|
39
|
+
* All arrays within Packer Builder namespace are converted to hashes with well defined keys -- this allows for easy knockout capability based on key name.
|
40
|
+
* The provisioners hash uses a Fixnum key to allow for defining an order that provisioners will be written to the Packer template.
|
41
|
+
|
42
|
+
#### Base Template Syntax
|
43
|
+
|
44
|
+
The most basic Racker template would be the following:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
Racker::Processor.register_template do |t|
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
This template would not define a variable, builder, provisioner or post-processor and would be a pretty boring template.
|
52
|
+
|
53
|
+
#### Variables Namespace
|
54
|
+
|
55
|
+
Racker templates support the `variables` namespace which is a hash. This hash maps one to one to a Packer template's variables section.
|
56
|
+
|
57
|
+
This is an example of a basic `variables` definition:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
Racker::Processor.register_template do |t|
|
61
|
+
# Define the variables
|
62
|
+
t.variables = {
|
63
|
+
'iso_checksum' => '6232efa014d9c6798396b63152c4c9a08b279f5e',
|
64
|
+
'iso_checksum_type' => 'sha1',
|
65
|
+
'iso_url' => 'http://mirrors.kernel.org/centos/6.4/isos/x86_64/CentOS-6.4-x86_64-minimal.iso',
|
66
|
+
'kickstart_file' => 'template1-ks.cfg',
|
67
|
+
'vagrant_output_file' => "./boxes/centos-6.4-{{.Provider}}.box"
|
68
|
+
}
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
#### Builders Namespace
|
73
|
+
|
74
|
+
Racker templates support the `builders` namespace which is a hash, keyed by the name of the builder.
|
75
|
+
|
76
|
+
All Packer arrays inside of this namespace should be represented as hashes in Racker. Racker will use the value when creating the template, the key is there purely for allowing you to override/knockout as necessary.
|
77
|
+
|
78
|
+
This is an abbreviated example of adding a builder named 'test' that is a 'virtualbox-iso' builder type:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
Racker::Processor.register_template do |t|
|
82
|
+
# Define the builders
|
83
|
+
t.builders['test'] = {
|
84
|
+
'type' => 'virtualbox-iso',
|
85
|
+
'guest_os_type' => 'RedHat_64',
|
86
|
+
'headless' => true,
|
87
|
+
'format' => 'ova',
|
88
|
+
'guest_additions_path' => "VBoxGuestAdditions_{{.Version}}.iso",
|
89
|
+
'iso_checksum' => "{{user `iso_checksum`}}",
|
90
|
+
'iso_checksum_type' => "{{user `iso_checksum_type`}}",
|
91
|
+
'iso_url' => "{{user `iso_url`}}",
|
92
|
+
'virtualbox_version_file' => '.vbox_version',
|
93
|
+
'boot_command' => {
|
94
|
+
0 => '<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/{{user `kickstart_file`}}<enter><wait>'
|
95
|
+
},
|
96
|
+
'boot_wait' => '10s',
|
97
|
+
'http_directory' => 'http_directory',
|
98
|
+
'ssh_port' => 22,
|
99
|
+
'ssh_username' => 'root',
|
100
|
+
'ssh_password' => 'asdfasdf',
|
101
|
+
'ssh_wait_timeout' => '10000s',
|
102
|
+
'shutdown_command' => 'shutdown -P now',
|
103
|
+
'disk_size' => 8096,
|
104
|
+
'vboxmanage' => {
|
105
|
+
'memory' => [ 'modifyvm', '{{.Name}}', '--memory', '1024' ],
|
106
|
+
'cpus' => [ 'modifyvm', '{{.Name}}', '--cpus', '1' ],
|
107
|
+
'ioapic' => [ 'modifyvm', '{{.Name}}', '--ioapic', 'on' ]
|
108
|
+
}
|
109
|
+
}
|
110
|
+
end
|
111
|
+
```
|
112
|
+
One of the sections of node in this builder is the `vboxmanage`. It has been converted into a Hash to make it easier to knockout.
|
113
|
+
|
114
|
+
#### Provisioners Namespace
|
115
|
+
|
116
|
+
Racker templates support the `provisioners` namespace which is a Fixnum keyed hash.
|
117
|
+
|
118
|
+
When generating the Packer template, Racker will order the provisioners based upon the Fixnum key, this allows complete control on the ordering of provisioners throughout Racker templates.
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
Racker::Processor.register_template do |t|
|
122
|
+
# Define the provisioners
|
123
|
+
t.provisioners = {
|
124
|
+
0 => {
|
125
|
+
'update-cacert-bundle' => {
|
126
|
+
'type' => 'shell',
|
127
|
+
'script' => 'scripts/common/update-cacert-bundle.sh'
|
128
|
+
},
|
129
|
+
},
|
130
|
+
300 => {
|
131
|
+
'install-chef-11.8.0' => {
|
132
|
+
'type' => 'shell',
|
133
|
+
'script' => 'scripts/common/install-chef-11.8.0.sh'
|
134
|
+
},
|
135
|
+
},
|
136
|
+
500 => {
|
137
|
+
'install-guest-additions-dependencies' => {
|
138
|
+
'type' => 'shell',
|
139
|
+
'scripts' => [
|
140
|
+
'scripts/common/install-guest-additions.sh'
|
141
|
+
],
|
142
|
+
},
|
143
|
+
},
|
144
|
+
750 => {
|
145
|
+
'disable-services' => {
|
146
|
+
'type' => 'shell',
|
147
|
+
'script' => 'scripts/centos-6/disable-services.sh'
|
148
|
+
},
|
149
|
+
},
|
150
|
+
900 => {
|
151
|
+
'prepare-vagrant-instance' => {
|
152
|
+
'type' => 'shell',
|
153
|
+
'script' => 'scripts/common/prepare-vagrant-instance.sh',
|
154
|
+
'only' => ['test']
|
155
|
+
},
|
156
|
+
'prepare-ec2-instance' => {
|
157
|
+
'type' => 'shell',
|
158
|
+
'script' => 'scripts/common/prepare-ec2-instance.sh',
|
159
|
+
'only' => ['amazon']
|
160
|
+
},
|
161
|
+
}
|
162
|
+
}
|
163
|
+
end
|
164
|
+
```
|
165
|
+
|
166
|
+
#### Post-Processors Namespace
|
167
|
+
|
168
|
+
Racker templates support the `postprocessors` namespace which is a hash, keyed by the name of the post-processor.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
Racker::Processor.register_template do |t|
|
172
|
+
# Define the post-processors
|
173
|
+
t.postprocessors['vagrant'] = {
|
174
|
+
'type' => 'vagrant',
|
175
|
+
'output' => '{{user `vagrant_output_file`}}',
|
176
|
+
'compression_level' => 7,
|
177
|
+
'keep_input_artifact' => true,
|
178
|
+
'only' => ['virtualbox-vagrant','vmware-vagrant']
|
179
|
+
}
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
### Putting it all together
|
184
|
+
|
185
|
+
Racker offers 2 very basic example templates `example/template1.rb` and `example/template2.rb` as well as the resulting packer template from the two templates run through Racker.
|
186
|
+
|
187
|
+
To experiement with these templates, after installing Racker, and cloning this repo you can execute the following:
|
188
|
+
|
189
|
+
$ racker ./example/template1rb ./example/tempalte2.rb ./example/packer.json
|
190
|
+
|
191
|
+
While these two templates are not all inclusive of the capabilities of Racker, it shows off the ability to have a basic template, and a second template that removes the pieces of the template that target Amazon, as well as adds two chef solo provisioner steps.
|
192
|
+
|
193
|
+
## Testing
|
194
|
+
|
195
|
+
TODO: This section needs to be written
|
196
|
+
|
197
|
+
## Outstanding Development
|
198
|
+
|
199
|
+
* The following builders have not been fully tested:
|
200
|
+
* docker
|
201
|
+
* qemu
|
202
|
+
* Implement unit testing
|
203
|
+
* Travis CI
|
204
|
+
* Additional documentation work
|
205
|
+
* Add capability to target specific packer versions should the packer template format change.
|
206
|
+
* Add quick init to generate a basic Racker template
|
207
|
+
|
208
|
+
## Contributions
|
209
|
+
|
210
|
+
Feel free to fork and request a pull, or submit a ticket
|
211
|
+
https://github.com/aspring/racker/issues
|
212
|
+
|
213
|
+
## License
|
214
|
+
|
215
|
+
This project is available under the MIT license. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
begin
|
5
|
+
Bundler.setup(:default, :development)
|
6
|
+
rescue Bundler::BundlerError => e
|
7
|
+
$stderr.puts e.message
|
8
|
+
$stderr.puts 'Run `bundle install` to install missing gems'
|
9
|
+
exit e.status_code
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rake'
|
13
|
+
require 'rspec/core'
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
require 'rubocop/rake_task'
|
16
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
17
|
+
t.pattern = FileList['spec/**/*_spec.rb']
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Run RSpec with code coverage'
|
21
|
+
task :coverage do
|
22
|
+
ENV['COVERAGE'] = 'true'
|
23
|
+
Rake::Task['spec'].execute
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rubocop/rake_task'
|
27
|
+
Rubocop::RakeTask.new(:rubocop) do |t|
|
28
|
+
# Specify the files we will look at
|
29
|
+
t.patterns = ['bin', File.join('{lib}','**', '*.rb')]
|
30
|
+
|
31
|
+
# Do not fail on error
|
32
|
+
t.fail_on_error = false
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'yard'
|
36
|
+
YARD::Rake::YardocTask.new
|
37
|
+
|
38
|
+
task default: [:spec]
|
data/bin/racker
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
if RUBY_VERSION >= '1.9.2'
|
5
|
+
require 'log4r'
|
6
|
+
|
7
|
+
begin
|
8
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
9
|
+
require 'racker'
|
10
|
+
|
11
|
+
# Create the initial logger
|
12
|
+
log = Log4r::Logger.new('racker')
|
13
|
+
|
14
|
+
# Set the output to STDOUT
|
15
|
+
log.outputters = Log4r::Outputter.stdout
|
16
|
+
|
17
|
+
# We set the initial log level to ERROR
|
18
|
+
log.level = Log4r::ERROR
|
19
|
+
|
20
|
+
# Let the CLI do its thing
|
21
|
+
exit_code = Racker::CLI.new(ARGV.dup).execute!
|
22
|
+
|
23
|
+
log.info("Exit code: #{exit_code}")
|
24
|
+
Kernel.exit!(exit_code)
|
25
|
+
rescue Exception => e
|
26
|
+
log = Log4r::Logger.new('racker')
|
27
|
+
log.outputters = Log4r::Outputter.stdout
|
28
|
+
log.error("Rackers encountered an unexpected error!")
|
29
|
+
log.error()
|
30
|
+
log.error("Details:")
|
31
|
+
log.error(e.inspect)
|
32
|
+
log.error(e.message)
|
33
|
+
log.error(e.backtrace.join('\n'))
|
34
|
+
exit e.status_code if e.respond_to?(:status_code)
|
35
|
+
exit 999
|
36
|
+
end
|
37
|
+
else
|
38
|
+
puts 'Racker supports only Ruby 1.9.2+'
|
39
|
+
exit(-1)
|
40
|
+
end
|
data/lib/racker.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'racker/builders/builder'
|
3
|
+
|
4
|
+
module Racker
|
5
|
+
module Builders
|
6
|
+
# This is the Amazon builder
|
7
|
+
class Amazon < Racker::Builders::Builder
|
8
|
+
def to_packer(name, config)
|
9
|
+
log = Log4r::Logger['racker']
|
10
|
+
log.debug("Entering #{self.class}.#{__method__}")
|
11
|
+
config = super(name, config)
|
12
|
+
|
13
|
+
%w(ami_block_device_mappings ami_groups ami_product_codes ami_regions ami_users chroot_mounts copy_files launch_block_device_mappings security_group_ids).each do |key|
|
14
|
+
if config.key? key
|
15
|
+
log.info("Converting #{key} to packer value...")
|
16
|
+
config[key] = convert_hash_to_packer_value(config[key])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
log.debug("Leaving #{self.class}.#{__method__}")
|
21
|
+
config
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Racker
|
4
|
+
|
5
|
+
module Builders
|
6
|
+
# This is the Builder base class
|
7
|
+
class Builder
|
8
|
+
def to_packer(name, config)
|
9
|
+
log = Log4r::Logger['racker']
|
10
|
+
log.debug("Entering #{self.class}.#{__method__}")
|
11
|
+
|
12
|
+
# Set the name of the builder
|
13
|
+
log.info("Setting config name to #{name}")
|
14
|
+
config['name'] = name
|
15
|
+
|
16
|
+
log.debug("Leaving #{self.class}.#{__method__}")
|
17
|
+
config
|
18
|
+
end
|
19
|
+
|
20
|
+
def convert_hash_to_packer_value(config)
|
21
|
+
config.kind_of?(Hash) ? config.values : config
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'racker/builders/builder'
|
3
|
+
|
4
|
+
module Racker
|
5
|
+
module Builders
|
6
|
+
# This is the DigitalOcean builder
|
7
|
+
class DigitalOcean < Racker::Builders::Builder
|
8
|
+
def to_packer(name, config)
|
9
|
+
log = Log4r::Logger['racker']
|
10
|
+
log.debug("Entering #{self.class}.#{__method__}")
|
11
|
+
config = super(name, config)
|
12
|
+
|
13
|
+
# There are no special cases at this point
|
14
|
+
|
15
|
+
# %w().each do |key|
|
16
|
+
# if config.key? key
|
17
|
+
# log.info("Converting #{key} to packer value...")
|
18
|
+
# config[key] = convert_hash_to_packer_value(config[key])
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
22
|
+
log.debug("Leaving #{self.class}.#{__method__}")
|
23
|
+
config
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'racker/builders/builder'
|
3
|
+
|
4
|
+
module Racker
|
5
|
+
module Builders
|
6
|
+
# This is the Docker builder
|
7
|
+
class Docker < Racker::Builders::Builder
|
8
|
+
def to_packer(name, config)
|
9
|
+
log = Log4r::Logger['racker']
|
10
|
+
log.debug("Entering #{self.class}.#{__method__}")
|
11
|
+
config = super(name, config)
|
12
|
+
|
13
|
+
%w(run_command).each do |key|
|
14
|
+
if config.key? key
|
15
|
+
log.info("Converting #{key} to packer value...")
|
16
|
+
config[key] = convert_hash_to_packer_value(config[key])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
log.debug("Leaving #{self.class}.#{__method__}")
|
21
|
+
config
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|