builderator 0.3.15 → 1.0.0.pre.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +9 -0
- data/Gemfile.lock +440 -0
- data/README.md +72 -18
- data/Rakefile +1 -2
- data/VERSION +1 -1
- data/bin/build-clean +102 -0
- data/bin/build-data +45 -0
- data/builderator.gemspec +7 -4
- data/docs/configuration.md +154 -0
- data/docs/configuration/cookbook.md +19 -0
- data/docs/configuration/profile.md +71 -0
- data/docs/versioning.md +65 -0
- data/lib/builderator.rb +3 -0
- data/lib/builderator/config.rb +93 -0
- data/lib/builderator/config/attributes.rb +287 -0
- data/lib/builderator/config/defaults.rb +163 -0
- data/lib/builderator/config/file.rb +336 -0
- data/lib/builderator/config/rash.rb +80 -0
- data/lib/builderator/control/cleaner.rb +138 -0
- data/lib/builderator/control/cookbook.rb +16 -0
- data/lib/builderator/control/data.rb +16 -0
- data/lib/builderator/control/data/image.rb +98 -0
- data/lib/builderator/control/version.rb +128 -0
- data/lib/builderator/control/version/auto.rb +48 -0
- data/lib/builderator/control/version/bump.rb +82 -0
- data/lib/builderator/control/version/comparable.rb +77 -0
- data/lib/builderator/control/version/git.rb +45 -0
- data/lib/builderator/control/version/scm.rb +92 -0
- data/lib/builderator/interface.rb +67 -0
- data/lib/builderator/interface/berkshelf.rb +38 -0
- data/lib/builderator/interface/packer.rb +75 -0
- data/lib/builderator/interface/vagrant.rb +31 -0
- data/lib/builderator/metadata.rb +5 -3
- data/lib/builderator/model/cleaner.rb +49 -0
- data/lib/builderator/model/cleaner/images.rb +93 -0
- data/lib/builderator/model/cleaner/instances.rb +58 -0
- data/lib/builderator/model/cleaner/launch_configs.rb +47 -0
- data/lib/builderator/model/cleaner/scaling_groups.rb +45 -0
- data/lib/builderator/model/cleaner/snapshots.rb +50 -0
- data/lib/builderator/model/cleaner/volumes.rb +48 -0
- data/lib/builderator/patch/berkshelf.rb +18 -0
- data/lib/builderator/patch/thor-actions.rb +47 -0
- data/lib/builderator/tasks.rb +127 -17
- data/lib/builderator/tasks/berkshelf.rb +63 -0
- data/lib/builderator/tasks/packer.rb +17 -56
- data/lib/builderator/tasks/vagrant.rb +111 -42
- data/lib/builderator/tasks/vendor.rb +94 -0
- data/lib/builderator/tasks/version.rb +58 -0
- data/lib/builderator/util.rb +37 -11
- data/lib/builderator/util/aws_exception.rb +1 -1
- data/lib/builderator/util/limit_exception.rb +12 -11
- data/lib/builderator/util/task_exception.rb +0 -2
- data/mkmf.log +4 -0
- data/spec/config_spec.rb +30 -0
- data/spec/data/Berksfile +6 -0
- data/spec/data/Buildfile +0 -0
- data/spec/data/Vagrantfile +0 -0
- data/spec/data/history.json +483 -0
- data/spec/data/packer.json +0 -0
- data/spec/interface_spec.rb +36 -0
- data/spec/resource/Buildfile +27 -0
- data/spec/spec_helper.rb +90 -0
- data/spec/version_spec.rb +282 -0
- data/template/Berksfile.erb +10 -0
- data/template/Buildfile.erb +28 -0
- data/template/Gemfile.erb +16 -0
- data/template/README.md.erb +61 -0
- data/template/Vagrantfile.erb +75 -0
- data/template/gitignore.erb +104 -0
- data/{.rubocop.yml → template/rubocop.erb} +0 -0
- metadata +203 -56
- data/.gitignore +0 -14
- data/lib/builderator/control/ami.rb +0 -65
- data/lib/builderator/control/clean.rb +0 -130
- data/lib/builderator/model.rb +0 -46
- data/lib/builderator/model/images.rb +0 -89
- data/lib/builderator/model/instances.rb +0 -55
- data/lib/builderator/model/launch_configs.rb +0 -46
- data/lib/builderator/model/scaling_groups.rb +0 -43
- data/lib/builderator/model/snapshots.rb +0 -49
- data/lib/builderator/model/volumes.rb +0 -48
- data/lib/builderator/tasks/ami.rb +0 -47
- data/lib/builderator/tasks/berks.rb +0 -68
- data/lib/builderator/tasks/clean.rb +0 -97
- data/lib/builderator/util/berkshim.rb +0 -34
- data/lib/builderator/util/cookbook.rb +0 -87
- data/lib/builderator/util/packer.rb +0 -39
- data/lib/builderator/util/shell.rb +0 -44
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative '../interface'
|
2
|
+
|
3
|
+
module Builderator
|
4
|
+
# :nodoc:
|
5
|
+
class Interface
|
6
|
+
class << self
|
7
|
+
def packer
|
8
|
+
@packer ||= Packer.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Generate packer.json
|
14
|
+
##
|
15
|
+
class Packer < Interface
|
16
|
+
command 'packer'
|
17
|
+
attr_reader :packerfile
|
18
|
+
|
19
|
+
def initialize(*_)
|
20
|
+
super
|
21
|
+
|
22
|
+
@packerfile ||= {
|
23
|
+
:builders => [],
|
24
|
+
:provisioners => []
|
25
|
+
}.tap do |json|
|
26
|
+
Config.profile.current.packer.build.each do |_, build|
|
27
|
+
json[:builders] << build.to_hash.tap do |b|
|
28
|
+
b[:tags] = Config.profile.current.tags
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
## Initialize the staging directory
|
33
|
+
json[:provisioners] << {
|
34
|
+
:type => 'shell',
|
35
|
+
:inline => "sudo mkdir -p #{Config.chef.staging_directory}/cache && "\
|
36
|
+
"sudo chown $(whoami) -R #{Config.chef.staging_directory}"
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
_artifact_provisioners
|
41
|
+
_chef_provisioner
|
42
|
+
end
|
43
|
+
|
44
|
+
def render
|
45
|
+
JSON.pretty_generate(packerfile)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
## Upload artifacts to the build container
|
51
|
+
def _artifact_provisioners
|
52
|
+
Config.profile.current.artifact.each do |_, artifact|
|
53
|
+
packerfile[:provisioners] << {
|
54
|
+
:type => 'file',
|
55
|
+
:source => artifact.path,
|
56
|
+
:destination => artifact.destination
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def _chef_provisioner
|
62
|
+
packerfile[:provisioners] << {
|
63
|
+
:type => 'chef-solo',
|
64
|
+
:run_list => Config.profile.current.chef.run_list,
|
65
|
+
:cookbook_paths => Config.local.cookbook_path,
|
66
|
+
:data_bags_path => Config.local.data_bag_path,
|
67
|
+
:environments_path => Config.local.environment_path,
|
68
|
+
:chef_environment => Config.profile.current.chef.environment,
|
69
|
+
:json => Config.profile.current.chef.node_attrs,
|
70
|
+
:staging_directory => Config.chef.staging_directory
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../interface'
|
2
|
+
|
3
|
+
module Builderator
|
4
|
+
# :nodoc:
|
5
|
+
class Interface
|
6
|
+
class << self
|
7
|
+
def vagrant
|
8
|
+
@vagrant ||= Vagrant.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Render a temporary Vagrantfile
|
14
|
+
##
|
15
|
+
class Vagrant < Interface
|
16
|
+
command 'vagrant'
|
17
|
+
template 'template/Vagrantfile.erb'
|
18
|
+
|
19
|
+
def command
|
20
|
+
c = ''
|
21
|
+
c << 'ulimit -n 1024; ' if bundled?
|
22
|
+
c << 'VAGRANT_I_KNOW_WHAT_IM_DOING_PLEASE_BE_QUIET=true ' if bundled?
|
23
|
+
c << which
|
24
|
+
end
|
25
|
+
|
26
|
+
def source
|
27
|
+
directory.join('Vagrantfile')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/builderator/metadata.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
require_relative './util'
|
2
|
+
|
3
|
+
# :nodoc:
|
1
4
|
module Builderator
|
2
|
-
|
3
|
-
|
4
|
-
DESCRIPTION = IO.read(File.join(PATH, 'README.md')) rescue 'README.md not found!'
|
5
|
+
VERSION = Util.source_path('VERSION').read rescue '0.0.1'
|
6
|
+
DESCRIPTION = Util.source_path('README.md').read rescue 'README.md not found!'
|
5
7
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Builderator
|
2
|
+
module Model
|
3
|
+
module Cleaner
|
4
|
+
##
|
5
|
+
# Shared model interface
|
6
|
+
##
|
7
|
+
class Base
|
8
|
+
attr_reader :resources
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
fetch(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch
|
15
|
+
@resources = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def find(filters = {})
|
19
|
+
Util.filter(resources, filters)
|
20
|
+
end
|
21
|
+
|
22
|
+
def select(set = [])
|
23
|
+
resources.select { |k, _| set.include?(k) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def in_use
|
27
|
+
find(Config.cleaner.filters)
|
28
|
+
end
|
29
|
+
|
30
|
+
def in_use?(key)
|
31
|
+
@in_use ||= in_use
|
32
|
+
|
33
|
+
@in_use.include?(key)
|
34
|
+
end
|
35
|
+
|
36
|
+
def unused
|
37
|
+
resources.reject { |k, _| in_use?(k) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
require_relative './cleaner/images'
|
45
|
+
require_relative './cleaner/instances'
|
46
|
+
require_relative './cleaner/launch_configs'
|
47
|
+
require_relative './cleaner/scaling_groups'
|
48
|
+
require_relative './cleaner/snapshots'
|
49
|
+
require_relative './cleaner/volumes'
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
# :nodoc:
|
7
|
+
module Cleaner
|
8
|
+
def self.images
|
9
|
+
@images ||= Images.new
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# EC2 AMI Resources
|
14
|
+
##
|
15
|
+
class Images < Model::Cleaner::Base
|
16
|
+
PROPERTIES = %w(image_location state owner_id public architecture image_type
|
17
|
+
name description root_device_type virtualization_type
|
18
|
+
hypervisor)
|
19
|
+
|
20
|
+
def fetch
|
21
|
+
@resources = {}.tap do |i|
|
22
|
+
Util.ec2.describe_images(:filters => [
|
23
|
+
{
|
24
|
+
:name => 'state',
|
25
|
+
:values => %w(available)
|
26
|
+
}
|
27
|
+
], :owners => %w(self)).each do |page|
|
28
|
+
page.images.each do |image|
|
29
|
+
properties = Util.from_tags(image.tags)
|
30
|
+
properties['creation_date'] = DateTime.iso8601(image.creation_date)
|
31
|
+
PROPERTIES.each { |pp| properties[pp] = image[pp.to_sym] }
|
32
|
+
|
33
|
+
i[image.image_id] = {
|
34
|
+
:id => image.image_id,
|
35
|
+
:properties => properties,
|
36
|
+
:snapshots => image.block_device_mappings.map { |b| b.ebs.snapshot_id rescue nil }.reject(&:nil?),
|
37
|
+
:parent => properties.fetch('parent_ami', '(undefined)')
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def snapshots
|
45
|
+
resources.values.map { |i| i[:snapshots] }.flatten
|
46
|
+
end
|
47
|
+
|
48
|
+
def latest
|
49
|
+
{}.tap do |latest|
|
50
|
+
## Group images
|
51
|
+
group_by = Config.cleaner.group_by
|
52
|
+
groups = {}.tap do |object|
|
53
|
+
break { 'all' => resources.values } if group_by.empty?
|
54
|
+
|
55
|
+
resources.each do |_, image|
|
56
|
+
## Construct a grouping-key from image properties
|
57
|
+
grouping_key = group_by.map do |grouping_property|
|
58
|
+
image[:properties].fetch(grouping_property.to_s, '(unknown)')
|
59
|
+
end.join(':')
|
60
|
+
|
61
|
+
## Create an array for the group if it doesn't already exist
|
62
|
+
## and add the image to it
|
63
|
+
(object[grouping_key] ||= []) << image
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
## Sort each grouping
|
68
|
+
groups.each do |_, group|
|
69
|
+
group.sort! { |a, b| b[:properties][Config.cleaner.sort_by] <=> a[:properties][Config.cleaner.sort_by] }
|
70
|
+
end
|
71
|
+
|
72
|
+
## Slice to `keep` length
|
73
|
+
groups.each do |_, group|
|
74
|
+
group.slice!(Config.cleaner.keep..-1)
|
75
|
+
end
|
76
|
+
|
77
|
+
## Reduce
|
78
|
+
groups.values.flatten.each { |i| latest[i[:id]] = i }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def in_use
|
83
|
+
{}.tap do |used|
|
84
|
+
used.merge!(select(Cleaner.instances.images))
|
85
|
+
used.merge!(select(Cleaner.launch_configs.images))
|
86
|
+
used.merge!(latest)
|
87
|
+
used.merge!(select(used.values.map { |i| i[:parent] }))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
# :nodoc:
|
7
|
+
module Cleaner
|
8
|
+
def self.instances
|
9
|
+
@instances ||= Instances.new
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# EC2 Instance resources
|
14
|
+
##
|
15
|
+
class Instances < Model::Cleaner::Base
|
16
|
+
PROPERTIES = %w(private_dns_name public_dns_name instance_type
|
17
|
+
subnet_id vpc_id private_ip_address public_ip_address
|
18
|
+
architecture root_device_type virtualization_type
|
19
|
+
hypervisor)
|
20
|
+
|
21
|
+
def fetch
|
22
|
+
@resources = {}.tap do |i|
|
23
|
+
Util.ec2.describe_instances(:filters => [
|
24
|
+
{
|
25
|
+
:name => 'instance-state-name',
|
26
|
+
:values => %w(pending running shutting-down stopping stopped)
|
27
|
+
}
|
28
|
+
]).each do |page|
|
29
|
+
page.reservations.each do |r|
|
30
|
+
r.instances.each do |instance|
|
31
|
+
properties = Util.from_tags(instance.tags)
|
32
|
+
properties['availability_zone'] = instance.placement.availability_zone
|
33
|
+
properties['creation_date'] = instance.launch_time.to_datetime
|
34
|
+
PROPERTIES.each { |pp| properties[pp] = instance[pp.to_sym] }
|
35
|
+
|
36
|
+
i[instance.instance_id] = {
|
37
|
+
:id => instance.instance_id,
|
38
|
+
:image => instance.image_id,
|
39
|
+
:volumes => instance.block_device_mappings.map { |b| b.ebs.volume_id },
|
40
|
+
:properties => properties
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def images
|
49
|
+
resources.values.map { |i| i[:image] }
|
50
|
+
end
|
51
|
+
|
52
|
+
def volumes
|
53
|
+
resources.values.map { |i| i[:volumes] }.flatten
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
# :nodoc:
|
7
|
+
module Cleaner
|
8
|
+
def self.launch_configs
|
9
|
+
@launch_configs ||= LaunchConfigs.new
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# ASG LaunchConfiguration Resources
|
14
|
+
##
|
15
|
+
class LaunchConfigs < Model::Cleaner::Base
|
16
|
+
PROPERTIES = %w(launch_configuration_arn key_name security_groups
|
17
|
+
user_data instance_type spot_price iam_instance_profile
|
18
|
+
ebs_optimized associate_public_ip_address placement_tenancy)
|
19
|
+
|
20
|
+
def fetch
|
21
|
+
@resources = {}.tap do |i|
|
22
|
+
Util.asg.describe_launch_configurations.each do |page|
|
23
|
+
page.launch_configurations.each do |l|
|
24
|
+
properties = { 'creation_date' => l.created_time.to_datetime }
|
25
|
+
PROPERTIES.each { |pp| properties[pp] = l[pp.to_sym] }
|
26
|
+
|
27
|
+
i[l.launch_configuration_name] = {
|
28
|
+
:id => l.launch_configuration_name,
|
29
|
+
:properties => properties,
|
30
|
+
:image => l.image_id
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def images
|
38
|
+
resources.values.map { |l| l[:image] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def in_use
|
42
|
+
select(Cleaner.scaling_groups.launch_configs)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
# :nodoc:
|
7
|
+
module Cleaner
|
8
|
+
def self.scaling_groups
|
9
|
+
@scaling_groups ||= ScalingGroups.new
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# AutoScaling Group Resoruces
|
14
|
+
##
|
15
|
+
class ScalingGroups < Model::Cleaner::Base
|
16
|
+
attr_reader :resources
|
17
|
+
PROPERTIES = %w(auto_scaling_group_arn min_size max_size desired_capacity
|
18
|
+
default_cooldown availability_zones load_balancer_names
|
19
|
+
vpc_zone_identifier status termination_policies)
|
20
|
+
|
21
|
+
def fetch
|
22
|
+
@resources = {}.tap do |i|
|
23
|
+
Util.asg.describe_auto_scaling_groups.each do |page|
|
24
|
+
page.auto_scaling_groups.each do |a|
|
25
|
+
properties = Util.from_tags(a.tags)
|
26
|
+
properties['creation_date'] = a.created_time.to_datetime
|
27
|
+
PROPERTIES.each { |pp| properties[pp] = a[pp.to_sym] }
|
28
|
+
|
29
|
+
i[a.launch_configuration_name] = {
|
30
|
+
:id => a.auto_scaling_group_name,
|
31
|
+
:properties => properties,
|
32
|
+
:config => a.launch_configuration_name
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def launch_configs
|
40
|
+
resources.values.map { |g| g[:config] }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
# :nodoc:
|
7
|
+
module Cleaner
|
8
|
+
def self.snapshots
|
9
|
+
@snapshots ||= Snapshots.new
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# EC2 Snapshot Resources
|
14
|
+
##
|
15
|
+
class Snapshots < Model::Cleaner::Base
|
16
|
+
PROPERTIES = %w(state owner_id description volume_size)
|
17
|
+
|
18
|
+
def fetch
|
19
|
+
@resources = {}.tap do |s|
|
20
|
+
Util.ec2.describe_snapshots(:filters => [
|
21
|
+
{
|
22
|
+
:name => 'status',
|
23
|
+
:values => %w(completed)
|
24
|
+
}
|
25
|
+
], :owner_ids => ['self']).each do |page|
|
26
|
+
page.snapshots.each do |snap|
|
27
|
+
properties = Util.from_tags(snap.tags)
|
28
|
+
properties['creation_date'] = snap.start_time.to_datetime
|
29
|
+
PROPERTIES.each { |pp| properties[pp] = snap[pp.to_sym] }
|
30
|
+
|
31
|
+
s[snap.snapshot_id] = {
|
32
|
+
:id => snap.snapshot_id,
|
33
|
+
:properties => properties,
|
34
|
+
:volume => snap.volume_id
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def in_use
|
42
|
+
{}.tap do |used|
|
43
|
+
used.merge!(select(Cleaner.volumes.snapshots))
|
44
|
+
used.merge!(select(Cleaner.images.snapshots))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|