heaven 0.0.13 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
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
data/Gemfile CHANGED
@@ -1,13 +1,4 @@
1
- source "http://rubygems.org"
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
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
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
@@ -1,4 +1,6 @@
1
- Copyright (c) 2011 Eugen Minciu
1
+ Copyright (c) 2013 Corey Donohoe
2
+
3
+ MIT License
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
@@ -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
- # encoding: utf-8
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"
@@ -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
@@ -1,4 +1,263 @@
1
- require 'uri'
1
+ require "heaven/version"
2
2
 
3
- require 'heaven/heaven'
4
- require 'heaven/god_watcher'
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
@@ -0,0 +1,3 @@
1
+ module Heaven
2
+ VERSION = "0.1.0"
3
+ 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
- hash: 5
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
- - Eugen Minciu
7
+ authors:
8
+ - Corey Donohoe
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-08-20 00:00:00 +03:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
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
- hash: 23
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
- version_requirements: &id003 !ruby/object:Gem::Requirement
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
- hash: 7
59
- segments:
60
- - 1
61
- - 6
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
- hash: 3
75
- segments:
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
- name: rcov
81
- description: A set of utilities to make it easier to work with god.
82
- email: eugen@lesseverything.com
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
- extra_rdoc_files:
88
- - LICENSE.txt
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.rdoc
56
+ - README.md
95
57
  - Rakefile
96
- - VERSION
58
+ - heaven.gemspec
97
59
  - lib/heaven.rb
98
- - lib/heaven/god_watcher.rb
99
- - lib/heaven/heaven.rb
100
- - test/helper.rb
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
- hash: 3
117
- segments:
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
- hash: 3
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.4.2
82
+ rubygems_version: 1.8.23
133
83
  signing_key:
134
84
  specification_version: 3
135
- summary: A set of utilities to make it easier to work with god.
85
+ summary: Up from the 36 Chambers of GitHub
136
86
  test_files: []
137
-
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,7 +0,0 @@
1
- require 'helper'
2
-
3
- class TestHeaven < Test::Unit::TestCase
4
- def test_something_for_real
5
- flunk "hey buddy, you should probably rename this file and start testing for real"
6
- end
7
- end