rubix 0.0.8 → 0.0.9

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.
data/README.rdoc CHANGED
@@ -175,14 +175,14 @@ Zabbix. (Credentials and addresses for the Zabbix server and the
175
175
  Zabbix API can all be customized; see the <tt>--help</tt> option.)
176
176
 
177
177
  # Send one data point -- this is tab separated!
178
- $ echo "foo.bar.baz 123" | zabbix_pipe --host='My Zabbix Host'
178
+ $ echo "foo.bar.baz 123" | zabbix_pipe --host='My Zabbix Host' --host_groups='My Zabbix Servers,Some Other Group'
179
179
  # Send a bunch of data points in a file
180
- $ cat my_data.tsv | zabbix_pipe --host='My Zabbix Host'
180
+ $ cat my_data.tsv | zabbix_pipe --host='My Zabbix Host' --host_groups='My Zabbix Servers,Some Other Group'
181
181
 
182
182
  You can also pass the file directly:
183
183
 
184
184
  # Send a bunch of data points in a file
185
- $ zabbix_pipe --host='My Zabbix Host' my_data.tsv
185
+ $ zabbix_pipe --host='My Zabbix Host' --host_groups='My Zabbix Servers,Some Other Group' my_data.tsv
186
186
 
187
187
  You can also listen from a named pipe. This is useful on a
188
188
  "production" system in which many processes may want to simply and
@@ -190,7 +190,7 @@ easily write somewhere without worrying about what happens.
190
190
 
191
191
  # In the first terminal
192
192
  $ mkfifo /dev/zabbix
193
- $ zabbix_pipe --pipe=/dev/zabbix --host='My Zabbix Host'
193
+ $ zabbix_pipe --pipe=/dev/zabbix --host='My Zabbix Host' --host_groups='My Zabbix Servers,Some Other Group'
194
194
 
195
195
  # In another terminal
196
196
  $ echo "foo.bar.baz 123" > /dev/zabbix
@@ -204,9 +204,9 @@ This simple block of JSON doesn't really add any power to
204
204
  +zabbix_pipe+. What becomes more interesting is that we can wedge in
205
205
  data for *diffferent* hosts, items, &c. when using JSON input:
206
206
 
207
- $ echo '{"host": "My first host", "data": [{"key": "foo.bar.baz", "value": 123}, {"key": "foo.bar.baz", "value": 101}]}' > /dev/zabbix
208
- $ echo '{"host": "My second host", "data": [{"key": "foo.bar.baz", "value": 123}, {"key": "foo.bar.baz", "value": 101}]}' > /dev/zabbix
209
- $ echo '{"host": "My third host", "data": [{"key": "foo.bar.baz", "value": 123}, {"key": "foo.bar.baz", "value": 101}]}' > /dev/zabbix
207
+ $ echo '{"host": "My first host", "host_groups": "My Zabbix Servers,Some Other Group", "data": [{"key": "foo.bar.baz", "value": 123}, {"key": "foo.bar.baz", "value": 101}]}' > /dev/zabbix
208
+ $ echo '{"host": "My second host", "host_groups": "My Zabbix Servers,Some Other Group", "data": [{"key": "foo.bar.baz", "value": 123}, {"key": "foo.bar.baz", "value": 101}]}' > /dev/zabbix
209
+ $ echo '{"host": "My third host", "host_groups": "My Zabbix Servers,Some Other Group", "data": [{"key": "foo.bar.baz", "value": 123}, {"key": "foo.bar.baz", "value": 101}]}' > /dev/zabbix
210
210
 
211
211
  Rubix will switch hosts on the fly.
212
212
 
@@ -331,9 +331,9 @@ Chef[http://www.opscode.com/chef/] and so Rubix comes with a
331
331
  def measure
332
332
  begin
333
333
  if Net::HTTP.get_response(uri).code.to_i == 200
334
- availability = 1
335
- else
336
- availability = 0
334
+ availability = 1
335
+ else
336
+ availability = 0
337
337
  end
338
338
  rescue => e
339
339
  availability = 0
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.8
1
+ 0.0.9
data/lib/rubix.rb CHANGED
@@ -10,15 +10,43 @@ module Rubix
10
10
  autoload :Connection, 'rubix/connection'
11
11
  autoload :Response, 'rubix/response'
12
12
  autoload :Sender, 'rubix/sender'
13
-
13
+
14
+ # Set up a <tt>Connection</tt> to a Zabbix API server.
15
+ #
16
+ # Only needs to be called once.
17
+ #
18
+ # # These are the defaults
19
+ # Rubix.connect 'localhost', 'admin', 'zabbix'
20
+ #
21
+ # # A server running on a custom port with different
22
+ # # credentials...
23
+ # Rubix.connect 'my.server.com:8080', 'foobar', 'bazbooz'
24
+ #
25
+ # @param [URI,String] server the address of the Zabbix API server to connect to
26
+ # @param [String] username the username of an existing Zabbix API <tt>User</tt> account with API access
27
+ # @param [String] password the password for this account
28
+ # @return [Rubix::Connection]
14
29
  def self.connect server, username=nil, password=nil
15
30
  self.connection = Connection.new(server, username, password)
16
31
  end
17
32
 
33
+ # Explicitly set the connection using a <tt>Rubix::Connection</tt>
34
+ # object.
35
+ #
36
+ # Rubix.connection = Rubix::Connection.new('http://localhost/api_jsonrpc.php', 'admin', 'zabbix')
37
+ #
38
+ # @param [Rubix::Connection] connection
39
+ # @return [Rubix::Connection]
18
40
  def self.connection= connection
19
41
  @connection = connection
20
42
  end
21
43
 
44
+ # Return the current connection to a Zabbix API. Useful for
45
+ # directly sending queries.
46
+ #
47
+ # Rubix.connection.request 'host.get', :filter => { "name" => "foobar" }
48
+ #
49
+ # @return [Rubix::Connection]
22
50
  def self.connection
23
51
  @connection ||= Connection.new('http://localhost/api_jsonrpc.php', 'admin', 'zabbix')
24
52
  return @connection if @connection.authorized?
@@ -26,10 +54,21 @@ module Rubix
26
54
  @connection
27
55
  end
28
56
 
57
+ # Base class for Rubix errors.
29
58
  Error = Class.new(RuntimeError)
59
+
60
+ # Errors with connecting to a Zabbix API.
30
61
  ConnectionError = Class.new(Error)
62
+
63
+ # Error authenticating with a Zabbix API.
31
64
  AuthenticationError = Class.new(Error)
65
+
66
+ # Error in a request to a Zabbix API.
32
67
  RequestError = Class.new(Error)
68
+
69
+ # Error detected locally in an API resource that will prevent it
70
+ # from being saved by the Zabbix API (i.e. - no host group for a
71
+ # host).
33
72
  ValidationError = Class.new(Error)
34
73
 
35
74
  end
@@ -1,13 +1,14 @@
1
1
  module Rubix
2
2
  module Associations
3
+
3
4
  module BelongsToHost
4
-
5
+
5
6
  def host= h
6
7
  return unless h
7
8
  @host = h
8
9
  @host_id = h.id
9
10
  end
10
-
11
+
11
12
  def host
12
13
  return @host if @host
13
14
  return unless @host_id
@@ -18,7 +19,7 @@ module Rubix
18
19
  return unless hid
19
20
  @host_id = hid
20
21
  end
21
-
22
+
22
23
  def host_id
23
24
  return @host_id if @host_id
24
25
  return unless @host
@@ -6,12 +6,44 @@ require 'rubix/log'
6
6
 
7
7
  module Rubix
8
8
 
9
+ # Wraps and abstracts the process of connecting to a Zabbix API.
9
10
  class Connection
10
11
 
11
12
  include Logs
12
13
 
13
- attr_reader :uri, :server, :auth, :request_id, :username, :password, :last_response
14
+ # @return [URI] The URI for the Zabbix API.
15
+ attr_reader :uri
14
16
 
17
+ # @return [Net::HTTP] the HTTP server backing the Zabbix API.
18
+ attr_reader :server
19
+
20
+ # @return [String] the authentication token provided by the Zabbix
21
+ # API for this session.
22
+ attr_reader :auth
23
+
24
+ # @return [Fixnum] the ID of the next request that will be sent.
25
+ attr_reader :request_id
26
+
27
+ # @return [String] the username of the Zabbix account used to authenticate
28
+ attr_reader :username
29
+
30
+ # @return [String] the password of the Zabbix account used to authenticate
31
+ attr_reader :password
32
+
33
+ # @return [Rubix::Response] the last response from the Zabbix API -- useful for logging purposes
34
+ attr_reader :last_response
35
+
36
+ # Set up a connection to a Zabbix API.
37
+ #
38
+ # The +uri_or_string+ can be either a string or a <tt>URI</tt>
39
+ # object.
40
+ #
41
+ # The +username+ and +password+ provided must correspond to an
42
+ # existing Zabbix account with API access enabled.
43
+ #
44
+ # @param [URI,String] uri_or_string the address of the Zabbix API server to connect to
45
+ # @param [String] username the username of an existing Zabbix API <tt>User</tt> account with API access
46
+ # @param [String] password the password for this account
15
47
  def initialize uri_or_string, username=nil, password=nil
16
48
  self.uri = uri_or_string
17
49
  @username = username || uri.user
@@ -19,6 +51,51 @@ module Rubix
19
51
  @request_id = 0
20
52
  end
21
53
 
54
+ # Send a request to the Zabbix API. Will return a Rubix::Response
55
+ # object.
56
+ #
57
+ # Documentation on what methods and parameters are available can
58
+ # be found in the {Zabbix API
59
+ # documentation}[http://www.zabbix.com/documentation/1.8/api]
60
+ #
61
+ # Rubix.connection.request 'host.get', 'filter' => { 'host' => 'foobar' }
62
+ #
63
+ # @param [String] method the name of the Zabbix API method
64
+ # @param [Hash,Array] params parameters for the method call
65
+ # @retrn [Rubix::Response]
66
+ def request method, params
67
+ authorize! unless authorized?
68
+ till_response do
69
+ raw_params = {
70
+ :jsonrpc => "2.0",
71
+ :id => request_id,
72
+ :method => method,
73
+ :params => params,
74
+ :auth => auth
75
+ }
76
+ send_raw_request(raw_params)
77
+ end
78
+ end
79
+
80
+ # Has this connection already been authorized and provided with a
81
+ # authorization token from the Zabbix API?
82
+ def authorized?
83
+ !auth.nil?
84
+ end
85
+
86
+ # Force the connection to execute an authorization request and
87
+ # renew (or set) the authorization token.
88
+ def authorize!
89
+ response = till_response { send_raw_request(authorization_params) }
90
+ raise AuthenticationError.new("Could not authenticate with Zabbix API at #{uri}: #{response.error_message}") if response.error?
91
+ raise AuthenticationError.new("Malformed response from Zabbix API: #{response.body}") unless response.string?
92
+ @auth = response.result
93
+ end
94
+
95
+ # Set the URI for this connection's Zabbix API server.
96
+ #
97
+ # @param [String, URI] uri_or_string the address of the Zabbix API.
98
+ # @return [Net::HTTP]
22
99
  def uri= uri_or_string
23
100
  if uri_or_string.respond_to?(:host)
24
101
  @uri = uri_or_string
@@ -29,10 +106,12 @@ module Rubix
29
106
  @server = Net::HTTP.new(uri.host, uri.port)
30
107
  end
31
108
 
32
- def authorized?
33
- !auth.nil?
34
- end
109
+ protected
35
110
 
111
+ # The parameters used for constructing an authorization request
112
+ # with the Zabbix API.
113
+ #
114
+ # @return [Hash]
36
115
  def authorization_params
37
116
  {
38
117
  :jsonrpc => "2.0",
@@ -45,13 +124,17 @@ module Rubix
45
124
  }
46
125
  end
47
126
 
48
- def authorize!
49
- response = till_response { send_raw_request(authorization_params) }
50
- raise AuthenticationError.new("Could not authenticate with Zabbix API at #{uri}: #{response.error_message}") if response.error?
51
- raise AuthenticationError.new("Malformed response from Zabbix API: #{response.body}") unless response.string?
52
- @auth = response.result
53
- end
54
-
127
+ # Attempt to execute a query until a non-5xx response is returned.
128
+ #
129
+ # 5xx responses can occur because the backend PHP server providing
130
+ # the Zabbix API can sometimes be unavailable if the serer is
131
+ # restarting or something like that. We keep trying until that
132
+ # doesn't happen.
133
+ #
134
+ # You shouldn't have to use this method directly -- the
135
+ # <tt>Rubix::Connection#authorize!</tt> and
136
+ # <tt>Rubix::Connection#request</tt> methods already use this
137
+ # functionality.
55
138
  def till_response attempt=1, max_attempts=5, &block
56
139
  response = block.call
57
140
  Rubix.logger.log(Logger::DEBUG, "RECV: #{response.body}") if Rubix.logger
@@ -65,21 +148,25 @@ module Rubix
65
148
  @last_response = Response.new(response)
66
149
  end
67
150
  end
68
-
69
- def request method, params
70
- authorize! unless authorized?
71
- till_response do
72
- raw_params = {
73
- :jsonrpc => "2.0",
74
- :id => request_id,
75
- :method => method,
76
- :params => params,
77
- :auth => auth
78
- }
79
- send_raw_request(raw_params)
151
+
152
+ # Send the POST request to the Zabbix API.
153
+ #
154
+ # @param [Hash, #to_json] raw_params the complete parameters of the request.
155
+ # @return [Net::HTTP::Response]
156
+ def send_raw_request raw_params
157
+ @request_id += 1
158
+ begin
159
+ raw_response = server.request(raw_post_request(raw_params))
160
+ rescue NoMethodError, SocketError => e
161
+ raise RequestError.new("Could not connect to Zabbix server at #{host_with_port}")
80
162
  end
163
+ raw_response
81
164
  end
82
-
165
+
166
+ # Generate the raw POST request to send to the Zabbix API
167
+ #
168
+ # @param [Hash, #to_json] raw_params the complete parameters of the request.
169
+ # @return [Net::HTTP::Post]
83
170
  def raw_post_request raw_params
84
171
  json_body = raw_params.to_json
85
172
  Rubix.logger.log(Logger::DEBUG, "SEND: #{json_body}") if Rubix.logger
@@ -89,6 +176,9 @@ module Rubix
89
176
  end
90
177
  end
91
178
 
179
+ # Used for generating helpful error messages.
180
+ #
181
+ # @return [String]
92
182
  def host_with_port
93
183
  if uri.port.nil? || uri.port.to_i == 80
94
184
  uri.host
@@ -97,15 +187,5 @@ module Rubix
97
187
  end
98
188
  end
99
189
 
100
- def send_raw_request raw_params
101
- @request_id += 1
102
- begin
103
- raw_response = server.request(raw_post_request(raw_params))
104
- rescue NoMethodError, SocketError => e
105
- raise RequestError.new("Could not connect to Zabbix server at #{host_with_port}")
106
- end
107
- raw_response
108
- end
109
-
110
190
  end
111
191
  end
data/lib/rubix/log.rb CHANGED
@@ -2,21 +2,40 @@ require 'logger'
2
2
 
3
3
  module Rubix
4
4
 
5
+ # Set the Rubix logger. Set to +nil+ to disable all logging.
6
+ #
7
+ # @param [Logger] l the logger to use
5
8
  def self.logger= l
6
9
  @logger = l
7
10
  end
8
11
 
12
+ # The current Rubix logger.
13
+ #
14
+ # @return [Logger, nil]
9
15
  def self.logger
10
16
  return @logger unless @logger.nil?
11
17
  @logger = default_logger
12
18
  end
13
19
 
20
+ # The default logger.
21
+ #
22
+ # @return [Logger]
14
23
  def self.default_logger
15
24
  @logger = Logger.new(default_log_path)
16
25
  @logger.level = default_log_severity
17
26
  @logger
18
27
  end
19
28
 
29
+ # The default logger's severity.
30
+ #
31
+ # Will attempt to read from
32
+ #
33
+ # - <tt>Settings[:log_level]</tt> if <tt>Settings</tt> is defined (see Configliere[http://github.com/infochimps/configliere])
34
+ # - the <tt>RUBIX_LOG_LEVEL</tt> environment variable if defined
35
+ #
36
+ # The default is 'info'.
37
+ #
38
+ # @return [Fixnum]
20
39
  def self.default_log_severity
21
40
  case
22
41
  when defined?(Settings) && Settings[:log_level]
@@ -34,6 +53,14 @@ module Rubix
34
53
  end
35
54
  end
36
55
 
56
+ # The default logger's path.
57
+ #
58
+ # Will attempt to read from
59
+ #
60
+ # - <tt>Settings[:log]</tt> if <tt>Settings</tt> is defined (see Configliere[http://github.com/infochimps/configliere])
61
+ # - the <tt>RUBIX_LOG_PATH</tt> environment variable if defined
62
+ #
63
+ # Defaults to writing <tt>stdout</tt>.
37
64
  def self.default_log_path
38
65
  case
39
66
  when defined?(Settings) && Settings[:log]
@@ -46,29 +73,46 @@ module Rubix
46
73
  $stdout
47
74
  end
48
75
  end
49
-
76
+
77
+ # This module can be included by any class to enable logging to the
78
+ # <tt>Rubix.logger</tt>.
50
79
  module Logs
51
80
 
81
+ # Write a log message with severity +debug+.
82
+ #
83
+ # @param [Array<String>] args
52
84
  def debug *args
53
85
  return unless Rubix.logger
54
86
  Rubix.logger.log(Logger::DEBUG, args.join(' '))
55
87
  end
56
88
 
89
+ # Write a log message with severity +info+.
90
+ #
91
+ # @param [Array<String>] args
57
92
  def info *args
58
93
  return unless Rubix.logger
59
94
  Rubix.logger.log(Logger::INFO, args.join(' '))
60
95
  end
61
96
 
97
+ # Write a log message with severity +warn+.
98
+ #
99
+ # @param [Array<String>] args
62
100
  def warn *args
63
101
  return unless Rubix.logger
64
102
  Rubix.logger.log(Logger::WARN, args.join(' '))
65
103
  end
66
104
 
105
+ # Write a log message with severity +error+.
106
+ #
107
+ # @param [Array<String>] args
67
108
  def error *args
68
109
  return unless Rubix.logger
69
110
  Rubix.logger.log(Logger::ERROR, args.join(' '))
70
111
  end
71
112
 
113
+ # Write a log message with severity +fatal+.
114
+ #
115
+ # @param [Array<String>] args
72
116
  def fatal *args
73
117
  return unless Rubix.logger
74
118
  Rubix.logger.log(Logger::FATAL, args.join(' '))