build-cloud 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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