singel 0.2.1 → 0.2.2
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 +4 -4
- data/.gitignore +3 -0
- data/bin/singel +3 -53
- data/lib/config.rb +64 -0
- data/lib/executor.rb +46 -34
- data/lib/orchestrator.rb +69 -65
- data/lib/string.rb +33 -0
- data/lib/template.rb +27 -27
- data/lib/uploader.rb +9 -7
- data/singel.gemspec +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aaa5865dd1830b229c430c5846b5ef4b28c586b0
|
4
|
+
data.tar.gz: 54c9c871c502e99a8e9f9103868ae7355217e1bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d27fb80019dd99723ae69fd2e9c18a2be5316cea852457a8072851b9c84cd67b99157c0db4efb486f7cc5b58d5fbe6087c68a4d8dbb73e0c240a90d597a63483
|
7
|
+
data.tar.gz: f61553aed236cdf546ce82fb544213d8ad51d6eb0215e6e02a79c565f87fc14a5b408a79a42f90adbbbbecd9132e578e7ee53beef1ef58bc573c0b0bfa54357f
|
data/.gitignore
CHANGED
data/bin/singel
CHANGED
@@ -25,64 +25,14 @@ begin
|
|
25
25
|
require 'aws-sdk-core'
|
26
26
|
require 'json'
|
27
27
|
require 'pty'
|
28
|
+
require 'config.rb'
|
28
29
|
require 'orchestrator.rb'
|
29
30
|
require 'executor.rb'
|
30
31
|
require 'uploader.rb'
|
31
32
|
require 'template.rb'
|
33
|
+
require 'string.rb'
|
32
34
|
rescue LoadError => e
|
33
35
|
raise "Missing gem or lib #{e}"
|
34
36
|
end
|
35
37
|
|
36
|
-
|
37
|
-
class String
|
38
|
-
def to_green
|
39
|
-
"\033[32m#{self}\033[0m"
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_red
|
43
|
-
"\033[31m#{self}\033[0m"
|
44
|
-
end
|
45
|
-
|
46
|
-
def indent(double_space_count = 1)
|
47
|
-
double_space_count.times { insert(0, ' ') }
|
48
|
-
self
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def parse_opts
|
53
|
-
options = { :templates => [], :builders => [], :packer_dir => File.expand_path('./packer') }
|
54
|
-
banner = "Singel - Unified system image creation using Packer\n\n" \
|
55
|
-
"Usage: singel [action] [options]\n\n" \
|
56
|
-
" Actions:\n" \
|
57
|
-
" build: Build system images\n" \
|
58
|
-
" list: List available image templates and builder types (AMI, Virtualbox, etc)\n\n" \
|
59
|
-
" Options:\n"
|
60
|
-
OptionParser.new do |opts|
|
61
|
-
opts.banner = banner
|
62
|
-
opts.on('-t', '--templates t1.json,t2.json', Array, 'Build only the specified comma separated list of templates') do |t|
|
63
|
-
options[:templates] = t
|
64
|
-
end
|
65
|
-
opts.on('-b', '--builders type1,type2', Array, 'Build only the specified comma separated list of builder types') do |b|
|
66
|
-
options[:builders] = b
|
67
|
-
end
|
68
|
-
opts.on('-p', '--packer_dir PATH', 'Path to the packer dir containing templates and other files') do |p|
|
69
|
-
options[:packer_dir] = File.expand_path(p)
|
70
|
-
end
|
71
|
-
opts.on('-h', '--help', 'Displays Help') do
|
72
|
-
puts opts
|
73
|
-
exit
|
74
|
-
end
|
75
|
-
end.parse!(ARGV)
|
76
|
-
|
77
|
-
options
|
78
|
-
end
|
79
|
-
|
80
|
-
unless ARGV[0]
|
81
|
-
puts "You must provide an action for singel to execute on\n".to_red
|
82
|
-
ARGV << '-h'
|
83
|
-
end
|
84
|
-
|
85
|
-
# parse the user provided options
|
86
|
-
options = parse_opts
|
87
|
-
|
88
|
-
SingelOrchestrator.new(options).run
|
38
|
+
Singel::SingelOrchestrator.new.run
|
data/lib/config.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Tim Smith (<tim@cozy.co>)
|
4
|
+
# Copyright:: Copyright (c) 2014 Tim Smith
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Singel
|
20
|
+
# allow fetching the config anywhere in the app
|
21
|
+
module Config
|
22
|
+
require 'string.rb'
|
23
|
+
|
24
|
+
# return the config object or parse the options fresh
|
25
|
+
def self.config
|
26
|
+
@config ||= parse_opts
|
27
|
+
end
|
28
|
+
|
29
|
+
# parse options passed from the command line
|
30
|
+
def self.parse_opts
|
31
|
+
options = { :templates => [], :builders => [], :packer_dir => File.expand_path('./packer') }
|
32
|
+
banner = "Singel - Unified system image creation using Packer\n\n" \
|
33
|
+
"Usage: singel [action] [options]\n\n" \
|
34
|
+
" Actions:\n" \
|
35
|
+
" build: Build system images\n" \
|
36
|
+
" list: List available image templates and builder types (AMI, Virtualbox, etc)\n\n" \
|
37
|
+
" Options:\n"
|
38
|
+
OptionParser.new do |opts|
|
39
|
+
opts.banner = banner
|
40
|
+
opts.on('-t', '--templates t1.json,t2.json', Array, 'Build only the specified comma separated list of templates') do |t|
|
41
|
+
options[:templates] = t
|
42
|
+
end
|
43
|
+
opts.on('-b', '--builders type1,type2', Array, 'Build only the specified comma separated list of builder types') do |b|
|
44
|
+
options[:builders] = b
|
45
|
+
end
|
46
|
+
opts.on('-p', '--packer_dir PATH', 'Path to the packer dir containing templates and other files') do |p|
|
47
|
+
options[:packer_dir] = File.expand_path(p)
|
48
|
+
end
|
49
|
+
opts.on('-h', '--help', 'Displays Help') do
|
50
|
+
puts opts
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
end.parse!(ARGV)
|
54
|
+
|
55
|
+
options
|
56
|
+
end
|
57
|
+
|
58
|
+
# if no argument was passed or the first arg starts with - (aka it's not actually an action)
|
59
|
+
if ARGV[0].nil? || ARGV[0][0] == '-'
|
60
|
+
puts "\nYou must provide an action for singel to execute on:\n".to_red
|
61
|
+
ARGV << '-h'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/executor.rb
CHANGED
@@ -16,47 +16,59 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
module Singel
|
20
|
+
# executes packer commands against template object
|
21
|
+
class PackerExecutor
|
22
|
+
def initialize(template, builders)
|
23
|
+
@template = template
|
24
|
+
@file_path = template.path
|
25
|
+
@template_builders = template.builders
|
26
|
+
@specified_builders = builders
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
# print out the builders for this template
|
30
|
+
def list
|
31
|
+
puts File.basename(@file_path, '.json') + ':'
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
builders = @template.builders_hash
|
34
|
+
if builders.empty?
|
35
|
+
puts '- No builders found'.indent.to_red
|
36
|
+
else
|
37
|
+
builders.each_pair do |name, type|
|
38
|
+
puts "- #{name} (type: #{type})".indent
|
39
|
+
end
|
38
40
|
end
|
39
41
|
end
|
40
|
-
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
def build
|
44
|
+
puts "Building #{File.basename(@file_path, '.json')}:".to_green
|
45
|
+
stream_cmd("packer build #{build_options} #{@file_path}")
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
# specify the builders if any were passed
|
49
|
+
def build_options
|
50
|
+
"-only=#{@specified_builders.join(',')}" unless @specified_builders.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
def stream_cmd(command)
|
54
|
+
PTY.spawn(command) do |r, _w, pid|
|
55
|
+
begin
|
56
|
+
r.each { |line| print line; }
|
57
|
+
rescue Errno::EIO
|
58
|
+
# this is an expected behavior when an app is done sending output
|
59
|
+
ensure
|
60
|
+
Process.wait(pid)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
exit_error unless $CHILD_STATUS == 0
|
64
|
+
rescue PTY::ChildExited
|
65
|
+
exit_error unless $CHILD_STATUS == 0
|
66
|
+
end
|
51
67
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
rescue Errno::EIO
|
57
|
-
end
|
68
|
+
# throw and error message and exit with and error status
|
69
|
+
def exit_error
|
70
|
+
puts "An error occured during the packer run.\nSee the above output for more details.".to_red
|
71
|
+
exit!
|
58
72
|
end
|
59
|
-
rescue PTY::ChildExited
|
60
|
-
puts 'The child process exited!'
|
61
73
|
end
|
62
74
|
end
|
data/lib/orchestrator.rb
CHANGED
@@ -16,86 +16,90 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
19
|
+
module Singel
|
20
|
+
# class to control validation of configs / prereqs and to
|
21
|
+
# fire off the individual executor instances to build each template
|
22
|
+
class SingelOrchestrator
|
23
|
+
include Singel::Config
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
puts "-----------------------------------------\n\n"
|
25
|
+
def initialize
|
26
|
+
@options = Singel::Config.config
|
27
|
+
end
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
# main method used to kick off the run
|
30
|
+
def run
|
31
|
+
puts "\nsingel - unified image creation tool"
|
32
|
+
puts "-----------------------------------------\n\n"
|
35
33
|
|
36
|
-
|
37
|
-
|
34
|
+
check_dirs
|
35
|
+
check_executables
|
36
|
+
@templates = find_templates
|
37
|
+
check_aws_keys
|
38
38
|
|
39
|
-
|
40
|
-
def check_dirs
|
41
|
-
unless Dir.exist?(@options[:packer_dir])
|
42
|
-
puts "#{@options[:packer_dir]} not present.".to_red
|
43
|
-
puts "See help for information on specifying an alternate dir.\n".to_red
|
44
|
-
exit!
|
39
|
+
execute_command(ARGV[0])
|
45
40
|
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# make a test connection using the AWS keys to determine if they're valid
|
49
|
-
def check_aws_keys
|
50
|
-
ec2 = Aws::EC2::Client.new(region: 'us-east-1')
|
51
|
-
ec2.describe_instance_status
|
52
|
-
rescue
|
53
|
-
puts 'Could not connect to EC2. Check your local AWS credentials before continuing.'.to_red
|
54
|
-
exit!
|
55
|
-
end
|
56
41
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
puts "Could not find #{name} binary #{binary}. You must install #{name} before continuing.".to_red unless $CHILD_STATUS
|
42
|
+
# check to make sure the packer dir exists
|
43
|
+
def check_dirs
|
44
|
+
unless Dir.exist?(@options[:packer_dir])
|
45
|
+
puts "#{@options[:packer_dir]} not present.".to_red
|
46
|
+
puts "See help for information on specifying an alternate dir.\n".to_red
|
63
47
|
exit!
|
64
48
|
end
|
65
49
|
end
|
66
|
-
end
|
67
50
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
51
|
+
# make a test connection using the AWS keys to determine if they're valid
|
52
|
+
def check_aws_keys
|
53
|
+
ec2 = Aws::EC2::Client.new(region: 'us-east-1')
|
54
|
+
ec2.describe_instance_status
|
55
|
+
rescue
|
56
|
+
puts 'Could not connect to EC2. Check your local AWS credentials before continuing.'.to_red
|
57
|
+
exit!
|
58
|
+
end
|
59
|
+
|
60
|
+
# check to make sure the prereq binaries present
|
61
|
+
def check_executables
|
62
|
+
{ 'Virtualbox' => 'vboxwebsrv', 'Packer' => 'packer' }.each_pair do |name, binary|
|
63
|
+
`which #{binary} 2>&1`
|
64
|
+
unless $CHILD_STATUS.success?
|
65
|
+
puts "Could not find #{name} binary #{binary}. You must install #{name} before continuing.".to_red unless $CHILD_STATUS
|
66
|
+
exit!
|
67
|
+
end
|
75
68
|
end
|
69
|
+
end
|
76
70
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
71
|
+
# find the available packer templates on the host
|
72
|
+
def find_templates
|
73
|
+
# find packer templates on disk since none were passed via args
|
74
|
+
if @options[:templates].empty?
|
75
|
+
templates = []
|
76
|
+
Dir.foreach(@options[:packer_dir]) do |item|
|
77
|
+
templates << File.join(@options[:packer_dir], item) if File.extname(item).downcase == '.json'
|
78
|
+
end
|
79
|
+
|
80
|
+
# throw and error and exist if we still dont find any templates
|
81
|
+
if templates.empty?
|
82
|
+
puts "No packer templates found in the 'packer' dir. Cannot continue.".to_red
|
83
|
+
exit!
|
84
|
+
end
|
85
|
+
templates
|
86
|
+
else # parse the arg provided template list
|
87
|
+
@options[:templates].map { |x| File.join(@options[:packer_dir], x) }
|
81
88
|
end
|
82
|
-
templates
|
83
|
-
else # parse the arg provided template list
|
84
|
-
@options[:templates].map { |x| File.join(@options[:packer_dir], x) }
|
85
89
|
end
|
86
|
-
end
|
87
90
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
91
|
+
# run the passed command per packer template
|
92
|
+
def execute_command(cmd)
|
93
|
+
@templates.each do |t|
|
94
|
+
template = PackerTemplate.new(t)
|
95
|
+
executor = PackerExecutor.new(template, @options[:builders])
|
96
|
+
puts "Packer template validation for #{template.path} failed.\n".to_red unless template.validates?
|
97
|
+
begin
|
98
|
+
executor.send(cmd)
|
99
|
+
rescue NoMethodError
|
100
|
+
puts "Action \"#{cmd}\" not found. Cannot continue".to_red
|
101
|
+
exit!
|
102
|
+
end
|
99
103
|
end
|
100
104
|
end
|
101
105
|
end
|
data/lib/string.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Tim Smith (<tim@cozy.co>)
|
4
|
+
# Copyright:: Copyright (c) 2014 Tim Smith
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
# add a few methods for manipulating text
|
20
|
+
class String
|
21
|
+
def to_green
|
22
|
+
"\033[32m#{self}\033[0m"
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_red
|
26
|
+
"\033[31m#{self}\033[0m"
|
27
|
+
end
|
28
|
+
|
29
|
+
def indent(double_space_count = 1)
|
30
|
+
double_space_count.times { insert(0, ' ') }
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
data/lib/template.rb
CHANGED
@@ -16,38 +16,38 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
|
19
|
+
module Singel
|
20
|
+
# instance of a single packer template with methods to validate and extract data
|
21
|
+
class PackerTemplate
|
22
|
+
attr_accessor :path, :name
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@path = File.expand_path(path)
|
27
|
-
@name = File.basename(@path, '.json')
|
28
|
-
@file = File.read(path)
|
29
|
-
end
|
24
|
+
def initialize(path)
|
25
|
+
@path = File.expand_path(path)
|
26
|
+
@name = File.basename(@path, '.json')
|
27
|
+
@file = File.read(path)
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def json
|
31
|
+
@parsed || @parsed = JSON.parse(@file)
|
32
|
+
end
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
def builders
|
35
|
+
json['builders'].map { |b| b['name'] }
|
36
|
+
end
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
def builders_hash
|
39
|
+
builders = {}
|
40
|
+
json['builders'].each do |builder|
|
41
|
+
builders[builder['name']] = builder['type']
|
42
|
+
end
|
43
|
+
builders
|
43
44
|
end
|
44
|
-
builders
|
45
|
-
end
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
# shell out to packer to validate the config files for correctness
|
47
|
+
def validates?
|
48
|
+
Dir.chdir(File.dirname(@path))
|
49
|
+
`packer validate #{@path} 2>&1`
|
50
|
+
$CHILD_STATUS.success? ? true : false
|
51
|
+
end
|
52
52
|
end
|
53
53
|
end
|
data/lib/uploader.rb
CHANGED
@@ -16,13 +16,15 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
module Singel
|
20
|
+
# uploads the packer artifacts to S3
|
21
|
+
class SingelUploader
|
22
|
+
def initialize(template)
|
23
|
+
@file_path = template
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
def push
|
27
|
+
puts "- Would be uploading the artifact for #{File.basename(@file_path, '.json')}".to_green.indent
|
28
|
+
end
|
27
29
|
end
|
28
30
|
end
|
data/singel.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: singel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-core
|
@@ -68,8 +68,10 @@ files:
|
|
68
68
|
- README.md
|
69
69
|
- Rakefile
|
70
70
|
- bin/singel
|
71
|
+
- lib/config.rb
|
71
72
|
- lib/executor.rb
|
72
73
|
- lib/orchestrator.rb
|
74
|
+
- lib/string.rb
|
73
75
|
- lib/template.rb
|
74
76
|
- lib/uploader.rb
|
75
77
|
- singel.gemspec
|