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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 48baf4bb78a9121f6268913550ac1cdf5157aa1c
|
4
|
+
data.tar.gz: 761c4a044264ad1109a534ab41a382076d2298bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 988210a27ccc466c5b0d1fa5548aae42524043b6c31fe290cbbf27e2d13d42f094b1552662befa899c7b047906b60e9153e71afb88598b3d2598ae5c337b5bbd
|
7
|
+
data.tar.gz: 20a6c23658cd4e12f583319512b42609fe6aa5fb0f894d56d01283248839c9f97223aaf69a22c381d6f573de514e41a2619f5b7799c8e9706349783e37ff318b
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 John Manero
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Builderator
|
2
|
+
__Tools to make CI Packer builds awesome__
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'builderator'
|
10
|
+
```
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install builderator
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
Run `bundle exec thor build help`
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
|
26
|
+
1. Fork it ( https://github.com/[my-github-username]/builderator/fork )
|
27
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
28
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
29
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
30
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/Thorfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'thor-scmversion'
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.10
|
data/bin/build
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
unless ENV.include?('BUNDLE_GEMFILE')
|
3
|
+
puts ''
|
4
|
+
puts ' / \\'
|
5
|
+
puts ' | ^ |'
|
6
|
+
puts " ಠ _ ಠ It looks like you're trying to run Builderator outside of Bundler!"
|
7
|
+
puts ' || || This is aggressively discouraged! Please re-run your command'
|
8
|
+
puts ' || || prepended with `bundle exec`'
|
9
|
+
puts ' || ||'
|
10
|
+
puts ' | | See http://bundler.io/ for help setting up Bundler and creating a Gemfile'
|
11
|
+
puts ' \\/'
|
12
|
+
puts ''
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
require_relative '../lib/builderator/tasks'
|
17
|
+
Builderator::Tasks::CLI.start(ARGV)
|
data/builderator.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'builderator/metadata'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'builderator'
|
8
|
+
spec.version = Builderator::VERSION
|
9
|
+
spec.authors = ['John Manero']
|
10
|
+
spec.email = ['jmanero@rapid7.com']
|
11
|
+
spec.summary = 'Tools to make CI Packer builds awesome'
|
12
|
+
spec.description = Builderator::DESCRIPTION
|
13
|
+
spec.homepage = 'https://github.com/rapid7/builderator'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = Dir[File.join(Builderator::PATH, 'bin/*')].map { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
22
|
+
|
23
|
+
spec.add_dependency 'aws-sdk', '~> 2.0'
|
24
|
+
spec.add_dependency 'bundler', '~> 1.7.0'
|
25
|
+
spec.add_dependency 'berkshelf', '~> 3.2'
|
26
|
+
spec.add_dependency 'chef', '~> 12.0'
|
27
|
+
spec.add_dependency 'thor', '~> 0.19.0'
|
28
|
+
spec.add_dependency 'thor-scmversion', '1.7.0'
|
29
|
+
end
|
data/docs/clean.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
build-clean
|
2
|
+
===========
|
3
|
+
Tasks to delete/deregister abandoned EC2 resources
|
4
|
+
|
5
|
+
### Options
|
6
|
+
* `--commit` Execute cleanup task. Default behavior is to display resources that would be removed
|
7
|
+
* `--filter KEY VALUE [KEY VALUE []]` Key/value pairs to filter resources. Valid keys include tags and native resource properties (See `describe` responses in the Ruby AWS-SDK)
|
8
|
+
|
9
|
+
### Commands
|
10
|
+
* `configs` Delete launch configurations that are not associated with an autoscaling group.
|
11
|
+
|
12
|
+
* `images` Delete images that are not associated with a launch configuration, a running instance, or are tagged as the 'parent' of an image that qualifies for any of the previous three conditions. Additionally, a fixed number of images can be retained per ordered groups.
|
13
|
+
|
14
|
+
**Options**
|
15
|
+
* `--group-by KEY [KEY []]` Tags/properties to group images by for pruning
|
16
|
+
* `--sort-by KEY` Tag/property to sort grouped images on (Default: creation_date)
|
17
|
+
* `--keep N` Number of images in each group to keep (Default: 0)
|
18
|
+
|
19
|
+
* `snapshots` Delete snapshots that are not associated with existing volumes or images.
|
20
|
+
|
21
|
+
* `volumes` Delete volumes that are not attached to instances.
|
data/lib/builderator.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
require_relative '../util'
|
5
|
+
|
6
|
+
module Builderator
|
7
|
+
module Control
|
8
|
+
##
|
9
|
+
# Find AMI IDs to use for sources
|
10
|
+
##
|
11
|
+
module AMI
|
12
|
+
## Account IDs of public image owners
|
13
|
+
module Owners
|
14
|
+
SELF = 'self'.freeze
|
15
|
+
UBUNTU = '099720109477'.freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
## Filter fields defined in http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Builderator::Util.ec2.html#describe_images-instance_method
|
19
|
+
FILTERS = %w(architecture block-device-mapping.delete-on-termination
|
20
|
+
block-device-mapping.device-name block-device-mapping.snapshot-id
|
21
|
+
block-device-mapping.volume-size block-device-mapping.volume-type
|
22
|
+
description hypervisor image-id image-type is-public kernel-id
|
23
|
+
manifest-location name owner-alias owner-id platform product-code
|
24
|
+
product-code.type ramdisk-id root-device-name root-device-type
|
25
|
+
state state-reason-code state-reason-message virtualization-type).freeze
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def search(filters = {})
|
29
|
+
[].tap do |images|
|
30
|
+
Builderator::Util.ec2.describe_images(search_options(filters)).each { |page| images.push(*page.images) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def latest(filters)
|
35
|
+
search(filters).sort do |a, b|
|
36
|
+
DateTime.iso8601(b.creation_date) <=> DateTime.iso8601(a.creation_date)
|
37
|
+
end.first
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def search_options(filters)
|
43
|
+
{}.tap do |options|
|
44
|
+
options[:image_ids] = Util.to_array(filters.delete(:image_id)) if filters.include?(:image_id)
|
45
|
+
options[:owners] = Util.to_array(filters.delete(:owner) { 'self' })
|
46
|
+
|
47
|
+
rfilters = [].tap do |f|
|
48
|
+
filters.each do |k, v|
|
49
|
+
next if v.nil?
|
50
|
+
|
51
|
+
f << {
|
52
|
+
:name => FILTERS.include?(k.to_s) ? k : "tag:#{ k }",
|
53
|
+
:values => Util.to_array(v)
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
options[:filters] = rfilters unless rfilters.empty?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require_relative '../model'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Control
|
6
|
+
##
|
7
|
+
# Control logic for cleanup tasks
|
8
|
+
##
|
9
|
+
module Clean
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def options(arg = nil)
|
13
|
+
return @options unless arg.is_a?(Hash)
|
14
|
+
|
15
|
+
@options = arg.clone
|
16
|
+
|
17
|
+
Util.region(@options.delete('region'))
|
18
|
+
@commit = @options.delete('commit') { false }
|
19
|
+
@limit = @options.delete('limit') { true }
|
20
|
+
|
21
|
+
@options
|
22
|
+
end
|
23
|
+
|
24
|
+
def configs!
|
25
|
+
resources = Model.launch_configs.unused(options)
|
26
|
+
|
27
|
+
limit!(Model::LaunchConfigs, 'Cleanup Launch Configurations', resources, &Proc.new)
|
28
|
+
aborted!(&Proc.new)
|
29
|
+
|
30
|
+
resources.each do |l, _|
|
31
|
+
yield :remove, "Launch Configuration #{ l }", :red
|
32
|
+
Model.launch_configs.resources.delete(l)
|
33
|
+
|
34
|
+
next unless commit?
|
35
|
+
# puts "delete_launch_configuration(:launch_configuration_name => #{l})"
|
36
|
+
Util.asg.delete_launch_configuration(:launch_configuration_name => l)
|
37
|
+
end
|
38
|
+
rescue Aws::AutoScaling::Errors::ServiceError => e
|
39
|
+
exceptions << Util::AwsException.new('Cleanup Launch Configurations', e)
|
40
|
+
yield(*exceptions.last.status)
|
41
|
+
end
|
42
|
+
|
43
|
+
def images!
|
44
|
+
resources = Model.images.unused(options)
|
45
|
+
|
46
|
+
limit!(Model::Images, 'Cleanup Images', resources, &Proc.new)
|
47
|
+
aborted!(&Proc.new)
|
48
|
+
|
49
|
+
resources.each do |i, image|
|
50
|
+
yield :remove, "Image #{ i } (#{ image[:properties]['name'] })", :red
|
51
|
+
Model.images.resources.delete(i)
|
52
|
+
|
53
|
+
next unless commit?
|
54
|
+
puts "deregister_image(:image_id => #{i})"
|
55
|
+
# Util.ec2.deregister_image(:image_id => i)
|
56
|
+
end
|
57
|
+
rescue Aws::EC2::Errors::ServiceError => e
|
58
|
+
exceptions << Util::AwsException.new('Cleanup Images', e)
|
59
|
+
yield(*exceptions.last.status)
|
60
|
+
end
|
61
|
+
|
62
|
+
def snapshots!
|
63
|
+
resources = Model.snapshots.unused
|
64
|
+
|
65
|
+
limit!(Model::Snapshots, 'Cleanup Snapshots', resources, &Proc.new)
|
66
|
+
aborted!(&Proc.new)
|
67
|
+
|
68
|
+
resources.each do |s, _|
|
69
|
+
yield :remove, "Snapshot #{ s }", :red
|
70
|
+
Model.snapshots.resources.delete(s)
|
71
|
+
|
72
|
+
next unless commit?
|
73
|
+
puts "delete_snapshot(:snapshot_id => #{s})"
|
74
|
+
# Util.ec2.delete_snapshot(:snapshot_id => s)
|
75
|
+
end
|
76
|
+
rescue Aws::EC2::Errors::ServiceError => e
|
77
|
+
exceptions << Util::AwsException.new('Cleanup Snapshots', e)
|
78
|
+
yield(*exceptions.last.status)
|
79
|
+
end
|
80
|
+
|
81
|
+
def volumes!
|
82
|
+
resources = Model.volumes.unused
|
83
|
+
|
84
|
+
limit!(Model::Volumes, 'Cleanup Volumes', resources, &Proc.new)
|
85
|
+
aborted!(&Proc.new)
|
86
|
+
|
87
|
+
resources.each do |v, _|
|
88
|
+
yield :remove, "Volume #{ v }", :red
|
89
|
+
Model.volumes.resources.delete(v)
|
90
|
+
|
91
|
+
next unless commit?
|
92
|
+
puts "delete_volume(:volume_id => #{v})"
|
93
|
+
# Util.ec2.delete_volume(:volume_id => v)
|
94
|
+
end
|
95
|
+
rescue Aws::EC2::Errors::ServiceError => e
|
96
|
+
exceptions << Util::AwsException.new('Cleanup Volumes', e)
|
97
|
+
yield(*exceptions.last.status)
|
98
|
+
end
|
99
|
+
|
100
|
+
def commit?
|
101
|
+
@commit && !@abort
|
102
|
+
end
|
103
|
+
|
104
|
+
def limit?
|
105
|
+
@limit
|
106
|
+
end
|
107
|
+
|
108
|
+
def aborted?
|
109
|
+
@commit && @abort
|
110
|
+
end
|
111
|
+
|
112
|
+
def exceptions
|
113
|
+
@exceptions ||= []
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def aborted!
|
119
|
+
yield :aborted, 'The following resources will NOT be removed because'\
|
120
|
+
' safty constraints have not been met!', :yellow if aborted?
|
121
|
+
end
|
122
|
+
|
123
|
+
def limit!(klass, task, resources)
|
124
|
+
return unless limit? && (resources.size >= klass::LIMIT)
|
125
|
+
|
126
|
+
exceptions << Util::LimitException.new(klass, task, resources)
|
127
|
+
@abort = true
|
128
|
+
|
129
|
+
yield(*exceptions.last.status)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Builderator
|
2
|
+
module Model
|
3
|
+
##
|
4
|
+
# Shared model interface
|
5
|
+
##
|
6
|
+
class Base
|
7
|
+
attr_reader :resources
|
8
|
+
LIMIT = 4
|
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 reject(set = [])
|
27
|
+
resources.reject { |k, _| set.include?(k) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def in_use(options = {})
|
31
|
+
find(options.fetch('filters', {}))
|
32
|
+
end
|
33
|
+
|
34
|
+
def unused(options = {})
|
35
|
+
Util.filter(reject(in_use(options)), options.fetch('filters', {}))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
require_relative './model/images'
|
42
|
+
require_relative './model/instances'
|
43
|
+
require_relative './model/launch_configs'
|
44
|
+
require_relative './model/scaling_groups'
|
45
|
+
require_relative './model/snapshots'
|
46
|
+
require_relative './model/volumes'
|