elasticsearch-watcher 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 997c4ba2c5e12dbd058aa6ce597770019f7f6fbd
4
+ data.tar.gz: 4b9088c48307f47f57b56426abb7030f7b8c2cfa
5
+ SHA512:
6
+ metadata.gz: 5852020cbae6eb416ebdf4ed1ca99d0d4271d3dcd6324772a182575bb22fe8a6d388d96a706b12d6c2ca5b1aee0dfc3a507cb993b3b37428079050e34f749ea3
7
+ data.tar.gz: 2d1327265ba961cda13400847caa802b37bdaf78029994db88fe6c1cd61b402d6b9b97a20273fc91e2bb1b5de90e66f66d98864fd54d165ae53453e3fb7d9bce
@@ -0,0 +1,22 @@
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
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in elasticsearch-watcher.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2015 Elasticsearch
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,166 @@
1
+ # Elasticsearch::Watcher
2
+
3
+ This library provides Ruby API for the [_Watcher_](https://www.elastic.co/products/watcher) plugin.
4
+
5
+ Please refer to the [_Watcher_ documentation](http://www.elastic.co/guide/en/watcher/current/index.html)
6
+ for information about the plugin.
7
+
8
+ ## Installation
9
+
10
+ Install the package from [Rubygems](https://rubygems.org):
11
+
12
+ gem install elasticsearch-watcher
13
+
14
+ To use an unreleased version, either add it to your `Gemfile` for [Bundler](http://gembundler.com):
15
+
16
+ gem 'elasticsearch-watcher', git: 'git://github.com/elasticsearch/elasticsearch-ruby.git'
17
+
18
+ or install it from a source code checkout:
19
+
20
+ git clone https://github.com/elasticsearch/elasticsearch-ruby.git
21
+ cd elasticsearch-ruby/elasticsearch-watcher
22
+ bundle install
23
+ rake install
24
+
25
+ ## Usage
26
+
27
+ The documentation for the Ruby API methods is available at <http://www.rubydoc.info/gems/elasticsearch-watcher>.
28
+
29
+ A comprehensive example of registering a watch, triggering the actions, and getting information
30
+ about the watch execution is quoted below.
31
+
32
+ ```ruby
33
+ require 'elasticsearch'
34
+ require 'elasticsearch/watcher'
35
+
36
+ client = Elasticsearch::Client.new url: 'http://localhost:9200', log: true
37
+ client.transport.logger.formatter = proc do |severity, datetime, progname, msg| "\e[2m#{msg}\e[0m\n" end
38
+
39
+ # Delete the Watcher and test indices
40
+ #
41
+ client.indices.delete index: ['alerts', 'test', '.watches', '.watch_history*'], ignore: 404
42
+
43
+ # Print information about the Watcher plugin
44
+ #
45
+ puts "Watcher #{client.watcher.info['version']['number']}"
46
+
47
+ # Register a new watch
48
+ #
49
+ client.watcher.put_watch id: 'error_500', body: {
50
+ # Label the watch
51
+ #
52
+ metadata: { tags: ['errors'] },
53
+
54
+ # Run the watch every 10 seconds
55
+ #
56
+ trigger: { schedule: { interval: '10s' } },
57
+
58
+ # Search for at least 3 documents matching the condition
59
+ #
60
+ condition: { script: { inline: 'ctx.payload.hits.total > 3' } },
61
+
62
+ # Throttle the watch execution for 30 seconds
63
+ #
64
+ throttle_period: '30s',
65
+
66
+ # The search request to execute
67
+ #
68
+ input: { search: {
69
+ request: {
70
+ indices: ['test'],
71
+ body: {
72
+ query: {
73
+ filtered: {
74
+ query: { match: { status: 500 } },
75
+ filter: { range: { timestamp: { from: '{{ctx.trigger.scheduled_time}}||-5m', to: '{{ctx.trigger.triggered_time}}' } } }
76
+ }
77
+ },
78
+ # Return statistics about different hosts
79
+ #
80
+ aggregations: {
81
+ hosts: { terms: { field: 'host' } }
82
+ }
83
+ }}}},
84
+
85
+ # The actions to perform
86
+ #
87
+ actions: {
88
+ send_email: {
89
+ transform: {
90
+ # Transform the data for the template
91
+ #
92
+ script: 'return [ total: ctx.payload.hits.total, hosts: ctx.payload.aggregations.hosts.buckets.collect { [ host: it.key, errors: it.doc_count ] }, errors: ctx.payload.hits.hits.collect { it._source } ];'
93
+ },
94
+ email: { to: 'alerts@example.com',
95
+ subject: '[ALERT] {{ctx.watch_id}}',
96
+ body: "Received {{ctx.payload.total}} error documents in the last 5 minutes.\n\nHosts:\n\n{{#ctx.payload.hosts}}* {{host}} ({{errors}})\n{{/ctx.payload.hosts}}",
97
+ attach_data: true }
98
+ },
99
+ index_payload: {
100
+ # Transform the data to be stored
101
+ #
102
+ transform: { script: 'return [ watch_id: ctx.watch_id, payload: ctx.payload ]' },
103
+ index: { index: 'alerts', doc_type: 'alert' }
104
+ },
105
+ ping_webhook: {
106
+ webhook: {
107
+ method: 'POST',
108
+ host: 'localhost',
109
+ port: 4567,
110
+ path: '/',
111
+ body: %q|{"watch_id" : "{{ctx.watch_id}}", "payload" : "{{ctx.payload}}"}| }
112
+ }
113
+ }
114
+ }
115
+
116
+ # Index documents to trigger the watch
117
+ #
118
+ 5.times do
119
+ client.index index: 'test', type: 'd',
120
+ body: { timestamp: Time.now.utc.iso8601, status: 500, host: "10.0.0.#{rand(1..3)}" }
121
+ end
122
+
123
+ # Wait a bit...
124
+ #
125
+ print "Waiting 30 seconds..."
126
+ $i=0; while $i < 30 do
127
+ sleep(1); print('.'); $i+=1
128
+ end; puts "\n"
129
+
130
+ # Display information about watch execution
131
+ #
132
+ puts '='*80, ""
133
+ client.search(index: '.watch_history*', q: 'watch_id:error_500', sort: 'timestamp:asc')['hits']['hits'].each do |r|
134
+ puts "#{r['_id']} : #{r['_source']['state']}"
135
+ end
136
+
137
+ # Delete the watch
138
+ #
139
+ puts "Deleting the watch..."
140
+ client.watcher.delete_watch id: 'error_500', master_timeout: '30s', force: true
141
+ ```
142
+
143
+ You can run a simple [Sinatra](https://github.com/sinatra/sinatra/) server
144
+ to test the `webhook` action with the following Ruby code:
145
+
146
+ ```bash
147
+ ruby -r sinatra -r json -e 'post("/") { json = JSON.parse(request.body.read); puts %Q~Received #{json["watch_id"]} with payload: #{json["payload"]}~ }'
148
+ ```
149
+
150
+ ## License
151
+
152
+ This software is licensed under the Apache 2 license, quoted below.
153
+
154
+ Copyright (c) 2015 Elasticsearch <http://www.elasticsearch.org>
155
+
156
+ Licensed under the Apache License, Version 2.0 (the "License");
157
+ you may not use this file except in compliance with the License.
158
+ You may obtain a copy of the License at
159
+
160
+ http://www.apache.org/licenses/LICENSE-2.0
161
+
162
+ Unless required by applicable law or agreed to in writing, software
163
+ distributed under the License is distributed on an "AS IS" BASIS,
164
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
165
+ See the License for the specific language governing permissions and
166
+ limitations under the License.
@@ -0,0 +1,99 @@
1
+ require 'pathname'
2
+ require 'bundler/gem_tasks'
3
+
4
+ __current__ = Pathname( File.expand_path('..', __FILE__) )
5
+
6
+ task(:default) { system "rake --tasks" }
7
+ task :test => 'test:unit'
8
+
9
+ # ----- Test tasks ------------------------------------------------------------
10
+
11
+ require 'rake/testtask'
12
+ namespace :test do
13
+ Rake::TestTask.new(:unit) do |test|
14
+ test.libs << 'lib' << 'test'
15
+ test.test_files = FileList["test/unit/**/*_test.rb"]
16
+ # test.verbose = true
17
+ # test.warning = true
18
+ end
19
+
20
+ desc "Run integration tests"
21
+ task :integration do
22
+ unless ENV['TEST_REST_API_SPEC']
23
+ puts "[!] Please export the TEST_REST_API_SPEC variable with a path to the Watcher YAML tests"
24
+ exit(1)
25
+ end
26
+
27
+ # Define the task
28
+ t = Rake::TestTask.new(:integration) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.test_files = FileList["../elasticsearch-api/test/integration/yaml_test_runner.rb", "test/integration/**/*_test.rb"]
31
+ end
32
+
33
+ # Run the task
34
+ args = [t.ruby_opts_string, t.run_code, t.file_list_string, t.option_list].join(' ')
35
+
36
+ ruby args do |ok, status|
37
+ if !ok && status.respond_to?(:signaled?) && status.signaled?
38
+ raise SignalException.new(status.termsig)
39
+ elsif !ok
40
+ fail "Command failed with status (#{status.exitstatus}): " + "[ruby #{args}]"
41
+ end
42
+ end
43
+ end
44
+
45
+ desc "Run unit and integration tests"
46
+ task :all do
47
+ Rake::Task['test:ci_reporter'].invoke if ENV['CI']
48
+ Rake::Task['test:unit'].invoke
49
+ Rake::Task['test:integration'].invoke
50
+ end
51
+
52
+ desc "Initialize or update the repository with integration tests"
53
+ task :update do
54
+ sh "git --git-dir=#{__current__.join('tmp/elasticsearch-watcher/.git')} --work-tree=#{__current__.join('tmp/elasticsearch-watcher')} fetch origin --verbose"
55
+ begin
56
+ puts %x[git --git-dir=#{__current__.join('tmp/elasticsearch-watcher/.git')} --work-tree=#{__current__.join('tmp/elasticsearch-watcher')} pull --verbose]
57
+ rescue Exception => @exception
58
+ @failed = true
59
+ end
60
+
61
+ if @failed || !$?.success?
62
+ STDERR.puts "", "[!] Error while pulling -- #{@exception}"
63
+ end
64
+
65
+ puts "\n", "CHANGES:", '-'*80
66
+ sh "git --git-dir=#{__current__.join('tmp/elasticsearch-watcher/.git')} --work-tree=#{__current__.join('tmp/elasticsearch-watcher')} log --oneline ORIG_HEAD..HEAD | cat", :verbose => false
67
+ end
68
+
69
+ namespace :cluster do
70
+ desc "Start Elasticsearch nodes for tests"
71
+ task :start do
72
+ $LOAD_PATH << File.expand_path('../../elasticsearch-transport/lib', __FILE__) << File.expand_path('../test', __FILE__)
73
+ require 'elasticsearch/extensions/test/cluster'
74
+ Elasticsearch::Extensions::Test::Cluster.start
75
+ end
76
+
77
+ desc "Stop Elasticsearch nodes for tests"
78
+ task :stop do
79
+ $LOAD_PATH << File.expand_path('../../elasticsearch-transport/lib', __FILE__) << File.expand_path('../test', __FILE__)
80
+ require 'elasticsearch/extensions/test/cluster'
81
+ Elasticsearch::Extensions::Test::Cluster.stop
82
+ end
83
+ end
84
+ end
85
+
86
+ # ----- Documentation tasks ---------------------------------------------------
87
+
88
+ require 'yard'
89
+ YARD::Rake::YardocTask.new(:doc) do |t|
90
+ t.options = %w| --embed-mixins --markup=markdown |
91
+ end
92
+
93
+ # ----- Code analysis tasks ---------------------------------------------------
94
+
95
+ require 'cane/rake_task'
96
+ Cane::RakeTask.new(:quality) do |cane|
97
+ cane.abc_max = 15
98
+ cane.no_style = true
99
+ end
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elasticsearch/watcher/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "elasticsearch-watcher"
8
+ s.version = Elasticsearch::Watcher::VERSION
9
+ s.authors = ["Karel Minarik"]
10
+ s.email = ["karel.minarik@elasticsearch.org"]
11
+ s.description = %q{Ruby Integrations for Elasticsearch Watcher plugin (WIP)}
12
+ s.summary = s.description
13
+ s.homepage = ""
14
+ s.license = "Apache 2"
15
+
16
+ s.files = `git ls-files`.split($/)
17
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "elasticsearch-api"
22
+
23
+ s.add_development_dependency "bundler", "~> 1.3"
24
+ s.add_development_dependency "rake"
25
+
26
+ s.add_development_dependency "elasticsearch"
27
+ s.add_development_dependency "elasticsearch-extensions"
28
+
29
+ s.add_development_dependency 'shoulda-context'
30
+ s.add_development_dependency 'activesupport'
31
+ s.add_development_dependency 'turn'
32
+ s.add_development_dependency 'mocha'
33
+ s.add_development_dependency 'minitest', '~> 4.0'
34
+ s.add_development_dependency 'minitest-reporters'
35
+ s.add_development_dependency 'simplecov'
36
+ s.add_development_dependency 'simplecov-rcov'
37
+ s.add_development_dependency 'yard'
38
+ s.add_development_dependency 'cane'
39
+ s.add_development_dependency 'pry'
40
+ end
@@ -0,0 +1 @@
1
+ require 'elasticsearch/watcher'
@@ -0,0 +1,37 @@
1
+ require "elasticsearch/watcher/version"
2
+
3
+ Dir[ File.expand_path('../watcher/api/actions/**/*.rb', __FILE__) ].each { |f| require f }
4
+
5
+ module Elasticsearch
6
+ module Watcher
7
+ def self.included(base)
8
+ base.__send__ :include, Elasticsearch::API::Watcher
9
+ end
10
+ end
11
+ end
12
+
13
+ module Elasticsearch
14
+ module API
15
+ module Watcher
16
+ module Actions; end
17
+
18
+ # Client for the "watcher" namespace (includes the {Watcher::Actions} methods)
19
+ #
20
+ class WatcherClient
21
+ include Elasticsearch::API::Common::Client,
22
+ Elasticsearch::API::Common::Client::Base,
23
+ Elasticsearch::API::Watcher::Actions
24
+ end
25
+
26
+ # Proxy method for {WatcherClient}, available in the receiving object
27
+ #
28
+ def watcher
29
+ @watcher ||= WatcherClient.new(self)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ Elasticsearch::API.__send__ :include, Elasticsearch::API::Watcher
36
+
37
+ Elasticsearch::Transport::Client.__send__ :include, Elasticsearch::API::Watcher if defined?(Elasticsearch::Transport::Client)
@@ -0,0 +1,27 @@
1
+ module Elasticsearch
2
+ module API
3
+ module Watcher
4
+ module Actions
5
+
6
+ # Throttle the execution of the watch by acknowledging it
7
+ #
8
+ # @option arguments [String] :id Watch ID (*Required*)
9
+ #
10
+ # @see http://www.elastic.co/guide/en/watcher/current/appendix-api-ack-watch.html
11
+ #
12
+ def ack_watch(arguments={})
13
+ raise ArgumentError, "Required argument 'id' missing" unless arguments[:id]
14
+ valid_params = [
15
+ :master_timeout
16
+ ]
17
+ method = 'PUT'
18
+ path = "_watcher/watch/#{arguments[:id]}/_ack"
19
+ params = {}
20
+ body = nil
21
+
22
+ perform_request(method, path, params, body).body
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ module Elasticsearch
2
+ module API
3
+ module Watcher
4
+ module Actions
5
+
6
+ # Delete a specific watch
7
+ #
8
+ # @option arguments [String] :id Watch ID (*Required*)
9
+ # @option arguments [Boolean] :force Ignore any locks on the watch and force the execution
10
+ #
11
+ # @see http://www.elastic.co/guide/en/watcher/current/appendix-api-delete-watch.html
12
+ #
13
+ def delete_watch(arguments={})
14
+ raise ArgumentError, "Required argument 'id' missing" unless arguments[:id]
15
+ valid_params = [
16
+ :master_timeout,
17
+ :force
18
+ ]
19
+ method = 'DELETE'
20
+ path = "_watcher/watch/#{arguments[:id]}"
21
+ params = {}
22
+ body = nil
23
+
24
+ perform_request(method, path, params, body).body
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end