bigbang 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.
data/README ADDED
@@ -0,0 +1,19 @@
1
+
2
+
3
+ # creates the base images
4
+ bigbang base
5
+
6
+ # run the instances
7
+ bigbang explode <universe-info.rb>
8
+
9
+ # list universes
10
+ bigbang list
11
+
12
+ # kill a universe
13
+ bigbang kill <universe-name>
14
+
15
+ # resize clusters
16
+ bigbang resize
17
+
18
+ # test configuration
19
+ bigbang test
data/bin/bigbang ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + "/../lib/bigbang"
4
+
5
+ def help
6
+ puts "test"
7
+ end
8
+
9
+ $universe = nil
10
+
11
+ def self.universe(&block)
12
+ $universe = u = BigBang::Universe.new
13
+ u.instance_eval(&block)
14
+ end
15
+
16
+ if ARGV.empty?
17
+ help
18
+ exit 1
19
+ end
20
+
21
+ case ARGV[0]
22
+ when 'test':
23
+ load './universe.rb'
24
+ $universe.test
25
+ when 'explode':
26
+ if ARGV.size < 2 then
27
+ puts "#{$0} explode <universe name>"
28
+ exit 1
29
+ end
30
+ require 'universe.rb'
31
+ $universe.explode(ARGV[1])
32
+ when 'list':
33
+ require 'universe.rb'
34
+ $universe.list
35
+ when 'kill':
36
+ if ARGV.size < 2 then
37
+ puts "#{$0} kill <universe name>"
38
+ exit 1
39
+ end
40
+ require 'universe.rb'
41
+ $universe.kill(ARGV[1])
42
+ else
43
+ puts "unknown command #{ARGV[0]}"
44
+ exit 2
45
+ end
46
+
@@ -0,0 +1,10 @@
1
+ require 'bigbang/instance'
2
+
3
+ module BigBang
4
+ class Cluster < Instance
5
+ def initialize(name)
6
+ super(name)
7
+ end
8
+ attr_accessor :size
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module BigBang
2
+ class Config
3
+ attr_accessor :access_key_id, :secret_key, :dns_opts, :domain
4
+ def dns(d) @dns_opts = d; end
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ require 'bigbang/config'
2
+ require 'bigbang/instance'
3
+ require 'bigbang/cluster'
4
+
5
+ module BigBang
6
+ module DSL
7
+ def cluster(name, &block)
8
+ @instances << Cluster.new(name).tap do |cluster|
9
+ cluster.instance_eval(&block)
10
+ end
11
+ end
12
+
13
+ def instance(name, &block)
14
+ @instances << Instance.new(name).tap do |i|
15
+ i.instance_eval(&block)
16
+ end
17
+ end
18
+
19
+ def config(&block)
20
+ @config = Config.new.tap do |c|
21
+ c.instance_eval(&block)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ class Ec2BootstrapGenerator
2
+ def generate_from_dir(path)
3
+ basedir = File.dirname(__FILE__) + "/../../"
4
+ tmp=%x(mktemp -d /tmp/gen-ec2-userdata.XXXXX).strip
5
+ %x(mkdir -p #{tmp}/data)
6
+ %x(cp -r #{path}/* #{tmp}/data/)
7
+ %x(cp #{basedir}/src/* #{tmp})
8
+ tmptar=%x(mktemp /tmp/gen-ec2-userdata.XXXXX.tar.gz).strip
9
+ %x(tar -czf #{tmptar} -C #{tmp} .)
10
+
11
+ File.new("#{basedir}/src/bootstrap.sh").read +
12
+ File.new(tmptar).read
13
+ end
14
+
15
+ def generate_from_hash(h)
16
+ tmp=%x(mktemp -d /tmp/gen-ec2-userdata.XXXXX).strip
17
+ h.each_pair do |k,v|
18
+ f = File.new("#{tmp}/#{k}", "w")
19
+ f.write(v)
20
+ f.close
21
+ end
22
+
23
+ generate_from_dir(tmp).tap do |r|
24
+ %x(rm -fr #{tmp})
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ module BigBang
2
+ class Instance
3
+ def initialize(name)
4
+ @name = name
5
+ end
6
+
7
+ attr_accessor :ami, :key_name, :type,
8
+ :name, :elastic_ip,
9
+ :domain, :wildcard_domain,
10
+ :bootstrap_repo,
11
+ :bootstrap_params
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ module BigBang
2
+ class Provider
3
+ def initialize(config)
4
+ @config = config
5
+ end
6
+
7
+ def ec2
8
+ return @ec2 unless @ec2.nil?
9
+ @ec2 = AWS::EC2::Base.new(
10
+ :access_key_id => @config.access_key_id,
11
+ :secret_access_key => @config.secret_key)
12
+ end
13
+
14
+ def dns
15
+ return @dns unless @dns.nil?
16
+ @dns = Fog::DNS.new(@config.dns_opts)
17
+ end
18
+
19
+ def configured_zone
20
+ dns.zones.find { |z| z.domain == @config.domain }
21
+ end
22
+
23
+ def create_dns(domain, addr)
24
+ configured_zone.records.create(
25
+ :value => addr,
26
+ :name => domain,
27
+ :type => "A")
28
+ end
29
+
30
+ def eips
31
+ aset = ec2.describe_addresses.addressesSet
32
+ if aset.nil?
33
+ return []
34
+ else
35
+ return aset.item
36
+ end
37
+ end
38
+
39
+ def free_eips
40
+ eips.find_all { |eip| eip.instanceId.nil? }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,246 @@
1
+ require 'base64'
2
+ require 'AWS'
3
+ require 'ap'
4
+ require 'set'
5
+ require 'fog'
6
+ require 'bigbang/provider'
7
+ require 'bigbang/instance'
8
+ require 'bigbang/dsl'
9
+ require 'bigbang/ec2-git-bootstrap'
10
+
11
+ module BigBang
12
+ class Universe
13
+ def initialize
14
+ @clusters = []
15
+ @instances = []
16
+ end
17
+
18
+ include DSL
19
+
20
+ def provider
21
+ return @provider unless @provider.nil?
22
+ @provider = Provider.new(@config)
23
+ end
24
+
25
+ def get_instances
26
+ rset = provider.ec2.describe_instances.reservationSet
27
+ if rset.nil?
28
+ return []
29
+ else
30
+ instances = []
31
+ rset.item.each do |reservation|
32
+ reservation.instancesSet.item.each do |i|
33
+ instances << i
34
+ end
35
+ end
36
+ return instances
37
+ end
38
+ end
39
+
40
+ def test
41
+ ap provider.eips
42
+ get_instances
43
+ puts "ec2 access OK"
44
+ @instances.collect { |i| i.ami }.to_set.each do |ami|
45
+ begin
46
+ provider.ec2.describe_images(:image_id => [ami])
47
+ rescue AWS::InvalidAMIIDNotFound => e
48
+ puts "ami #{ami} not found"
49
+ end
50
+ end
51
+ puts "AMI's OK"
52
+ if provider.configured_zone.nil?
53
+ puts "Configured DNS domain zone not found"
54
+ else
55
+ puts "DNS domain OK"
56
+ end
57
+ end
58
+
59
+ def wait_for_eips(expected)
60
+ print "waiting for eips to be allocated"
61
+ STDOUT.flush
62
+ addrs = provider.free_eips
63
+ while(addrs.size < expected)
64
+ sleep(1)
65
+ print "."
66
+ STDOUT.flush
67
+ addrs = provider.free_eips
68
+ end
69
+ puts
70
+ addrs
71
+ end
72
+
73
+ def allocate_addresses
74
+ instances = @instances.find_all { |i| i.elastic_ip == true }
75
+ if instances.empty?
76
+ puts "no need to allocate elastic ips"
77
+ return
78
+ end
79
+ free_ips = provider.free_eips
80
+ toalloc = instances.size
81
+ blacklist = free_ips
82
+ if free_ips.size > 0
83
+ n = nil
84
+ if free_ips.size >= instances.size
85
+ n = instances.size
86
+ else
87
+ n = free_ips.size
88
+ end
89
+ confirm("Use #{n} of your #{free_ips.size} free eips?") do
90
+ blacklist = []
91
+ toalloc -= n
92
+ end
93
+ end
94
+ puts "need to alloc: #{toalloc}"
95
+ 1.upto(toalloc) do |i|
96
+ puts "allocating eip address #{i}"
97
+ provider.ec2.allocate_address
98
+ end
99
+
100
+ addrs = wait_for_eips(free_ips.size + toalloc)
101
+ avail_ips = addrs.collect { |a| a.publicIp }.to_set
102
+ black_ips = blacklist.collect { |a| a.publicIp }.to_set
103
+ (avail_ips - black_ips).to_a[0,instances.size]
104
+ end
105
+
106
+ def running_instances
107
+ get_instances.find_all { |i| i.instanceState.name == "running" }
108
+ end
109
+
110
+ def running_instances_count(ids)
111
+ running_instances.count { |i| ids.include?(i.instanceId) }
112
+ end
113
+
114
+ def wait_for_running(instances)
115
+ ids = instances.collect { |i| i.instanceId }.to_set
116
+ print "Waiting for all instances to be in running state. "
117
+ STDOUT.flush
118
+ while running_instances_count(ids) < instances.size
119
+ print "."
120
+ sleep(5)
121
+ STDOUT.flush
122
+ end
123
+ puts
124
+ end
125
+
126
+ def run_instances(name)
127
+ instances = []
128
+ gen = Ec2BootstrapGenerator.new
129
+ @instances.each do |instance|
130
+ userdata = Base64.encode64(gen.generate_from_hash(
131
+ "bootstrap-repo" => instance.bootstrap_repo
132
+ ))
133
+ res = provider.ec2.run_instances(
134
+ :image_id => instance.ami,
135
+ :key_name => instance.key_name,
136
+ :instance_type => instance.type,
137
+ :user_data => userdata)
138
+ ap res
139
+ res.instancesSet.item.each do |i|
140
+ instances << i
141
+ provider.ec2.create_tags(:resource_id => i.instanceId,
142
+ :tag => [
143
+ { 'bb_name' => instance.name },
144
+ { 'bb_universe' => name},
145
+ ])
146
+ end
147
+ end
148
+ instances.tap do |i|
149
+ wait_for_running(i)
150
+ end
151
+ end
152
+
153
+ def assign_addresses(instances, addrs)
154
+ if instances.size != addrs.size
155
+ raise "error: instances number and addresses don't match"
156
+ end
157
+
158
+ instances.each_index do |i|
159
+ puts "associating address #{addrs[i]} " +
160
+ "to instance #{instances[i].instanceId}"
161
+ provider.ec2.associate_address(
162
+ :instance_id => instances[i].instanceId,
163
+ :public_ip => addrs[i])
164
+ end
165
+ end
166
+
167
+ def create_dns_entries(name, instances, addrs)
168
+ @instances.each_index do |i|
169
+ domains = [@instances[i].domain]
170
+ if @instances[i].domain.is_a?(Array)
171
+ domains = @instances[i].domain
172
+ end
173
+ domains.each do |domain|
174
+ domain = "#{name}.#{domain}"
175
+ puts "creating domain #{domain}.#{@config.domain} to #{addrs[i]}"
176
+ provider.create_dns(domain, addrs[i])
177
+ if @instances[i].wildcard_domain == true
178
+ provider.create_dns("*.#{domain}", addrs[i])
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ def explode(name)
185
+ free_eips = allocate_addresses
186
+ confirm("Will assign the following ips:\n" +
187
+ "#{free_eips.join("\n")}\nConfirm") do
188
+ instances = run_instances(name)
189
+ assign_addresses(instances, free_eips)
190
+ create_dns_entries(name, instances, free_eips)
191
+ end
192
+ end
193
+
194
+ def tags
195
+ tag_set = provider.ec2.describe_tags(:filter =>
196
+ [{'key' => 'bb_universe'}]).tagSet
197
+ if tag_set.nil?
198
+ return []
199
+ end
200
+
201
+ tag_set.item
202
+ end
203
+
204
+ def list
205
+ universes = Set.new
206
+ tags.each do |tag|
207
+ universes << tag.value
208
+ end
209
+ universes.each do |u|
210
+ puts u
211
+ end
212
+ end
213
+
214
+ def confirm(msg)
215
+ print "#{msg}? [y/N] "
216
+ if STDIN.gets.strip == "y"
217
+ yield
218
+ return true
219
+ else
220
+ puts "skipping"
221
+ return false
222
+ end
223
+ end
224
+
225
+ def kill_instance(tag, running)
226
+ instance = running.find { |i| i.instanceId == tag.resourceId }
227
+ if instance.nil?
228
+ puts "instance #{tag.resourceId} is not running. skipping"
229
+ return
230
+ end
231
+ confirm("kill instance #{tag.resourceId}") do
232
+ provider.ec2.terminate_instances(:instance_id => [tag.resourceId])
233
+ puts "sent termination signal to #{tag.resourceId}"
234
+ end
235
+ end
236
+
237
+ def kill(name)
238
+ running = running_instances
239
+ tags.find_all do |tag|
240
+ tag.value == name
241
+ end.each do |tag|
242
+ send("kill_#{tag.resourceType}", tag, running)
243
+ end
244
+ end
245
+ end
246
+ end
data/lib/bigbang.rb ADDED
@@ -0,0 +1,2 @@
1
+
2
+ require 'bigbang/universe'
data/src/bootstrap.sh ADDED
@@ -0,0 +1,31 @@
1
+ #!/bin/bash
2
+ function extract()
3
+ {
4
+ SKIP=`awk '/^__TARFILE_FOLLOWS__/ { print NR + 1; exit 0; }' $0`
5
+
6
+ #remember our file name
7
+ THIS=`pwd`/$0
8
+ tmp=$(mktemp -d /tmp/bootstrap.XXXXX)
9
+
10
+ # take the tarfile and pipe it into tar
11
+ echo "decompressing to $tmp"
12
+ cd $tmp
13
+ tail -n +$SKIP $THIS | tar -xz
14
+ export EC2_GIT_BOOTSTRAP_PATH=$tmp/data
15
+ chmod -R a+Xr $tmp
16
+ ./post-extract.sh
17
+ }
18
+
19
+ set -x
20
+ log=/var/log/ec2-git-bootstrap.log
21
+ extract > $log
22
+ echo "EC2-GIT-BOOTSTRAP: Completed!" >> $log
23
+
24
+ #
25
+ # place any bash script here you need.
26
+ # Any script here will happen after the tar file extract.
27
+ echo "Finished"
28
+ exit 0
29
+
30
+ # NOTE: Don't place any newline characters after the last line below.
31
+ __TARFILE_FOLLOWS__
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ exec ssh -o "StrictHostKeyChecking no" -i ./data/id_rsa $1 $2
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+ set -x
3
+ apt-get -y install git
4
+ export GIT_SSH=./git-ssh-wrap.sh
5
+ repo=$(mktemp -d /tmp/git-bootstrap.XXXXX)
6
+ git clone $(cat data/bootstrap-repo) $repo
7
+ cd $repo
8
+ ./run
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bigbang
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Giorgenes Gelatti
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-15 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: fog
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: amazon-ec2
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ description: ""
50
+ email: giorgenes@gmail.com
51
+ executables:
52
+ - bigbang
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - src/git-ssh-wrap.sh
59
+ - src/post-extract.sh
60
+ - src/bootstrap.sh
61
+ - bin/bigbang
62
+ - README
63
+ - lib/bigbang.rb
64
+ - lib/bigbang/instance.rb
65
+ - lib/bigbang/provider.rb
66
+ - lib/bigbang/dsl.rb
67
+ - lib/bigbang/universe.rb
68
+ - lib/bigbang/ec2-git-bootstrap.rb
69
+ - lib/bigbang/config.rb
70
+ - lib/bigbang/cluster.rb
71
+ has_rdoc: true
72
+ homepage: http://github.com/giorgenes/bigbang/
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.6.2
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: ""
105
+ test_files: []
106
+