rubix 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +10 -10
- data/VERSION +1 -1
- data/lib/rubix.rb +40 -1
- data/lib/rubix/associations/belongs_to_host.rb +4 -3
- data/lib/rubix/connection.rb +114 -34
- data/lib/rubix/log.rb +45 -1
- data/lib/rubix/models/model.rb +143 -9
- data/lib/rubix/response.rb +85 -13
- data/lib/rubix/sender.rb +122 -18
- data/spec/requests/application_request_spec.rb +36 -38
- data/spec/requests/host_group_request_spec.rb +40 -22
- data/spec/requests/host_request_spec.rb +55 -49
- data/spec/requests/item_request_spec.rb +49 -53
- data/spec/requests/template_request_spec.rb +34 -34
- data/spec/requests/user_macro_request_spec.rb +33 -27
- data/spec/spec_helper.rb +1 -13
- data/spec/support/integration_helper.rb +34 -1
- data/spec/test.yml +11 -3
- metadata +22 -8
data/lib/rubix/models/model.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
module Rubix
|
2
2
|
|
3
|
+
# A base class for all Zabbix models to subclass.
|
4
|
+
#
|
3
5
|
# It might be worth using ActiveModel -- but maybe not. The goal is
|
4
6
|
# to keep dependencies low while still retaining expressiveness.
|
5
7
|
class Model
|
6
8
|
|
7
|
-
|
9
|
+
# @return [Hash]] the properties this model was initialized with
|
10
|
+
attr_accessor :properties
|
11
|
+
|
12
|
+
# @return [Fixnum, nil] the ID of this model
|
13
|
+
attr_accessor :id
|
8
14
|
|
9
15
|
extend Logs
|
10
16
|
include Logs
|
@@ -15,28 +21,40 @@ module Rubix
|
|
15
21
|
|
16
22
|
# This is the name of the resource as used inside Rubix -- Host,
|
17
23
|
# HostGroup, UserMacro, &c.
|
24
|
+
#
|
25
|
+
# @return [String]
|
18
26
|
def self.resource_name
|
19
27
|
self.to_s.split('::').last
|
20
28
|
end
|
21
29
|
|
22
30
|
# This is the name of *this* resource instance, using this
|
23
31
|
# object's 'name' property if possible.
|
32
|
+
#
|
33
|
+
# @return [String]
|
24
34
|
def resource_name
|
25
35
|
"#{self.class.resource_name} #{respond_to?(:name) ? self.name : self.id}"
|
26
36
|
end
|
27
37
|
|
28
38
|
# This is the name of the resource as used by Zabbix -- host,
|
29
39
|
# hostgroup, usermacro, &c.
|
40
|
+
#
|
41
|
+
# @return [String]
|
30
42
|
def self.zabbix_name
|
31
43
|
resource_name.downcase
|
32
44
|
end
|
33
45
|
|
34
46
|
# This is the name of the id field returned in Zabbix responses --
|
35
|
-
# hostid
|
47
|
+
# +hostid+, +groupid+, +hostmacroid+, &c.
|
48
|
+
#
|
49
|
+
# @return [String]
|
36
50
|
def self.id_field
|
37
51
|
"#{zabbix_name}id"
|
38
52
|
end
|
39
53
|
|
54
|
+
# This is the name of the id field returned in Zabbix responses --
|
55
|
+
# +hostid+, +groupid+, +hostmacroid+, &c.
|
56
|
+
#
|
57
|
+
# @return [String]
|
40
58
|
def id_field
|
41
59
|
self.class.id_field
|
42
60
|
end
|
@@ -45,43 +63,83 @@ module Rubix
|
|
45
63
|
# == Initialization ==
|
46
64
|
#
|
47
65
|
|
66
|
+
# Create a new model instance. This may represent a new or
|
67
|
+
# existing Zabbix resource.
|
68
|
+
#
|
69
|
+
# @param [Hash] properties
|
70
|
+
# @option properties [Fixnum] id the ID of the resource in Zabbix (typically blank for a new resource)
|
48
71
|
def initialize properties={}
|
49
72
|
@properties = properties
|
50
73
|
@id = properties[:id]
|
51
74
|
end
|
52
75
|
|
76
|
+
# Send a request to the Zabbix API. This is just a convenience
|
77
|
+
# method for <tt>Rubix::Connection#request</tt>.
|
78
|
+
#
|
79
|
+
# @param [String] method
|
80
|
+
# @param [Hash,Array] params
|
81
|
+
# @return [Rubix::Response]
|
53
82
|
def request method, params
|
54
83
|
self.class.request(method, params)
|
55
84
|
end
|
56
85
|
|
86
|
+
# Send a request to the Zabbix API. This is just a convenience
|
87
|
+
# method for <tt>Rubix::Connection#request</tt>.
|
88
|
+
#
|
89
|
+
# @param [String] method
|
90
|
+
# @param [Hash,Array] params
|
91
|
+
# @return [Rubix::Response]
|
57
92
|
def self.request method, params
|
58
93
|
Rubix.connection && Rubix.connection.request(method, params)
|
59
94
|
end
|
60
95
|
|
96
|
+
# Is this a new record? We can tell because the ID must be blank.
|
61
97
|
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
|
98
|
+
# @return [true, false]
|
65
99
|
def new_record?
|
66
100
|
@id.nil?
|
67
101
|
end
|
68
102
|
|
103
|
+
# Save this record.
|
104
|
+
#
|
105
|
+
# Will create new records and update old ones.
|
106
|
+
#
|
107
|
+
# @return [true, false]
|
69
108
|
def save
|
70
109
|
new_record? ? create : update
|
71
110
|
end
|
72
|
-
|
111
|
+
|
112
|
+
# Validate this record.
|
113
|
+
#
|
114
|
+
# Override this method in a subclass and have it raise a
|
115
|
+
# <tt>Rubix::ValidationError</tt> if validation fails.
|
116
|
+
#
|
117
|
+
# @return [true, false]
|
73
118
|
def validate
|
74
119
|
true
|
75
120
|
end
|
76
121
|
|
122
|
+
#
|
123
|
+
# == Create ==
|
124
|
+
#
|
125
|
+
|
126
|
+
# Parameters for creating a new resource of this type.
|
127
|
+
#
|
128
|
+
# @return [Hash]
|
77
129
|
def create_params
|
78
130
|
{}
|
79
131
|
end
|
80
132
|
|
133
|
+
# Send a request to create this resource.
|
134
|
+
#
|
135
|
+
# @return [Rubix::Response]
|
81
136
|
def create_request
|
82
137
|
request("#{self.class.zabbix_name}.create", create_params)
|
83
138
|
end
|
84
139
|
|
140
|
+
# Create this resource.
|
141
|
+
#
|
142
|
+
# @return [true, false]
|
85
143
|
def create
|
86
144
|
return false unless validate
|
87
145
|
response = create_request
|
@@ -95,14 +153,27 @@ module Rubix
|
|
95
153
|
end
|
96
154
|
end
|
97
155
|
|
156
|
+
#
|
157
|
+
# == Update ==
|
158
|
+
#
|
159
|
+
|
160
|
+
# Parameters for updating a resource of this type.
|
161
|
+
#
|
162
|
+
# @return [Hash]
|
98
163
|
def update_params
|
99
164
|
create_params.merge({id_field => id})
|
100
165
|
end
|
101
166
|
|
167
|
+
# Send a request to update this resource.
|
168
|
+
#
|
169
|
+
# @return [Rubix::Response]
|
102
170
|
def update_request
|
103
171
|
request("#{self.class.zabbix_name}.update", update_params)
|
104
172
|
end
|
105
173
|
|
174
|
+
# Update this resource.
|
175
|
+
#
|
176
|
+
# @return [true, false]
|
106
177
|
def update
|
107
178
|
return false unless validate
|
108
179
|
return create if new_record?
|
@@ -121,18 +192,37 @@ module Rubix
|
|
121
192
|
end
|
122
193
|
end
|
123
194
|
|
195
|
+
# A hook that will be run before this resource is updated.
|
196
|
+
#
|
197
|
+
# Override this in a subclass to implement any desired
|
198
|
+
# before-update functionality. Must return +true+ or +false+.
|
199
|
+
#
|
200
|
+
# @return [true, false]
|
124
201
|
def before_update
|
125
202
|
true
|
126
203
|
end
|
127
204
|
|
205
|
+
#
|
206
|
+
# == Destroy ==
|
207
|
+
#
|
208
|
+
|
209
|
+
# Parameters for destroying this resource.
|
210
|
+
#
|
211
|
+
# @return [Array<Fixnum>]
|
128
212
|
def destroy_params
|
129
213
|
[id]
|
130
214
|
end
|
131
215
|
|
216
|
+
# Send a request to destroy this resource.
|
217
|
+
#
|
218
|
+
# @return [Rubix::Response]
|
132
219
|
def destroy_request
|
133
220
|
request("#{self.class.zabbix_name}.delete", destroy_params)
|
134
221
|
end
|
135
|
-
|
222
|
+
|
223
|
+
# Destroy this resource.
|
224
|
+
#
|
225
|
+
# @return [true, false]
|
136
226
|
def destroy
|
137
227
|
return true if new_record?
|
138
228
|
return false unless before_destroy
|
@@ -150,6 +240,12 @@ module Rubix
|
|
150
240
|
end
|
151
241
|
end
|
152
242
|
|
243
|
+
# A hook that will be run before this resource is destroyed.
|
244
|
+
#
|
245
|
+
# Override this in a subclass to implement any desired
|
246
|
+
# before-destroy functionality. Must return +true+ or +false+.
|
247
|
+
#
|
248
|
+
# @return [true, false]
|
153
249
|
def before_destroy
|
154
250
|
true
|
155
251
|
end
|
@@ -158,18 +254,33 @@ module Rubix
|
|
158
254
|
# == Index ==
|
159
255
|
#
|
160
256
|
|
257
|
+
# Parameters for 'get'-type requests for this resource's type.
|
258
|
+
#
|
259
|
+
# @return [Hash]
|
161
260
|
def self.get_params
|
162
261
|
{ :output => :extend }
|
163
262
|
end
|
164
263
|
|
264
|
+
# Parameters to list all the objects of this resource's type.
|
265
|
+
#
|
266
|
+
# @param [Hash] options options for filtering the list of all resources.
|
267
|
+
# @return [Hash]
|
165
268
|
def self.all_params options={}
|
166
269
|
get_params.merge(options)
|
167
270
|
end
|
168
271
|
|
272
|
+
# Send a request to list all objects of this resource's type.
|
273
|
+
#
|
274
|
+
# @param [Hash] options options for filtering the list of all resources.
|
275
|
+
# @return [Rubix::Response]
|
169
276
|
def self.all_request options={}
|
170
277
|
request("#{zabbix_name}.get", all_params(options))
|
171
278
|
end
|
172
279
|
|
280
|
+
# List all objects of this resource's type.
|
281
|
+
#
|
282
|
+
# @param [Hash] options options for filtering the list of all resources.
|
283
|
+
# @return [Array<Rubix::Model>]
|
173
284
|
def self.all options={}
|
174
285
|
response = all_request(options)
|
175
286
|
if response.has_data?
|
@@ -180,22 +291,39 @@ module Rubix
|
|
180
291
|
end
|
181
292
|
end
|
182
293
|
|
183
|
-
|
184
|
-
|
294
|
+
# Execute block once for each element of the result set.
|
295
|
+
#
|
296
|
+
# @param [Hash] options options for filtering the list of all resources.
|
297
|
+
# @return [Array<Rubix::Model>]
|
298
|
+
def self.each options={}, &block
|
299
|
+
all(options).each(&block)
|
185
300
|
end
|
186
301
|
|
187
302
|
#
|
188
303
|
# == Show ==
|
189
304
|
#
|
190
305
|
|
306
|
+
# Parameters for finding a specific resource.
|
307
|
+
#
|
308
|
+
# @param [Hash] options specify properties about the object to find
|
309
|
+
# @return [Hash]
|
191
310
|
def self.find_params options={}
|
192
311
|
get_params.merge(options)
|
193
312
|
end
|
194
313
|
|
314
|
+
# Send a find request for a specific resource.
|
315
|
+
#
|
316
|
+
# @param [Hash] options specify properties about the object to find
|
317
|
+
# @return [Rubix::Response]
|
195
318
|
def self.find_request options={}
|
196
319
|
request("#{zabbix_name}.get", find_params(options))
|
197
320
|
end
|
198
321
|
|
322
|
+
# Find a resource using the given +options+ or return +nil+ if
|
323
|
+
# none is found.
|
324
|
+
#
|
325
|
+
# @param [Hash] options specify properties about the object to find
|
326
|
+
# @return [Rubix::Model, nil]
|
199
327
|
def self.find options={}
|
200
328
|
response = find_request(options)
|
201
329
|
case
|
@@ -209,6 +337,12 @@ module Rubix
|
|
209
337
|
end
|
210
338
|
end
|
211
339
|
|
340
|
+
# Find a resource using the given +options+ or create one if none
|
341
|
+
# can be found. Will return +false+ if the object cannot be found
|
342
|
+
# and cannot be created.
|
343
|
+
#
|
344
|
+
# @param [Hash] options specify properties about the object to find
|
345
|
+
# @return [Rubix::Model, false]
|
212
346
|
def self.find_or_create options={}
|
213
347
|
response = find_request(options)
|
214
348
|
case
|
data/lib/rubix/response.rb
CHANGED
@@ -2,10 +2,22 @@ require 'json'
|
|
2
2
|
|
3
3
|
module Rubix
|
4
4
|
|
5
|
+
# A class used to wrap Net::HTTP::Response objects to make it easier
|
6
|
+
# to inspect them for various cases.
|
5
7
|
class Response
|
6
8
|
|
7
|
-
|
9
|
+
# @return [Net::HTTP::Response] the raw HTTP response from the Zabbix API
|
10
|
+
attr_reader :http_response
|
8
11
|
|
12
|
+
# @return [Fixnum] the raw HTTP response code
|
13
|
+
attr_reader :code
|
14
|
+
|
15
|
+
# @return [String] the raw HTTP response body
|
16
|
+
attr_reader :body
|
17
|
+
|
18
|
+
# Wrap a <tt>Net::HTTP::Response</tt>.
|
19
|
+
#
|
20
|
+
# @param [Net::HTTP::Response] http_response
|
9
21
|
def initialize(http_response)
|
10
22
|
@http_response = http_response
|
11
23
|
@body = http_response.body
|
@@ -13,9 +25,12 @@ module Rubix
|
|
13
25
|
end
|
14
26
|
|
15
27
|
#
|
16
|
-
# Parsing
|
28
|
+
# == Parsing ==
|
17
29
|
#
|
18
|
-
|
30
|
+
|
31
|
+
# The parsed JSON body.
|
32
|
+
#
|
33
|
+
# @return [Hash]
|
19
34
|
def parsed
|
20
35
|
return @parsed if @parsed
|
21
36
|
if non_200?
|
@@ -30,31 +45,64 @@ module Rubix
|
|
30
45
|
end
|
31
46
|
|
32
47
|
#
|
33
|
-
# Error Handling
|
48
|
+
# == Error Handling ==
|
34
49
|
#
|
35
50
|
|
51
|
+
# Was the response *not* a 200?
|
52
|
+
#
|
53
|
+
# @return [true,false]
|
36
54
|
def non_200?
|
37
55
|
code != 200
|
38
56
|
end
|
39
|
-
|
57
|
+
|
58
|
+
# Was the response an error? This will return +true+ if
|
59
|
+
#
|
60
|
+
# - the response was not a 200
|
61
|
+
# - the response was a 200 and contains an +error+ key
|
62
|
+
#
|
63
|
+
# @return [true, false]
|
40
64
|
def error?
|
41
65
|
non_200? || (parsed.is_a?(Hash) && parsed['error'])
|
42
66
|
end
|
43
67
|
|
68
|
+
# Was this response successful? Successful responses must
|
69
|
+
#
|
70
|
+
# - have a 200 response code
|
71
|
+
# - *not* have an +error+ key in the response
|
72
|
+
#
|
73
|
+
# @return [true, false]
|
74
|
+
def success?
|
75
|
+
!error?
|
76
|
+
end
|
77
|
+
|
78
|
+
# Was the response a *Zabbix* error, implying a 200 with an
|
79
|
+
# +error+ key.
|
80
|
+
#
|
81
|
+
# @return [true, false]
|
44
82
|
def zabbix_error?
|
45
83
|
code == 200 && error?
|
46
84
|
end
|
47
85
|
|
86
|
+
# Returns the error code of a Zabbix error or +nil+ if this wasn't
|
87
|
+
# an error.
|
88
|
+
#
|
89
|
+
# @return [nil, Fixnum]
|
48
90
|
def error_code
|
49
91
|
return unless error?
|
50
92
|
(non_200? ? code : parsed['error']['code'].to_i) rescue 0
|
51
93
|
end
|
52
|
-
|
94
|
+
|
95
|
+
# Returns the Zabbix type of the error or +nil+ if this wasn't an error.
|
96
|
+
#
|
97
|
+
# @return [nil, String]
|
53
98
|
def error_type
|
54
99
|
return unless error?
|
55
100
|
(non_200? ? "Non-200 Error" : parsed['error']['message']) rescue 'Unknown Error'
|
56
101
|
end
|
57
102
|
|
103
|
+
# Return an error message or +nil+ if this wasn't an error.
|
104
|
+
#
|
105
|
+
# @return [String, nil]
|
58
106
|
def error_message
|
59
107
|
return unless error?
|
60
108
|
begin
|
@@ -70,51 +118,75 @@ module Rubix
|
|
70
118
|
end
|
71
119
|
end
|
72
120
|
|
73
|
-
def success?
|
74
|
-
!error?
|
75
|
-
end
|
76
|
-
|
77
121
|
#
|
78
|
-
# Inspecting contents
|
122
|
+
# == Inspecting contents ==
|
79
123
|
#
|
80
124
|
|
125
|
+
# The contents of the +result+ key. Returns +nil+ if an error.
|
81
126
|
def result
|
127
|
+
return if error?
|
82
128
|
parsed['result']
|
83
129
|
end
|
84
|
-
|
130
|
+
|
131
|
+
# Return the contents of +key+ *within* the +result+ key or +nil+
|
132
|
+
# if an error.
|
85
133
|
def [] key
|
86
134
|
return if error?
|
87
135
|
result[key]
|
88
136
|
end
|
89
137
|
|
138
|
+
# Return the +first+ element of the +result+ key or +nil+ if an
|
139
|
+
# error.
|
90
140
|
def first
|
91
141
|
return if error?
|
92
142
|
result.first
|
93
143
|
end
|
94
144
|
|
145
|
+
# Is the +result+ key empty?
|
146
|
+
#
|
147
|
+
# @return [true, false]
|
95
148
|
def empty?
|
149
|
+
return true unless result
|
96
150
|
result.empty?
|
97
151
|
end
|
98
152
|
|
153
|
+
# Does this response "have data" in the sense that
|
154
|
+
#
|
155
|
+
# - it is a successful response (see <tt>Rubix::Response#success?</tt>)
|
156
|
+
# - it has a +result+ key which is not empty
|
99
157
|
def has_data?
|
100
158
|
success? && (!empty?)
|
101
159
|
end
|
102
|
-
|
160
|
+
|
161
|
+
# Is the contents of the *first* element of the +result+ key a
|
162
|
+
# Hash?
|
163
|
+
#
|
164
|
+
# @return [true, false]
|
103
165
|
def hash?
|
104
166
|
return false if error?
|
105
167
|
result.is_a?(Hash) && result.size > 0 && result.first.last
|
106
168
|
end
|
107
169
|
|
170
|
+
# Is the contents of the *first* element of the +result+ key an
|
171
|
+
# Array?
|
172
|
+
#
|
173
|
+
# @return [true, false]
|
108
174
|
def array?
|
109
175
|
return false if error?
|
110
176
|
result.is_a?(Array) && result.size > 0 && result.first
|
111
177
|
end
|
112
178
|
|
179
|
+
# Is the contents of the +result+ key a String?
|
180
|
+
#
|
181
|
+
# @return [true, false]
|
113
182
|
def string?
|
114
183
|
return false if error?
|
115
184
|
result.is_a?(String) && result.size > 0
|
116
185
|
end
|
117
186
|
|
187
|
+
# Is the contents of the +result+ key either +true+ or +false+?
|
188
|
+
#
|
189
|
+
# @return [true, false]
|
118
190
|
def boolean?
|
119
191
|
return false if error?
|
120
192
|
result == true || result == false
|