eye-patch 0.0.4 → 0.0.5

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: 6ccc9b1afad17fb6c48380c118b5b98fef372f38
4
- data.tar.gz: caf7686b488014a72041764a33d546cd862048e2
3
+ metadata.gz: 2b5844cb0bcc8406207a5838cf37b7c508096423
4
+ data.tar.gz: cdeffbc2afbfce475d4680ff91db40a9ec09ff6b
5
5
  SHA512:
6
- metadata.gz: cc8f68ecfb3fe72e52227190422287b9b379c958421640b0bad27626816fb546b933400b21b7fe65dfb6eb938c68e21261a6e64d9877f6f4b82bcec145a699e5
7
- data.tar.gz: 780c1b16f806ca7222fb2936ff0ed759230fcc9745d80bb46bff115264b8bebec1fb8a4e7def2e49e7a6fb8c04603014b7ed0a847f11f50d4f19daf40676b485
6
+ metadata.gz: 8c6eaabb46e382d2e04eb2f41286cab9f218d0b7a32c837ad057da6b55c838f0a9241abc726514fe63c5d32837abc3e39dd766499e3be80a5f20d0c003f84275
7
+ data.tar.gz: abc4cb6a750ceacb722d4be06d537858b2339d7d5c07c57b2abb2e306d83cccc65658e9f3443c61eb0e578974333b30676842bb37a002792b54e6fe8693f4cb2
data/eye-patch.gemspec CHANGED
@@ -21,9 +21,10 @@ Gem::Specification.new do |spec|
21
21
  spec.test_files = spec.files.grep(%r{^test/})
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_development_dependency "bundler", "~> 1.3"
25
- spec.add_development_dependency "rake"
26
-
27
24
  spec.add_dependency "eye"
28
25
  spec.add_dependency "chronic_duration"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.3"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "mocha"
29
30
  end
data/lib/eye/patch.rb CHANGED
@@ -15,11 +15,11 @@ module Eye::Patch
15
15
  require "eye/patch/version"
16
16
 
17
17
  def self.parse(filename)
18
- settings = Eye::Patch::Settings.new(filename)
18
+ settings = Settings.new(filename)
19
19
 
20
- config = Eye::Config.new(
21
- Eye::Patch::Config.new(settings),
22
- Eye::Patch::Application.new(settings))
20
+ config = ::Eye::Config.new(
21
+ Config.new(settings),
22
+ Application.new(settings))
23
23
  config.validate!
24
24
 
25
25
  config
@@ -1,73 +1,49 @@
1
- class Eye::Patch::Application < Hash
1
+ require_relative "group_set"
2
+ require_relative "option_set"
2
3
 
3
- def initialize(settings)
4
- super()
5
- @settings = settings
6
- self[settings[:name].to_s] = parse
7
- end
4
+ module Eye::Patch
8
5
 
9
- private
6
+ class Application < Hash
10
7
 
11
- def parse
12
- @config = {}
8
+ def initialize(settings)
9
+ super()
10
+ @settings = settings
11
+ self[settings[:name]] = parse
12
+ end
13
13
 
14
- parse_configuration
15
- parse_processes
14
+ private
16
15
 
17
- @config
18
- end
16
+ def parse
17
+ parse_configuration
18
+ parse_processes
19
19
 
20
- def root_settings
21
- @root_settings ||= (@settings[:application] || {}).merge(
22
- notify: parse_notifications,
23
- triggers: parse_triggers,
24
- checks: parse_checks )
25
- end
26
-
27
- def parse_notifications
28
- Array(@settings[:notifications]).each_with_object({}) do |notify, monitors|
29
- monitors[notify[:name].to_s] = notify[:level].to_sym
20
+ @config
30
21
  end
31
- end
32
22
 
33
- def parse_triggers
34
- Array(@settings[:triggers]).each_with_object({}) do |trigger, triggers|
35
- trigger_data = Eye::Trigger.name_and_class(trigger[:name].to_sym)
36
- triggers[trigger_data[:name]] = trigger[:config].merge(type: trigger_data[:type])
23
+ def parse_configuration
24
+ @config = (@settings[:application] || {}).merge(
25
+ name: @settings[:name],
26
+ notify: notifications,
27
+ triggers: triggers,
28
+ checks: checks )
37
29
  end
38
- end
39
30
 
40
- def parse_checks
41
- Array(@settings[:checks]).each_with_object({}) do |check, checks|
42
- check_data = Eye::Checker.name_and_class(check[:name].to_sym)
43
- checks[check_data[:name]] = check[:config].merge(type: check_data[:type])
31
+ def parse_processes
32
+ @config[:groups] = GroupSet.new(@config, @settings[:processes])
44
33
  end
45
- end
46
-
47
- def parse_configuration
48
- @config.merge!(root_settings)
49
- end
50
-
51
- def parse_processes
52
- @config[:groups] = {}
53
34
 
54
- Array(@settings[:processes]).group_by{ |item| item[:group] }.each do |group_name, items|
55
- name = group_name || "__default__"
56
- parse_group(name, items)
35
+ def notifications
36
+ Array(@settings[:notifications]).each_with_object({}) do |notify, monitors|
37
+ monitors[notify[:name]] = notify[:level].to_sym
38
+ end
57
39
  end
58
- end
59
40
 
60
- def parse_group(name, processes)
61
- @config[:groups][name] = root_settings.merge(
62
- application: @settings[:name].to_s,
63
- processes: parse_process_list(name, processes))
64
- end
41
+ def triggers
42
+ OptionSet.new(Eye::Trigger, @settings[:triggers])
43
+ end
65
44
 
66
- def parse_process_list(group_name, processes)
67
- processes.each_with_object({}) do |process, process_map|
68
- process_map[process[:name].to_s] = root_settings.merge(process[:config]).merge(
69
- name: process[:name].to_s,
70
- group: group_name )
45
+ def checks
46
+ OptionSet.new(Eye::Checker, @settings[:checks])
71
47
  end
72
48
  end
73
49
  end
@@ -0,0 +1,31 @@
1
+ Capistrano::Configuration.instance.load do
2
+
3
+ _cset(:eye_default_hooks) { true }
4
+ _cset(:eye_config) { "config/eye.yml" }
5
+ _cset(:eye_bin) { "bundle exec eye-patch" }
6
+ _cset(:eye_roles) { :app }
7
+
8
+ if fetch(:eye_default_hooks)
9
+ after "deploy:stop", "eye:stop"
10
+ after "deploy:start", "eye:start"
11
+ before "deploy:restart", "eye:restart"
12
+ end
13
+
14
+ namespace :eye do
15
+
16
+ desc "Start eye with the desired configuration file"
17
+ task :start, roles: -> { fetch(:eye_roles) } do
18
+ run "cd #{current_path} && #{fetch(:eye_bin)} l #{fetch(:eye_config)}"
19
+ end
20
+
21
+ desc "Stop eye and all of its monitored tasks"
22
+ task :stop, roles: -> { fetch(:eye_roles) } do
23
+ run "cd #{current_path} && #{fetch(:eye_bin)} stop all && #{fetch(:eye_bin)} q"
24
+ end
25
+
26
+ desc "Restart all tasks monitored by eye"
27
+ task :restart, roles: -> { fetch(:eye_roles) } do
28
+ run "cd #{current_path} && #{fetch(:eye_bin)} r all"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "process_set"
2
+
3
+ module Eye::Patch
4
+
5
+ class GroupSet < Hash
6
+
7
+ def initialize(application, processes)
8
+ @application = application
9
+
10
+ Array(processes).group_by{ |item| item[:group] }.each do |group_name, items|
11
+ name = group_name || "__default__"
12
+ parse_group(name, items)
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def parse_group(name, processes)
19
+ self[name] = @application.merge(
20
+ name: name,
21
+ application: @application[:name])
22
+
23
+ self[name][:processes] = ProcessSet.new(self[name], processes)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ module Eye::Patch
2
+ class OptionSet < Hash
3
+
4
+ def initialize(option_class, options)
5
+ Array(options).each do |option|
6
+ option_data = option_class.name_and_class(option[:name].to_sym)
7
+ self[option_data[:name]] = option[:config].merge(type: option_data[:type])
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ module Eye::Patch
2
+
3
+ class ProcessSet < Hash
4
+
5
+ def initialize(group, processes)
6
+ @group = group
7
+
8
+ Array(processes).each do |process|
9
+ parse_process(process)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def parse_process(process)
16
+ if process[:count]
17
+ parse_process_cluster(process)
18
+ else
19
+ parse_single_process(process[:name], process[:config])
20
+ end
21
+ end
22
+
23
+ def parse_process_cluster(process)
24
+ process[:count].times do |index|
25
+ name = "#{process[:name]}-#{index}"
26
+ parse_single_process(name, indexed_config(process[:config], index))
27
+ end
28
+ end
29
+
30
+ def parse_single_process(name, config)
31
+ self[name] = @group.merge(config).merge(
32
+ name: name,
33
+ group: @group[:name] )
34
+ end
35
+
36
+ def indexed_config(config, index)
37
+ config.each_with_object({}) do |(key, value), result|
38
+ result[key] = value.is_a?(String) ? value.gsub("{ID}", index.to_s) : value
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,34 +1,36 @@
1
- require "chronic_duration"
1
+ require_relative "value_parser"
2
2
 
3
- class Eye::Patch::Settings
3
+ module Eye::Patch
4
4
 
5
- def initialize(filename)
6
- @settings = YAML.load(File.open(filename))
7
- end
5
+ class Settings
8
6
 
9
- def [](value)
10
- parsed[value]
11
- end
7
+ def initialize(filename)
8
+ @settings = YAML.load(File.open(filename))
9
+ end
12
10
 
13
- private
11
+ def [](value)
12
+ parsed[value]
13
+ end
14
14
 
15
- def parsed
16
- @parsed ||= parse(@settings)
17
- end
15
+ private
16
+
17
+ def parsed
18
+ @parsed ||= parse(@settings)
19
+ end
18
20
 
19
- def parse(item)
20
- case item
21
- when Hash
22
- item.each_with_object({}) do |(key, val), result|
23
- result[key.to_sym] = parse(val)
21
+ def parse(item)
22
+ case item
23
+ when Hash
24
+ item.each_with_object({}) do |(key, val), result|
25
+ result[key.to_sym] = parse(val)
26
+ end
27
+ when Array
28
+ item.map { |val| parse(val) }
29
+ when String
30
+ ValueParser.parse(item)
31
+ else
32
+ item
24
33
  end
25
- when Array
26
- item.map { |val| parse(val) }
27
- when String
28
- # Assume that we should parse any time-like values
29
- item =~ /\b(hour|second|minute)s?\b/ ? ChronicDuration.parse(item) : item
30
- else
31
- item
32
34
  end
33
35
  end
34
36
  end
@@ -0,0 +1,32 @@
1
+ require "chronic_duration"
2
+
3
+ module Eye::Patch
4
+
5
+ class ValueParser
6
+
7
+ TIME_MATCHER = / (?<duration>(week|day|hour|minute|second)s?)( |\Z)/.freeze
8
+ SIZE_MATCHER = / (?<size>(tera|giga|mega|kilo)?bytes?)( |\Z)/.freeze
9
+ MATCHERS = {
10
+ time: TIME_MATCHER,
11
+ size: SIZE_MATCHER }.freeze
12
+
13
+ def self.parse(value)
14
+ result = MATCHERS.detect do |match_type, matcher|
15
+ break send(:"parse_#{match_type}", value) if value.match(matcher)
16
+ end
17
+
18
+ result || value
19
+ end
20
+
21
+ private
22
+
23
+ def self.parse_time(value)
24
+ ChronicDuration.parse(value)
25
+ end
26
+
27
+ def self.parse_size(value)
28
+ unit = value.match(SIZE_MATCHER)[:size]
29
+ value.gsub(/[^\d.]/, "").to_f.send(unit)
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  module Eye
2
2
  module Patch
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -0,0 +1,51 @@
1
+ name: Test Application
2
+
3
+ config:
4
+ logger: /path/to/log/eye.log
5
+
6
+ application:
7
+ working_dir: /path/to/application
8
+
9
+ notifications:
10
+ - name: monitoring
11
+ type: jabber
12
+ level: info
13
+ contact: test+admin@example.com
14
+ config:
15
+ from: test+notifier@example.com
16
+
17
+ triggers:
18
+ - name: flapping
19
+ config:
20
+ times: 10
21
+ within: 1 minute
22
+
23
+ checks:
24
+ - name: memory
25
+ config:
26
+ times: 3
27
+ every: 20 seconds
28
+ below: 1.5 gigabytes
29
+
30
+ processes:
31
+ - name: my-process
32
+ config:
33
+ start_timeout: 25 seconds
34
+ start_command: bundle exec my-process
35
+ pid_file: tmp/pids/my-process.pid
36
+ - name: first-grouped-process
37
+ group: my-group
38
+ config:
39
+ start_command: bundle exec grouped-process
40
+ pid_file: tmp/pids/first-grouped-process.pid
41
+ - name: second-grouped-process
42
+ group: my-group
43
+ config:
44
+ start_command: bundle exec grouped-process
45
+ pid_file: tmp/pids/second-grouped-process.pid
46
+ - name: clustered-process
47
+ group: cluster
48
+ count: 2
49
+ config:
50
+ start_command: bundle exec clustered-process
51
+ pid_file: "tmp/pids/clustered-process-{ID}.pid"
@@ -0,0 +1,22 @@
1
+ require_relative "../../../test_helper"
2
+
3
+ describe Eye::Patch::ValueParser do
4
+
5
+ it "parses time values" do
6
+ assert_equal 2.weeks, Eye::Patch::ValueParser.parse("2 weeks")
7
+ assert_equal 1.5.hours, Eye::Patch::ValueParser.parse("1.5 hours")
8
+ assert_equal 50.minutes, Eye::Patch::ValueParser.parse("50 minutes")
9
+ assert_equal 3.seconds, Eye::Patch::ValueParser.parse("3 seconds")
10
+ end
11
+
12
+ it "parses size values" do
13
+ assert_equal 3.2.gigabytes, Eye::Patch::ValueParser.parse("3.2 gigabytes")
14
+ assert_equal 2.4.megabytes, Eye::Patch::ValueParser.parse("2.4 megabytes")
15
+ assert_equal 1.kilobyte, Eye::Patch::ValueParser.parse("1 kilobyte")
16
+ end
17
+
18
+ it "uses strict word boundary characters" do
19
+ assert_equal "second-thing", Eye::Patch::ValueParser.parse("second-thing")
20
+ assert_equal "minutes", Eye::Patch::ValueParser.parse("minutes")
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ require_relative "../../../test_helper"
2
+
3
+ describe Eye::Patch do
4
+
5
+ it "defines a version" do
6
+ assert Eye::Patch::VERSION
7
+ end
8
+ end
@@ -0,0 +1,83 @@
1
+ require_relative "../../test_helper"
2
+
3
+ describe Eye::Patch do
4
+ before do
5
+ @fixture = File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. fixtures test.yml]))
6
+ @original = YAML.load(File.open(@fixture))
7
+ end
8
+
9
+ describe ".parse" do
10
+ before do
11
+ Eye::Config.any_instance.stubs(:validate!)
12
+ @parsed = Eye::Patch.parse(@fixture)
13
+
14
+ @settings = @parsed.settings
15
+ @applications = @parsed.applications
16
+ @application = @applications.values.first
17
+ end
18
+
19
+ it "returns an Eye::Config" do
20
+ assert_kind_of Eye::Config, @parsed
21
+ end
22
+
23
+ it "gives the application an appropriate name" do
24
+ assert_equal @original["name"], @applications.keys.first
25
+ assert_equal @original["name"], @application[:name]
26
+ end
27
+
28
+ it "parses contacts for notification" do
29
+ notification = @original["notifications"].first
30
+
31
+ assert_equal notification["config"]["from"], @settings[notification["type"].to_sym][:from]
32
+ assert_equal notification["type"].to_sym, @settings[:contacts][notification["name"]][:type]
33
+ assert_equal notification["level"].to_sym, @application[:notify][notification["name"]]
34
+ end
35
+
36
+ it "parses triggers" do
37
+ trigger = @original["triggers"].first
38
+ parsed_trigger = @application[:triggers][trigger["name"].to_sym]
39
+
40
+ assert_equal trigger["config"]["times"], parsed_trigger[:times]
41
+ assert_equal Eye::Patch::ValueParser.parse(trigger["config"]["within"]), parsed_trigger[:within]
42
+ end
43
+
44
+ it "parses checks" do
45
+ check = @original["checks"].first
46
+ parsed_check = @application[:checks][check["name"].to_sym]
47
+
48
+ assert_equal check["config"]["times"], parsed_check[:times]
49
+ assert_equal Eye::Patch::ValueParser.parse(check["config"]["every"]), parsed_check[:every]
50
+ assert_equal Eye::Patch::ValueParser.parse(check["config"]["below"]), parsed_check[:below]
51
+ end
52
+
53
+ it "splits processes into groups" do
54
+ grouped_processes = @original["processes"].select { |process| process["group"] && !process["count"] }
55
+ grouped_processes.each do |process|
56
+ assert_equal process["group"], @application[:groups][process["group"]][:processes][process["name"]][:group]
57
+ end
58
+ end
59
+
60
+ it "puts ungrouped processes into the __default__ group" do
61
+ lone_processes = @original["processes"].reject { |process| process["group"] }
62
+ lone_processes.each do |process|
63
+ assert_equal "__default__", @application[:groups]["__default__"][:processes][process["name"]][:group]
64
+ end
65
+ end
66
+
67
+ it "creates process clusters" do
68
+ process = @original["processes"].detect { |process| process["count"] }
69
+ process["count"].times do |index|
70
+ name = "#{process["name"]}-#{index}"
71
+ parsed_process = @application[:groups][process["group"]][:processes][name]
72
+
73
+ assert_equal process["group"], parsed_process[:group]
74
+ assert_equal process["config"]["pid_file"].gsub("{ID}", index.to_s), parsed_process[:pid_file]
75
+ end
76
+ end
77
+
78
+ it "passes application configurations down to processes" do
79
+ process = @application[:groups]["__default__"][:processes].values.first
80
+ assert_equal @application[:triggers], process[:triggers]
81
+ end
82
+ end
83
+ end
data/test/test_helper.rb CHANGED
@@ -1 +1,5 @@
1
- require 'minitest/autorun'
1
+ require "minitest/autorun"
2
+ require "minitest/unit"
3
+ require "mocha/mini_test"
4
+
5
+ require File.expand_path("../../lib/eye/patch.rb", __FILE__)
metadata CHANGED
@@ -1,37 +1,37 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eye-patch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Horner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-02 00:00:00.000000000 Z
11
+ date: 2014-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
14
+ name: eye
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
20
- type: :development
19
+ version: '0'
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: chronic_duration
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
- type: :development
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
@@ -39,13 +39,27 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: eye
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - '>='
46
60
  - !ruby/object:Gem::Version
47
61
  version: '0'
48
- type: :runtime
62
+ type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
@@ -53,13 +67,13 @@ dependencies:
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: chronic_duration
70
+ name: mocha
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - '>='
60
74
  - !ruby/object:Gem::Version
61
75
  version: '0'
62
- type: :runtime
76
+ type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
@@ -86,10 +100,19 @@ files:
86
100
  - lib/eye/notify/ses.rb
87
101
  - lib/eye/patch.rb
88
102
  - lib/eye/patch/application.rb
103
+ - lib/eye/patch/capistrano.rb
89
104
  - lib/eye/patch/config.rb
105
+ - lib/eye/patch/group_set.rb
106
+ - lib/eye/patch/option_set.rb
90
107
  - lib/eye/patch/overrides.rb
108
+ - lib/eye/patch/process_set.rb
91
109
  - lib/eye/patch/settings.rb
110
+ - lib/eye/patch/value_parser.rb
92
111
  - lib/eye/patch/version.rb
112
+ - test/fixtures/test.yml
113
+ - test/lib/eye/patch/value_parser_test.rb
114
+ - test/lib/eye/patch/version_test.rb
115
+ - test/lib/eye/patch_test.rb
93
116
  - test/test_helper.rb
94
117
  homepage: https://github.com/tablexi/eye-patch
95
118
  licenses:
@@ -117,4 +140,8 @@ specification_version: 4
117
140
  summary: Eye::Patch abstracts out the Eye DSL to allow you to load your configuration
118
141
  from a structured YAML file, rather than relying on Eye's built-in DSL.
119
142
  test_files:
143
+ - test/fixtures/test.yml
144
+ - test/lib/eye/patch/value_parser_test.rb
145
+ - test/lib/eye/patch/version_test.rb
146
+ - test/lib/eye/patch_test.rb
120
147
  - test/test_helper.rb