build-cloud 0.0.1

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: 44ac926d7827973fce157398265b248b9f2263df
4
+ data.tar.gz: 4d4ae065f177a4c2cd16840c5501c3d90b7f27fa
5
+ SHA512:
6
+ metadata.gz: 63aa3403dddf30aa6623d1b006953fb00fed715e1099eda8070d1f5a7bc27ba7549e86347c0490da46d310232a52aa20cd6d73c44adf2341e6093176993cdd97
7
+ data.tar.gz: 18380bcc47e5ac2c635210e59f0d90c67aaf94c00be3609d3f2eab5a2589db2740e28455791fcf3cc652032d66ea4c8afeb634ecb3d616395639376da2dcb9fe
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 The Scale Factory
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,29 @@
1
+ # Build::Cloud
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'build-cloud'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install build-cloud
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/build-cloud/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/build-cloud ADDED
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.push( File.join( File.dirname(__FILE__), 'lib' ) )
4
+
5
+ require 'optparse'
6
+
7
+ require 'build-cloud'
8
+ require 'build-cloud/component'
9
+ require 'build-cloud/vpc'
10
+ require 'build-cloud/subnet'
11
+ require 'build-cloud/routetable'
12
+ require 'build-cloud/route'
13
+ require 'build-cloud/zone'
14
+ require 'build-cloud/securitygroup'
15
+ require 'build-cloud/launchconfiguration'
16
+ require 'build-cloud/loadbalancer'
17
+ require 'build-cloud/asgroup'
18
+ require 'build-cloud/r53recordset'
19
+ require 'build-cloud/rdsserver'
20
+ require 'build-cloud/dbsubnetgroup'
21
+ require 'build-cloud/dbparametergroup'
22
+ require 'build-cloud/cachesubnetgroup'
23
+ require 'build-cloud/cachecluster'
24
+ require 'build-cloud/cacheparametergroup'
25
+ require 'build-cloud/iamrole'
26
+ require 'build-cloud/s3bucket'
27
+ require 'build-cloud/instance'
28
+ require 'build-cloud/networkinterface'
29
+ require 'build-cloud/internetgateway'
30
+
31
+ options = {}
32
+ optparse = OptionParser.new do |opts|
33
+
34
+ options[:config] = nil
35
+ opts.on('-c', '--config=file', 'Config file path') do |c|
36
+ options[:config] = c
37
+ end
38
+
39
+ options[:debug] = false
40
+ opts.on('-d', '--debug', 'Enable debugging') do
41
+ options[:debug] = true
42
+ end
43
+
44
+ options[:mock] = false
45
+ opts.on('-m', '--mock', 'Use fog\'s mock interfaces') do
46
+ options[:mock] = true
47
+ end
48
+
49
+ options[:all] = false
50
+ opts.on('--all', 'Select all objects') do
51
+ options[:all] = true
52
+ end
53
+
54
+ options[:create] = false
55
+ opts.on('--create', 'Create objects') do
56
+ options[:create] = true
57
+ end
58
+
59
+ options[:delete] = false
60
+ opts.on('--delete', 'Delete objects') do
61
+ options[:delete] = true
62
+ end
63
+
64
+ options[:read] = false
65
+ opts.on('--read', 'read objects') do
66
+ options[:read] = true
67
+ end
68
+
69
+ options[:pry] = false
70
+ opts.on('--pry', 'Start pry console') do
71
+ options[:pry] = true
72
+ end
73
+
74
+ options[:find_type] = []
75
+ opts.on('--find-type=t', 'Find objects by type') do |t|
76
+ options[:find_type].push(t.to_sym)
77
+ end
78
+
79
+ options[:find] = {}
80
+ opts.on('--find=f', 'Find objects by key match') do |f|
81
+ args = f.split('=')
82
+ options[:find][ args[0].to_sym ] = args[1]
83
+ end
84
+
85
+
86
+ end
87
+
88
+ begin
89
+
90
+ optparse.parse!
91
+
92
+ if options[:config].nil?
93
+ raise OptionParser::MissingArgument, "--config"
94
+ end
95
+
96
+ if options[:create] and options[:delete]
97
+ raise OptionParser::InvalidOption, "Choose only one of --create or --delete"
98
+ end
99
+
100
+ if !options[:create] and !options[:delete]
101
+ options[:read] = true
102
+ end
103
+
104
+ if options[:all] and ( !options[:find].empty? or options[:find_type].length > 0 )
105
+ raise OptionParser::InvalidOption, "Use either --all or the --find/--find-type options, not both"
106
+ end
107
+
108
+ options[:find_type].each do |ft|
109
+ if !BuildCloud.dispatch.keys.include?(ft)
110
+ raise OptionParser::InvalidOption, "--find-type didn't match one of #{BuildCloud.dispatch.keys.join(', ')}"
111
+ end
112
+ end
113
+
114
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
115
+
116
+ $stderr.puts $!.to_s
117
+ $stderr.puts optparse
118
+ exit 2
119
+
120
+ end
121
+
122
+ log = Logger.new(STDERR)
123
+
124
+ if options[:debug]
125
+ log.level = Logger::DEBUG
126
+ else
127
+ log.level = Logger::INFO
128
+ end
129
+
130
+ inf = BuildCloud.new( :config => options[:config], :logger => log, :mock => options[:mock] )
131
+
132
+
133
+ if options[:all]
134
+
135
+ objects = inf.all
136
+
137
+ else
138
+
139
+ objects = []
140
+
141
+ options[:find_type].each do |ft|
142
+ objects.concat inf.find( ft, options[:find] )
143
+ end
144
+
145
+ if objects.length == 0
146
+ $stderr.puts "Didn't find any matching object"
147
+ end
148
+
149
+ end
150
+
151
+
152
+ if options[:create]
153
+
154
+ objects.each do |o|
155
+ begin
156
+ o.create
157
+ o.wait_until_ready
158
+ rescue Fog::Errors::MockNotImplemented => e
159
+ log.error("No Fog mock support for #{o.class}")
160
+ end
161
+ end
162
+
163
+ elsif options[:delete]
164
+
165
+ objects.reverse.each do |o|
166
+ o.delete
167
+ end
168
+
169
+ elsif options[:read]
170
+
171
+ objects.each do |o|
172
+ puts o.inspect
173
+ end
174
+
175
+ end
176
+
177
+
178
+ if options[:pry]
179
+ inf.pry
180
+ end
181
+
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "build-cloud"
7
+ spec.version = "0.0.1"
8
+ spec.authors = ["The Scale Factory"]
9
+ spec.email = ["info@scalefactory.com"]
10
+ spec.summary = %q{Tools for building resources in AWS}
11
+ spec.homepage = "https://github.com/scalefactory/build-cloud"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.5"
20
+ spec.add_development_dependency "rake"
21
+
22
+ spec.add_dependency "fog", ">=1.22.0"
23
+ spec.add_dependency "pry", ">=0.9.12.6"
24
+ end
@@ -0,0 +1,68 @@
1
+ class BuildCloud::ASGroup
2
+
3
+ include ::BuildCloud::Component
4
+
5
+ @@objects = []
6
+
7
+ def initialize ( fog_interfaces, log, options = {} )
8
+
9
+ @as = fog_interfaces[:as]
10
+ @log = log
11
+ @options = options
12
+
13
+ @log.debug( options.inspect )
14
+
15
+ required_options(:id, :launch_configuration_name, :min_size, :max_size,
16
+ :desired_capacity, :availability_zones, :health_check_grace_period)
17
+ require_one_of(:vpc_zone_identifier, :subnet_names)
18
+
19
+ end
20
+
21
+ def create
22
+
23
+ return if exists?
24
+
25
+ @log.info( "Creating AS Group #{@options[:id]}" )
26
+
27
+ options = @options.dup
28
+
29
+ unless options[:vpc_zone_identifier]
30
+
31
+ subnet_ids = []
32
+
33
+ options[:subnet_names].each do |subnet|
34
+ subnet_ids << BuildCloud::Subnet.get_id_by_name( subnet )
35
+ end
36
+
37
+ options.delete(:subnet_names)
38
+ options[:vpc_zone_identifier] = subnet_ids.join(',')
39
+
40
+ end
41
+
42
+ @log.debug( options )
43
+
44
+ asg = @as.groups.new( options )
45
+ asg.save
46
+
47
+ @log.debug( asg.inspect )
48
+
49
+ end
50
+
51
+ def read
52
+ @as.groups.select { |g| g.id == @options[:id] }.first
53
+ end
54
+
55
+ alias_method :fog_object, :read
56
+
57
+ def delete
58
+
59
+ return unless exists?
60
+
61
+ @log.info( "Deleting ASG #{@options[:id]}" )
62
+
63
+ fog_object.destroy( :force => true )
64
+
65
+ end
66
+
67
+ end
68
+
@@ -0,0 +1,66 @@
1
+
2
+ class BuildCloud::CacheCluster
3
+
4
+ include ::BuildCloud::Component
5
+
6
+ @@objects = []
7
+
8
+ def initialize ( fog_interfaces, log, options = {} )
9
+
10
+ @elasticache = fog_interfaces[:elasticache]
11
+ @log = log
12
+ @options = options
13
+
14
+ @log.debug( options.inspect )
15
+
16
+ required_options(:id, :node_type, :num_nodes, :auto_minor_version_upgrade,
17
+ :engine, :cache_subnet_group_name)
18
+ require_one_of(:vpc_security_groups, :vpc_security_group_names)
19
+
20
+ end
21
+
22
+ def create
23
+
24
+ return if exists?
25
+
26
+ @log.info( "Creating Elasticache Cluster #{@options[:id]}" )
27
+
28
+ options = @options.dup
29
+
30
+ unless options[:vpc_security_groups]
31
+
32
+ options[:vpc_security_groups] = []
33
+
34
+ options[:vpc_security_group_names].each do |sg|
35
+ options[:vpc_security_groups] << BuildCloud::SecurityGroup. get_id_by_name( sg )
36
+ end
37
+
38
+ options.delete(:vpc_security_group_names)
39
+
40
+ end
41
+
42
+ cluster = @elasticache.clusters.new( options )
43
+ cluster.save
44
+
45
+ @log.debug( cluster.inspect )
46
+
47
+ end
48
+
49
+ def read
50
+ @elasticache.clusters.select { |c| c.id == @options[:id] }.first
51
+ end
52
+
53
+ alias_method :fog_object, :read
54
+
55
+ def delete
56
+
57
+ return unless exists?
58
+
59
+ @log.info( "Deleting Elasticache cluster #{@options[:id]}" )
60
+
61
+ fog_object.destroy
62
+
63
+ end
64
+
65
+ end
66
+
@@ -0,0 +1,61 @@
1
+
2
+ class BuildCloud::CacheParameterGroup
3
+
4
+ include ::BuildCloud::Component
5
+
6
+ @@objects = []
7
+
8
+ def initialize ( fog_interfaces, log, options = {} )
9
+
10
+ @elasticache = fog_interfaces[:elasticache]
11
+ @log = log
12
+ @options = options
13
+
14
+ @log.debug( options.inspect )
15
+
16
+ required_options(:family, :description, :id, :params)
17
+
18
+ end
19
+
20
+ def create
21
+
22
+ return if exists?
23
+
24
+ @log.info( "Creating Cache Parameter Group #{@options[:id]}" )
25
+
26
+ options = @options.dup
27
+
28
+ param_group = @elasticache.create_cache_parameter_group(options[:id], options[:description], options[:family])
29
+
30
+ @log.debug( param_group.inspect )
31
+
32
+ params = @elasticache.modify_cache_parameter_group options[:id], options[:params].collect! { |c|
33
+ {
34
+ 'ParameterName' => c[:param_name],
35
+ 'ParameterValue' => c[:param_value],
36
+ }
37
+ }
38
+
39
+ @log.debug( params.inspect )
40
+
41
+ end
42
+
43
+ def read
44
+ @elasticache.parameter_groups.select { |g| g.id == "#{@options[:id]}".downcase }.first
45
+ end
46
+
47
+ alias_method :fog_object, :read
48
+
49
+ def delete
50
+
51
+ return unless exists?
52
+
53
+ @log.info( "Deleting Cache Parameter Group #{@options[:id]}" )
54
+
55
+ puts fog_object.inspect
56
+ fog_object.destroy
57
+
58
+ end
59
+
60
+ end
61
+
@@ -0,0 +1,64 @@
1
+
2
+ class BuildCloud::CacheSubnetGroup
3
+
4
+ include ::BuildCloud::Component
5
+
6
+ @@objects = []
7
+
8
+ def initialize ( fog_interfaces, log, options = {} )
9
+
10
+ @elasticache = fog_interfaces[:elasticache]
11
+ @log = log
12
+ @options = options
13
+
14
+ @log.debug( options.inspect )
15
+
16
+ required_options(:name)
17
+ require_one_of(:subnet_ids, :subnet_names)
18
+
19
+ end
20
+
21
+ def create
22
+
23
+ return if exists?
24
+
25
+ @log.info( "Creating Cache Subnet Group #{@options[:id]}" )
26
+
27
+ options = @options.dup
28
+
29
+ unless options[:subnet_ids]
30
+
31
+ options[:subnet_ids] = []
32
+
33
+ options[:subnet_names].each do |sn|
34
+ options[:subnet_ids] << BuildCloud::Subnet.get_id_by_name( sn )
35
+ end
36
+
37
+ options.delete(:subnet_names)
38
+
39
+ end
40
+
41
+ group = @elasticache.create_cache_subnet_group( options[:name], options[:subnet_ids] )
42
+
43
+ @log.debug( group.inspect )
44
+
45
+ end
46
+
47
+ def read
48
+ @elasticache.subnet_groups.select { |g| g.id == @options[:name] }.first
49
+ end
50
+
51
+ alias_method :fog_object, :read
52
+
53
+ def delete
54
+
55
+ return unless exists?
56
+
57
+ @log.info( "Deleting Cache Subnet Group #{@options[:name]}" )
58
+
59
+ fog_object.destroy
60
+
61
+ end
62
+
63
+ end
64
+
@@ -0,0 +1,143 @@
1
+ module BuildCloud::Component
2
+
3
+ # Using idiom for putting class methods in mixin
4
+ # http://stackoverflow.com/questions/10692961/inheriting-class-methods-from-mixins
5
+
6
+ def self.included(base)
7
+ base.send :include, InstanceMethods
8
+ base.extend ClassMethods
9
+ end
10
+
11
+ module InstanceMethods
12
+
13
+ def [](key)
14
+ @options[key]
15
+ end
16
+
17
+ def has_key?(key)
18
+ @options.has_key?(key)
19
+ end
20
+
21
+ def exists?
22
+ !read.nil?
23
+ end
24
+
25
+ def ready_timeout
26
+ 30
27
+ end
28
+
29
+ def wait_until_ready
30
+
31
+ unless read.class.method_defined?(:ready?)
32
+ @log.debug("Can't wait for readiness on #{read.class.to_s}")
33
+ return
34
+ end
35
+
36
+ timeout = ready_timeout # default from this superclass
37
+
38
+ wait_timer = 1
39
+ start_time = Time.now.to_i
40
+
41
+ begin
42
+
43
+ if fog_object.ready?
44
+ @log.info("Object ready")
45
+ return true
46
+ end
47
+
48
+ @log.debug("Object not yet ready. Sleeping #{wait_timer}s")
49
+
50
+ sleep( wait_timer )
51
+
52
+ if wait_timer < 60
53
+ wait_timer *= 2
54
+ end
55
+
56
+ time_diff = Time.now.to_i - start_time
57
+
58
+ end while time_diff < timeout
59
+
60
+ @log.error("Timed out after #{timeout} waiting for #{read.class}")
61
+
62
+ end
63
+
64
+ def required_options( *required )
65
+
66
+ cn = self.class.name.split('::').last
67
+ missing = []
68
+
69
+ required.each do |o|
70
+ missing << o unless @options.has_key?(o)
71
+ end
72
+
73
+ if missing.length > 0
74
+ raise "#{cn} requires missing #{missing.join(', ')} option#{missing.length > 1 ? 's' : ''}"
75
+ end
76
+
77
+ end
78
+
79
+ def require_one_of( *required )
80
+
81
+ cn = self.class.name.split('::').last
82
+
83
+ intersection = @options.keys & required
84
+
85
+ if intersection.length != 1
86
+ raise "#{cn} requires only one of #{required.join(', ')}"
87
+ end
88
+
89
+
90
+ end
91
+
92
+ def to_s
93
+ return @options.to_yaml
94
+ end
95
+
96
+ end
97
+
98
+ module ClassMethods
99
+
100
+ # implied "self." for all methods here
101
+
102
+ def load( items, fog_interfaces, log )
103
+
104
+ objects = self.send :class_variable_get, :@@objects
105
+
106
+ items.each do |item|
107
+ objects << self.new( fog_interfaces, log, item )
108
+ end
109
+
110
+ objects
111
+
112
+ end
113
+
114
+
115
+ def search(options)
116
+
117
+ objects = self.send :class_variable_get, :@@objects
118
+
119
+ objects.select { |o|
120
+
121
+ matches = true
122
+
123
+ options.each_pair do |k,v|
124
+
125
+ unless o.has_key?(k) and o[k] == v
126
+ matches = false
127
+ end
128
+
129
+ end
130
+
131
+ matches
132
+
133
+ }
134
+
135
+ end
136
+
137
+ def objects
138
+ self.send :class_variable_get, :@@objects
139
+ end
140
+
141
+ end
142
+
143
+ end