poweriq_client 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +120 -11
- data/lib/poweriq_client/resource/base.rb +39 -0
- data/lib/poweriq_client/resource/job.rb +32 -1
- data/lib/poweriq_client/version.rb +1 -1
- data/poweriq_client.gemspec +2 -2
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -9,11 +9,12 @@ see the online Power IQ documentation (http://www.raritan.com/support/power-iq).
|
|
9
9
|
|
10
10
|
== Console
|
11
11
|
|
12
|
-
The Power IQ client comes with a interactive console.
|
12
|
+
The Power IQ client comes with a interactive console. From the console you can make REST API calls to Power IQ.
|
13
|
+
To run the console:
|
13
14
|
|
14
15
|
% poweriq_client
|
15
16
|
|
16
|
-
====
|
17
|
+
==== Options
|
17
18
|
|
18
19
|
Usage: poweriq_client [options]
|
19
20
|
-l, --less-typing Put resource objects in global namespace
|
@@ -25,7 +26,7 @@ The Power IQ client comes with a interactive console. To run the console:
|
|
25
26
|
|
26
27
|
==== Configuration
|
27
28
|
|
28
|
-
Create
|
29
|
+
Create the file $HOME/.poweriq_client. The contents of the file
|
29
30
|
should look similiar to below, adjusted to your Power IQ server:
|
30
31
|
|
31
32
|
default:
|
@@ -39,28 +40,31 @@ need to provide the configuration manually:
|
|
39
40
|
% poweriq_client
|
40
41
|
>> PowerIQ::Configuration.configure("user"=>"foo","password"=>"bar","host"=>"vm150")
|
41
42
|
|
42
|
-
|
43
|
+
== Examples
|
44
|
+
|
45
|
+
Start the client console:
|
46
|
+
% poweriq_client -u admin -p raritan -s vm163
|
43
47
|
|
44
48
|
Retrieve all outlets:
|
45
49
|
>> outlets_resource = PowerIQ::Resource::Outlet.new
|
46
50
|
https://vm163/api/v2/outlets
|
47
|
-
>> outlets_resource.get
|
51
|
+
>> outlets_json = outlets_resource.get
|
48
52
|
|
49
53
|
Retrieve one outlet:
|
50
54
|
>> outlet_resource = PowerIQ::Resource::Outlet.new('/381')
|
51
55
|
https://vm163/api/v2/outlets/381
|
52
|
-
>>
|
56
|
+
>> outlet_json = outlet_resource.get
|
53
57
|
|
54
58
|
Update an outlet:
|
55
59
|
>> outlet_resource = PowerIQ::Resource::Outlet.new('/381')
|
56
60
|
https://vm163/api/v2/outlets/381
|
57
|
-
>>
|
58
|
-
>>
|
59
|
-
>> outlet_resource.put
|
61
|
+
>> outlet_json = outlet_resource.get
|
62
|
+
>> outlet_json['outlet']['outlet_name'] = "New Name"
|
63
|
+
>> outlet_resource.put outlet_json.to_json
|
60
64
|
|
61
|
-
|
65
|
+
== Error Handling
|
62
66
|
|
63
|
-
When an error occurs
|
67
|
+
When an error occurs during an API call, the Power IQ server will return an appropriate HTTP response code, and include
|
64
68
|
a json response with error details. On the client side, an exception is thrown. Either the exception or the
|
65
69
|
resource object can be used to reveal details about what went wrong:
|
66
70
|
|
@@ -145,6 +149,111 @@ You can also catch the exception, and the exception will have the response objec
|
|
145
149
|
"trace" => "/var/oculan/home/tba/rails/src/lib/messaging/job_polling.rb:31:...."
|
146
150
|
}
|
147
151
|
|
152
|
+
== Jobs
|
153
|
+
|
154
|
+
Some resource actions will return a Job JSON structure. These actions either will always, or optionally execute
|
155
|
+
asynchronously. In order to determine when a job has been completed, the server must be polled for job
|
156
|
+
completeness. Methods on the job resource simplify this for you:
|
157
|
+
|
158
|
+
>> job = Job.new('/5')
|
159
|
+
https://vm163/api/v2/jobs/5
|
160
|
+
>> job.get
|
161
|
+
{
|
162
|
+
"job" => {
|
163
|
+
"id" => 5,
|
164
|
+
"user_id" => 1,
|
165
|
+
"status" => "ACTIVE",
|
166
|
+
"description" => nil,
|
167
|
+
"start_time" => "2011/10/07 14:54:32 +0000",
|
168
|
+
"end_time" => "2011/10/07 14:54:33 +0000",
|
169
|
+
"has_errors" => false,
|
170
|
+
"percent_complete" => .5,
|
171
|
+
"completed" => false,
|
172
|
+
"last_message" => "Job started",
|
173
|
+
"error_count" => 0
|
174
|
+
}
|
175
|
+
}
|
176
|
+
>> job.poll(:max=>12,:delay=>5)
|
177
|
+
true
|
178
|
+
>> job.response.json
|
179
|
+
{
|
180
|
+
"job" => {
|
181
|
+
"id" => 5,
|
182
|
+
"user_id" => 1,
|
183
|
+
"status" => "COMPLETED",
|
184
|
+
"description" => nil,
|
185
|
+
"start_time" => "2011/11/06 00:56:28 +0000",
|
186
|
+
"end_time" => "2011/11/06 00:56:47 +0000",
|
187
|
+
"has_errors" => true,
|
188
|
+
"percent_complete" => 1.0,
|
189
|
+
"completed" => true,
|
190
|
+
"last_message" => "Failed to set outlet id: 381 label on PDU 192.168.45.234. PowerIQ was unable to reach 192.168.45.234.",
|
191
|
+
"error_count" => 1
|
192
|
+
},
|
193
|
+
"job_messages" => [
|
194
|
+
[0] {
|
195
|
+
"id" => 15,
|
196
|
+
"unit_of_work" => 0.25,
|
197
|
+
"job_id" => 5,
|
198
|
+
"level" => "INFO",
|
199
|
+
"trace" => nil,
|
200
|
+
"start_time" => "2011/11/06 00:56:30 +0000",
|
201
|
+
"end_time" => nil,
|
202
|
+
"message_key" => ":magic.outlet_get_outlet_success",
|
203
|
+
"message_vars" => "{\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
|
204
|
+
"aborted" => false,
|
205
|
+
"message" => "Confirmed existence of Outlet 11"
|
206
|
+
},
|
207
|
+
[1] {
|
208
|
+
"id" => 16,
|
209
|
+
"unit_of_work" => 0.25,
|
210
|
+
"job_id" => 5,
|
211
|
+
"level" => "INFO",
|
212
|
+
"trace" => nil,
|
213
|
+
"start_time" => "2011/11/06 00:56:32 +0000",
|
214
|
+
"end_time" => nil,
|
215
|
+
"message_key" => ":magic.outlet_get_pdu_success",
|
216
|
+
"message_vars" => "{\"_pdu_id\":\"40\",\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
|
217
|
+
"aborted" => false,
|
218
|
+
"message" => "Confirmed existence of 192.168.45.234 for outlet Outlet 11."
|
219
|
+
},
|
220
|
+
[2] {
|
221
|
+
"id" => 17,
|
222
|
+
"unit_of_work" => 0.25,
|
223
|
+
"job_id" => 5,
|
224
|
+
"level" => "INFO",
|
225
|
+
"trace" => nil,
|
226
|
+
"start_time" => "2011/11/06 00:56:34 +0000",
|
227
|
+
"end_time" => nil,
|
228
|
+
"message_key" => ":magic.outlet_get_pdu_metadata_success",
|
229
|
+
"message_vars" => "{\"_pdu_id\":\"40\",\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
|
230
|
+
"aborted" => false,
|
231
|
+
"message" => "Retrieved plugin for 192.168.45.234."
|
232
|
+
},
|
233
|
+
[3] {
|
234
|
+
"id" => 18,
|
235
|
+
"unit_of_work" => 0.25,
|
236
|
+
"job_id" => 5,
|
237
|
+
"level" => "ERROR",
|
238
|
+
"trace" => "SNMP_ERROR_TIMEOUT",
|
239
|
+
"start_time" => "2011/11/06 00:56:47 +0000",
|
240
|
+
"end_time" => nil,
|
241
|
+
"message_key" => ":magic.outlet_rename_snmp_timeout",
|
242
|
+
"message_vars" => "{\"_pdu_id\":\"40\",\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
|
243
|
+
"aborted" => false,
|
244
|
+
"message" => "Failed to set outlet id: 381 label on PDU 192.168.45.234. PowerIQ was unable to reach 192.168.45.234."
|
245
|
+
}
|
246
|
+
]
|
247
|
+
}
|
248
|
+
|
249
|
+
* job.poll(:max=>5,:delay=>10) where :max is the maximum number of times to poll for job completeness, and :delay is the
|
250
|
+
amount of seconds to pause between each poll
|
251
|
+
* job.poll returns true if the job completed, false otherwise
|
252
|
+
* job.poll will also automatically retrieve all job_messages after completion
|
253
|
+
|
254
|
+
Please refer to the online Power IQ documentation (http://www.raritan.com/support/power-iq) for a list of resources
|
255
|
+
that optionally or require asynchrounous execution.
|
256
|
+
|
148
257
|
== Development
|
149
258
|
|
150
259
|
The Power IQ rest client uses the rest-client gem, with some
|
@@ -3,6 +3,14 @@ require 'rest_client'
|
|
3
3
|
module PowerIQ
|
4
4
|
module Resource
|
5
5
|
|
6
|
+
class ResourceError < StandardError
|
7
|
+
attr_accessor :resource
|
8
|
+
def initialize(msg=nil,resource=nil)
|
9
|
+
super(msg)
|
10
|
+
self.resource = resource
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
6
14
|
module ResponseHandler
|
7
15
|
def self.create(resource)
|
8
16
|
Proc.new { |response,request,result,&block|
|
@@ -42,6 +50,7 @@ module PowerIQ
|
|
42
50
|
|
43
51
|
class << self
|
44
52
|
attr_writer :host,:singular,:user,:password
|
53
|
+
|
45
54
|
def host
|
46
55
|
if(self == Base)
|
47
56
|
@host
|
@@ -49,6 +58,7 @@ module PowerIQ
|
|
49
58
|
@host || Base.host
|
50
59
|
end
|
51
60
|
end
|
61
|
+
|
52
62
|
def user
|
53
63
|
if(self == Base)
|
54
64
|
@user
|
@@ -56,6 +66,7 @@ module PowerIQ
|
|
56
66
|
@user || Base.user
|
57
67
|
end
|
58
68
|
end
|
69
|
+
|
59
70
|
def password
|
60
71
|
if(self == Base)
|
61
72
|
@password
|
@@ -63,6 +74,7 @@ module PowerIQ
|
|
63
74
|
@password || Base.password
|
64
75
|
end
|
65
76
|
end
|
77
|
+
|
66
78
|
def resource_name(pluralize=false)
|
67
79
|
base = self.name.demodulize
|
68
80
|
if(pluralize)
|
@@ -70,15 +82,42 @@ module PowerIQ
|
|
70
82
|
end
|
71
83
|
base.underscore
|
72
84
|
end
|
85
|
+
|
73
86
|
def resource_url
|
74
87
|
"https://#{self.host}/api/v2/#{self.resource_name(!self.singular?)}"
|
75
88
|
end
|
89
|
+
|
76
90
|
def singular?
|
77
91
|
@singular
|
78
92
|
end
|
93
|
+
end
|
79
94
|
|
95
|
+
def root_key(collection=false)
|
96
|
+
self.class.resource_name(collection)
|
80
97
|
end
|
81
98
|
|
99
|
+
def member?
|
100
|
+
!!url.match(%r{#{self.class.resource_url}/\d+$})
|
101
|
+
end
|
102
|
+
|
103
|
+
def json_available?
|
104
|
+
self.response && self.response.json && !self.response.json.empty? && self.response.json.has_key?(self.root_key)
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
|
109
|
+
def require_json!
|
110
|
+
unless(json_available?)
|
111
|
+
raise ResourceError.new("JSON response required. Did you GET the resource first?",self)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def require_member!
|
116
|
+
unless(member?)
|
117
|
+
raise ResourceError.new("Member resource required. Not a valid member resource specifier: #{url}",self)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
82
121
|
end
|
83
122
|
end
|
84
123
|
end
|
@@ -1,6 +1,37 @@
|
|
1
1
|
module PowerIQ
|
2
2
|
module Resource
|
3
|
-
class Job < PowerIQ::Resource::Base
|
3
|
+
class Job < PowerIQ::Resource::Base
|
4
|
+
|
5
|
+
def poll(options={:delay=>5,:max=>12})
|
6
|
+
require_member!
|
7
|
+
options.symbolize_keys!
|
8
|
+
poll_count = 0
|
9
|
+
unless(completed? || poll_count < options[:max])
|
10
|
+
poll_count += 1
|
11
|
+
get
|
12
|
+
Kernel.sleep(options[:delay])
|
13
|
+
end
|
14
|
+
begin
|
15
|
+
messages_json = Job.new(url+"/messages").get
|
16
|
+
self.response.json.merge!(messages_json)
|
17
|
+
rescue
|
18
|
+
end
|
19
|
+
completed? == true
|
20
|
+
end
|
21
|
+
|
22
|
+
def completed?
|
23
|
+
require_member!
|
24
|
+
require_json!
|
25
|
+
self.response.json[root_key]["completed"] == true
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_errors?
|
29
|
+
require_member!
|
30
|
+
require_json!
|
31
|
+
self.response.json[root_key]["has_errors"] == true
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
4
35
|
end
|
5
36
|
end
|
6
37
|
|
data/poweriq_client.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{poweriq_client}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Trent Albright}]
|
12
|
-
s.date = %q{2011-11-
|
12
|
+
s.date = %q{2011-11-07}
|
13
13
|
s.description = %q{Power IQ Rest API client for Power IQ 3.1}
|
14
14
|
s.email = %q{trent.albright@raritan.com}
|
15
15
|
s.executables = [%q{poweriq_client}]
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: poweriq_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.4.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Trent Albright
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-11-
|
13
|
+
date: 2011-11-07 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rest-client
|
@@ -166,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
166
166
|
requirements:
|
167
167
|
- - ">="
|
168
168
|
- !ruby/object:Gem::Version
|
169
|
-
hash: -
|
169
|
+
hash: -3128499524696260054
|
170
170
|
segments:
|
171
171
|
- 0
|
172
172
|
version: "0"
|