xymonclient 0.1.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.
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: