wary 0.0.1 → 0.0.2.pre.pre

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 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