Power IQ Client

Power IQ Rest API client for Power IQ 3.1. For a complete list of resources, routes, and methods available see the online Power IQ documentation (www.raritan.com/support/power-iq).

Installation

% gem install poweriq_client

Console

The Power IQ client comes with a interactive console. From the console you can make REST API calls to Power IQ. To run the console:

% poweriq_client

Options

Usage: poweriq_client [options]
  -l, --less-typing                Put resource objects in global namespace
                                   (ie PowerIQ::Resource::Outlet becomes Outlet)
  -c, --check-compatibility        Check client compatibility with server
  -u, --user [USER]                User name for authentication
  -p, --password [PASSWORD]        Password for authentication
  -s, --server [HOST]              Host name or IP of Power IQ

Configuration

Create the file $HOME/.poweriq_client. The contents of the file should look similiar to below, adjusted to your Power IQ server:

default:
  host: vm163
  user: admin
  password: raritan

If you do not use a configuration file, or the command line options above, you’ll need to provide the configuration manually:

% poweriq_client
>> PowerIQ::Configuration.configure("user"=>"foo","password"=>"bar","host"=>"vm150")

Examples

Start the client console:

% poweriq_client -u admin -p raritan -s vm163

Retrieve all outlets:

>> outlets_resource = PowerIQ::Resource::Outlet.new
https://vm163/api/v2/outlets
>> outlets_json = outlets_resource.get

Retrieve one outlet:

>> outlet_resource = PowerIQ::Resource::Outlet.new('/381')
https://vm163/api/v2/outlets/381
>> outlet_json = outlet_resource.get

Update an outlet:

>> outlet_resource = PowerIQ::Resource::Outlet.new('/381')
https://vm163/api/v2/outlets/381
>> outlet_json = outlet_resource.get
>> outlet_json['outlet']['outlet_name'] = "New Name"
>> outlet_resource.put outlet_json.to_json

Error Handling

When an error occurs during an API call, the Power IQ server will return an appropriate HTTP response code, and include a json response with error details. On the client side, an exception is thrown. Either the exception or the resource object can be used to reveal details about what went wrong:

>> outlet_resource = PowerIQ::Resource::Outlet.new('/381')
https://vm163/api/v2/outlets/381
>> outlet_json = outlet_resource.get
{
  "outlet" => {
               "id" => 381,
        "outlet_id" => 11,
      "outlet_name" => "Outlet 11",
        "device_id" => nil,
            "state" => "ON",
           "pdu_id" => 40,
          "reading" => {}
  }
}
>> outlet_json['outlet']['outlet_name']="foo"
"foo"
>> outlet_resource.put outlet_json.to_json
RestClient::UnprocessableEntity: 422 Unprocessable Entity
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/abstract_response.rb:48:in `return!'
      from /Users/tba/Workspaces/local/poweriq_client/lib/poweriq_client/resource/base.rb:11:in `block in create'
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/request.rb:228:in `call'
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/request.rb:228:in `process_result'
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/request.rb:178:in `block in transmit'
      from /Users/tba/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/http.rb:627:in `start'
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/request.rb:172:in `transmit'
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/request.rb:64:in `execute'
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/request.rb:33:in `execute'
      from /Users/tba/.rvm/gems/ruby-1.9.2-p180@poweriq_client/gems/rest-client-1.6.7/lib/restclient/resource.rb:76:in `put'
      from (irb):4
      from bin/poweriq_client:66:in `<main>'

The resource will always hold the last response from the latest rest invocation:

>> outlet_resource.response.json
{
     "error" => "Job::JobError",
  "messages" => [
      [0] "Job(ID:5) with 1 error(s) and status COMPLETED completed",
      [1] "Confirmed existence of foo",
      [2] "Confirmed existence of 192.168.45.234 for outlet  foo.",
      [3] "Retrieved plugin for 192.168.45.234.",
      [4] "Failed to set outlet id: 381 label on PDU 192.168.45.234.  PowerIQ was unable to reach 192.168.45.234."
  ],
       "job" => {
      "description" => nil,
         "end_time" => "2011/11/06 00:56:47 +0000",
       "has_errors" => true,
               "id" => 5,
       "start_time" => "2011/11/06 00:56:28 +0000",
           "status" => "COMPLETED",
          "user_id" => 1
  },
     "trace" => "/var/oculan/home/tba/rails/src/lib/messaging/job_polling.rb:31:...."
 }

You can also catch the exception, and the exception will have the response object in it:

>> exc = nil
>> begin outlet_resource.put outlet_json.to_json; rescue => exc; end
>> exc.response.json
{
     "error" => "Job::JobError",
  "messages" => [
      [0] "Job(ID:5) with 1 error(s) and status COMPLETED completed",
      [1] "Confirmed existence of foo",
      [2] "Confirmed existence of 192.168.45.234 for outlet  foo.",
      [3] "Retrieved plugin for 192.168.45.234.",
      [4] "Failed to set outlet id: 381 label on PDU 192.168.45.234.  PowerIQ was unable to reach 192.168.45.234."
  ],
       "job" => {
      "description" => nil,
         "end_time" => "2011/11/06 00:56:47 +0000",
       "has_errors" => true,
               "id" => 5,
       "start_time" => "2011/11/06 00:56:28 +0000",
           "status" => "COMPLETED",
          "user_id" => 1
  },
     "trace" => "/var/oculan/home/tba/rails/src/lib/messaging/job_polling.rb:31:...."
 }

Jobs

Some resource actions will return a Job JSON structure. These actions either will always, or optionally execute asynchronously. In order to determine when a job has been completed, the server must be polled for job completeness. Methods on the job resource simplify this for you:

>> job = Job.new('/5')
https://vm163/api/v2/jobs/5
>> job.poll(:max=>12,:delay=>5)
true
>> job.response.json
{
           "job" => {
                    "id" => 5,
               "user_id" => 1,
                "status" => "COMPLETED",
           "description" => nil,
            "start_time" => "2011/11/06 00:56:28 +0000",
              "end_time" => "2011/11/06 00:56:47 +0000",
            "has_errors" => true,
      "percent_complete" => 1.0,
             "completed" => true,
          "last_message" => "Failed to set outlet id: 381 label on PDU 192.168.45.234.  PowerIQ was unable to reach 192.168.45.234.",
           "error_count" => 1
  },
  "job_messages" => [
      [0] {
                    "id" => 15,
          "unit_of_work" => 0.25,
                "job_id" => 5,
                 "level" => "INFO",
                 "trace" => nil,
            "start_time" => "2011/11/06 00:56:30 +0000",
              "end_time" => nil,
           "message_key" => ":magic.outlet_get_outlet_success",
          "message_vars" => "{\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
               "aborted" => false,
               "message" => "Confirmed existence of Outlet 11"
      },
      [1] {
                    "id" => 16,
          "unit_of_work" => 0.25,
                "job_id" => 5,
                 "level" => "INFO",
                 "trace" => nil,
            "start_time" => "2011/11/06 00:56:32 +0000",
              "end_time" => nil,
           "message_key" => ":magic.outlet_get_pdu_success",
          "message_vars" => "{\"_pdu_id\":\"40\",\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
               "aborted" => false,
               "message" => "Confirmed existence of 192.168.45.234 for outlet  Outlet 11."
      },
      [2] {
                    "id" => 17,
          "unit_of_work" => 0.25,
                "job_id" => 5,
                 "level" => "INFO",
                 "trace" => nil,
            "start_time" => "2011/11/06 00:56:34 +0000",
              "end_time" => nil,
           "message_key" => ":magic.outlet_get_pdu_metadata_success",
          "message_vars" => "{\"_pdu_id\":\"40\",\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
               "aborted" => false,
               "message" => "Retrieved plugin for 192.168.45.234."
      },
      [3] {
                    "id" => 18,
          "unit_of_work" => 0.25,
                "job_id" => 5,
                 "level" => "ERROR",
                 "trace" => "SNMP_ERROR_TIMEOUT",
            "start_time" => "2011/11/06 00:56:47 +0000",
              "end_time" => nil,
           "message_key" => ":magic.outlet_rename_snmp_timeout",
          "message_vars" => "{\"_pdu_id\":\"40\",\"new_outlet_name\":\"foo\",\"_pdu_outlet_id\":\"381\"}",
               "aborted" => false,
               "message" => "Failed to set outlet id: 381 label on PDU 192.168.45.234.  PowerIQ was unable to reach 192.168.45.234."
      }
  ]
}
  • job.poll(:max=>5,:delay=>10) where :max is the maximum number of times to poll for job completeness, and :delay is the

amount of seconds to pause between each poll

  • job.poll returns true if the job completed, false otherwise

  • job.poll will also automatically retrieve all job_messages after completion

Please refer to the online Power IQ documentation (www.raritan.com/support/power-iq) for a list of resources that optionally or require asynchrounous execution.

Development

The Power IQ rest client uses the rest-client gem, with some modifications to make it easier to query Power IQ resources. For now you’ll need to view the source code for more details, however the usage is essentially the same as you see in the interactive console examples above.

Contributing to Power IQ Client

  • Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet

  • Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it

  • Fork the project

  • Start a feature/bugfix branch

  • Commit and push until you are happy with your contribution

  • Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Copyright © 2011 Raritan, INC. See LICENSE.txt for further details.