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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rubocop.yml +16 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +32 -0
  7. data/Rakefile +29 -0
  8. data/bin/image_builder +234 -0
  9. data/image_builder.gemspec +30 -0
  10. data/lib/image_builder.rb +38 -0
  11. data/lib/image_builder/backends/backend_base.rb +10 -0
  12. data/lib/image_builder/backends/packer.rb +109 -0
  13. data/lib/image_builder/builders/aws_base.rb +101 -0
  14. data/lib/image_builder/builders/aws_chroot.rb +33 -0
  15. data/lib/image_builder/builders/aws_ebs.rb +15 -0
  16. data/lib/image_builder/builders/aws_instance.rb +45 -0
  17. data/lib/image_builder/builders/builder_base.rb +12 -0
  18. data/lib/image_builder/builders/null.rb +39 -0
  19. data/lib/image_builder/post_processors/compress.rb +24 -0
  20. data/lib/image_builder/post_processors/post_processors_base.rb +10 -0
  21. data/lib/image_builder/post_processors/vagrant.rb +41 -0
  22. data/lib/image_builder/provisioners/chef_base.rb +96 -0
  23. data/lib/image_builder/provisioners/chef_client.rb +115 -0
  24. data/lib/image_builder/provisioners/chef_solo.rb +33 -0
  25. data/lib/image_builder/provisioners/file.rb +26 -0
  26. data/lib/image_builder/provisioners/provisioner_base.rb +10 -0
  27. data/lib/image_builder/provisioners/shell.rb +47 -0
  28. data/lib/image_builder/version.rb +4 -0
  29. data/spec/aws_chroot_builder_spec.rb +30 -0
  30. data/spec/aws_ebs_builder_spec.rb +30 -0
  31. data/spec/aws_instance_builder_spec.rb +30 -0
  32. data/spec/chef_client_provisioner_spec.rb +32 -0
  33. data/spec/chef_solo_provisioner_spec.rb +28 -0
  34. data/spec/compress_postprocessor_spec.rb +15 -0
  35. data/spec/fixtures/test-knife.rb +40 -0
  36. data/spec/null_builder_spec.rb +21 -0
  37. data/spec/packer_backend_spec.rb +145 -0
  38. data/spec/vagrant_postprocessor_spec.rb +20 -0
  39. metadata +236 -0
@@ -0,0 +1,10 @@
1
+ require_relative '../../image_builder.rb'
2
+
3
+ module ImageBuilder
4
+ module Backends
5
+ # Generic class doc comment
6
+ class Base
7
+ include ImageBuilder
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,109 @@
1
+ require_relative './backend_base.rb'
2
+ require 'json'
3
+ require 'mixlib/shellout'
4
+ require 'tempfile'
5
+
6
+ # rubocop:disable Style/ClassVars
7
+
8
+ module ImageBuilder
9
+ module Backends
10
+ # Generic class doc comment
11
+ class Packer < ImageBuilder::Backends::Base
12
+ attr_accessor :description
13
+ attr_accessor :min_packer_version
14
+ attr_accessor :builders
15
+ attr_accessor :post_processors
16
+ attr_accessor :provisioners
17
+ attr_accessor :variables
18
+
19
+ @@default_path = ['/bin', '/usr/bin', '/sbin', '/usr/sbin', '/usr/local/bin']
20
+ @@default_path << ::File.join(ENV['GEM_HOME'], 'bin') if ENV.key? 'GEM_HOME'
21
+
22
+ @@packer_exe = 'packer'
23
+
24
+ def initialize
25
+ @builders = []
26
+ @post_processors = []
27
+ @provisioners = []
28
+ @variables = {}
29
+ end
30
+
31
+ def self.packer_path(path)
32
+ @@packer_exe = ::File.expand_path(path)
33
+ @@default_path.unshift ::File.dirname(::File.expand_path(@@packer_exe))
34
+ end
35
+
36
+ def self.packer_path=(path)
37
+ packer_path(path)
38
+ end
39
+
40
+ # rubocop:disable Metrics/LineLength
41
+ def add_builder(builder_obj)
42
+ fail ArgumentError, 'Invalid builder object, does not respond to packer_hash()' unless builder_obj.respond_to?(:packer_hash)
43
+ @builders << builder_obj.packer_hash
44
+ end
45
+
46
+ def add_post_processor(post_obj)
47
+ fail ArgumentError, 'Invalid post-processor object, does not respond to packer_hash()' unless post_obj.respond_to?(:packer_hash)
48
+ @post_processors << post_obj.packer_hash
49
+ end
50
+
51
+ def add_provisioner(provisioner_obj)
52
+ fail ArgumentError, 'Invalid provisioner object, does not respond to packer_hash()' unless provisioner_obj.respond_to?(:packer_hash)
53
+ @provisioners << provisioner_obj.packer_hash
54
+ end
55
+ # rubocop:enable Metrics/LineLength
56
+
57
+ def add_variable(name, value = '')
58
+ @variables[name] = value
59
+ end
60
+
61
+ def build(args = [])
62
+ validate
63
+
64
+ cmd = [@@packer_exe, 'build'].concat(args)
65
+ cmd << '-'
66
+
67
+ # Some provisioners may take a long time to run without giving output (applying OS updates via Chef
68
+ # to CentOS6 comes to mind), so extend the timeout to an hour.
69
+ shellout = Mixlib::ShellOut.new(cmd, env: { 'PATH' => @@default_path.join(':') }, input: to_json, timeout: 3600)
70
+ shellout.live_stdout = STDOUT
71
+ shellout.live_stderr = STDERR
72
+ shellout.run_command
73
+ shellout.error!
74
+
75
+ true
76
+ end
77
+
78
+ def validate(args = [])
79
+ cmd = [@@packer_exe, 'validate'].concat(args)
80
+ cmd << '-'
81
+
82
+ shellout = Mixlib::ShellOut.new(cmd, env: { 'PATH' => @@default_path.join(':') }, input: to_json)
83
+ shellout.inspect
84
+ shellout.run_command
85
+ shellout.error!
86
+
87
+ shellout.stdout
88
+
89
+ true
90
+ end
91
+
92
+ def to_json
93
+ config = {}
94
+
95
+ attr_to_hash(config, :description)
96
+ attr_to_hash(config, :min_packer_version)
97
+ attr_to_hash(config, :variables)
98
+ attr_to_hash(config, :builders, true)
99
+ attr_to_hash(config, :provisioners)
100
+
101
+ # Special handling for post-processors, since the packer config name uses '-', and ruby doesn't
102
+ # like those (you know....subtraction operator, and all that)
103
+ config['post-processors'] = @post_processors unless @post_processors.nil? || @post_processors.empty?
104
+
105
+ config.to_json
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,101 @@
1
+ require_relative './builder_base.rb'
2
+
3
+ module ImageBuilder
4
+ module Builders
5
+ module AWS
6
+ # Generic class doc comment
7
+ class Base < ImageBuilder::Builders::Base
8
+ attr_accessor :access_key
9
+ attr_accessor :ami_name
10
+ attr_accessor :instance_type
11
+ attr_accessor :region
12
+ attr_accessor :secret_key
13
+ attr_accessor :source_ami
14
+ attr_accessor :ssh_username
15
+ # - opt -
16
+ attr_accessor :ami_block_device_mappings
17
+ attr_accessor :ami_description
18
+ attr_accessor :ami_groups
19
+ attr_accessor :ami_product_codes
20
+ attr_accessor :ami_regions
21
+ attr_accessor :ami_users
22
+ attr_accessor :ami_virtualization_type
23
+ attr_accessor :associate_public_ip_address
24
+ attr_accessor :availability_zone
25
+ attr_accessor :enhanced_networking
26
+ attr_accessor :iam_instance_profile
27
+ attr_accessor :launch_block_device_mappings
28
+ attr_accessor :run_tags
29
+ attr_accessor :security_group_id
30
+ attr_accessor :security_group_ids
31
+ attr_accessor :spot_price
32
+ attr_accessor :spot_price_auto_product
33
+ attr_accessor :ssh_port
34
+ attr_accessor :ssh_private_key_file
35
+ attr_accessor :ssh_private_ip
36
+ attr_accessor :ssh_timeout
37
+ attr_accessor :subnet_id
38
+ attr_accessor :tags
39
+ attr_accessor :temporary_key_pair_name
40
+ attr_accessor :token
41
+ attr_accessor :user_data
42
+ attr_accessor :user_data_file
43
+ attr_accessor :vpc_id
44
+
45
+ attr_reader :type
46
+
47
+ def initialize
48
+ @access_key = ENV['AWS_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY']
49
+ @secret_key = ENV['AWS_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_KEY']
50
+ @region = 'us-east-1'
51
+ end
52
+
53
+ def self.default_block_device_mappings
54
+ [
55
+ { device_name: '/dev/sdf', virtual_name: 'ephemeral0' },
56
+ { device_name: '/dev/sdg', virtual_name: 'ephemeral1' },
57
+ { device_name: '/dev/sdh', virtual_name: 'ephemeral2' },
58
+ { device_name: '/dev/sdi', virtual_name: 'ephemeral3' }
59
+ ]
60
+ end
61
+
62
+ def self.default_launch_block_device_mappings
63
+ [
64
+ { device_name: '/dev/sdb', no_device: true },
65
+ { device_name: '/dev/sdc', no_device: true },
66
+ { device_name: '/dev/sdd', no_device: true }
67
+ ]
68
+ end
69
+
70
+ def packer_hash
71
+ hash = {}
72
+
73
+ req_attrs = [
74
+ :type, :name, :access_key, :ami_name, :instance_type,
75
+ :region, :secret_key, :source_ami, :ssh_username
76
+ ]
77
+
78
+ opt_attrs = [
79
+ :ami_description, :ami_groups, :ami_product_codes, :ami_regions, :ami_regions, :ami_users,
80
+ :ami_virtualization_type, :associate_public_ip_address, :availability_zone, :enhanced_networking,
81
+ :iam_instance_profile, :run_tags, :security_group_id, :security_group_ids, :spot_price,
82
+ :spot_price_auto_product, :ssh_port, :ssh_private_key_file, :ssh_private_ip, :ssh_timeout,
83
+ :subnet_id, :tags, :temporary_key_pair_name, :token, :user_data, :user_data_file, :vpc_id,
84
+ :launch_block_device_mappings, :ami_block_device_mappings
85
+ ]
86
+
87
+ # Required attrs
88
+ req_attrs.each do |a|
89
+ attr_to_hash(hash, a, true)
90
+ end
91
+
92
+ opt_attrs.each do |a|
93
+ attr_to_hash(hash, a)
94
+ end
95
+
96
+ hash
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,33 @@
1
+ require_relative './aws_base.rb'
2
+
3
+ module ImageBuilder
4
+ module Builders
5
+ module AWS
6
+ # Generic class doc comment
7
+ class Chroot < ImageBuilder::Builders::AWS::Base
8
+ attr_accessor :chroot_mounts
9
+ attr_accessor :command_wrapper
10
+ attr_accessor :copy_files
11
+ attr_accessor :device_path
12
+ attr_accessor :mount_path
13
+
14
+ def initialize
15
+ super
16
+ @type = 'amazon-chroot'
17
+ end
18
+
19
+ def packer_hash
20
+ hash = super
21
+
22
+ attr_to_hash(hash, :chroot_mounts)
23
+ attr_to_hash(hash, :command_wrapper)
24
+ attr_to_hash(hash, :copy_files)
25
+ attr_to_hash(hash, :device_path)
26
+ attr_to_hash(hash, :mount_path)
27
+
28
+ hash
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ require_relative './aws_base.rb'
2
+
3
+ module ImageBuilder
4
+ module Builders
5
+ module AWS
6
+ # Generic class doc comment
7
+ class EBS < ImageBuilder::Builders::AWS::Base
8
+ def initialize
9
+ super
10
+ @type = 'amazon-ebs'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ require_relative './aws_base.rb'
2
+
3
+ module ImageBuilder
4
+ module Builders
5
+ module AWS
6
+ # Generic class doc comment
7
+ class Instance < ImageBuilder::Builders::AWS::Base
8
+ attr_accessor :account_id
9
+ attr_accessor :s3_bucket
10
+ attr_accessor :x509_cert_path
11
+ attr_accessor :x509_key_path
12
+ # - opt -
13
+ attr_accessor :bundle_destination
14
+ attr_accessor :bundle_prefix
15
+ attr_accessor :bundle_upload_command
16
+ attr_accessor :bundle_vol_command
17
+ attr_accessor :x509_upload_path
18
+
19
+ def initialize
20
+ super
21
+ @type = 'amazon-instance'
22
+ end
23
+
24
+ def packer_hash
25
+ hash = super
26
+
27
+ # Required
28
+ attr_to_hash(hash, :account_id, true)
29
+ attr_to_hash(hash, :s3_bucket, true)
30
+ attr_to_hash(hash, :x509_cert_path, true)
31
+ attr_to_hash(hash, :x509_key_path, true)
32
+
33
+ # Optional
34
+ attr_to_hash(hash, :bundle_destination)
35
+ attr_to_hash(hash, :bundle_prefix)
36
+ attr_to_hash(hash, :bundle_upload_command)
37
+ attr_to_hash(hash, :bundle_vol_command)
38
+ attr_to_hash(hash, :x509_upload_path)
39
+
40
+ hash
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../../image_builder.rb'
2
+
3
+ module ImageBuilder
4
+ module Builders
5
+ # Generic class doc comment
6
+ class Base
7
+ include ImageBuilder
8
+
9
+ attr_accessor :name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,39 @@
1
+ require_relative './builder_base.rb'
2
+ require 'etc'
3
+
4
+ module ImageBuilder
5
+ module Builders
6
+ # Generic class doc comment
7
+ class Null < ImageBuilder::Builders::Base
8
+ attr_accessor :host
9
+ attr_accessor :ssh_password
10
+ attr_accessor :ssh_username
11
+ attr_accessor :ssh_private_key_file
12
+ attr_accessor :port
13
+
14
+ attr_reader :type
15
+
16
+ def initialize
17
+ @type = 'null'
18
+ @host = '127.0.0.1'
19
+ @port = 22
20
+ @ssh_username = Etc.getlogin
21
+ @ssh_private_key_file = ::File.join(::Dir.home, '.ssh', 'id_rsa')
22
+ end
23
+
24
+ def packer_hash
25
+ hash = {}
26
+
27
+ attr_to_hash(hash, :type, true)
28
+ attr_to_hash(hash, :name, true)
29
+ attr_to_hash(hash, :host, true)
30
+ attr_to_hash(hash, :ssh_username, true)
31
+ attr_to_hash(hash, :ssh_password)
32
+ attr_to_hash(hash, :ssh_private_key_file)
33
+ attr_to_hash(hash, :port)
34
+
35
+ hash
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ require_relative './post_processors_base.rb'
2
+
3
+ module ImageBuilder
4
+ module PostProcessors
5
+ # Generic class doc comment
6
+ class Compress < ImageBuilder::PostProcessors::Base
7
+ attr_accessor :output
8
+ attr_reader :type
9
+
10
+ def initialize
11
+ @type = 'compress'
12
+ end
13
+
14
+ def packer_hash
15
+ hash = {}
16
+
17
+ attr_to_hash(hash, :type, true)
18
+ attr_to_hash(hash, :output, true)
19
+
20
+ hash
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ require_relative '../../image_builder.rb'
2
+
3
+ module ImageBuilder
4
+ module PostProcessors
5
+ # Generic class doc comment
6
+ class Base
7
+ include ImageBuilder
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,41 @@
1
+ require_relative './post_processors_base.rb'
2
+
3
+ module ImageBuilder
4
+ module PostProcessors
5
+ # Generic class doc comment
6
+ class Vagrant < ImageBuilder::PostProcessors::Base
7
+ attr_accessor :compression_level
8
+ attr_accessor :include
9
+ attr_accessor :keep_input_artifact
10
+ attr_accessor :output
11
+ attr_accessor :vagrantfile_template
12
+ attr_accessor :override
13
+
14
+ attr_reader :type
15
+
16
+ def initialize
17
+ @type = 'vagrant'
18
+ @compression_level = 6
19
+ @keep_input_artifact = false
20
+ end
21
+
22
+ def add_override(provider, override_hash)
23
+ @override[provider] = override_hash
24
+ end
25
+
26
+ def packer_hash
27
+ hash = {}
28
+
29
+ attr_to_hash(hash, :type, true)
30
+ attr_to_hash(hash, :compression_level)
31
+ attr_to_hash(hash, :include)
32
+ attr_to_hash(hash, :keep_input_artifact)
33
+ attr_to_hash(hash, :output)
34
+ attr_to_hash(hash, :vagrantfile_template)
35
+ attr_to_hash(hash, :override)
36
+
37
+ hash
38
+ end
39
+ end
40
+ end
41
+ end