image_builder 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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