image_builder 0.0.1
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 +7 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/Rakefile +29 -0
- data/bin/image_builder +234 -0
- data/image_builder.gemspec +30 -0
- data/lib/image_builder.rb +38 -0
- data/lib/image_builder/backends/backend_base.rb +10 -0
- data/lib/image_builder/backends/packer.rb +109 -0
- data/lib/image_builder/builders/aws_base.rb +101 -0
- data/lib/image_builder/builders/aws_chroot.rb +33 -0
- data/lib/image_builder/builders/aws_ebs.rb +15 -0
- data/lib/image_builder/builders/aws_instance.rb +45 -0
- data/lib/image_builder/builders/builder_base.rb +12 -0
- data/lib/image_builder/builders/null.rb +39 -0
- data/lib/image_builder/post_processors/compress.rb +24 -0
- data/lib/image_builder/post_processors/post_processors_base.rb +10 -0
- data/lib/image_builder/post_processors/vagrant.rb +41 -0
- data/lib/image_builder/provisioners/chef_base.rb +96 -0
- data/lib/image_builder/provisioners/chef_client.rb +115 -0
- data/lib/image_builder/provisioners/chef_solo.rb +33 -0
- data/lib/image_builder/provisioners/file.rb +26 -0
- data/lib/image_builder/provisioners/provisioner_base.rb +10 -0
- data/lib/image_builder/provisioners/shell.rb +47 -0
- data/lib/image_builder/version.rb +4 -0
- data/spec/aws_chroot_builder_spec.rb +30 -0
- data/spec/aws_ebs_builder_spec.rb +30 -0
- data/spec/aws_instance_builder_spec.rb +30 -0
- data/spec/chef_client_provisioner_spec.rb +32 -0
- data/spec/chef_solo_provisioner_spec.rb +28 -0
- data/spec/compress_postprocessor_spec.rb +15 -0
- data/spec/fixtures/test-knife.rb +40 -0
- data/spec/null_builder_spec.rb +21 -0
- data/spec/packer_backend_spec.rb +145 -0
- data/spec/vagrant_postprocessor_spec.rb +20 -0
- metadata +236 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
require_relative './provisioner_base.rb'
|
2
|
+
|
3
|
+
# rubocop:disable Style/EmptyLineBetweenDefs, Style/TrivialAccessors
|
4
|
+
|
5
|
+
module ImageBuilder
|
6
|
+
module Provisioners
|
7
|
+
module Chef
|
8
|
+
# Generic class doc comment
|
9
|
+
class Base < ImageBuilder::Provisioners::Base
|
10
|
+
attr_accessor :cookbook_paths
|
11
|
+
attr_accessor :config_template
|
12
|
+
attr_accessor :encrypted_data_bag_secret_path
|
13
|
+
attr_accessor :execute_command
|
14
|
+
attr_accessor :install_command
|
15
|
+
attr_accessor :json
|
16
|
+
attr_accessor :prevent_sudo
|
17
|
+
attr_accessor :run_list
|
18
|
+
attr_accessor :skip_install
|
19
|
+
attr_accessor :staging_directory
|
20
|
+
|
21
|
+
attr_reader :type
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@prevent_sudo = false
|
25
|
+
@skip_install = false
|
26
|
+
@encrypted_data_bag_secret_path = ENV['ENCRYPTED_DATA_BAG_SECRET']
|
27
|
+
end
|
28
|
+
|
29
|
+
# set attributes from something that looks like a knife.rb file
|
30
|
+
def self.from_file(path)
|
31
|
+
inst = new
|
32
|
+
@knife_file = ::File.expand_path(path)
|
33
|
+
|
34
|
+
# For knife hash params in knife.rb
|
35
|
+
knife = {} # rubocop:disable Lint/UselessAssignment
|
36
|
+
inst.instance_eval(IO.read(@knife_file))
|
37
|
+
|
38
|
+
inst
|
39
|
+
end
|
40
|
+
|
41
|
+
# Map knife.rb config options to their corresponding object attributes
|
42
|
+
# the :encrypted_data_bag_secret_path attribute is specific to the chef-solo
|
43
|
+
# provisioner, but we'll need it for all chef provisioners, since we need to
|
44
|
+
# upload it to the node before provisioning via the chef-client provisioner
|
45
|
+
def encrypted_data_bag_secret(sec)
|
46
|
+
@encrypted_data_bag_secret_path = sec
|
47
|
+
end
|
48
|
+
|
49
|
+
# While not used explicitly in the chef-client provisioner, this will give
|
50
|
+
# us consistent behavior across chef provisioners if we need to do a local
|
51
|
+
# cookbook lookup
|
52
|
+
def cookbook_path(path)
|
53
|
+
@cookbook_paths = [ENV['COOKBOOK_PATH']] << path
|
54
|
+
@cookbook_paths.flatten!
|
55
|
+
@cookbook_paths.compact!
|
56
|
+
@cookbook_paths.uniq!
|
57
|
+
end
|
58
|
+
|
59
|
+
def packer_hash
|
60
|
+
hash = { type: @type }
|
61
|
+
|
62
|
+
attr_to_hash(hash, :config_template)
|
63
|
+
attr_to_hash(hash, :execute_command)
|
64
|
+
attr_to_hash(hash, :install_command)
|
65
|
+
attr_to_hash(hash, :json)
|
66
|
+
attr_to_hash(hash, :prevent_sudo)
|
67
|
+
attr_to_hash(hash, :run_list)
|
68
|
+
attr_to_hash(hash, :skip_install)
|
69
|
+
attr_to_hash(hash, :staging_directory)
|
70
|
+
|
71
|
+
hash
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
attr_reader :knife_file
|
77
|
+
|
78
|
+
# These attributes might be found in a knife.rb file, but may not be used for
|
79
|
+
# a specific provisioner. This is only here to ensure the instance_eval in the
|
80
|
+
# from_file method (above) passes
|
81
|
+
def log_level(_lvl) end
|
82
|
+
def log_location(_loc) end
|
83
|
+
def node_name(_name) end
|
84
|
+
def client_key(_key) end
|
85
|
+
def validation_client_name(_client) end
|
86
|
+
def validation_key(_key) end
|
87
|
+
def chef_server_url(_url) end
|
88
|
+
def cache_type(_type) end
|
89
|
+
def cache_options(_opts) end
|
90
|
+
def cookbook_copyright(_x) end
|
91
|
+
def cookbook_email(_mail) end
|
92
|
+
def name(_name = nil) end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require_relative './chef_base.rb'
|
2
|
+
|
3
|
+
# rubocop:disable Style/TrivialAccessors
|
4
|
+
|
5
|
+
module ImageBuilder
|
6
|
+
module Provisioners
|
7
|
+
module Chef
|
8
|
+
# Generic class doc comment
|
9
|
+
class Client < ImageBuilder::Provisioners::Chef::Base
|
10
|
+
attr_accessor :chef_environment
|
11
|
+
attr_accessor :node_name
|
12
|
+
attr_accessor :server_url # required
|
13
|
+
attr_accessor :skip_clean_client
|
14
|
+
attr_accessor :skip_clean_node
|
15
|
+
attr_accessor :validation_client_name
|
16
|
+
attr_accessor :validation_key_path
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
@skip_clean_client = false
|
21
|
+
@skip_clean_node = false
|
22
|
+
@type = 'chef-client'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Map chef-client provisioner knife.rb config options
|
26
|
+
# to their corresponding object attributes
|
27
|
+
def node_name(name = nil)
|
28
|
+
@node_name = name unless name.nil? || name.strip.empty?
|
29
|
+
@node_name
|
30
|
+
end
|
31
|
+
|
32
|
+
def chef_server_url(url)
|
33
|
+
@server_url = url
|
34
|
+
end
|
35
|
+
|
36
|
+
# Since this has an attr_accessor of the same name, need to
|
37
|
+
# write this as a getter & setter method
|
38
|
+
def validation_client_name(name = nil)
|
39
|
+
@validation_client_name = name unless name.nil?
|
40
|
+
@validation_client_name
|
41
|
+
end
|
42
|
+
|
43
|
+
def validation_key(key)
|
44
|
+
@validation_key_path = fixup_key_path(key)
|
45
|
+
end
|
46
|
+
|
47
|
+
def packer_hash
|
48
|
+
hash = super
|
49
|
+
|
50
|
+
# Required attrs
|
51
|
+
attr_to_hash(hash, :server_url, true)
|
52
|
+
|
53
|
+
# Optional attrs
|
54
|
+
attr_to_hash(hash, :chef_environment)
|
55
|
+
attr_to_hash(hash, :node_name)
|
56
|
+
attr_to_hash(hash, :skip_clean_client)
|
57
|
+
attr_to_hash(hash, :skip_clean_node)
|
58
|
+
attr_to_hash(hash, :validation_client_name)
|
59
|
+
attr_to_hash(hash, :validation_key_path)
|
60
|
+
|
61
|
+
hash
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# This may not come in as a valid file after reading knife.rb, try some fixups
|
67
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
68
|
+
def fixup_key_path(path)
|
69
|
+
return path if path.nil? || path.empty?
|
70
|
+
|
71
|
+
unless ::File.exist?(path)
|
72
|
+
file_name = ::File.basename(path)
|
73
|
+
sec_var = @encrypted_data_bag_secret_path
|
74
|
+
sec_env = ENV['ENCRYPTED_DATA_BAG_SECRET']
|
75
|
+
|
76
|
+
# Pearson-centric env vars
|
77
|
+
merle_key = ENV['MERLE_VALIDATOR']
|
78
|
+
path = check_file(merle_key) if valid_path?(merle_key)
|
79
|
+
|
80
|
+
merle = ENV['MERLE']
|
81
|
+
path = check_file(::File.join(merle, file_name)) if valid_path?(merle) && path.nil?
|
82
|
+
|
83
|
+
# 'standard' location checks
|
84
|
+
if valid_path?(@knife_file) && path.nil?
|
85
|
+
dir = ::File.dirname(@knife_file)
|
86
|
+
path = check_file(::File.join(dir, file_name))
|
87
|
+
end
|
88
|
+
|
89
|
+
if valid_path?(sec_var) && path.nil?
|
90
|
+
dir = ::File.dirname(sec_var)
|
91
|
+
path = check_file(::File.join(dir, file_name))
|
92
|
+
end
|
93
|
+
|
94
|
+
if valid_path?(sec_env) && path.nil?
|
95
|
+
dir = ::File.dirname(sec_env)
|
96
|
+
path = check_file(::File.join(dir, file_name))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
path
|
101
|
+
end
|
102
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
103
|
+
|
104
|
+
def check_file(path)
|
105
|
+
return path if ::File.exist?(path)
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def valid_path?(path)
|
110
|
+
!path.nil? && !path.strip.empty?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative './chef_base.rb'
|
2
|
+
|
3
|
+
# rubocop:disable Style/TrivialAccessors
|
4
|
+
|
5
|
+
module ImageBuilder
|
6
|
+
module Provisioners
|
7
|
+
module Chef
|
8
|
+
# Generic class doc comment
|
9
|
+
class Solo < ImageBuilder::Provisioners::Chef::Base
|
10
|
+
attr_accessor :data_bags_path
|
11
|
+
attr_accessor :remote_cookbook_paths
|
12
|
+
attr_accessor :roles_path
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
super
|
16
|
+
@type = 'chef-solo'
|
17
|
+
end
|
18
|
+
|
19
|
+
def packer_hash
|
20
|
+
hash = super
|
21
|
+
|
22
|
+
attr_to_hash(hash, :data_bags_path)
|
23
|
+
attr_to_hash(hash, :remote_cookbook_paths)
|
24
|
+
attr_to_hash(hash, :roles_path)
|
25
|
+
attr_to_hash(hash, :cookbook_paths)
|
26
|
+
attr_to_hash(hash, :encrypted_data_bag_secret_path)
|
27
|
+
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative './provisioner_base.rb'
|
2
|
+
|
3
|
+
module ImageBuilder
|
4
|
+
module Provisioners
|
5
|
+
# Generic class doc comment
|
6
|
+
class File < ImageBuilder::Provisioners::Base
|
7
|
+
attr_accessor :source
|
8
|
+
attr_accessor :destination
|
9
|
+
|
10
|
+
attr_reader :type
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@type = 'file'
|
14
|
+
end
|
15
|
+
|
16
|
+
def packer_hash
|
17
|
+
hash = { type: @type }
|
18
|
+
|
19
|
+
attr_to_hash(hash, :source, true)
|
20
|
+
attr_to_hash(hash, :destination, true)
|
21
|
+
|
22
|
+
hash
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative './provisioner_base.rb'
|
2
|
+
|
3
|
+
module ImageBuilder
|
4
|
+
module Provisioners
|
5
|
+
# Generic class doc comment
|
6
|
+
class Shell < ImageBuilder::Provisioners::Base
|
7
|
+
# Only one of these is allowed/required
|
8
|
+
attr_accessor :inline
|
9
|
+
attr_accessor :script
|
10
|
+
attr_accessor :scripts
|
11
|
+
|
12
|
+
# Optional
|
13
|
+
attr_accessor :binary
|
14
|
+
attr_accessor :environment_vars
|
15
|
+
attr_accessor :execute_command
|
16
|
+
attr_accessor :inline_shebang
|
17
|
+
attr_accessor :remote_path
|
18
|
+
attr_accessor :start_retry_timeout
|
19
|
+
|
20
|
+
attr_reader :type
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@type = 'shell'
|
24
|
+
end
|
25
|
+
|
26
|
+
def packer_hash
|
27
|
+
hash = { type: @type }
|
28
|
+
|
29
|
+
# Let packer enforce the validation requirements
|
30
|
+
# for these attributes, don't make them required
|
31
|
+
attr_to_hash(hash, :inline)
|
32
|
+
attr_to_hash(hash, :script)
|
33
|
+
attr_to_hash(hash, :scripts)
|
34
|
+
|
35
|
+
# Optional attrs
|
36
|
+
attr_to_hash(hash, :binary)
|
37
|
+
attr_to_hash(hash, :environment_vars)
|
38
|
+
attr_to_hash(hash, :execute_command)
|
39
|
+
attr_to_hash(hash, :inline_shebang)
|
40
|
+
attr_to_hash(hash, :remote_path)
|
41
|
+
attr_to_hash(hash, :start_retry_timeout)
|
42
|
+
|
43
|
+
hash
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../lib/image_builder/builders/aws_chroot.rb'
|
2
|
+
|
3
|
+
describe ImageBuilder::Builders::AWS::Chroot do
|
4
|
+
before(:each) do
|
5
|
+
@obj = ImageBuilder::Builders::AWS::Chroot.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has the expected default block device mappings as a class attribute' do
|
9
|
+
expected = [
|
10
|
+
{ device_name: '/dev/sdf', virtual_name: 'ephemeral0' },
|
11
|
+
{ device_name: '/dev/sdg', virtual_name: 'ephemeral1' },
|
12
|
+
{ device_name: '/dev/sdh', virtual_name: 'ephemeral2' },
|
13
|
+
{ device_name: '/dev/sdi', virtual_name: 'ephemeral3' }
|
14
|
+
]
|
15
|
+
|
16
|
+
devs = ImageBuilder::Builders::AWS::Chroot.default_block_device_mappings
|
17
|
+
|
18
|
+
expect(devs).to eql expected
|
19
|
+
expect(devs[1][:device_name]).to eql '/dev/sdg'
|
20
|
+
expect(devs[1][:virtual_name]).to eql 'ephemeral1'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'has the correct packer type' do
|
24
|
+
expect(@obj.type).to eql 'amazon-chroot'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'implements packer_hash()' do
|
28
|
+
expect(@obj.respond_to? :packer_hash).to be true
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../lib/image_builder/builders/aws_ebs.rb'
|
2
|
+
|
3
|
+
describe ImageBuilder::Builders::AWS::EBS do
|
4
|
+
before(:each) do
|
5
|
+
@obj = ImageBuilder::Builders::AWS::EBS.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has the expected default block device mappings as a class attribute' do
|
9
|
+
expected = [
|
10
|
+
{ device_name: '/dev/sdf', virtual_name: 'ephemeral0' },
|
11
|
+
{ device_name: '/dev/sdg', virtual_name: 'ephemeral1' },
|
12
|
+
{ device_name: '/dev/sdh', virtual_name: 'ephemeral2' },
|
13
|
+
{ device_name: '/dev/sdi', virtual_name: 'ephemeral3' }
|
14
|
+
]
|
15
|
+
|
16
|
+
devs = ImageBuilder::Builders::AWS::EBS.default_block_device_mappings
|
17
|
+
|
18
|
+
expect(devs).to eql expected
|
19
|
+
expect(devs[1][:device_name]).to eql '/dev/sdg'
|
20
|
+
expect(devs[1][:virtual_name]).to eql 'ephemeral1'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'has the correct packer type' do
|
24
|
+
expect(@obj.type).to eql 'amazon-ebs'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'implements packer_hash()' do
|
28
|
+
expect(@obj.respond_to? :packer_hash).to be true
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../lib/image_builder/builders/aws_instance.rb'
|
2
|
+
|
3
|
+
describe ImageBuilder::Builders::AWS::Instance do
|
4
|
+
before(:each) do
|
5
|
+
@obj = ImageBuilder::Builders::AWS::Instance.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has the expected default block device mappings as a class attribute' do
|
9
|
+
expected = [
|
10
|
+
{ device_name: '/dev/sdf', virtual_name: 'ephemeral0' },
|
11
|
+
{ device_name: '/dev/sdg', virtual_name: 'ephemeral1' },
|
12
|
+
{ device_name: '/dev/sdh', virtual_name: 'ephemeral2' },
|
13
|
+
{ device_name: '/dev/sdi', virtual_name: 'ephemeral3' }
|
14
|
+
]
|
15
|
+
|
16
|
+
devs = ImageBuilder::Builders::AWS::Instance.default_block_device_mappings
|
17
|
+
|
18
|
+
expect(devs).to eql expected
|
19
|
+
expect(devs[1][:device_name]).to eql '/dev/sdg'
|
20
|
+
expect(devs[1][:virtual_name]).to eql 'ephemeral1'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'has the correct packer type' do
|
24
|
+
expect(@obj.type).to eql 'amazon-instance'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'implements packer_hash()' do
|
28
|
+
expect(@obj.respond_to? :packer_hash).to be true
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative '../lib/image_builder/provisioners/chef_client.rb'
|
2
|
+
|
3
|
+
describe ImageBuilder::Provisioners::Chef::Client do
|
4
|
+
before(:each) do
|
5
|
+
@obj = ImageBuilder::Provisioners::Chef::Client.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has the expected default attributes' do
|
9
|
+
expect(@obj.prevent_sudo).to be false
|
10
|
+
expect(@obj.skip_install).to be false
|
11
|
+
expect(@obj.skip_clean_client).to be false
|
12
|
+
expect(@obj.skip_clean_node).to be false
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'loads the expected parameters from a file as a class method' do
|
16
|
+
# @obj.from_file(::File.join(::File.dirname(__FILE__), 'fixtures', 'test-knife.rb'))
|
17
|
+
obj = ImageBuilder::Provisioners::Chef::Client.from_file(::File.join(::File.dirname(__FILE__), 'fixtures', 'test-knife.rb'))
|
18
|
+
|
19
|
+
expect(obj.validation_client_name).to eql 'chef-validator'
|
20
|
+
expect(obj.validation_key_path).to eql '/dev/null'
|
21
|
+
expect(obj.server_url).to eql 'https://chef.chefserver.com/'
|
22
|
+
expect(obj.encrypted_data_bag_secret_path).to eql ENV['ENCRYPTED_DATA_BAG_SECRET']
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has the correct packer type' do
|
26
|
+
expect(@obj.type).to eql 'chef-client'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'implements packer_hash()' do
|
30
|
+
expect(@obj.respond_to? :packer_hash).to be true
|
31
|
+
end
|
32
|
+
end
|