builderator 0.3.10
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 +14 -0
- data/.rubocop.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +2 -0
- data/Thorfile +1 -0
- data/VERSION +1 -0
- data/bin/build +17 -0
- data/builderator.gemspec +29 -0
- data/docs/clean.md +21 -0
- data/lib/builderator.rb +4 -0
- data/lib/builderator/control/ami.rb +64 -0
- data/lib/builderator/control/clean.rb +134 -0
- data/lib/builderator/metadata.rb +5 -0
- data/lib/builderator/model.rb +46 -0
- data/lib/builderator/model/images.rb +89 -0
- data/lib/builderator/model/instances.rb +55 -0
- data/lib/builderator/model/launch_configs.rb +46 -0
- data/lib/builderator/model/scaling_groups.rb +43 -0
- data/lib/builderator/model/snapshots.rb +49 -0
- data/lib/builderator/model/volumes.rb +48 -0
- data/lib/builderator/tasks.rb +37 -0
- data/lib/builderator/tasks/ami.rb +37 -0
- data/lib/builderator/tasks/berks.rb +68 -0
- data/lib/builderator/tasks/clean.rb +94 -0
- data/lib/builderator/tasks/cookbook.rb +42 -0
- data/lib/builderator/tasks/packer.rb +72 -0
- data/lib/builderator/tasks/vagrant.rb +66 -0
- data/lib/builderator/util.rb +53 -0
- data/lib/builderator/util/aws_exception.rb +31 -0
- data/lib/builderator/util/berkshim.rb +34 -0
- data/lib/builderator/util/cookbook.rb +42 -0
- data/lib/builderator/util/limit_exception.rb +38 -0
- data/lib/builderator/util/packer.rb +39 -0
- data/lib/builderator/util/shell.rb +44 -0
- data/lib/builderator/util/task_exception.rb +22 -0
- metadata +210 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
|
7
|
+
def self.images
|
8
|
+
@images ||= Images.new
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# EC2 AMI Resources
|
13
|
+
##
|
14
|
+
class Images < Model::Base
|
15
|
+
LIMIT = 24
|
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(options = {})
|
49
|
+
{}.tap do |latest|
|
50
|
+
## Group images
|
51
|
+
group_by = options.fetch('group-by', [])
|
52
|
+
groups = {}.tap do |g|
|
53
|
+
break { 'all' => resources.values } if group_by.empty?
|
54
|
+
|
55
|
+
resources.each do |_, image|
|
56
|
+
(g[group_by.map do |gg|
|
57
|
+
image[:properties].fetch(gg.to_s, '(unknown)')
|
58
|
+
end.join(':')] ||= []) << image
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
## Sort each grouping
|
63
|
+
sort_by = options.fetch('sort-by', 'creation_date')
|
64
|
+
groups.each do |_, group|
|
65
|
+
group.sort! { |a, b| b[:properties][sort_by] <=> a[:properties][sort_by] }
|
66
|
+
end
|
67
|
+
|
68
|
+
## Slice to `keep` length
|
69
|
+
keep = options.fetch('keep', 5)
|
70
|
+
groups.each do |_, group|
|
71
|
+
group.slice!(keep..-1)
|
72
|
+
end
|
73
|
+
|
74
|
+
## Reduce
|
75
|
+
groups.values.flatten.each { |i| latest[i[:id]] = i }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def in_use(options = {})
|
80
|
+
{}.tap do |used|
|
81
|
+
used.merge!(select(Model.instances.images))
|
82
|
+
used.merge!(select(Model.launch_configs.images))
|
83
|
+
used.merge!(latest(options))
|
84
|
+
used.merge!(select(used.values.map { |i| i[:parent] }))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
|
7
|
+
def self.instances
|
8
|
+
@instances ||= Instances.new
|
9
|
+
end
|
10
|
+
##
|
11
|
+
# EC2 Instance resources
|
12
|
+
##
|
13
|
+
class Instances < Model::Base
|
14
|
+
PROPERTIES = %w(private_dns_name public_dns_name instance_type
|
15
|
+
subnet_id vpc_id private_ip_address public_ip_address
|
16
|
+
architecture root_device_type virtualization_type
|
17
|
+
hypervisor)
|
18
|
+
|
19
|
+
def fetch
|
20
|
+
@resources = {}.tap do |i|
|
21
|
+
Util.ec2.describe_instances(:filters => [
|
22
|
+
{
|
23
|
+
:name => 'instance-state-name',
|
24
|
+
:values => %w(pending running shutting-down stopping stopped)
|
25
|
+
}
|
26
|
+
]).each do |page|
|
27
|
+
page.reservations.each do |r|
|
28
|
+
r.instances.each do |instance|
|
29
|
+
properties = Util.from_tags(instance.tags)
|
30
|
+
properties['availability_zone'] = instance.placement.availability_zone
|
31
|
+
properties['creation_date'] = instance.launch_time.to_datetime
|
32
|
+
PROPERTIES.each { |pp| properties[pp] = instance[pp.to_sym] }
|
33
|
+
|
34
|
+
i[instance.instance_id] = {
|
35
|
+
:id => instance.instance_id,
|
36
|
+
:image => instance.image_id,
|
37
|
+
:volumes => instance.block_device_mappings.map { |b| b.ebs.volume_id },
|
38
|
+
:properties => properties
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def images
|
47
|
+
resources.values.map { |i| i[:image] }
|
48
|
+
end
|
49
|
+
|
50
|
+
def volumes
|
51
|
+
resources.values.map { |i| i[:volumes] }.flatten
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
|
7
|
+
def self.launch_configs
|
8
|
+
@launch_configs ||= LaunchConfigs.new
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# ASG LaunchConfiguration Resources
|
13
|
+
##
|
14
|
+
class LaunchConfigs < Model::Base
|
15
|
+
LIMIT = 24
|
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(Model.scaling_groups.launch_configs)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
|
7
|
+
def self.scaling_groups
|
8
|
+
@scaling_groups ||= ScalingGroups.new
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# AutoScaling Group Resoruces
|
13
|
+
##
|
14
|
+
class ScalingGroups < Model::Base
|
15
|
+
attr_reader :resources
|
16
|
+
PROPERTIES = %w(auto_scaling_group_arn min_size max_size desired_capacity
|
17
|
+
default_cooldown availability_zones load_balancer_names
|
18
|
+
vpc_zone_identifier status termination_policies)
|
19
|
+
|
20
|
+
def fetch
|
21
|
+
@resources = {}.tap do |i|
|
22
|
+
Util.asg.describe_auto_scaling_groups.each do |page|
|
23
|
+
page.auto_scaling_groups.each do |a|
|
24
|
+
properties = Util.from_tags(a.tags)
|
25
|
+
properties['creation_date'] = a.created_time.to_datetime
|
26
|
+
PROPERTIES.each { |pp| properties[pp] = a[pp.to_sym] }
|
27
|
+
|
28
|
+
i[a.launch_configuration_name] = {
|
29
|
+
:id => a.auto_scaling_group_name,
|
30
|
+
:properties => properties,
|
31
|
+
:config => a.launch_configuration_name
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def launch_configs
|
39
|
+
resources.values.map { |g| g[:config] }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
|
7
|
+
def self.snapshots
|
8
|
+
@snapshots ||= Snapshots.new
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# EC2 Snapshot Resources
|
13
|
+
##
|
14
|
+
class Snapshots < Model::Base
|
15
|
+
LIMIT = 24
|
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(Model.volumes.snapshots))
|
44
|
+
used.merge!(select(Model.images.snapshots))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Model
|
6
|
+
|
7
|
+
def self.volumes
|
8
|
+
@volumes ||= Volumes.new
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# EC2 Volume Resources
|
13
|
+
##
|
14
|
+
class Volumes < Model::Base
|
15
|
+
LIMIT = 8
|
16
|
+
PROPERTIES = %w(size availability_zone state volume_type iops)
|
17
|
+
|
18
|
+
def fetch
|
19
|
+
@resources = {}.tap do |v|
|
20
|
+
Util.ec2.describe_volumes.each do |page|
|
21
|
+
page.volumes.each do |vol|
|
22
|
+
properties = Util.from_tags(vol.tags)
|
23
|
+
properties['creation_date'] = vol.create_time.to_datetime
|
24
|
+
PROPERTIES.each { |pp| properties[pp] = vol[pp.to_sym] }
|
25
|
+
|
26
|
+
|
27
|
+
v[vol.volume_id] = {
|
28
|
+
:id => vol.volume_id,
|
29
|
+
:properties => properties,
|
30
|
+
:snapshot => vol.snapshot_id
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def snapshots
|
38
|
+
resources.values.map { |v| v[:snapshot] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def in_use(_)
|
42
|
+
{}.tap do |used|
|
43
|
+
used.merge!(select(Model.instances.volumes))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require_relative './tasks/ami'
|
3
|
+
require_relative './tasks/berks'
|
4
|
+
require_relative './tasks/clean'
|
5
|
+
require_relative './tasks/cookbook'
|
6
|
+
require_relative './tasks/packer'
|
7
|
+
require_relative './tasks/vagrant'
|
8
|
+
|
9
|
+
module Builderator
|
10
|
+
module Tasks
|
11
|
+
class CLI < Thor
|
12
|
+
desc 'ami SUBCOMMAND', 'Search for AMI IDs'
|
13
|
+
subcommand 'ami', Builderator::Tasks::AMI
|
14
|
+
|
15
|
+
desc 'berks SUBCOMMAND', 'Berkshelf helpers'
|
16
|
+
subcommand 'berks', Builderator::Tasks::Berks
|
17
|
+
|
18
|
+
desc 'clean SUBCOMMAND', 'Clean up things'
|
19
|
+
subcommand 'clean', Builderator::Tasks::Clean
|
20
|
+
|
21
|
+
desc 'cookbook SUBCOMMAND', 'Cookbook tasks'
|
22
|
+
subcommand 'cookbook', Builderator::Tasks::Cookbook
|
23
|
+
|
24
|
+
|
25
|
+
desc 'packer SUBCOMMAND', 'Run Packer tasks'
|
26
|
+
subcommand 'packer', Builderator::Tasks::Packer
|
27
|
+
|
28
|
+
desc 'vagrant SUBCOMMAND', 'Run Vagrant tasks'
|
29
|
+
subcommand 'vagrant', Builderator::Tasks::Vagrant
|
30
|
+
|
31
|
+
desc 'version', 'Print gem version'
|
32
|
+
def version
|
33
|
+
puts Builderator::VERSION
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require_relative '../control/ami'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Tasks
|
6
|
+
class AMI < Thor
|
7
|
+
namespace :ami
|
8
|
+
|
9
|
+
class_option :root_device_type,
|
10
|
+
:default => 'ebs',
|
11
|
+
:desc => 'The type of the root device volume (ebs | instance-store)'
|
12
|
+
class_option :virtualization_type,
|
13
|
+
:default => 'hvm',
|
14
|
+
:desc => 'The virtualization type (paravirtual | hvm)'
|
15
|
+
class_option :architecture,
|
16
|
+
:default => 'x86_64',
|
17
|
+
:desc => 'The image architecture (i386 | x86_64)'
|
18
|
+
|
19
|
+
desc 'ubuntu SEARCH', 'Print the latest AMI ID for an Ubuntu image matching the SEARCH string'
|
20
|
+
def ubuntu(search = '*/hvm-ssd/ubuntu-trusty-daily-amd64-server-20*')
|
21
|
+
puts Control::AMI.latest(:owner => Builderator::Control::AMI::Owners::UBUNTU,
|
22
|
+
'root-device-type' => options['root_device_type'],
|
23
|
+
'virtualization-type' => options['virtualization_type'],
|
24
|
+
'architecture' => options['architecture'],
|
25
|
+
'name' => search).image_id
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'private [KEY VALUE ...]', 'Find the latest AMI ID with tags KEY=VALUE'
|
29
|
+
def private(*args)
|
30
|
+
puts Control::AMI.latest({ :owner => Builderator::Control::AMI::Owners::SELF,
|
31
|
+
'root-device-type' => options['root_device_type'],
|
32
|
+
'virtualization-type' => options['virtualization_type'],
|
33
|
+
'architecture' => options['architecture'] }.merge(Hash[*args])).image_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'thor/actions'
|
3
|
+
require_relative './cookbook'
|
4
|
+
require_relative '../util/cookbook'
|
5
|
+
|
6
|
+
module Builderator
|
7
|
+
module Tasks
|
8
|
+
class Berks < Thor
|
9
|
+
include Thor::Actions
|
10
|
+
class_option :config, :aliases => :c, :desc => "Path to Berkshelf's config.json"
|
11
|
+
class_option :cookbook, :aliases => :b, :desc => 'Path to the cookbook to use'
|
12
|
+
class_option :version, :type => :boolean,
|
13
|
+
:default => true,
|
14
|
+
:desc => 'Write current verison to file'
|
15
|
+
|
16
|
+
desc "local [PATH = #{ Util::Cookbook::DEFAULT_VENDOR }]", 'Vendor the local cookbook source and its dependencies'
|
17
|
+
def local(path = Util::Cookbook::DEFAULT_VENDOR)
|
18
|
+
Util::Cookbook.path(options['cookbook'])
|
19
|
+
|
20
|
+
command = 'BERKS_INSTALL_FROM=source'
|
21
|
+
command << " berks vendor #{ path }"
|
22
|
+
command << " -c #{ options['config'] }" if options.include?('config')
|
23
|
+
command << " -b #{ Util::Cookbook.berksfile }"
|
24
|
+
|
25
|
+
remove_file File.expand_path('Berksfile.lock', Util::Cookbook.path)
|
26
|
+
invoke Tasks::Cookbook, 'metadata', [], options
|
27
|
+
run command
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "vendor [PATH = #{ Util::Cookbook::DEFAULT_VENDOR }]", 'Vendor a cookbook release and its dependencies'
|
31
|
+
def vendor(path = Util::Cookbook::DEFAULT_VENDOR)
|
32
|
+
Util::Cookbook.path(options['cookbook'])
|
33
|
+
|
34
|
+
command = 'BERKS_INSTALL_FROM=release'
|
35
|
+
command << " berks vendor #{ path }"
|
36
|
+
command << " -c #{ options['config'] }" if options.include?('config')
|
37
|
+
command << " -b #{ Util::Cookbook.berksfile }"
|
38
|
+
|
39
|
+
remove_file File.expand_path('Berksfile.lock', Util::Cookbook.path)
|
40
|
+
run command
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'upload', 'Upload the local cookbook source and its dependencies to the Chef server'
|
44
|
+
option 'dry-run', :type => :boolean, :default => false
|
45
|
+
def upload(path = Util::Cookbook::DEFAULT_VENDOR)
|
46
|
+
command = 'BERKS_INSTALL_FROM=source'
|
47
|
+
command << " berks upload"
|
48
|
+
command << " -c #{ options['config'] }" if options.include?('config')
|
49
|
+
command << " -b #{ Util::Cookbook.berksfile }"
|
50
|
+
|
51
|
+
invoke Tasks::Berks, :local, [path], options
|
52
|
+
|
53
|
+
return say_status :dryrun, command if options['dry-run']
|
54
|
+
run command
|
55
|
+
end
|
56
|
+
|
57
|
+
desc 'uncache', 'Delete the Berkshelf cache'
|
58
|
+
def uncache
|
59
|
+
remove_dir File.join(ENV['HOME'], '.berkshelf/cookbooks')
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "clean [PATH = #{ Util::Cookbook::DEFAULT_VENDOR }]", 'Remove a local vendor directory'
|
63
|
+
def clean(path = Util::Cookbook::DEFAULT_VENDOR)
|
64
|
+
remove_dir path
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|