awsborn 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +66 -1
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/awsborn/awsborn.rb +22 -2
- data/lib/awsborn/git_branch.rb +30 -0
- data/lib/awsborn/rake.rb +64 -0
- data/lib/awsborn/server.rb +27 -2
- data/lib/awsborn.rb +1 -0
- metadata +24 -8
data/README.mdown
CHANGED
@@ -16,8 +16,8 @@ that are not running.
|
|
16
16
|
require 'awsborn'
|
17
17
|
|
18
18
|
# If not set, will be picked up from ENV['AMAZON_ACCESS_KEY_ID']
|
19
|
-
# and ENV['AMAZON_SECRET_ACCESS_KEY'].
|
20
19
|
Awsborn.access_key_id = 'AAAAAAAAAAAA'
|
20
|
+
# Can be picked up from ENV['AMAZON_SECRET_ACCESS_KEY'] or Keychain (OS X)
|
21
21
|
Awsborn.secret_access_key = 'KKKKKKKKKKKK'
|
22
22
|
|
23
23
|
# Logs to `awsborn.log` in current dir with level INFO by default.
|
@@ -155,6 +155,71 @@ This is what we use with the AMI above:
|
|
155
155
|
echo 'Bootstrapping Chef - done'
|
156
156
|
echo '-------------------------'
|
157
157
|
|
158
|
+
## Running with Chef Solo
|
159
|
+
|
160
|
+
Awsborn integrates with [Chef Solo](http://github.com/opscode/chef). An example from reality:
|
161
|
+
|
162
|
+
Awsborn.access_key_id = 'AKIAJHL53MPX7LPCKIFQ'
|
163
|
+
|
164
|
+
class LogServer < Awsborn::Server
|
165
|
+
instance_type :m1_small
|
166
|
+
image_id 'ami-2fc2e95b', :sudo_user => 'ubuntu'
|
167
|
+
security_group 'Basic web'
|
168
|
+
keys '../keys/*'
|
169
|
+
bootstrap_script 'chef-bootstrap.sh'
|
170
|
+
monitor true
|
171
|
+
|
172
|
+
cluster do
|
173
|
+
domain 'releware.net'
|
174
|
+
server :log_a, :zone => :eu_west_1a, :disk => {:sdf => "vol-a857b8c1"}, :ip => 'log-a'
|
175
|
+
server :log_b, :zone => :eu_west_1b, :disk => {:sdf => "vol-aa57b8c3"}, :ip => 'log-b'
|
176
|
+
end
|
177
|
+
|
178
|
+
def chef_dna
|
179
|
+
{
|
180
|
+
:user => "lumberjack",
|
181
|
+
:host => host_name,
|
182
|
+
:users => [
|
183
|
+
{
|
184
|
+
:username => "lumberjack",
|
185
|
+
:authorized_keys => key_data,
|
186
|
+
:gid => 1001,
|
187
|
+
:uid => 1001,
|
188
|
+
:sudo => true,
|
189
|
+
}
|
190
|
+
],
|
191
|
+
:packages => %w[
|
192
|
+
vim
|
193
|
+
heirloom-mailx
|
194
|
+
],
|
195
|
+
:gems => [
|
196
|
+
"rake"
|
197
|
+
],
|
198
|
+
:ebs_volumes => [
|
199
|
+
{:device => "sdf", :path => "/apps"}
|
200
|
+
],
|
201
|
+
:recipes => [
|
202
|
+
"packages",
|
203
|
+
"users",
|
204
|
+
"sudo",
|
205
|
+
"openssh",
|
206
|
+
"ec2-ebs",
|
207
|
+
"git",
|
208
|
+
"gems",
|
209
|
+
]
|
210
|
+
}
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
Just add a `Rakefile` in the same directory:
|
215
|
+
|
216
|
+
require 'awsborn'
|
217
|
+
include Awsborn::Chef::Rake
|
218
|
+
require './servers'
|
219
|
+
|
220
|
+
You are now able to run `rake` to start all servers and run Chef on each of them.
|
221
|
+
See `rake -T` for more options.
|
222
|
+
|
158
223
|
## Bugs and surprising features
|
159
224
|
|
160
225
|
No bugs are known at this time.
|
data/Rakefile
CHANGED
@@ -11,6 +11,7 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/icehouse/awsborn"
|
12
12
|
gem.authors = ["David Vrensk"]
|
13
13
|
gem.add_dependency "icehouse-right_aws", ">= 1.11.0"
|
14
|
+
gem.add_dependency "json_pure", ">= 1.2.3"
|
14
15
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
16
|
gem.add_development_dependency "webmock", ">= 0.9.1"
|
16
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/awsborn/awsborn.rb
CHANGED
@@ -3,7 +3,7 @@ module Awsborn
|
|
3
3
|
class ServerError < StandardError ; end
|
4
4
|
|
5
5
|
class << self
|
6
|
-
attr_writer :access_key_id, :secret_access_key, :logger
|
6
|
+
attr_writer :access_key_id, :secret_access_key, :logger, :remote_chef_path
|
7
7
|
attr_accessor :verbose
|
8
8
|
|
9
9
|
Awsborn.verbose = true
|
@@ -13,7 +13,27 @@ module Awsborn
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def secret_access_key
|
16
|
-
@secret_access_key
|
16
|
+
unless @secret_access_key
|
17
|
+
@secret_access_key = ENV['AMAZON_SECRET_ACCESS_KEY']
|
18
|
+
if @secret_access_key.to_s == ''
|
19
|
+
@secret_access_key = secret_access_key_from_keychain(access_key_id)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@secret_access_key
|
23
|
+
end
|
24
|
+
|
25
|
+
def secret_access_key_from_keychain (key_id)
|
26
|
+
@credentials ||= {}
|
27
|
+
unless @credentials[key_id]
|
28
|
+
dump = `security -q find-generic-password -a "#{key_id}" -g 2>&1`
|
29
|
+
secret_key = dump[/password: "(.*)"/, 1]
|
30
|
+
@credentials[key_id] = secret_key
|
31
|
+
end
|
32
|
+
@credentials[key_id]
|
33
|
+
end
|
34
|
+
|
35
|
+
def remote_chef_path
|
36
|
+
@remote_chef_path ||= '/etc/chef'
|
17
37
|
end
|
18
38
|
|
19
39
|
def logger
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Awsborn
|
2
|
+
class GitBranch
|
3
|
+
|
4
|
+
attr_reader :branch
|
5
|
+
|
6
|
+
def initialize (branch)
|
7
|
+
require 'git'
|
8
|
+
@branch = branch
|
9
|
+
end
|
10
|
+
|
11
|
+
def file (path)
|
12
|
+
path, file = File.split(path)
|
13
|
+
|
14
|
+
repo = Git.open(root)
|
15
|
+
tree = repo.branches[branch].gcommit.gtree
|
16
|
+
path.each { |dir| tree = tree.subtrees[dir] }
|
17
|
+
tree.blobs[file].contents
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def root
|
23
|
+
dir = File.expand_path('.')
|
24
|
+
while dir != '/'
|
25
|
+
return dir if File.directory?(File.join(dir, '.git'))
|
26
|
+
dir = File.dirname(dir)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/awsborn/rake.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Awsborn
|
2
|
+
module Chef
|
3
|
+
module Rake
|
4
|
+
|
5
|
+
def default_cluster
|
6
|
+
default_klass = Awsborn::Server.children.first
|
7
|
+
default_klass.clusters.first
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Start all servers (if needed) and deploy with chef"
|
11
|
+
task :default => [:start, :cook]
|
12
|
+
|
13
|
+
desc "Start all servers"
|
14
|
+
task :start do
|
15
|
+
default_cluster.launch
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Run chef on all servers"
|
19
|
+
task :cook => [:check_syntax] do
|
20
|
+
default_cluster.each do |server|
|
21
|
+
server.cook
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Check your cookbooks and config files for syntax errors"
|
26
|
+
task :check_syntax do
|
27
|
+
Dir["**/*.rb"].each do |recipe|
|
28
|
+
RakeFileUtils.verbose(false) do
|
29
|
+
sh %{ruby -c #{recipe} > /dev/null} do |ok, res|
|
30
|
+
raise "Syntax error in #{recipe}" if not ok
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Create a new cookbook (with cookbook=name)"
|
37
|
+
task :new_cookbook do
|
38
|
+
create_cookbook("cookbooks")
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_cookbook(dir)
|
42
|
+
raise "Must provide a cookbook=" unless ENV["cookbook"]
|
43
|
+
puts "** Creating cookbook #{ENV["cookbook"]}"
|
44
|
+
sh "mkdir -p #{File.join(dir, ENV["cookbook"], "attributes")}"
|
45
|
+
sh "mkdir -p #{File.join(dir, ENV["cookbook"], "recipes")}"
|
46
|
+
sh "mkdir -p #{File.join(dir, ENV["cookbook"], "definitions")}"
|
47
|
+
sh "mkdir -p #{File.join(dir, ENV["cookbook"], "libraries")}"
|
48
|
+
sh "mkdir -p #{File.join(dir, ENV["cookbook"], "files", "default")}"
|
49
|
+
sh "mkdir -p #{File.join(dir, ENV["cookbook"], "templates", "default")}"
|
50
|
+
|
51
|
+
unless File.exists?(File.join(dir, ENV["cookbook"], "recipes", "default.rb"))
|
52
|
+
open(File.join(dir, ENV["cookbook"], "recipes", "default.rb"), "w") do |file|
|
53
|
+
file.puts <<-EOH
|
54
|
+
#
|
55
|
+
# Cookbook Name:: #{ENV["cookbook"]}
|
56
|
+
# Recipe:: default
|
57
|
+
#
|
58
|
+
EOH
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/awsborn/server.rb
CHANGED
@@ -8,7 +8,11 @@ module Awsborn
|
|
8
8
|
end
|
9
9
|
|
10
10
|
class << self
|
11
|
-
attr_accessor :logger
|
11
|
+
attr_accessor :logger, :children, :clusters
|
12
|
+
def inherited (klass)
|
13
|
+
@children ||= []
|
14
|
+
@children << klass
|
15
|
+
end
|
12
16
|
def image_id (*args)
|
13
17
|
unless args.empty?
|
14
18
|
@image_id = args.first
|
@@ -42,7 +46,9 @@ module Awsborn
|
|
42
46
|
end
|
43
47
|
|
44
48
|
def cluster (&block)
|
45
|
-
|
49
|
+
@clusters ||= []
|
50
|
+
@clusters << ServerCluster.build(self, &block)
|
51
|
+
@clusters.last
|
46
52
|
end
|
47
53
|
def logger
|
48
54
|
@logger ||= Awsborn.logger
|
@@ -163,6 +169,25 @@ module Awsborn
|
|
163
169
|
end
|
164
170
|
end
|
165
171
|
|
172
|
+
def cook
|
173
|
+
upload_cookbooks
|
174
|
+
run_chef
|
175
|
+
end
|
176
|
+
|
177
|
+
def upload_cookbooks
|
178
|
+
logger.info "Uploading cookbooks to #{host_name}"
|
179
|
+
File.open("config/dna.json", "w") { |f| f.write(chef_dna.to_json) }
|
180
|
+
sh "rsync -rl --delete --exclude '.*' ./ root@#{host_name}:#{Awsborn.remote_chef_path}"
|
181
|
+
ensure
|
182
|
+
File.delete("config/dna.json")
|
183
|
+
end
|
184
|
+
|
185
|
+
def run_chef
|
186
|
+
logger.info "Running chef on #{host_name}"
|
187
|
+
# Absolute path to config files to avoid a nasty irrational bug.
|
188
|
+
sh "ssh root@#{host_name} \"cd #{Awsborn.remote_chef_path}; chef-solo -c #{Awsborn.remote_chef_path}/config/solo.rb -j #{Awsborn.remote_chef_path}/config/dna.json\""
|
189
|
+
end
|
190
|
+
|
166
191
|
def ec2
|
167
192
|
@ec2 ||= Ec2.new(zone)
|
168
193
|
end
|
data/lib/awsborn.rb
CHANGED
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- David Vrensk
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-19 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -32,9 +32,23 @@ dependencies:
|
|
32
32
|
type: :runtime
|
33
33
|
version_requirements: *id001
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
35
|
+
name: json_pure
|
36
36
|
prerelease: false
|
37
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 2
|
44
|
+
- 3
|
45
|
+
version: 1.2.3
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rspec
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
52
|
requirements:
|
39
53
|
- - ">="
|
40
54
|
- !ruby/object:Gem::Version
|
@@ -44,11 +58,11 @@ dependencies:
|
|
44
58
|
- 9
|
45
59
|
version: 1.2.9
|
46
60
|
type: :development
|
47
|
-
version_requirements: *
|
61
|
+
version_requirements: *id003
|
48
62
|
- !ruby/object:Gem::Dependency
|
49
63
|
name: webmock
|
50
64
|
prerelease: false
|
51
|
-
requirement: &
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
66
|
requirements:
|
53
67
|
- - ">="
|
54
68
|
- !ruby/object:Gem::Version
|
@@ -58,7 +72,7 @@ dependencies:
|
|
58
72
|
- 1
|
59
73
|
version: 0.9.1
|
60
74
|
type: :development
|
61
|
-
version_requirements: *
|
75
|
+
version_requirements: *id004
|
62
76
|
description: Awsborn lets you define and launch a server cluster on Amazon EC2.
|
63
77
|
email: david@icehouse.se
|
64
78
|
executables: []
|
@@ -80,7 +94,9 @@ files:
|
|
80
94
|
- lib/awsborn/ec2.rb
|
81
95
|
- lib/awsborn/extensions/object.rb
|
82
96
|
- lib/awsborn/extensions/proc.rb
|
97
|
+
- lib/awsborn/git_branch.rb
|
83
98
|
- lib/awsborn/known_hosts_updater.rb
|
99
|
+
- lib/awsborn/rake.rb
|
84
100
|
- lib/awsborn/server.rb
|
85
101
|
- lib/awsborn/server_cluster.rb
|
86
102
|
- spec/awsborn_spec.rb
|