ops 1.0.0.pre → 1.1.0
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.
- checksums.yaml +4 -4
- data/README.md +27 -7
- data/lib/ops.rb +2 -3
- data/lib/ops/config.rb +8 -8
- data/lib/ops/heartbeat.rb +4 -7
- data/lib/ops/revision.rb +89 -31
- data/lib/ops/server.rb +22 -12
- data/lib/ops/server/helpers.rb +6 -14
- data/lib/ops/server/views/{env.html.erb → env.erb} +0 -0
- data/lib/ops/server/views/{layout.html.erb → layout.erb} +0 -0
- data/lib/ops/server/views/version.erb +76 -0
- data/lib/ops/version.rb +1 -1
- metadata +25 -73
- data/.gitignore +0 -18
- data/.rspec +0 -2
- data/Gemfile +0 -16
- data/Gemfile.lock +0 -129
- data/LICENSE +0 -7
- data/Rakefile +0 -28
- data/examples/rails3/.gitignore +0 -15
- data/examples/rails3/.rspec +0 -3
- data/examples/rails3/Gemfile +0 -5
- data/examples/rails3/Gemfile.lock +0 -130
- data/examples/rails3/Rakefile +0 -13
- data/examples/rails3/config.ru +0 -4
- data/examples/rails3/config/application.rb +0 -37
- data/examples/rails3/config/boot.rb +0 -6
- data/examples/rails3/config/environment.rb +0 -5
- data/examples/rails3/config/initializers/secret_token.rb +0 -1
- data/examples/rails3/config/locales/en.yml +0 -5
- data/examples/rails3/config/routes.rb +0 -3
- data/examples/rails3/public/404.html +0 -26
- data/examples/rails3/public/422.html +0 -26
- data/examples/rails3/public/500.html +0 -25
- data/examples/rails3/public/favicon.ico +0 -0
- data/examples/rails3/public/index.html +0 -14
- data/examples/rails3/public/robots.txt +0 -5
- data/examples/rails3/script/rails +0 -6
- data/examples/rails3/spec/functional/ops_routes_spec.rb +0 -69
- data/examples/rails3/spec/spec_helper.rb +0 -5
- data/examples/sample_deploys/1234/REVISION +0 -1
- data/examples/sample_deploys/1234/VERSION +0 -1
- data/examples/sample_deploys/2341/REVISION +0 -1
- data/examples/sample_deploys/2341/VERSION +0 -1
- data/examples/sample_deploys/3412/REVISION +0 -1
- data/examples/sample_deploys/3412/VERSION +0 -1
- data/examples/sample_deploys/4123/REVISION +0 -1
- data/examples/sample_deploys/4123/VERSION +0 -1
- data/examples/sinatra/.rspec +0 -3
- data/examples/sinatra/Rakefile +0 -15
- data/examples/sinatra/app.rb +0 -14
- data/examples/sinatra/config.ru +0 -20
- data/examples/sinatra/spec/functional/ops_routes_spec.rb +0 -69
- data/examples/sinatra/spec/spec_helper.rb +0 -3
- data/lib/ops/server/views/version.html.erb +0 -53
- data/ops.gemspec +0 -22
- data/spec/functional/ops_routes_spec.rb +0 -69
- data/spec/ops/config_spec.rb +0 -0
- data/spec/ops/heartbeat_spec.rb +0 -49
- data/spec/ops/revision_spec.rb +0 -42
- data/spec/ops/server_spec.rb +0 -66
- data/spec/ops/version_spec.rb +0 -7
- data/spec/ops_spec.rb +0 -9
- data/spec/spec_helper.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5858a2e0dde21d89b70cb34b9e96ca51829443c
|
4
|
+
data.tar.gz: d502e55582d6d4ff4b027c7f5dc507c2f1816da4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb1b3cafc156a9da0719726ca846d84c74d1ab2da4fd0689573a640515878413538d33688f113a1d25fa2a9d8360fb4d4b9933ce640281ad8178ff4639fabff4
|
7
|
+
data.tar.gz: f70c5bcdb1be85cf20d36064a72035301f75a2f1bef054838924c710915e27691dc25200c5bd816d370543fea98c88a1138217f8b3fdf32e2fae877c617071d4
|
data/README.md
CHANGED
@@ -1,9 +1,22 @@
|
|
1
|
-
Ops
|
2
|
-
|
1
|
+
# Ops
|
2
|
+
This gem provides standardized support for obtaining environment, version, and heartbeat information from Sinatra or Rails-based web applications.
|
3
3
|
|
4
4
|
[](https://codeclimate.com/github/primedia/ops)
|
5
|
+
[](https://travis-ci.org/rentpath/ops)
|
6
|
+
|
7
|
+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
8
|
+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
9
|
+
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
|
10
|
+
|
11
|
+
- [Installation](#installation)
|
12
|
+
- [For Rails apps:](#for-rails-apps)
|
13
|
+
- [For Sinatra apps:](#for-sinatra-apps)
|
14
|
+
- [Adding Custom Heartbeats](#adding-custom-heartbeats)
|
15
|
+
- [The Configuration Service Adapter (Optional)](#the-configuration-service-adapter-optional)
|
16
|
+
- [Running tests](#running-tests)
|
17
|
+
|
18
|
+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
5
19
|
|
6
|
-
This gem provides standardized support for obtaining environment, version, and heartbeat information from Sinatra or Rails-based web applications.
|
7
20
|
|
8
21
|
**You will likely want to block or restrict access to the following routes:**
|
9
22
|
|
@@ -27,7 +40,7 @@ This gem replaces the now-deprecated [ops_routes](https://github.com/rentpath/op
|
|
27
40
|
Installation
|
28
41
|
------------
|
29
42
|
|
30
|
-
### For Rails
|
43
|
+
### For Rails apps:
|
31
44
|
|
32
45
|
1. Add the gem to your project's Gemfile:
|
33
46
|
```ruby
|
@@ -40,6 +53,7 @@ Installation
|
|
40
53
|
Ops.setup do |config|
|
41
54
|
config.file_root = Rails.root
|
42
55
|
config.environment = Rails.env
|
56
|
+
config.repo_name = 'my_repository_name'
|
43
57
|
config.config_service_adapter = something_that_responds_to_call # optional
|
44
58
|
end
|
45
59
|
```
|
@@ -79,8 +93,8 @@ Installation
|
|
79
93
|
```ruby
|
80
94
|
# Implementation within rack cascade:
|
81
95
|
run Rack::Cascade.new([
|
82
|
-
|
83
|
-
|
96
|
+
MyApp,
|
97
|
+
MySearch::App,
|
84
98
|
Ops.rack_app('/ops')
|
85
99
|
])
|
86
100
|
```
|
@@ -98,7 +112,10 @@ Ops.add_heartbeat :mysql do
|
|
98
112
|
end
|
99
113
|
```
|
100
114
|
|
101
|
-
The mysql example shown above would be accessed at ops/heartbeat/mysql.
|
115
|
+
The mysql example shown above would be accessed at ops/heartbeat/mysql.
|
116
|
+
The heartbeat page will return a `200 ‘OK’` as long as the provided block returns true.
|
117
|
+
If an error is raised, the heartbeat does not exist, or the block returns a falsey value,
|
118
|
+
a `500` will be returned instead.
|
102
119
|
|
103
120
|
|
104
121
|
## The Configuration Service Adapter (Optional)
|
@@ -124,3 +141,6 @@ Proc.new { |_| { key: 'value' } }
|
|
124
141
|
|
125
142
|
Then just provide your "callable" per the installation instructions above.
|
126
143
|
|
144
|
+
### Running tests
|
145
|
+
|
146
|
+
script/test
|
data/lib/ops.rb
CHANGED
data/lib/ops/config.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Ops
|
2
2
|
class Config
|
3
|
-
def initialize(data={})
|
3
|
+
def initialize(data = {})
|
4
4
|
@data = {}
|
5
5
|
update!(data)
|
6
6
|
end
|
@@ -16,16 +16,16 @@ module Ops
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def []=(key, value)
|
19
|
-
if value.class == Hash
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
@data[key.to_sym] = if value.class == Hash
|
20
|
+
Config.new(value)
|
21
|
+
else
|
22
|
+
value
|
23
|
+
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def method_missing(sym, *args)
|
26
|
+
def method_missing(sym, *args) # rubocop:disable Style/MethodMissing
|
27
27
|
if sym.to_s =~ /(.+)=$/
|
28
|
-
self[
|
28
|
+
self[Regexp.last_match(1)] = args.first
|
29
29
|
else
|
30
30
|
self[sym]
|
31
31
|
end
|
data/lib/ops/heartbeat.rb
CHANGED
@@ -23,13 +23,10 @@ module Ops
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def check(name)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
puts "Exception: #{e}\n#{e.backtrace[2..-1].join("\n")}" unless heartbeats[name.to_sym].nil?
|
31
|
-
return false
|
32
|
-
end
|
26
|
+
return heartbeats[name.to_sym].call
|
27
|
+
rescue StandardError => e
|
28
|
+
puts "Error: #{e}\n#{e.backtrace[2..-1].join("\n")}" unless heartbeats[name.to_sym].nil?
|
29
|
+
return false
|
33
30
|
end
|
34
31
|
end
|
35
32
|
|
data/lib/ops/revision.rb
CHANGED
@@ -1,63 +1,121 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
1
|
module Ops
|
4
2
|
class Revision
|
5
|
-
|
3
|
+
attr_writer :branch_source
|
6
4
|
|
7
|
-
def initialize(new_headers={}, opts = Ops.config)
|
5
|
+
def initialize(new_headers = {}, opts = Ops.config)
|
8
6
|
@file_root = opts.file_root.to_s # convert to string in case they pass us a Pathname
|
9
7
|
@environment = opts.environment
|
10
8
|
@headers = new_headers
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
@
|
11
|
+
def version_or_branch
|
12
|
+
@version ||= if version_file?
|
13
|
+
chomp(version_file).gsub('^{}', '')
|
14
|
+
elsif development? && branch_source.call =~ /^\* (.*)$/
|
15
|
+
Regexp.last_match(1)
|
16
|
+
else
|
17
|
+
'Unknown (VERSION file is missing)'
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
|
-
def
|
18
|
-
@
|
21
|
+
def previous_versions
|
22
|
+
@previous_versions ||= get_previous_by_time
|
19
23
|
end
|
20
24
|
|
21
|
-
def
|
22
|
-
|
25
|
+
def get_previous_by_time
|
26
|
+
get_previous_versions.sort_by { |a| a[:time] }
|
23
27
|
end
|
24
28
|
|
25
|
-
def
|
26
|
-
|
29
|
+
def get_previous_versions
|
30
|
+
Dir["#{path}/../*"].each_with_object([]) do |dir, array|
|
31
|
+
next if dir =~ /#{current_dir}$/
|
32
|
+
version, revision = File.join(dir, 'VERSION'), File.join(dir, 'REVISION')
|
33
|
+
array << stats_hash(version: version, revision: revision) if File.exist?(version) && File.exist?(revision)
|
34
|
+
end
|
27
35
|
end
|
28
36
|
|
29
|
-
|
37
|
+
def path
|
38
|
+
File.absolute_path file_root
|
39
|
+
end
|
30
40
|
|
31
|
-
def
|
32
|
-
|
41
|
+
def current_dir
|
42
|
+
file_root.split('/').last
|
33
43
|
end
|
34
44
|
|
35
|
-
def
|
36
|
-
|
45
|
+
def stats_hash(files)
|
46
|
+
{ version: get_version(files[:version]),
|
47
|
+
revision: get_revision(files[:revision]),
|
48
|
+
time: get_time(files[:revision]) }
|
37
49
|
end
|
38
50
|
|
39
|
-
def
|
40
|
-
|
51
|
+
def get_version(file)
|
52
|
+
chomp(file).gsub('^{}', '')
|
41
53
|
end
|
42
54
|
|
43
|
-
def
|
44
|
-
|
55
|
+
def get_revision(file)
|
56
|
+
chomp file
|
45
57
|
end
|
46
58
|
|
47
|
-
def
|
48
|
-
|
49
|
-
parse_info_file(name)
|
50
|
-
else
|
51
|
-
{name.downcase.gsub('-', '_') => "No #{name} file found"}
|
52
|
-
end
|
59
|
+
def chomp(file)
|
60
|
+
File.read(file).chomp
|
53
61
|
end
|
54
62
|
|
55
|
-
def
|
56
|
-
|
63
|
+
def get_time(file)
|
64
|
+
File.stat(file).mtime
|
57
65
|
end
|
58
66
|
|
59
|
-
|
60
|
-
|
67
|
+
attr_reader :file_root
|
68
|
+
|
69
|
+
attr_reader :environment
|
70
|
+
|
71
|
+
def development?
|
72
|
+
environment == 'development'
|
73
|
+
end
|
74
|
+
|
75
|
+
def version_file
|
76
|
+
@version_file ||= File.join(file_root, 'VERSION')
|
77
|
+
end
|
78
|
+
|
79
|
+
def version_file?
|
80
|
+
File.exist? version_file
|
81
|
+
end
|
82
|
+
|
83
|
+
def revision_file
|
84
|
+
@revision_file ||= File.join(file_root, 'REVISION')
|
85
|
+
end
|
86
|
+
|
87
|
+
def revision_file?
|
88
|
+
File.exist? revision_file
|
89
|
+
end
|
90
|
+
|
91
|
+
def deploy_date
|
92
|
+
@deploy_date ||= if version_file?
|
93
|
+
get_time version_file
|
94
|
+
elsif development?
|
95
|
+
'Live'
|
96
|
+
else
|
97
|
+
'Unknown (VERSION file is missing)'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def last_commit
|
102
|
+
@last_commit ||= if revision_file?
|
103
|
+
chomp revision_file
|
104
|
+
elsif development? && `git show` =~ /^commit (.*)$/
|
105
|
+
Regexp.last_match(1)
|
106
|
+
else
|
107
|
+
'Unknown (REVISION file is missing)'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def headers
|
112
|
+
@headers.select { |k, v| k.match(/^[-A-Z_].*$/) }
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def branch_source
|
118
|
+
@branch_source ||= -> { `git branch` }
|
61
119
|
end
|
62
120
|
end
|
63
121
|
end
|
data/lib/ops/server.rb
CHANGED
@@ -1,22 +1,30 @@
|
|
1
1
|
require 'sinatra/base'
|
2
|
-
require 'sinatra/respond_to'
|
3
2
|
require 'ops/server/helpers'
|
4
3
|
require 'json'
|
5
4
|
|
6
5
|
module Ops
|
7
6
|
class Server < Sinatra::Base
|
8
|
-
|
9
|
-
|
10
|
-
set :views,
|
7
|
+
dir = File.dirname(File.expand_path('', __FILE__))
|
8
|
+
set :views, "#{dir}/server/views"
|
9
|
+
# set :views, File.dirname(File.expand_path('/../server/views', __FILE__))
|
11
10
|
|
12
11
|
helpers Ops::Helpers
|
13
12
|
|
14
13
|
def request_headers
|
15
|
-
env.each_with_object({}) { |(k,v), headers| headers[k] = v }
|
14
|
+
env.each_with_object({}) { |(k, v), headers| headers[k] = v }
|
16
15
|
end
|
17
16
|
|
18
|
-
def jsonified_version(version, headers)
|
19
|
-
JSON.generate(
|
17
|
+
def jsonified_version(version, previous_versions, headers)
|
18
|
+
JSON.generate(
|
19
|
+
version: version.version_or_branch,
|
20
|
+
revision: version.last_commit,
|
21
|
+
previous_versions: previous_versions,
|
22
|
+
headers: headers
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def json_request?
|
27
|
+
!!Array(params['format'] || request.accept).detect { |f| f.to_s =~ /json/ }
|
20
28
|
end
|
21
29
|
|
22
30
|
get '/env/?' do
|
@@ -24,14 +32,17 @@ module Ops
|
|
24
32
|
erb :env
|
25
33
|
end
|
26
34
|
|
27
|
-
get '/version
|
35
|
+
get '/version/?:format?', provides: %i(html json) do
|
28
36
|
@version = Revision.new(request_headers)
|
37
|
+
@previous_versions = @version.previous_versions
|
29
38
|
@headers = @version.headers
|
30
39
|
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
if json_request?
|
41
|
+
content_type 'application/json'
|
42
|
+
return jsonified_version(@version, @previous_versions, @headers)
|
34
43
|
end
|
44
|
+
|
45
|
+
erb :version
|
35
46
|
end
|
36
47
|
|
37
48
|
get '/heartbeat/?' do
|
@@ -62,4 +73,3 @@ module Ops
|
|
62
73
|
end
|
63
74
|
end
|
64
75
|
end
|
65
|
-
|
data/lib/ops/server/helpers.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Ops
|
2
2
|
module Helpers
|
3
|
-
GITHUB_ORG_LINK = 'https://github.com/rentpath'
|
3
|
+
GITHUB_ORG_LINK = 'https://github.com/rentpath'.freeze
|
4
4
|
|
5
5
|
def hostname
|
6
6
|
@hostname ||= `/bin/hostname` || 'Unknown'
|
@@ -25,22 +25,14 @@ module Ops
|
|
25
25
|
github_link 'commit', commit
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
|
28
|
+
def repo_name
|
29
|
+
Ops.config[:repo_name] || app_name
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
output << "{\n"
|
36
|
-
output << object.collect { |key, value|
|
37
|
-
" " * indent + " #{print_detail key} => #{print_detail value, indent+1}"
|
38
|
-
}.join(",\n") << "\n"
|
39
|
-
output << " " * indent + "}"
|
40
|
-
else
|
41
|
-
output << object.inspect
|
32
|
+
def github_link(resource, subresource)
|
33
|
+
unless subresource =~ /^Unknown/
|
34
|
+
"<a href='#{GITHUB_ORG_LINK}/#{repo_name}/#{resource}/#{subresource}'>#{subresource}</a>"
|
42
35
|
end
|
43
|
-
output
|
44
36
|
end
|
45
37
|
end
|
46
38
|
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,76 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="spacer"></div>
|
3
|
+
<div id="version">
|
4
|
+
<div class="label">
|
5
|
+
<%= "#{app_name} Version" %>
|
6
|
+
</div>
|
7
|
+
<div class="value">
|
8
|
+
<%= version_link @version.version_or_branch %>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
<div class="spacer"></div>
|
12
|
+
<div id="date">
|
13
|
+
<div class="label">Date Deployed</div>
|
14
|
+
<div class="value"><%= @version.deploy_date %></div>
|
15
|
+
</div>
|
16
|
+
<div class="spacer"></div>
|
17
|
+
<div id="commit">
|
18
|
+
<div class="label">Last Commit</div>
|
19
|
+
<div class="value">
|
20
|
+
<%= commit_link(@version.last_commit)%>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
<div class="spacer"></div>
|
24
|
+
<div id="host">
|
25
|
+
<div class="label">Host</div>
|
26
|
+
<div class="value"><%= hostname %></div>
|
27
|
+
</div>
|
28
|
+
<div class="spacer"></div>
|
29
|
+
<div id="environment">
|
30
|
+
<div class="label">Environment</div>
|
31
|
+
<div class="value"><%= @version.environment %></div>
|
32
|
+
</div>
|
33
|
+
<div class="spacer"></div>
|
34
|
+
<div id="previous_versions">
|
35
|
+
<div class="label">Previous Versions</div>
|
36
|
+
<div class="value">
|
37
|
+
<% unless @previous_versions.empty? %>
|
38
|
+
<table>
|
39
|
+
<tr class="header">
|
40
|
+
<td>Time</td>
|
41
|
+
<td>Version</td>
|
42
|
+
<td>Commit</td>
|
43
|
+
</tr>
|
44
|
+
<% @previous_versions.each_with_index do |version, i| %>
|
45
|
+
<tr class="<%= i%2==0 ? 'even' : nil %>">
|
46
|
+
<td>
|
47
|
+
<%= version[:time].strftime('%x %X') %>
|
48
|
+
</td>
|
49
|
+
<td>
|
50
|
+
<%= version_link(version[:version]) %>
|
51
|
+
</td>
|
52
|
+
<td>
|
53
|
+
<%= commit_link(version[:revision]) %>
|
54
|
+
</td>
|
55
|
+
</tr>
|
56
|
+
<% end %>
|
57
|
+
</table>
|
58
|
+
<% end %>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
<div class="spacer"></div>
|
62
|
+
<div id="headers">
|
63
|
+
<div class="label">Headers</div>
|
64
|
+
<div class="value">
|
65
|
+
<table>
|
66
|
+
<% @headers.sort_by{ |h| h.first }.each_with_index do |(header, value), i| %>
|
67
|
+
<tr class="<%= i%2==0 ? 'even' : nil %>">
|
68
|
+
<td><%= header %></td>
|
69
|
+
<td><%= value %></td>
|
70
|
+
</tr>
|
71
|
+
<% end %>
|
72
|
+
</table>
|
73
|
+
</div>
|
74
|
+
</div>
|
75
|
+
<div class="clear"></div>
|
76
|
+
</div>
|