xymonclient 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 53c615d0c431bab59303f6e27d944dc89b2f8f3c
4
+ data.tar.gz: d279ec888695080dd90901dd5c3a2230c37b95f6
5
+ SHA512:
6
+ metadata.gz: bed8acb18cdbb7b3c1dc5ce9c381433c3138fc142637e4a2456b14f1fb15f0a25e8b8f4505a257a2c35ce17b7dca38e2561b8a78ee634cbbe72d820fc748b33e
7
+ data.tar.gz: 24a02a76ebaff377408a6423f127050a27ec416bcf2c3c6d7c638a31e421833ec4321c79d530b4120946251201100e5c361e25e168f03a6c637d3a88cca36a38
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in xymonclient.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,60 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ xymonclient (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.3.0)
10
+ codeclimate-test-reporter (1.0.3)
11
+ simplecov
12
+ diff-lcs (1.2.5)
13
+ docile (1.1.5)
14
+ json (2.0.2-java)
15
+ parser (2.3.1.4)
16
+ ast (~> 2.2)
17
+ powerpack (0.1.1)
18
+ rainbow (2.1.0)
19
+ rake (10.5.0)
20
+ rspec (3.5.0)
21
+ rspec-core (~> 3.5.0)
22
+ rspec-expectations (~> 3.5.0)
23
+ rspec-mocks (~> 3.5.0)
24
+ rspec-core (3.5.4)
25
+ rspec-support (~> 3.5.0)
26
+ rspec-expectations (3.5.0)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.5.0)
29
+ rspec-mocks (3.5.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.5.0)
32
+ rspec-support (3.5.0)
33
+ rubocop (0.40.0)
34
+ parser (>= 2.3.1.0, < 3.0)
35
+ powerpack (~> 0.1)
36
+ rainbow (>= 1.99.1, < 3.0)
37
+ ruby-progressbar (~> 1.7)
38
+ unicode-display_width (~> 1.0, >= 1.0.1)
39
+ ruby-progressbar (1.8.1)
40
+ simplecov (0.12.0)
41
+ docile (~> 1.1.0)
42
+ json (>= 1.8, < 3)
43
+ simplecov-html (~> 0.10.0)
44
+ simplecov-html (0.10.0)
45
+ unicode-display_width (1.1.1)
46
+
47
+ PLATFORMS
48
+ java
49
+
50
+ DEPENDENCIES
51
+ bundler (~> 1.13)
52
+ codeclimate-test-reporter (~> 1.0)
53
+ rake (~> 10.0)
54
+ rspec (~> 3.0)
55
+ rubocop (= 0.40)
56
+ simplecov (~> 0.12.0)
57
+ xymonclient!
58
+
59
+ BUNDLED WITH
60
+ 1.13.6
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2016 Orange <http://orange.com>
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.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ [![Gem Version](https://badge.fury.io/rb/xymonclient.svg)](https://badge.fury.io/rb/xymonclient)
2
+ [![Build Status](https://travis-ci.org/dchauviere/ruby-xymonclient.svg?branch=master)](https://travis-ci.org/dchauviere/ruby-xymonclient)
3
+ [![Code Climate](https://codeclimate.com/github/dchauviere/ruby-xymonclient/badges/gpa.svg)](https://codeclimate.com/github/dchauviere/ruby-xymonclient)
4
+ <a href="https://codeclimate.com/github/dchauviere/ruby-xymonclient/coverage"><img src="https://codeclimate.com/github/dchauviere/ruby-xymonclient/badges/coverage.svg" /></a>
5
+ # XymonClient
6
+
7
+ XymonClient is a ruby library for interacting with Xymon
8
+
9
+ Features:
10
+ * Send status
11
+ * Ack
12
+ * Enable/Disable
13
+ * Helper Class 'Service' for building sensors easily
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'xymonclient'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install xymonclient
30
+
31
+ ## Usage
32
+
33
+ ### Basic usage
34
+ ```ruby
35
+ require 'xymonclient'
36
+
37
+ client = XymonClient::Client.new(['localhost:1984'])
38
+ client.status('myhost', 'service1', 'green', 'additional data')
39
+
40
+ ```
41
+
42
+ ### Service wrapper
43
+ ```ruby
44
+ require 'xymonclient/service'
45
+
46
+ service = XymonClient::Service.new(['localhost:1984'],
47
+ 'name' => 'service1',
48
+ 'host' => 'myhost',
49
+ 'header' => 'A sample header',
50
+ 'footer' => 'A sample footer',
51
+ 'items' => {
52
+ 'ITEM1' => {
53
+ 'label' => 'Gauge Item 1',
54
+ 'type' => 'gauge',
55
+ 'threshold' => {
56
+ 'order' => '<',
57
+ 'critical' => 5,
58
+ 'warning' => 10,
59
+ 'nan_status' => 'red'
60
+ }
61
+ },
62
+ 'ITEM2' => {
63
+ 'label' => 'String Item 2',
64
+ 'type' => 'string',
65
+ 'threshold' => {
66
+ 'inclusive' => false,
67
+ 'critical' => ['all is Ok !']
68
+ }
69
+ }
70
+ }
71
+ )
72
+ service.update_item('ITEM1', 3)
73
+ service.update_item('ITEM2', 'all is Ok !')
74
+ service.status
75
+ ```
76
+
77
+ ## Development
78
+
79
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
80
+
81
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
82
+
83
+ ## Contributing
84
+
85
+ Bug reports and pull requests are welcome on GitHub at https://github.com/dchauviere/xymonclient.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'xymonclient'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,23 @@
1
+ require 'xymonclient/exception'
2
+
3
+ module XymonClient
4
+ ##
5
+ # static methods of servers discovery
6
+ class ServerDiscovery
7
+ def find_from_file(file = '/etc/xymon/xymonclient.cfg')
8
+ result = []
9
+ open(file, 'r').read.each_line do |line|
10
+ next unless line =~ /^XYMSRV=/ || line =~ /^XYMSERVERS=/
11
+ ip = line.scan(/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/)
12
+ if ip[0] != '0.0.0.0' && line =~ /^XYMSRV=/
13
+ result << xymsrv_ip
14
+ break
15
+ else
16
+ result = ip
17
+ end
18
+ end
19
+ raise NoXymonServerDefined if result.empty?
20
+ result.map { |ip| { host: ip, port: 1984 } }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ module XymonClient
2
+ class NoXymonServerDefined < StandardError
3
+ end
4
+
5
+ class InvalidStatus < StandardError
6
+ end
7
+
8
+ class InvalidServer < StandardError
9
+ end
10
+
11
+ class InvalidDuration < StandardError
12
+ end
13
+
14
+ class InvalidService < StandardError
15
+ end
16
+
17
+ class InvalidHost < StandardError
18
+ end
19
+
20
+ class InvalidServiceItem < StandardError
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ module XymonClient
2
+ TIMESTRING_DEFINITION = {
3
+ '' => 60,
4
+ 'm' => 60,
5
+ 'h' => 60 * 60,
6
+ 'd' => 60 * 60 * 24,
7
+ 'w' => 60 * 60 * 24 * 7
8
+ }.freeze
9
+
10
+ def self.valid_status?(status)
11
+ %w(green yellow red purple blue clear).include?(status)
12
+ end
13
+
14
+ def self.valid_duration?(duration)
15
+ duration =~ /^[0-9]+[hmwd]?$/
16
+ end
17
+
18
+ def self.timestring_to_time(timestring)
19
+ time_matched = /^([0-9]+)([hmdw]{0,1})$/.match(timestring)
20
+ raise InvalidTimeString unless time_matched
21
+ time_matched[1].to_i * TIMESTRING_DEFINITION[time_matched[2]]
22
+ end
23
+
24
+ def self.hostsvc(host, service)
25
+ raise XymonClient::InvalidHost, host if host == ''
26
+ raise XymonClient::InvalidService, service if service == ''
27
+ host.tr('.', ',') + '.' + service
28
+ end
29
+
30
+ ##
31
+ # Class container for isolating context for ERB templating
32
+ class ERBContext
33
+ def initialize(hash)
34
+ hash.each_pair do |key, value|
35
+ instance_variable_set('@' + key.to_s, value)
36
+ end
37
+ end
38
+
39
+ def context
40
+ binding
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,133 @@
1
+ require 'erb'
2
+ require 'xymonclient'
3
+ require 'xymonclient/helpers'
4
+ require 'xymonclient/serviceitem'
5
+
6
+ module XymonClient
7
+ ##
8
+ # Manage a Service, can contains multiple items to monitor
9
+ class Service < XymonClient::Client
10
+ attr_reader :name
11
+ attr_accessor :status
12
+ attr_reader :details
13
+ DEFAULT_DETAILS_TEMPLATE = 'Generated at <%= @timestamp %> ' \
14
+ "for <%= @lifetime %> \n<%= @header %>\n" \
15
+ '<% @items.each do |item| %>' \
16
+ "&<%= item['status'] %> <%= item['label'] %>: <%= item['value'] %>\n" \
17
+ "<% end %>\n" \
18
+ "<%= @footer %>\n".freeze
19
+
20
+ def initialize(servers, config)
21
+ super(servers)
22
+ @info = { 'items' => {} }
23
+ update_config(config)
24
+ end
25
+
26
+ def update_config(config)
27
+ raise InvalidService if config.fetch('name', '') == ''
28
+ raise InvalidService if config.fetch('host', '') == ''
29
+ @info['name'] = config['name']
30
+ @info['host'] = config['host']
31
+ @info['details_template'] = config.fetch(
32
+ 'details_template',
33
+ DEFAULT_DETAILS_TEMPLATE
34
+ )
35
+ @info['lifetime'] = config.fetch('lifetime', '30m')
36
+ @info['enabled'] = config.fetch('enabled', true)
37
+ @info['header'] = config.fetch('header', '')
38
+ @info['footer'] = config.fetch('footer', '')
39
+ if config.fetch('items', {}).empty?
40
+ @info['items'] = {}
41
+ else
42
+ _update_items_config(config)
43
+ end
44
+ @info['purple_item_status'] = config.fetch('purple_item_status', 'red')
45
+ @info['status'] = @info.fetch('status', config.fetch('status', 'purple'))
46
+ end
47
+
48
+ def update_item(name, value)
49
+ raise InvalidServiceItem unless @info['items'].include?(name)
50
+ @info['items'][name].value = value
51
+ end
52
+
53
+ def status
54
+ return 'clear' unless @info['enabled']
55
+ items_status = @info['items'].map do |_key, value|
56
+ if value.info['status'] == 'purple'
57
+ @info['purple_item_status']
58
+ else
59
+ value.info['status']
60
+ end
61
+ end
62
+ @info['status'] = unless items_status.empty?
63
+ if items_status.include?('red')
64
+ 'red'
65
+ elsif items_status.include?('yellow') && \
66
+ @status != 'red'
67
+ 'yellow'
68
+ else
69
+ 'green'
70
+ end
71
+ end
72
+ details = _details
73
+ super(
74
+ @info['host'],
75
+ @info['name'],
76
+ @info['status'],
77
+ details,
78
+ @info['lifetime']
79
+ )
80
+ [@info['status'], details]
81
+ end
82
+
83
+ def enable
84
+ super(@info['host'], @info['name'])
85
+ end
86
+
87
+ def disable(duration, message)
88
+ super(@info['host'], @info['name'], duration, message)
89
+ end
90
+
91
+ def board(fields = [])
92
+ super(@info['host'], @info['name'], fields)
93
+ end
94
+
95
+ def ack(duration, message)
96
+ super(@info['host'], @info['name'], duration, message)
97
+ end
98
+
99
+ private
100
+
101
+ def _details
102
+ @info['timestamp'] = Time.now
103
+ context = @info.reject { |key, _value| key == 'items' }
104
+ context['items'] = @info['items'].map { |_key, value| value.info }
105
+ ERB.new(@info['details_template']).result(
106
+ XymonClient::ERBContext.new(context).context
107
+ )
108
+ end
109
+
110
+ def _create_serviceitem(config)
111
+ case config.fetch('type', '')
112
+ when 'gauge'
113
+ ServiceItemGauge.new(config)
114
+ when 'string'
115
+ ServiceItemString.new(config)
116
+ else
117
+ ServiceItem.new(config)
118
+ end
119
+ end
120
+
121
+ def _update_items_config(config)
122
+ # cleanup old items and update old items
123
+ @info['items'].keep_if { |key, _value| config.fetch('items').key?(key) }
124
+ @info['items'].each do |item_name, item_value|
125
+ item_value.update_config(config['items'][item_name])
126
+ end
127
+ # add new items
128
+ config['items'].each do |item_name, item_config|
129
+ @info['items'][item_name] = _create_serviceitem(item_config)
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,133 @@
1
+ require 'xymonclient'
2
+ require 'xymonclient/helpers'
3
+
4
+ module XymonClient
5
+ ##
6
+ # Manage an item to monitor
7
+ class ServiceItem
8
+ attr_accessor :value
9
+ attr_reader :info
10
+
11
+ def initialize(config)
12
+ raise InvalidServiceItemName if config.fetch('label', '') == ''
13
+ @info = {
14
+ 'label' => config['label'],
15
+ 'type' => config['type'],
16
+ 'description' => config.fetch('description', ''),
17
+ 'enabled' => config.fetch('enabled', true),
18
+ 'status' => 'purple',
19
+ 'lifetime' => config.fetch('lifetime', '30m'),
20
+ 'time' => Time.at(0)
21
+ }
22
+ end
23
+
24
+ def value=(value)
25
+ @info['value'] = value
26
+ @info['time'] = Time.now
27
+ status
28
+ end
29
+
30
+ def value
31
+ @info['value']
32
+ end
33
+
34
+ def status
35
+ @info['status'] = \
36
+ if !@info['enabled']
37
+ 'clear'
38
+ elsif Time.now - @info['time'] > \
39
+ XymonClient.timestring_to_time(@info['lifetime'])
40
+ 'purple'
41
+ elsif XymonClient.valid_status?(@info['value'])
42
+ @info['value']
43
+ else
44
+ 'red'
45
+ end
46
+ end
47
+ end
48
+
49
+ ##
50
+ class ServiceItemGauge < ServiceItem
51
+ def initialize(config)
52
+ super(config)
53
+ @info['threshold'] = config.fetch('threshold', {})
54
+ @info['nan_status'] = config.fetch('nan_status', 'green')
55
+ end
56
+
57
+ def status
58
+ @info['status'] = \
59
+ if !@info['enabled']
60
+ 'clear'
61
+ elsif Time.now - @info['time'] > \
62
+ XymonClient.timestring_to_time(@info['lifetime'])
63
+ 'purple'
64
+ elsif value.instance_of?(Float) && value.nan?
65
+ @info['threshold'].fetch('nan_status', 'red')
66
+ elsif @info['threshold'].key?('critical') && \
67
+ _threshold_reached?('critical')
68
+ 'red'
69
+ elsif @info['threshold'].key?('warning') && \
70
+ _threshold_reached?('warning')
71
+ 'yellow'
72
+ else
73
+ 'green'
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def _threshold_reached?(threshold)
80
+ case @info['threshold'].fetch('order', '<')
81
+ when '<'
82
+ @info['value'] < @info['threshold'][threshold]
83
+ when '>'
84
+ @info['value'] > @info['threshold'][threshold]
85
+ when '<='
86
+ @info['value'] <= @info['threshold'][threshold]
87
+ when '>='
88
+ @info['value'] >= @info['threshold'][threshold]
89
+ end
90
+ end
91
+ end
92
+
93
+ ##
94
+ class ServiceItemString < ServiceItem
95
+ def initialize(config)
96
+ super(config)
97
+ @info['threshold'] = config.fetch('threshold', {})
98
+ end
99
+
100
+ def status
101
+ @info['status'] = \
102
+ if !@info['enabled']
103
+ 'clear'
104
+ elsif Time.now - @info['time'] > \
105
+ XymonClient.timestring_to_time(@info['lifetime'])
106
+ 'purple'
107
+ elsif @info['threshold'].key?('critical') && \
108
+ _threshold_reached?('critical')
109
+ 'red'
110
+ elsif @info['threshold'].key?('warning') && \
111
+ _threshold_reached?('warning')
112
+ 'yellow'
113
+ else
114
+ 'green'
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def _threshold_reached?(threshold)
121
+ inclusive = @info['threshold'].fetch('inclusive', true)
122
+ values = @info['value']
123
+ if values.instance_of?(Array)
124
+ value_is_included = values.any? do |value|
125
+ @info['threshold'][threshold].include?(value)
126
+ end
127
+ else
128
+ value_is_included = @info['threshold'][threshold].include?(values)
129
+ end
130
+ (inclusive && value_is_included) || (!inclusive && !value_is_included)
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,3 @@
1
+ module XymonClient
2
+ VERSION = '0.1.1'.freeze
3
+ end
@@ -0,0 +1,105 @@
1
+ require 'xymonclient/version'
2
+ require 'xymonclient/exception'
3
+ require 'xymonclient/discovery'
4
+ require 'xymonclient/helpers'
5
+ require 'socket'
6
+
7
+ module XymonClient
8
+ ##
9
+ # Client object for interacting with Xymon server(s)
10
+ # Params:
11
+ # - servers: array of string 'hostname' or 'hostname:port'
12
+ # (port default to 1984)
13
+ class Client
14
+ attr_reader :servers
15
+
16
+ def initialize(servers = [])
17
+ @servers = \
18
+ if servers.empty?
19
+ XymonClient::ServerDiscovery.find_from_file
20
+ else
21
+ _parse_servers(servers)
22
+ end
23
+ end
24
+
25
+ def status(host, service, status, message, lifetime = '30m')
26
+ raise XymonClient::InvalidDuration, lifetime \
27
+ unless XymonClient.valid_duration?(lifetime)
28
+ raise XymonClient::InvalidStatus, status \
29
+ unless XymonClient.valid_status?(status)
30
+ _send_to_all(
31
+ "status+#{lifetime} " \
32
+ "#{XymonClient.hostsvc(host, service)} #{status} #{message}"
33
+ )
34
+ end
35
+
36
+ def disable(host, service, duration, message)
37
+ raise XymonClient::InvalidDuration, duration \
38
+ unless XymonClient.valid_duration?(duration)
39
+ _send_to_all(
40
+ "disable #{XymonClient.hostsvc(host, service)} #{duration} #{message}"
41
+ )
42
+ end
43
+
44
+ def enable(host, service)
45
+ _send_to_all("enable #{XymonClient.hostsvc(host, service)}")
46
+ end
47
+
48
+ def drop(host, service = '')
49
+ _send_to_all("drop #{host} #{service}")
50
+ end
51
+
52
+ def board(host, service, fields = [])
53
+ response = {}
54
+ @servers.each do |server|
55
+ response[server] = _send(
56
+ server,
57
+ "xymondboard host=#{host} test=#{service} fields=#{fields.join(';')}"
58
+ )
59
+ end
60
+ response
61
+ end
62
+
63
+ def ack(host, service, duration, message)
64
+ raise XymonClient::InvalidDuration, duration \
65
+ unless XymonClient.valid_duration?(duration)
66
+ cookies = board(host, service, ['cookie'])
67
+ @servers.each do |server|
68
+ _send(
69
+ server,
70
+ "xymondack #{cookies[server].to_i} #{duration} #{message}"
71
+ ) if cookies[server].to_i != -1
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def _send_to_all(message)
78
+ @servers.each { |server| _send(server, message) }
79
+ end
80
+
81
+ def _send(server, message)
82
+ # TODO: validate response from all servers ( and retry ?)
83
+ socket = TCPSocket.open(server[:host], server[:port])
84
+ socket.puts message
85
+ socket.close_write
86
+ socket.gets
87
+ ensure
88
+ socket.close if socket
89
+ end
90
+
91
+ def _parse_servers(servers = [])
92
+ raise XymonClient::NoXymonServerDefined if servers.empty?
93
+ servers.map do |server|
94
+ case server
95
+ when /[^:]+:[0-9]*/
96
+ { host: server.split(':')[0], port: server.split(':')[1].to_i }
97
+ when /[^:]*/
98
+ { host: server, port: 1984 }
99
+ else
100
+ raise XymonClient::InvalidServer, server
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'xymonclient/service'
3
+ require 'socket'
4
+
5
+ describe XymonClient do
6
+ describe XymonClient::Service do
7
+ let(:service) do
8
+ XymonClient::Service.new(
9
+ ['localhost'],
10
+ 'name' => 'service1',
11
+ 'host' => 'myhost',
12
+ 'header' => 'A sample header',
13
+ 'footer' => 'A sample footer',
14
+ 'items' => {
15
+ 'ITEM1' => {
16
+ 'label' => 'Gauge Item 1',
17
+ 'type' => 'gauge',
18
+ 'threshold' => {
19
+ 'order' => '<',
20
+ 'critical' => 5,
21
+ 'warning' => 10,
22
+ 'nan_status' => 'red'
23
+ }
24
+ },
25
+ 'ITEM2' => {
26
+ 'label' => 'String Item 2',
27
+ 'type' => 'string',
28
+ 'threshold' => {
29
+ 'inclusive' => false,
30
+ 'critical' => ['all is Ok !']
31
+ }
32
+ }
33
+ }
34
+ )
35
+ end
36
+
37
+ it 'should send a valid status and details' do
38
+ service.update_item('ITEM1', 3)
39
+ service.update_item('ITEM2', 'all is Ok !')
40
+ allow(service).to receive(:_send) { '' }
41
+ # rubocop:disable LineLength
42
+ expect(service.status[0]).to eq('red')
43
+ expect(service.status[1]).to match(
44
+ /Generated at .* for 30m \nA sample header\n&red Gauge Item 1: 3\n&green String Item 2: all is Ok !\n\nA sample footer/
45
+ )
46
+ # rubocop:enable LineLength
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+ require 'xymonclient'
3
+ require 'xymonclient/serviceitem'
4
+
5
+ describe XymonClient do
6
+ describe XymonClient::ServiceItem do
7
+ let(:config) { { 'label' => 'Item 1' } }
8
+
9
+ it 'should return purple status at start' do
10
+ expect(described_class.new(config).status).to eq('purple')
11
+ end
12
+
13
+ it 'should return red status on bad value' do
14
+ baditem = described_class.new(config)
15
+ baditem.value = 'badstatus'
16
+ expect(baditem.status).to eq('red')
17
+ end
18
+
19
+ it 'should return clear status if disabled' do
20
+ config['enabled'] = false
21
+ expect(described_class.new(config).status).to eq('clear')
22
+ end
23
+ end
24
+
25
+ describe XymonClient::ServiceItemGauge do
26
+ let(:config) { { 'label' => 'Item 1' } }
27
+
28
+ it 'should return red status when value is above critical threshold' do
29
+ config['threshold'] = { 'order' => '>', 'critical' => 10, 'warning' => 5 }
30
+ item = described_class.new(config)
31
+ item.value = 11
32
+ expect(item.status).to eq('red')
33
+ end
34
+
35
+ it 'should return yellow status when value is between warning and ' \
36
+ 'critical threshold' do
37
+ config['threshold'] = { 'order' => '>', 'critical' => 10, 'warning' => 5 }
38
+ item = described_class.new(config)
39
+ item.value = 7
40
+ expect(item.status).to eq('yellow')
41
+ end
42
+
43
+ it 'should return green status when value is under warning threshold' do
44
+ config['threshold'] = { 'order' => '>', 'critical' => 10, 'warning' => 5 }
45
+ item = described_class.new(config)
46
+ item.value = 3
47
+ expect(item.status).to eq('green')
48
+ end
49
+ end
50
+
51
+ describe XymonClient::ServiceItemString do
52
+ describe 'inclusive' do
53
+ let(:config) { { 'label' => 'Item 1', 'threshold' => {'inclusive' => true, 'critical' => ['foo'], 'warning' => ['bar']}} }
54
+ it 'should return red status when value is included in critical threshold' do
55
+ item = described_class.new(config)
56
+ item.value = 'foo'
57
+ expect(item.status).to eq('red')
58
+ end
59
+
60
+ it 'should return yellow status when value is included in warning threshold' do
61
+ item = described_class.new(config)
62
+ item.value = 'bar'
63
+ expect(item.status).to eq('yellow')
64
+ end
65
+
66
+ it 'should return green status when values is not included in critical/warning threshold' do
67
+ item = described_class.new(config)
68
+ item.value = 'other'
69
+ expect(item.status).to eq('green')
70
+ end
71
+ end
72
+
73
+ describe 'exclusive' do
74
+ let(:config) { { 'label' => 'Item 1', 'threshold' => {'inclusive' => false, 'critical' => ['foo'], 'warning' => ['bar']}} }
75
+ it 'should return red status when "foo" is not included in critical threshold' do
76
+ item = described_class.new(config)
77
+ item.value = ['bar']
78
+ expect(item.status).to eq('red')
79
+ end
80
+
81
+ it 'should return yellow status when "bar" is not included in warning threshold' do
82
+ item = described_class.new(config)
83
+ item.value = ['foo']
84
+ expect(item.status).to eq('yellow')
85
+ end
86
+
87
+ it 'should return green status when all values are included in critical/warning threshold' do
88
+ item = described_class.new(config)
89
+ item.value = ['foo', 'bar']
90
+ expect(item.status).to eq('green')
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,5 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
+ require 'xymonclient'
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'xymonclient/helpers'
3
+
4
+ describe XymonClient do
5
+ describe XymonClient::Client do
6
+ let(:client) { XymonClient::Client.new(['foo', 'bar:19840']) }
7
+
8
+ it 'should send a status with default lifetime (30m)' do
9
+ allow(client).to receive(:_send) { '' }
10
+ expect(client).to receive(:_send).with(
11
+ kind_of(Hash),
12
+ 'status+30m my,host.myservice green all is good'
13
+ )
14
+ client.status('my.host', 'myservice', 'green', 'all is good')
15
+ end
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xymonclient
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - David Chauviere
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: '0.40'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: '0.40'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.12.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.12.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: codeclimate-test-reporter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
97
+ description: Interact with Xymon server, send status, ack, enable/disable
98
+ email:
99
+ - david.chauviere@orange.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - Gemfile
105
+ - Gemfile.lock
106
+ - LICENSE
107
+ - README.md
108
+ - Rakefile
109
+ - bin/console
110
+ - bin/setup
111
+ - lib/xymonclient.rb
112
+ - lib/xymonclient/discovery.rb
113
+ - lib/xymonclient/exception.rb
114
+ - lib/xymonclient/helpers.rb
115
+ - lib/xymonclient/service.rb
116
+ - lib/xymonclient/serviceitem.rb
117
+ - lib/xymonclient/version.rb
118
+ - spec/service_spec.rb
119
+ - spec/serviceitem_spec.rb
120
+ - spec/spec_helper.rb
121
+ - spec/xymonclient_spec.rb
122
+ homepage: https://github.com/dchauviere/ruby-xymonclient
123
+ licenses:
124
+ - Apache-2.0
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.6.6
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Xymon client library
146
+ test_files: []
147
+ has_rdoc: