heaven 0.0.13 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +3 -12
- data/LICENSE.txt +3 -1
- data/README.md +29 -0
- data/Rakefile +1 -53
- data/heaven.gemspec +23 -0
- data/lib/heaven.rb +262 -3
- data/lib/heaven/version.rb +3 -0
- metadata +56 -107
- data/Gemfile.lock +0 -20
- data/README.rdoc +0 -19
- data/VERSION +0 -1
- data/lib/heaven/god_watcher.rb +0 -169
- data/lib/heaven/heaven.rb +0 -96
- data/test/helper.rb +0 -17
- data/test/test_heaven.rb +0 -7
data/.gitignore
ADDED
data/Gemfile
CHANGED
@@ -1,13 +1,4 @@
|
|
1
|
-
source
|
2
|
-
# Add dependencies required to use your gem here.
|
3
|
-
# Example:
|
4
|
-
# gem "activesupport", ">= 2.3.5"
|
1
|
+
source 'https://rubygems.org'
|
5
2
|
|
6
|
-
#
|
7
|
-
|
8
|
-
gem "god", ">= 0"
|
9
|
-
group :development do
|
10
|
-
gem "bundler", "~> 1.0.0"
|
11
|
-
gem "jeweler", "~> 1.6.4"
|
12
|
-
gem "rcov", ">= 0"
|
13
|
-
end
|
3
|
+
# Specify your gem's dependencies in heaven.gemspec
|
4
|
+
gemspec
|
data/LICENSE.txt
CHANGED
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Heaven
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'heaven'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install heaven
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
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
CHANGED
@@ -1,53 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bundler'
|
5
|
-
begin
|
6
|
-
Bundler.setup(:default, :development)
|
7
|
-
rescue Bundler::BundlerError => e
|
8
|
-
$stderr.puts e.message
|
9
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
-
exit e.status_code
|
11
|
-
end
|
12
|
-
require 'rake'
|
13
|
-
|
14
|
-
require 'jeweler'
|
15
|
-
Jeweler::Tasks.new do |gem|
|
16
|
-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
-
gem.name = "heaven"
|
18
|
-
gem.homepage = "http://github.com/minciue/heaven"
|
19
|
-
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{A set of utilities to make it easier to work with god.}
|
21
|
-
gem.description = %Q{A set of utilities to make it easier to work with god.}
|
22
|
-
gem.email = "eugen@lesseverything.com"
|
23
|
-
gem.authors = ["Eugen Minciu"]
|
24
|
-
# dependencies defined in Gemfile
|
25
|
-
end
|
26
|
-
Jeweler::RubygemsDotOrgTasks.new
|
27
|
-
|
28
|
-
require 'rake/testtask'
|
29
|
-
Rake::TestTask.new(:test) do |test|
|
30
|
-
test.libs << 'lib' << 'test'
|
31
|
-
test.pattern = 'test/**/test_*.rb'
|
32
|
-
test.verbose = true
|
33
|
-
end
|
34
|
-
|
35
|
-
require 'rcov/rcovtask'
|
36
|
-
Rcov::RcovTask.new do |test|
|
37
|
-
test.libs << 'test'
|
38
|
-
test.pattern = 'test/**/test_*.rb'
|
39
|
-
test.verbose = true
|
40
|
-
test.rcov_opts << '--exclude "gems/*"'
|
41
|
-
end
|
42
|
-
|
43
|
-
task :default => :test
|
44
|
-
|
45
|
-
require 'rake/rdoctask'
|
46
|
-
Rake::RDocTask.new do |rdoc|
|
47
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
-
|
49
|
-
rdoc.rdoc_dir = 'rdoc'
|
50
|
-
rdoc.title = "heaven #{version}"
|
51
|
-
rdoc.rdoc_files.include('README*')
|
52
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
-
end
|
1
|
+
require "bundler/gem_tasks"
|
data/heaven.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'heaven/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "heaven"
|
8
|
+
spec.version = Heaven::VERSION
|
9
|
+
spec.authors = ["Corey Donohoe"]
|
10
|
+
spec.email = ["atmos@atmos.org"]
|
11
|
+
spec.description = %q{GitHub Style Deployment App}
|
12
|
+
spec.summary = %q{Up from the 36 Chambers of GitHub}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
data/lib/heaven.rb
CHANGED
@@ -1,4 +1,263 @@
|
|
1
|
-
require
|
1
|
+
require "heaven/version"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
module Heaven
|
4
|
+
# Your code goes here...
|
5
|
+
# class UnicornProcessRestartTimeout < StandardError; end
|
6
|
+
|
7
|
+
# Find a deployable application by name
|
8
|
+
#
|
9
|
+
# Needs to be defined in config/apps.yml
|
10
|
+
def self.app_for(name)
|
11
|
+
Heaven::App.app_for(name)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Logger for sending output to syslog easily
|
15
|
+
#
|
16
|
+
def self.logger
|
17
|
+
@logger ||= Syslog.open("heaven")
|
18
|
+
end
|
19
|
+
|
20
|
+
# The current sha1 that the code is running under
|
21
|
+
#
|
22
|
+
# Returns the short sha for the running process
|
23
|
+
def self.current_sha
|
24
|
+
@current_sha ||= `cd #{root} && git rev-parse HEAD`[0..7]
|
25
|
+
end
|
26
|
+
|
27
|
+
# The root of the heaven project directory
|
28
|
+
#
|
29
|
+
# Returns the absolute path to the heaven project on disk
|
30
|
+
def self.root
|
31
|
+
@root ||= File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
32
|
+
end
|
33
|
+
|
34
|
+
# The installed gems base directory
|
35
|
+
#
|
36
|
+
# We reference files inside of the gem after installation. This gives you
|
37
|
+
# easy access to files in local development and when installed via rubygems
|
38
|
+
def self.base
|
39
|
+
File.expand_path("../", __FILE__)
|
40
|
+
end
|
41
|
+
|
42
|
+
# The user on the remote system that capistrano commands are issued as
|
43
|
+
#
|
44
|
+
# If you're not running inside the VPN, your user probably isn't git
|
45
|
+
#
|
46
|
+
# Returns the UNIX username of the deploy user on the remote system
|
47
|
+
def self.deploy_user
|
48
|
+
@deploy_user ||= 'git'
|
49
|
+
end
|
50
|
+
|
51
|
+
# Set the deploy user capistrano commands are invoked as
|
52
|
+
#
|
53
|
+
# If you're not running inside the VPN, your user probably isn't git.
|
54
|
+
# Use this method to set the user.
|
55
|
+
#
|
56
|
+
# Returns the UNIX username of the deploy user on the remote system
|
57
|
+
def self.deploy_user=(username)
|
58
|
+
@deploy_user = username
|
59
|
+
end
|
60
|
+
|
61
|
+
# The number of fe and fs machines we have for an environment
|
62
|
+
#
|
63
|
+
# fe3.stg.github.com is available but excluded because its rebuild so often
|
64
|
+
#
|
65
|
+
# A Hash based on environment keys that keeps count
|
66
|
+
def self.host_info
|
67
|
+
@host_info ||= {
|
68
|
+
'staging' => { 'fe' => 2, 'fs' => 1, 'worker' => 0 },
|
69
|
+
'production' => { 'fe' => 19, 'fs' => 37, 'worker' => 6 },
|
70
|
+
'lab' => { 'fe' => 1, 'fs' => 0, 'worker' => 0 },
|
71
|
+
'garage' => { 'fe' => 1, 'fs' => 0, 'worker' => 0 },
|
72
|
+
'spider-skull-island' => { 'fe' => 1, 'fs' => 0, 'worker' => 0 },
|
73
|
+
'machine-room' => { 'fe' => 1, 'fs' => 1, 'worker' => 0 },
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
# List of full hostnames that are offline for now
|
78
|
+
#
|
79
|
+
# Can be comma delimited for more than one host
|
80
|
+
# Only useful for fileserver and frontends
|
81
|
+
#
|
82
|
+
# Returns an array of full hostnames
|
83
|
+
def self.offline_hosts
|
84
|
+
@offline_hosts ||= %w(fe5.rs.github.com
|
85
|
+
fe6.rs.github.com
|
86
|
+
fe7.rs.github.com
|
87
|
+
fe8.rs.github.com
|
88
|
+
fe9.rs.github.com
|
89
|
+
fe10.rs.github.com
|
90
|
+
fe11.rs.github.com
|
91
|
+
fe12.rs.github.com
|
92
|
+
fe14.rs.github.com
|
93
|
+
fe15.rs.github.com
|
94
|
+
db2a.rs.github.com
|
95
|
+
fe1.stg.github.com
|
96
|
+
fs1a.rs.github.com
|
97
|
+
fs1b.rs.github.com
|
98
|
+
fs24a.rs.github.com
|
99
|
+
fs24b.rs.github.com)
|
100
|
+
end
|
101
|
+
|
102
|
+
# List the available receipts
|
103
|
+
#
|
104
|
+
# Returns an array of available rackspace application names
|
105
|
+
def self.available_capistrano_applications
|
106
|
+
Heaven::Targets::Capistrano.available_applications
|
107
|
+
end
|
108
|
+
|
109
|
+
# List the available heroku applications
|
110
|
+
#
|
111
|
+
# Returns an array of available heroku application names
|
112
|
+
def self.available_heroku_applications
|
113
|
+
Heaven::Targets::Heroku.deployments.map { |app| app.name }
|
114
|
+
end
|
115
|
+
|
116
|
+
# List the available constructable speakeasy applications
|
117
|
+
#
|
118
|
+
# Returns an array of available constructable speakeasy application names
|
119
|
+
def self.available_constructable_applications
|
120
|
+
Heaven::Targets::Speakeasy.all.map { |app| app.name.downcase }
|
121
|
+
end
|
122
|
+
|
123
|
+
# List all available applications by name
|
124
|
+
#
|
125
|
+
# Returns an array of applications you can ship
|
126
|
+
def self.all_available_applications
|
127
|
+
(available_capistrano_applications | available_heroku_applications | available_constructable_applications).sort
|
128
|
+
end
|
129
|
+
|
130
|
+
# Print the apps that you can deploy
|
131
|
+
#
|
132
|
+
# Defaults to stdout
|
133
|
+
#
|
134
|
+
# Returns nil
|
135
|
+
def self.print_available_applications(out = $stdout)
|
136
|
+
out.puts "Available Applications:"
|
137
|
+
out.puts "-" * 23
|
138
|
+
Heaven.all_available_applications.each do |app|
|
139
|
+
out.printf "%023s\n", app
|
140
|
+
end
|
141
|
+
out.puts
|
142
|
+
end
|
143
|
+
|
144
|
+
# Domain suffix based on environment
|
145
|
+
def self.domain_suffix(environment)
|
146
|
+
case environment
|
147
|
+
when "production","lab"
|
148
|
+
".rs.github.com"
|
149
|
+
else
|
150
|
+
".stg.github.com"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Given a list of hosts, exclude the current offline hosts
|
155
|
+
#
|
156
|
+
# Returns a filtered list of full hostnames to deploy to
|
157
|
+
def self.filter_hosts(hosts)
|
158
|
+
hosts.map do |host|
|
159
|
+
offline_hosts.include?(host) ? nil : host
|
160
|
+
end.compact
|
161
|
+
end
|
162
|
+
|
163
|
+
# Get all file servers in the given environment
|
164
|
+
#
|
165
|
+
# Returns an array of full domain names for all file servers
|
166
|
+
def self.file_servers(environment)
|
167
|
+
if environment == 'machine-room'
|
168
|
+
return [
|
169
|
+
'github-fs102a-cp1-prd.iad.github.net',
|
170
|
+
'github-fs102b-cp1-prd.iad.github.net'
|
171
|
+
]
|
172
|
+
end
|
173
|
+
hosts = [ ]
|
174
|
+
suffix = domain_suffix(environment)
|
175
|
+
1.upto(host_info[environment]["fs"]) do |i|
|
176
|
+
hosts << "fs#{i}a#{suffix}"
|
177
|
+
hosts << "fs#{i}b#{suffix}"
|
178
|
+
end
|
179
|
+
filter_hosts(hosts)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Get all frontends in the given environment
|
183
|
+
#
|
184
|
+
# Returns an array of full domain names for all frontends
|
185
|
+
def self.frontends(environment)
|
186
|
+
return ['github-staff2-pe1-prd.aws.github.net'] if environment == 'garage'
|
187
|
+
return ['github-staff3-pe1-prd.aws.github.net'] if environment == 'spider-skull-island'
|
188
|
+
return ['github-staff4-cp1-prd.iad.github.net'] if environment == 'machine-room'
|
189
|
+
|
190
|
+
hosts = [ ]
|
191
|
+
prefix = environment == 'lab' ? 'staff' : 'fe'
|
192
|
+
suffix = domain_suffix(environment)
|
193
|
+
1.upto(host_info[environment]["fe"]) do |i|
|
194
|
+
hosts << "#{prefix}#{i}#{suffix}"
|
195
|
+
end
|
196
|
+
filter_hosts(hosts)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Get all workers in the given environment
|
200
|
+
#
|
201
|
+
# Returns an array of full domain names for all frontends
|
202
|
+
def self.workers(environment)
|
203
|
+
hosts = [ ]
|
204
|
+
suffix = domain_suffix(environment)
|
205
|
+
1.upto(host_info[environment]["worker"]) do |i|
|
206
|
+
hosts << "worker#{i}#{suffix}"
|
207
|
+
end
|
208
|
+
hosts << "github-worker7-cp1-prd.iad.github.net" if environment == "production"
|
209
|
+
filter_hosts(hosts)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Get all frontends in the given environment
|
213
|
+
#
|
214
|
+
# Returns a comma delimited string of of the full hostnames for all frontends
|
215
|
+
def self.hosts_for_fes(environment)
|
216
|
+
frontends(environment).join(",")
|
217
|
+
end
|
218
|
+
|
219
|
+
# Get all file servers in the given environment
|
220
|
+
#
|
221
|
+
# Returns a comma delimited string of of the full hostnames for all frontends
|
222
|
+
def self.hosts_for_fses(environment)
|
223
|
+
file_servers(environment).join(",")
|
224
|
+
end
|
225
|
+
|
226
|
+
# Get all worker servers in the given environment
|
227
|
+
#
|
228
|
+
# Returns a comma delimited string of of the full hostnames for all frontends
|
229
|
+
def self.hosts_for_workers(environment)
|
230
|
+
workers(environment).join(",")
|
231
|
+
end
|
232
|
+
|
233
|
+
# Expand requested hosts to wildcard match for convenience
|
234
|
+
#
|
235
|
+
# For subset deployments you can specify the hosts you want as comma delimited matches
|
236
|
+
#
|
237
|
+
# ["fe" ] => ["fe1.rs.github.com", "fe2.rs.github.com", "fe3.rs.github.com",
|
238
|
+
# "fe4.rs.github.com", "fe5.rs.github.com", "fe6.rs.github.com", "fe7.rs.github.com"]
|
239
|
+
# ["fe1","fe2" ] => ["fe1.rs.github.com", "fe2.rs.github.com"]
|
240
|
+
# ["fs" ] => ["fs1a.rs.github.com", "fs1b.rs.github.com", "fs2a.rs.github.com", "fs2b.rs.github.com", ... ]
|
241
|
+
# ["fe1","fs2" ] => ["fe1.rs.github.com", "fs2a.rs.github.com", "fs2b.rs.github.com"]
|
242
|
+
def self.expand_hosts(prefixes, environment)
|
243
|
+
suffix = domain_suffix(environment)
|
244
|
+
prefixes.map do |host_prefix|
|
245
|
+
case host_prefix
|
246
|
+
when /fe$/
|
247
|
+
hosts_for_fes(environment)
|
248
|
+
when /fs$/
|
249
|
+
hosts_for_fses(environment)
|
250
|
+
when /worker$/
|
251
|
+
hosts_for_workers(environment)
|
252
|
+
when /fs\d+$/
|
253
|
+
"#{host_prefix}a#{suffix},#{host_prefix}b#{suffix}"
|
254
|
+
when /staff$/
|
255
|
+
"#{host_prefix}1#{suffix}"
|
256
|
+
when /\.aws\.github\.net$/
|
257
|
+
host_prefix
|
258
|
+
else
|
259
|
+
"#{host_prefix}#{suffix}"
|
260
|
+
end
|
261
|
+
end.join(",")
|
262
|
+
end
|
263
|
+
end
|
metadata
CHANGED
@@ -1,137 +1,86 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: heaven
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 13
|
10
|
-
version: 0.0.13
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
13
|
-
-
|
7
|
+
authors:
|
8
|
+
- Corey Donohoe
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
type: :runtime
|
23
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
|
-
requirements:
|
26
|
-
- - ">="
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
hash: 3
|
29
|
-
segments:
|
30
|
-
- 0
|
31
|
-
version: "0"
|
32
|
-
requirement: *id001
|
33
|
-
prerelease: false
|
34
|
-
name: god
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
type: :development
|
37
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
12
|
+
date: 2013-06-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
38
17
|
none: false
|
39
|
-
requirements:
|
18
|
+
requirements:
|
40
19
|
- - ~>
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
segments:
|
44
|
-
- 1
|
45
|
-
- 0
|
46
|
-
- 0
|
47
|
-
version: 1.0.0
|
48
|
-
requirement: *id002
|
49
|
-
prerelease: false
|
50
|
-
name: bundler
|
51
|
-
- !ruby/object:Gem::Dependency
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
52
22
|
type: :development
|
53
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
25
|
none: false
|
55
|
-
requirements:
|
26
|
+
requirements:
|
56
27
|
- - ~>
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
- 4
|
63
|
-
version: 1.6.4
|
64
|
-
requirement: *id003
|
65
|
-
prerelease: false
|
66
|
-
name: jeweler
|
67
|
-
- !ruby/object:Gem::Dependency
|
68
|
-
type: :development
|
69
|
-
version_requirements: &id004 !ruby/object:Gem::Requirement
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
70
33
|
none: false
|
71
|
-
requirements:
|
72
|
-
- -
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
|
75
|
-
|
76
|
-
- 0
|
77
|
-
version: "0"
|
78
|
-
requirement: *id004
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
79
39
|
prerelease: false
|
80
|
-
|
81
|
-
|
82
|
-
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: GitHub Style Deployment App
|
47
|
+
email:
|
48
|
+
- atmos@atmos.org
|
83
49
|
executables: []
|
84
|
-
|
85
50
|
extensions: []
|
86
|
-
|
87
|
-
|
88
|
-
-
|
89
|
-
- README.rdoc
|
90
|
-
files:
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
91
54
|
- Gemfile
|
92
|
-
- Gemfile.lock
|
93
55
|
- LICENSE.txt
|
94
|
-
- README.
|
56
|
+
- README.md
|
95
57
|
- Rakefile
|
96
|
-
-
|
58
|
+
- heaven.gemspec
|
97
59
|
- lib/heaven.rb
|
98
|
-
- lib/heaven/
|
99
|
-
|
100
|
-
|
101
|
-
- test/test_heaven.rb
|
102
|
-
has_rdoc: true
|
103
|
-
homepage: http://github.com/minciue/heaven
|
104
|
-
licenses:
|
60
|
+
- lib/heaven/version.rb
|
61
|
+
homepage: ''
|
62
|
+
licenses:
|
105
63
|
- MIT
|
106
64
|
post_install_message:
|
107
65
|
rdoc_options: []
|
108
|
-
|
109
|
-
require_paths:
|
66
|
+
require_paths:
|
110
67
|
- lib
|
111
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
69
|
none: false
|
113
|
-
requirements:
|
114
|
-
- -
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
|
117
|
-
|
118
|
-
- 0
|
119
|
-
version: "0"
|
120
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
75
|
none: false
|
122
|
-
requirements:
|
123
|
-
- -
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
|
126
|
-
segments:
|
127
|
-
- 0
|
128
|
-
version: "0"
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
129
80
|
requirements: []
|
130
|
-
|
131
81
|
rubyforge_project:
|
132
|
-
rubygems_version: 1.
|
82
|
+
rubygems_version: 1.8.23
|
133
83
|
signing_key:
|
134
84
|
specification_version: 3
|
135
|
-
summary:
|
85
|
+
summary: Up from the 36 Chambers of GitHub
|
136
86
|
test_files: []
|
137
|
-
|
data/Gemfile.lock
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: http://rubygems.org/
|
3
|
-
specs:
|
4
|
-
git (1.2.5)
|
5
|
-
god (0.11.0)
|
6
|
-
jeweler (1.6.4)
|
7
|
-
bundler (~> 1.0)
|
8
|
-
git (>= 1.2.5)
|
9
|
-
rake
|
10
|
-
rake (0.9.2)
|
11
|
-
rcov (0.9.10)
|
12
|
-
|
13
|
-
PLATFORMS
|
14
|
-
ruby
|
15
|
-
|
16
|
-
DEPENDENCIES
|
17
|
-
bundler (~> 1.0.0)
|
18
|
-
god
|
19
|
-
jeweler (~> 1.6.4)
|
20
|
-
rcov
|
data/README.rdoc
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
= heaven
|
2
|
-
|
3
|
-
A set of utilities to make it easier to work with god.
|
4
|
-
|
5
|
-
== Contributing to heaven
|
6
|
-
|
7
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
-
* Fork the project
|
10
|
-
* Start a feature/bugfix branch
|
11
|
-
* Commit and push until you are happy with your contribution
|
12
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
-
|
15
|
-
== Copyright
|
16
|
-
|
17
|
-
Copyright (c) 2011 Eugen Minciu. See LICENSE.txt for
|
18
|
-
further details.
|
19
|
-
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.0.13
|
data/lib/heaven/god_watcher.rb
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
class HeavenConfigurationError < StandardError; end
|
2
|
-
class GodWatcher # :nodoc:all
|
3
|
-
def initialize(name, options = {})
|
4
|
-
@name = name
|
5
|
-
@start = options[:start]
|
6
|
-
@stop = options[:stop]
|
7
|
-
@restart = options[:restart]
|
8
|
-
@pid_file = options[:pid_file]
|
9
|
-
@log_file = options[:log_file]
|
10
|
-
@uid = options[:uid]
|
11
|
-
@gid = options[:gid]
|
12
|
-
|
13
|
-
@interval = options[:interval] || 15.seconds
|
14
|
-
@grace = options[:grace] || 15.seconds
|
15
|
-
|
16
|
-
@behaviors = options[:behaviors] || []
|
17
|
-
|
18
|
-
@max_memory = options[:max_memory] || 250.megabytes
|
19
|
-
@max_cpu = options[:max_cpu] || 50.percent
|
20
|
-
@max_times = options[:max_times] || 5
|
21
|
-
|
22
|
-
@check_flapping = options[:check_flapping].nil? ? true : options[:check_flapping]
|
23
|
-
@check_memory = options[:check_memory].nil? ? true : options[:check_memory]
|
24
|
-
@check_cpu = options[:check_cpu].nil? ? true : options[:check_cpu]
|
25
|
-
@check_url = options[:check_url].nil? ? false : options[:check_url]
|
26
|
-
|
27
|
-
@email_notifications = options[:email_notifications] || false
|
28
|
-
@email_from_address = options[:email_from_address]
|
29
|
-
@email_from_name = options[:email_from_name] || "God"
|
30
|
-
@email_delivery_method = options[:email_delivery_method] || :sendmail
|
31
|
-
@email_to = options[:email_to] || []
|
32
|
-
|
33
|
-
@campfire_notifications = options[:campfire_notifications] || false
|
34
|
-
@campfire_subdomain = options[:campfire_subdomain]
|
35
|
-
@campfire_token = options[:campfire_token]
|
36
|
-
@campfire_room = options[:campfire_room]
|
37
|
-
|
38
|
-
@url = options[:url]
|
39
|
-
@url_timeout = options[:url_timeout] || 10.seconds
|
40
|
-
end
|
41
|
-
|
42
|
-
def watch
|
43
|
-
set_god_defaults unless @god_defaults_set
|
44
|
-
|
45
|
-
God.watch do |w|
|
46
|
-
w.name = @name
|
47
|
-
w.interval = @interval
|
48
|
-
w.start = @start
|
49
|
-
w.stop = @stop
|
50
|
-
w.restart = @restart if @restart # not mandatory, if we don't specify it god will do a stop and a start
|
51
|
-
w.pid_file = @pid_file if @pid_file
|
52
|
-
w.log = @log_file if @log_file
|
53
|
-
w.uid = @uid if @uid
|
54
|
-
w.gid = @gid if @gid
|
55
|
-
|
56
|
-
w.start_grace = @grace
|
57
|
-
w.restart_grace = @grace
|
58
|
-
|
59
|
-
@behaviors.each { |b| w.behavior(b) }
|
60
|
-
|
61
|
-
unless @check_url
|
62
|
-
# determine the state on startup
|
63
|
-
w.transition(:init, { true => :up, false => :start }) do |on|
|
64
|
-
on.condition(:process_running) do |c|
|
65
|
-
c.running = true
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# determine when process has finished starting
|
70
|
-
w.transition([:start, :restart], :up) do |on|
|
71
|
-
on.condition(:process_running) do |c|
|
72
|
-
c.running = true
|
73
|
-
end
|
74
|
-
|
75
|
-
# failsafe
|
76
|
-
on.condition(:tries) do |c|
|
77
|
-
c.times = @max_times
|
78
|
-
c.transition = :start
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# start if process is not running
|
83
|
-
w.transition(:up, :start) do |on|
|
84
|
-
on.condition(:process_exits)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
if @check_memory || @check_cpu
|
89
|
-
# restart if memory or cpu is too high
|
90
|
-
w.transition(:up, :restart) do |on|
|
91
|
-
if @check_memory
|
92
|
-
on.condition(:memory_usage) do |c|
|
93
|
-
c.above = @max_memory
|
94
|
-
c.times = @max_times
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
if @check_cpu
|
99
|
-
on.condition(:cpu_usage) do |c|
|
100
|
-
c.above = @max_cpu
|
101
|
-
c.times = @max_times
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
if @check_url
|
108
|
-
u = URI.parse(@url)
|
109
|
-
w.transition(:up, :restart) do |on|
|
110
|
-
on.condition(:http_response_code) do |c|
|
111
|
-
c.host = u.host
|
112
|
-
c.port = u.port
|
113
|
-
c.path = u.path
|
114
|
-
c.code_is_not = 200
|
115
|
-
c.timeout = @url_timeout
|
116
|
-
c.times = @max_times
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
if @check_flapping
|
122
|
-
w.lifecycle do |check|
|
123
|
-
check.condition(:flapping) do |c|
|
124
|
-
c.to_state = [:start, :restart]
|
125
|
-
c.times = 5
|
126
|
-
c.within = 5.minutes
|
127
|
-
c.transition = :unmonitored
|
128
|
-
c.retry_in = 10.minutes
|
129
|
-
c.retry_times = 5
|
130
|
-
c.retry_within = 2.hours
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def set_god_defaults
|
138
|
-
raise HeavenConfigurationError, "You must specify at least one email address" if @email_notifications == true && @to_emails.empty?
|
139
|
-
|
140
|
-
if @email_notifications
|
141
|
-
God::Contacts::Email.defaults do |d|
|
142
|
-
d.from_email = @email_from_address
|
143
|
-
d.from_name = @email_from_name
|
144
|
-
d.delivery_method = @email_delivery_method
|
145
|
-
end
|
146
|
-
|
147
|
-
@email_to.each do |email|
|
148
|
-
God.contact(:email) do |c|
|
149
|
-
c.name = email
|
150
|
-
c.to_email = email
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
if @campfire_notifications
|
156
|
-
God::Contacts::Campfire.defaults do |d|
|
157
|
-
d.subdomain = @campfire_subdomain
|
158
|
-
d.token = @campfire_token
|
159
|
-
d.room = @campfire_room
|
160
|
-
d.ssl = true
|
161
|
-
end
|
162
|
-
end
|
163
|
-
@god_defaults_set = true
|
164
|
-
end
|
165
|
-
|
166
|
-
def enforce(var, msg)
|
167
|
-
raise HeavenConfigurationError.new(msg) if var.blank?
|
168
|
-
end
|
169
|
-
end
|
data/lib/heaven/heaven.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
class Heaven
|
2
|
-
class << self
|
3
|
-
# Set the default options for all subsequent watch calls
|
4
|
-
#
|
5
|
-
# Available options are:
|
6
|
-
#
|
7
|
-
# start:: start command;mandatory
|
8
|
-
# stop:: stop command; mandatory
|
9
|
-
# restart:: restart command; optional, if none is specified then god will execute a stop and a start
|
10
|
-
#
|
11
|
-
# pid_file:: the full path of the pid file the service uses
|
12
|
-
# log_file:: the full path of the log file where all the daemon's output will be dumped
|
13
|
-
#
|
14
|
-
# uid:: the user this service needs to be run as
|
15
|
-
# gid:: the group this service needs to be run as
|
16
|
-
#
|
17
|
-
# interval:: interval to poll the service and check against the conditions (default: 15s)
|
18
|
-
# grace:: wait interval while starting or restarting the service before beginning to monitor it again (default: 15s)
|
19
|
-
# behaviors:: god behaviors to enforce for this service, see god documentation (default: [:clean_pid_file])
|
20
|
-
#
|
21
|
-
# check_flapping:: check to see if the process keeps being restarted ad-infinitum and stop trying to restart it
|
22
|
-
# check_memory:: check memory usage (default: true)
|
23
|
-
# check_cpu:: check cpu usage (default: true)
|
24
|
-
#
|
25
|
-
# max_memory:: restart the service if its memory usage exceeds this much on [max_times] consecutive polls (default: 250.megabytes)
|
26
|
-
# max_cpu:: restart the service if its cpu usage exceeds this much on [max_times] consecutive polls (default: 50.percent)
|
27
|
-
# max_times:: see the above (default: 5)
|
28
|
-
def defaults(options=nil)
|
29
|
-
if options.nil?
|
30
|
-
@defaults || {}
|
31
|
-
else
|
32
|
-
@defaults = options
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Watch a run-of-the-mill UNIX daemon
|
37
|
-
#
|
38
|
-
# It takes all the options available to defaults *and*:
|
39
|
-
# script:: name of the daemon's command script (it must take options stop, start and restart)
|
40
|
-
def watch_daemon(name, options = {})
|
41
|
-
script = options.delete(:script)
|
42
|
-
if script
|
43
|
-
options[:start] = "#{script} start"
|
44
|
-
options[:stop] = "#{script} stop"
|
45
|
-
options[:restart] = "#{script} restart"
|
46
|
-
end
|
47
|
-
|
48
|
-
GodWatcher.new(name, defaults.merge(options)).watch
|
49
|
-
end
|
50
|
-
|
51
|
-
# Watch a mongrel Rails app
|
52
|
-
#
|
53
|
-
# It takes all the options available to defaults *and*:
|
54
|
-
#
|
55
|
-
# env:: environment to run under
|
56
|
-
# root:: application's root dir (e.g. /var/rails/myapp/current)
|
57
|
-
# pid_prefix:: the prefix of the pid file (takes something like tmp/pids/yourapp and looks for pids like tmp/pids/yourapp.12345.pid)
|
58
|
-
# log_prefix:: the prefix of the mongrel log file (takes something like log/yourapp and looks for logs like log/yourapp.12345.log)
|
59
|
-
# ports:: a list of ports the mongrels run on
|
60
|
-
def watch_mongrel(name, options = {})
|
61
|
-
env = options.delete(:env)
|
62
|
-
root = options.delete(:root)
|
63
|
-
pid_prefix = options.delete(:pid_prefix)
|
64
|
-
log_prefix = options.delete(:log_prefix)
|
65
|
-
ports = options.delete(:ports)
|
66
|
-
|
67
|
-
ports.each do |port|
|
68
|
-
mongrel_hash = {
|
69
|
-
:start => "mongrel_rails start -d -e #{env} -c #{root} -p #{port} -P #{root}/#{pid_prefix}.#{port}.pid -l #{root}/#{log_prefix}.#{port}.log",
|
70
|
-
:stop => "mongrel_rails stop -c #{root} -p #{port} -P #{root}/#{pid_prefix}.#{port}.pid",
|
71
|
-
:pid_file => "/var/rails/lessmemories/current/log/mongrel.#{port}.pid"
|
72
|
-
}
|
73
|
-
GodWatcher.new("#{name}-#{env}-#{port}", defaults.merge(mongrel_hash).merge(options)).watch
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Watch a URL
|
78
|
-
#
|
79
|
-
# It takes all the options available to defaults *and*:
|
80
|
-
#
|
81
|
-
# url:: the url to watch
|
82
|
-
# url_timeout:: how long to wait for a status
|
83
|
-
#
|
84
|
-
# Note that the start and stop options are ignored, this just restarts the service
|
85
|
-
def watch_url(name, options = {})
|
86
|
-
options[:check_cpu] = false
|
87
|
-
options[:check_memory] = false
|
88
|
-
options[:check_flapping] = false
|
89
|
-
options[:check_url] = true
|
90
|
-
|
91
|
-
options[:start] = ""
|
92
|
-
options[:stop] = ""
|
93
|
-
GodWatcher.new(name, defaults.merge(options)).watch
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
data/test/helper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
begin
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'test/unit'
|
11
|
-
|
12
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
13
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
-
require 'heaven'
|
15
|
-
|
16
|
-
class Test::Unit::TestCase
|
17
|
-
end
|