elasticsearch-watcher 0.0.1

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