wary 0.0.1 → 0.0.2.pre.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3c9f67b4d79d35d1f832b9b814184e6a456db50
4
- data.tar.gz: 4edf54ee952fae330c32788d2c5cce8deb82accd
3
+ metadata.gz: f2bae8d44ad9538819dcffa48babd59376362ed1
4
+ data.tar.gz: 1d2e26a3e80ec3d694b0d1d59a469f89fb42d9fe
5
5
  SHA512:
6
- metadata.gz: d5bf9becd9a2b29b807399433223889cb0a1b963dfeabe635ebe99db625c1a7260299916a1a432db7acb6f7528988f28a1b51d2abf004704b03c0cfa9539bdbb
7
- data.tar.gz: aef51203c1e816fe9137d87c84ab5bd5632547bc02c748142a8518bfdf9be21d2212f137a0d89cb83678912e0bc24687f5be3d82ac17e157de588632b55730c1
6
+ metadata.gz: e1d692dd59085066fb17e8d2ade92e92d0d40ec570497aa3579fdd00531e73da1285f535fe6021c98659d10478f74294637b7f2ca01e5f4113b5d95f8dfb8b18
7
+ data.tar.gz: a71fc87563c582cfd8ed1de5ec558e0c75058f751fa4df48bf25c234c2b657e83f468f499b3c89f0ad0a05ebd350fe0def7de9e5aac83ad3fdeb2a4cbfee5048
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ script: "rspec"
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Wary
2
2
 
3
+ [![Code Climate](https://codeclimate.com/github/shostakovich/wary.png)](https://codeclimate.com/github/shostakovich/wary)
4
+ [![Build Status](https://travis-ci.org/shostakovich/wary.png?branch=master)](https://travis-ci.org/shostakovich/wary)
5
+
3
6
  TODO: Write a gem description
4
7
 
5
8
  ## Installation
data/example/wary.yml ADDED
@@ -0,0 +1,10 @@
1
+ :checks:
2
+ 'Load Average':
3
+ :class: LoadAverage
4
+ :alert_threshold: 2.0
5
+ 'Example.com':
6
+ :class: HttpStatus
7
+ :url: 'http://example.com'
8
+ 'Robots.txt exists':
9
+ :class: HttpStatus
10
+ :url: 'http://www.helpster.de/robots.txt'
@@ -0,0 +1,35 @@
1
+ require_relative '../check'
2
+ require_relative '../utils/http_client'
3
+
4
+ module Wary
5
+ module Check
6
+ class HttpStatus
7
+ include Wary::Check
8
+
9
+ def initialize(options)
10
+ @url = options.fetch(:url)
11
+ @http_client = options.fetch(:http_client) { HTTPClient.new }
12
+ configure(options)
13
+ end
14
+
15
+ def status
16
+ begin
17
+ response = @http_client.get_response(@url)
18
+ rescue => e
19
+ return failure("#{@url} down (#{e.message})")
20
+ end
21
+
22
+ if response.code == "200"
23
+ ok(message(response))
24
+ else
25
+ alert("#{@url} (#{response.code} #{response.message})")
26
+ end
27
+ end
28
+
29
+ private
30
+ def message(response)
31
+ "#{@url} (#{response.code} #{response.message})"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../status'
2
+ require_relative '../check'
3
+ require_relative '../load_meter'
4
+
5
+ module Wary
6
+ module Check
7
+ class LoadAverage
8
+ include Wary::Check
9
+
10
+ def initialize(options)
11
+ @load_meter = options.fetch(:load_meter) { Wary::LoadMeter.new }
12
+ @alert_threshold = options.fetch(:alert_threshold)
13
+ configure(options)
14
+ end
15
+
16
+ def status
17
+ begin
18
+ load = @load_meter.load
19
+ rescue => e
20
+ return failure(e.message)
21
+ end
22
+
23
+ if load < @alert_threshold
24
+ ok("Load #{load}")
25
+ else
26
+ alert("Load #{load} exceeds threshold (#{@alert_threshold})")
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
data/lib/wary/check.rb ADDED
@@ -0,0 +1,25 @@
1
+ require_relative 'check/load_average'
2
+ require_relative 'check/http_status'
3
+
4
+ module Wary
5
+ module Check
6
+ attr_reader :name
7
+
8
+ def configure(options)
9
+ @name = options.fetch(:name) { self.class.to_s }
10
+ end
11
+
12
+ private
13
+ def ok(message)
14
+ Status::OK.new(message)
15
+ end
16
+
17
+ def alert(message)
18
+ Status::Alert.new(message)
19
+ end
20
+
21
+ def failure(message)
22
+ Status::Failure.new(message)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ module Wary
2
+ class CheckSuite
3
+ attr_reader :checks
4
+
5
+ def initialize(checks)
6
+ @checks = checks
7
+ end
8
+
9
+ def empty?
10
+ checks.empty?
11
+ end
12
+
13
+ def status
14
+ if checks.any? { |c| c.status == :alert }
15
+ :alert
16
+ else
17
+ :ok
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,30 @@
1
+ require_relative 'utils/shell'
2
+
3
+ module Wary
4
+ class LoadMeter
5
+ class MeasurementFailed < StandardError; end
6
+
7
+ def initialize(shell = nil)
8
+ @shell = shell || Utils::Shell.new
9
+ end
10
+
11
+ def load
12
+ raw_load_avg_last_min.sub(',', '.').to_f
13
+ end
14
+
15
+ private
16
+ def raw_load_avg_last_min
17
+ matches = raw_data.match(/load averages\: ([0-9,\.]+)/)
18
+ if matches
19
+ matches[1]
20
+ else
21
+ raise Wary::LoadMeter::MeasurementFailed, "Could no extract load average from '#{raw_data}'"
22
+ end
23
+ end
24
+
25
+ def raw_data
26
+ String(@shell.execute('w h'))
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,37 @@
1
+ module Wary
2
+ module Status
3
+ class Base
4
+ attr_reader :message
5
+
6
+ def initialize(message)
7
+ @message = message
8
+ end
9
+
10
+ def ==(status_symbol)
11
+ status_symbol == to_sym
12
+ end
13
+
14
+ def to_sym
15
+ NotImplementedError
16
+ end
17
+ end
18
+
19
+ class OK < Base
20
+ def to_sym
21
+ :ok
22
+ end
23
+ end
24
+
25
+ class Alert < Base
26
+ def to_sym
27
+ :alert
28
+ end
29
+ end
30
+
31
+ class Failure < Base
32
+ def to_sym
33
+ :failure
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'check'
2
+ require_relative 'check_suite'
3
+
4
+ class Wary::SuiteBuilder
5
+ def initialize(configuration)
6
+ @checks = configuration.fetch(:checks) || []
7
+ end
8
+
9
+ def build
10
+ initialized_checks = @checks.map do |name, config|
11
+ klass = config.fetch(:class)
12
+ config[:name] = name
13
+ constantize("Wary::Check::#{klass}").new(config)
14
+ end
15
+
16
+ Wary::CheckSuite.new(initialized_checks)
17
+ end
18
+
19
+ private
20
+ def constantize(camel_cased_word)
21
+ names = camel_cased_word.split('::')
22
+ names.shift if names.empty? || names.first.empty?
23
+
24
+ constant = Object
25
+ names.each do |name|
26
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
27
+ end
28
+ constant
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ class HTTPClient
5
+ def get_response(url)
6
+ uri = URI(url)
7
+ Net::HTTP.get_response(uri)
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ # Pray to god that this works
2
+ module Wary
3
+ module Utils
4
+ class Shell
5
+ def execute(command)
6
+ `#{command}`
7
+ end
8
+ end
9
+ end
10
+ end
data/lib/wary/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Wary
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2-pre"
3
3
  end
data/lib/wary.rb CHANGED
@@ -1,5 +1,25 @@
1
- require "wary/version"
1
+ require 'yaml'
2
+ require 'terminal-table'
3
+
4
+ require_relative'wary/version'
5
+ require_relative 'wary/suite_builder'
2
6
 
3
7
  module Wary
4
- # Your code goes here...
8
+ def self.run
9
+ configuration = YAML.load_file(ENV['CONFIG'])
10
+ check_suite = SuiteBuilder.new(configuration).build
11
+
12
+ title = "Overall Check Suite Status (#{check_suite.status})"
13
+
14
+ headings = ['Name', 'Status', 'Message']
15
+ rows = check_suite.checks.map do |check|
16
+ [check.name, check.status.to_sym, check.status.message]
17
+ end
18
+
19
+ table = Terminal::Table.new(headings: headings, rows: rows, title: title)
20
+ table.align_column(1, :center)
21
+ puts table
22
+ end
5
23
  end
24
+
25
+ Wary.run
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'wary/check_suite'
3
+
4
+ describe Wary::CheckSuite do
5
+ let(:suite) { Wary::CheckSuite.new(checks) }
6
+
7
+ context 'for an empty list' do
8
+ let(:checks) { Array.new }
9
+
10
+ it 'is empty' do
11
+ expect(suite).to be_empty
12
+ end
13
+
14
+ it 'has the status OK if no checks are set' do
15
+ expect(suite.status).to eq(:ok)
16
+ end
17
+ end
18
+
19
+ context 'for a filled list' do
20
+ let(:checks) { [make_check] }
21
+
22
+ it 'is not empty' do
23
+ checks << double('Check')
24
+ expect(suite).to_not be_empty
25
+ end
26
+
27
+ it 'has the status ALERT if one ore more checks failed' do
28
+ checks << make_check(status: :alert)
29
+ expect(suite.status).to eq(:alert)
30
+ end
31
+ end
32
+
33
+ def make_check(stubs = {})
34
+ check = double('Check', stubs).as_null_object
35
+ check
36
+ end
37
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'wary/check/http_status'
3
+ describe Wary::Check::HttpStatus do
4
+ it_behaves_like 'a check'
5
+
6
+ let(:url) { 'http://example.com' }
7
+ let(:http_response) { double('Response') }
8
+ let(:http_client) { double('Client', get_response: http_response)}
9
+ let(:options) {{ url: url, http_client: http_client}}
10
+ let(:check) { Wary::Check::HttpStatus.new(options) }
11
+
12
+ context 'for the expected HTTP-Code' do
13
+ it 'signals OK' do
14
+ http_response.stub(code: '200', message: 'OK')
15
+ expect(status).to eq(:ok)
16
+ expect(status.message).to eq "#{url} (200 OK)"
17
+ end
18
+ end
19
+
20
+ context 'for an unexpected HTTP-Code' do
21
+ it 'signals alert' do
22
+ http_response.stub(code: '302', message: 'Found')
23
+ expect(status).to eq(:alert)
24
+ expect(status.message).to eq "#{url} (302 Found)"
25
+ end
26
+ end
27
+
28
+ context 'when something else is wrong' do
29
+ it 'signals failure' do
30
+ http_client.stub(:get_response).and_throw StandardError
31
+ expect(status).to eq(:failure)
32
+ expect(status.message).to match /#{url} down/
33
+ end
34
+ end
35
+
36
+ def status
37
+ check.status
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'wary/check/load_average'
3
+
4
+ describe Wary::Check::LoadAverage do
5
+ it_behaves_like 'a check'
6
+
7
+ let(:load_meter) { double('LoadMeter').as_null_object }
8
+ let(:threshold) { 2.00 }
9
+ let(:options) { {load_meter: load_meter, alert_threshold: threshold} }
10
+ let(:check) { Wary::Check::LoadAverage.new(options) }
11
+
12
+ context 'when the load is below the threshold' do
13
+ let(:load_meter) { double('LoadMeter', load: threshold - 0.01) }
14
+
15
+ it 'has the status :ok' do
16
+ expect(check.status).to eq(:ok)
17
+ end
18
+ end
19
+
20
+ context 'when the load is on or above the threshold' do
21
+ let(:load_meter) { double('LoadMeter', load: threshold) }
22
+
23
+ it 'has the status :alert' do
24
+ expect(check.status).to eq(:alert)
25
+ end
26
+ end
27
+
28
+ context 'when measuring the load failed' do
29
+ let(:load_meter) do
30
+ loadmeter = double('LoadMeter')
31
+ loadmeter.stub(:load).and_throw(StandardError)
32
+ loadmeter
33
+ end
34
+
35
+ it 'has the status :failure' do
36
+ expect(check.status).to eq(:failure)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,6 @@
1
+ describe Wary::LoadMeter do
2
+ it 'execute the load command' do
3
+ shell = double('Shell').should_receive(execute: 'w h')
4
+ Wary::LoadMeter.new(shell).load
5
+ end
6
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'wary/load_meter'
3
+
4
+ describe Wary::LoadMeter do
5
+ let(:shell) { double('Shell', execute: 'load averages: 1,25 1,22 1,19') }
6
+
7
+ it 'execute the load command' do
8
+ shell.should_receive(:execute).with('w h')
9
+
10
+ measure_load
11
+ end
12
+
13
+ it 'extracts the 1 min load' do
14
+ shell.stub(execute: 'load averages: 1,25 1,22 1,19')
15
+ expect(measure_load).to eq(1.25)
16
+ end
17
+
18
+ it 'throws an error if load not measurable' do
19
+ shell.stub(execute: 'Take this..')
20
+ expect { measure_load }.to raise_error(Wary::LoadMeter::MeasurementFailed)
21
+ end
22
+
23
+ def measure_load
24
+ Wary::LoadMeter.new(shell).load
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.configure do |config|
2
+ config.treat_symbols_as_metadata_keys_with_true_values = true
3
+ config.run_all_when_everything_filtered = true
4
+ config.filter_run :focus
5
+
6
+ config.order = 'random'
7
+ end
8
+
9
+ Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|f| require f}
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'wary/status'
3
+
4
+ describe Wary::Status::Alert do
5
+ it_behaves_like 'a status', :alert
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'wary/status'
3
+
4
+ describe Wary::Status::Failure do
5
+ it_behaves_like 'a status', :failure
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'wary/status'
3
+
4
+ describe Wary::Status::OK do
5
+ it_behaves_like 'a status', :ok
6
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'wary/suite_builder'
3
+
4
+ describe Wary::SuiteBuilder do
5
+ context 'for an empty list of checks' do
6
+ let(:configuration) { {:checks => nil} }
7
+
8
+ it 'builds an empty suite' do
9
+ expect(Wary::SuiteBuilder.new(configuration).build).to be_empty
10
+ end
11
+ end
12
+
13
+ context 'for one configured check' do
14
+ let(:configuration) do
15
+ { checks:
16
+ {'LoadAverage' =>
17
+ { class: 'LoadAverage',
18
+ alert_threshold: 2.0 } } }
19
+ end
20
+
21
+ it 'builds a suite with one check' do
22
+ expect(Wary::SuiteBuilder.new(configuration).build).to_not be_empty
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ shared_examples_for "a check" do
2
+ context 'with a custom name set' do
3
+ it 'has a custom name' do
4
+ options.merge!(name: 'foo')
5
+ expect(check.name).to eq 'foo'
6
+ end
7
+ end
8
+
9
+ context 'without a custom name' do
10
+ it 'has a default name' do
11
+ expect(check.name).to eq check.class.to_s
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ shared_examples_for "a status" do |status_symbol|
2
+ let(:message) { "Info" }
3
+ let(:status) { described_class.new(message) }
4
+
5
+ it 'has a message' do
6
+ expect(status.message).to eq message
7
+ end
8
+
9
+ it "is #{status_symbol}" do
10
+ expect(status).to eq(status_symbol)
11
+ end
12
+ end
data/wary.gemspec CHANGED
@@ -18,6 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency 'terminal-table'
22
+
21
23
  spec.add_development_dependency "bundler", "~> 1.3"
22
24
  spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
23
26
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wary
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2.pre.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Curth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-09 00:00:00.000000000 Z
11
+ date: 2013-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: terminal-table
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - '>='
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  description: Helps you keep track of your system's health
42
70
  email:
43
71
  - robert@rocu.de
@@ -46,12 +74,36 @@ extensions: []
46
74
  extra_rdoc_files: []
47
75
  files:
48
76
  - .gitignore
77
+ - .rspec
78
+ - .travis.yml
49
79
  - Gemfile
50
80
  - LICENSE.txt
51
81
  - README.md
52
82
  - Rakefile
83
+ - example/wary.yml
53
84
  - lib/wary.rb
85
+ - lib/wary/check.rb
86
+ - lib/wary/check/http_status.rb
87
+ - lib/wary/check/load_average.rb
88
+ - lib/wary/check_suite.rb
89
+ - lib/wary/load_meter.rb
90
+ - lib/wary/status.rb
91
+ - lib/wary/suite_builder.rb
92
+ - lib/wary/utils/http_client.rb
93
+ - lib/wary/utils/shell.rb
54
94
  - lib/wary/version.rb
95
+ - spec/check_suite_spec.rb
96
+ - spec/http_status_check_spec.rb
97
+ - spec/load_average_spec.rb
98
+ - spec/load_meter.rb
99
+ - spec/load_meter_spec.rb
100
+ - spec/spec_helper.rb
101
+ - spec/status_alert_spec.rb
102
+ - spec/status_failure_specc.rb
103
+ - spec/status_ok_spec.rb
104
+ - spec/suite_builder_spec.rb
105
+ - spec/support/shared_examples/a_check.rb
106
+ - spec/support/shared_examples/a_status.rb
55
107
  - wary.gemspec
56
108
  homepage: ''
57
109
  licenses:
@@ -68,13 +120,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
120
  version: '0'
69
121
  required_rubygems_version: !ruby/object:Gem::Requirement
70
122
  requirements:
71
- - - '>='
123
+ - - '>'
72
124
  - !ruby/object:Gem::Version
73
- version: '0'
125
+ version: 1.3.1
74
126
  requirements: []
75
127
  rubyforge_project:
76
128
  rubygems_version: 2.1.10
77
129
  signing_key:
78
130
  specification_version: 4
79
131
  summary: Wary
80
- test_files: []
132
+ test_files:
133
+ - spec/check_suite_spec.rb
134
+ - spec/http_status_check_spec.rb
135
+ - spec/load_average_spec.rb
136
+ - spec/load_meter.rb
137
+ - spec/load_meter_spec.rb
138
+ - spec/spec_helper.rb
139
+ - spec/status_alert_spec.rb
140
+ - spec/status_failure_specc.rb
141
+ - spec/status_ok_spec.rb
142
+ - spec/suite_builder_spec.rb
143
+ - spec/support/shared_examples/a_check.rb
144
+ - spec/support/shared_examples/a_status.rb