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 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
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ AllCops:
2
+ Exclude:
3
+ - libraries/**/*
4
+ - spec/**/*
5
+ - metadata.rb
6
+
7
+ Encoding:
8
+ Enabled: false
9
+ LineLength:
10
+ Enabled: false
11
+ HashSyntax:
12
+ Enabled: false
13
+ RescueModifier:
14
+ Enabled: false
15
+ MethodLength:
16
+ Max: 24
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in builderator.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
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)
@@ -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.
@@ -0,0 +1,4 @@
1
+ require 'builderator/metadata'
2
+
3
+ module Builderator
4
+ end
@@ -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,5 @@
1
+ module Builderator
2
+ PATH = File.expand_path('../../..', __FILE__)
3
+ VERSION = IO.read(File.join(PATH, 'VERSION')) rescue '0.0.1'
4
+ DESCRIPTION = IO.read(File.join(PATH, 'README.md')) rescue 'README.md not found!'
5
+ 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'