ibm_power_hmc 0.1.2 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -0
- data/.rubocop.yml +0 -0
- data/.rubocop_local.yml +2 -2
- data/CHANGELOG.md +0 -0
- data/Gemfile +0 -0
- data/Gemfile.lock +0 -0
- data/LICENSE +0 -0
- data/README.md +6 -0
- data/Rakefile +0 -0
- data/ibm_power_hmc.gemspec +0 -0
- data/lib/ibm_power_hmc/connection.rb +80 -48
- data/lib/ibm_power_hmc/job.rb +14 -29
- data/lib/ibm_power_hmc/parser.rb +202 -0
- data/lib/ibm_power_hmc/pcm.rb +94 -18
- data/lib/ibm_power_hmc/version.rb +1 -1
- data/lib/ibm_power_hmc.rb +2 -1
- metadata +8 -8
- data/lib/ibm_power_hmc/objects.rb +0 -150
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c95e9629a205e4276acce5737764da0da1cda5f5eb31dc7eef6adb72c12b3f4
|
4
|
+
data.tar.gz: 8b6c5e4f244cdfe42a317eaa95c992913aab9c387b90de04829fcfa9a6446775
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be586460348393017cc19cf04ddca66d4c5b2c11685242d0996a9e1536fcc7b36317d8498edc69cb98c9ebb0eccd182093f90063af9742b140506f9f75d7c8cc
|
7
|
+
data.tar.gz: 13504ec3baa2d6ac8712a1c3bd1b313876516ea0aa162338868a671b2cafd0ba57ee3b81689f95b0c2e89820c7a7a733295348a73e6b6cb3e1ffec79fa3dd487
|
data/.gitignore
CHANGED
File without changes
|
data/.rubocop.yml
CHANGED
File without changes
|
data/.rubocop_local.yml
CHANGED
data/CHANGELOG.md
CHANGED
File without changes
|
data/Gemfile
CHANGED
File without changes
|
data/Gemfile.lock
CHANGED
File without changes
|
data/LICENSE
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -42,6 +42,12 @@ puts hmc.name
|
|
42
42
|
puts hmc.version
|
43
43
|
```
|
44
44
|
|
45
|
+
Retrieving managed systems that are powered on:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
hc.managed_systems("State" => "operating")
|
49
|
+
```
|
50
|
+
|
45
51
|
Listing the logical partitions and virtual I/O servers of each managed system:
|
46
52
|
|
47
53
|
```ruby
|
data/Rakefile
CHANGED
File without changes
|
data/ibm_power_hmc.gemspec
CHANGED
File without changes
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
# Module for IBM HMC Rest API Client
|
4
4
|
module IbmPowerHmc
|
5
|
-
require_relative 'pcm.rb'
|
6
|
-
|
7
5
|
class Error < StandardError; end
|
8
6
|
|
9
7
|
##
|
@@ -19,7 +17,6 @@ module IbmPowerHmc
|
|
19
17
|
# @param port [Integer] TCP port number.
|
20
18
|
# @param validate_ssl [Boolean] Verify SSL certificates.
|
21
19
|
def initialize(host:, username: "hscroot", password:, port: 12_443, validate_ssl: true)
|
22
|
-
# Damien: use URI::HTTPS
|
23
20
|
@hostname = "#{host}:#{port}"
|
24
21
|
@username = username
|
25
22
|
@password = password
|
@@ -37,10 +34,8 @@ module IbmPowerHmc
|
|
37
34
|
:content_type => "application/vnd.ibm.powervm.web+xml; type=LogonRequest"
|
38
35
|
}
|
39
36
|
doc = REXML::Document.new("")
|
40
|
-
doc.add_element("LogonRequest",
|
41
|
-
|
42
|
-
"schemaVersion" => "V1_1_0"
|
43
|
-
})
|
37
|
+
doc.add_element("LogonRequest", "schemaVersion" => "V1_1_0")
|
38
|
+
doc.root.add_namespace("http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/")
|
44
39
|
doc.root.add_element("UserID").text = @username
|
45
40
|
doc.root.add_element("Password").text = @password
|
46
41
|
|
@@ -69,15 +64,6 @@ module IbmPowerHmc
|
|
69
64
|
@api_session_token = nil
|
70
65
|
end
|
71
66
|
|
72
|
-
def parse_feed(doc, myclass)
|
73
|
-
objs = []
|
74
|
-
doc.each_element("feed/entry") do |entry|
|
75
|
-
objs << myclass.new(entry)
|
76
|
-
end
|
77
|
-
objs
|
78
|
-
end
|
79
|
-
private :parse_feed
|
80
|
-
|
81
67
|
##
|
82
68
|
# @!method management_console
|
83
69
|
# Retrieve information about the management console.
|
@@ -85,20 +71,20 @@ module IbmPowerHmc
|
|
85
71
|
def management_console
|
86
72
|
method_url = "/rest/api/uom/ManagementConsole"
|
87
73
|
response = request(:get, method_url)
|
88
|
-
doc = REXML::Document.new(response.body)
|
89
74
|
# This request returns a feed with a single entry.
|
90
|
-
|
75
|
+
FeedParser.new(response.body).objects(:ManagementConsole).first
|
91
76
|
end
|
92
77
|
|
93
78
|
##
|
94
|
-
# @!method managed_systems
|
79
|
+
# @!method managed_systems(search = {})
|
95
80
|
# Retrieve the list of systems managed by the HMC.
|
81
|
+
# @param search [Hash] The optional property name and value to match.
|
96
82
|
# @return [Array<IbmPowerHmc::ManagedSystem>] The list of managed systems.
|
97
|
-
def managed_systems
|
83
|
+
def managed_systems(search = {})
|
98
84
|
method_url = "/rest/api/uom/ManagedSystem"
|
85
|
+
search.each { |key, value| method_url += "/search/(#{key}==#{value})" }
|
99
86
|
response = request(:get, method_url)
|
100
|
-
|
101
|
-
parse_feed(doc, ManagedSystem)
|
87
|
+
FeedParser.new(response.body).objects(:ManagedSystem)
|
102
88
|
end
|
103
89
|
|
104
90
|
##
|
@@ -106,31 +92,30 @@ module IbmPowerHmc
|
|
106
92
|
# Retrieve information about a managed system.
|
107
93
|
# @param sys_uuid [String] The UUID of the managed system.
|
108
94
|
# @param group_name [String] The extended group attributes.
|
109
|
-
# @return [IbmPowerHmc::ManagedSystem] The
|
95
|
+
# @return [IbmPowerHmc::ManagedSystem] The managed system.
|
110
96
|
def managed_system(sys_uuid, group_name = nil)
|
111
97
|
method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}"
|
112
98
|
method_url += "?group=#{group_name}" unless group_name.nil?
|
113
99
|
|
114
100
|
response = request(:get, method_url)
|
115
|
-
|
116
|
-
entry = doc.elements["entry"]
|
117
|
-
ManagedSystem.new(entry)
|
101
|
+
Parser.new(response.body).object(:ManagedSystem)
|
118
102
|
end
|
119
103
|
|
120
104
|
##
|
121
|
-
# @!method lpars(sys_uuid = nil)
|
105
|
+
# @!method lpars(sys_uuid = nil, search = {})
|
122
106
|
# Retrieve the list of logical partitions managed by the HMC.
|
123
107
|
# @param sys_uuid [String] The UUID of the managed system.
|
108
|
+
# @param search [Hash] The optional property name and value to match.
|
124
109
|
# @return [Array<IbmPowerHmc::LogicalPartition>] The list of logical partitions.
|
125
|
-
def lpars(sys_uuid = nil)
|
110
|
+
def lpars(sys_uuid = nil, search = {})
|
126
111
|
if sys_uuid.nil?
|
127
112
|
method_url = "/rest/api/uom/LogicalPartition"
|
113
|
+
search.each { |key, value| method_url += "/search/(#{key}==#{value})" }
|
128
114
|
else
|
129
115
|
method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/LogicalPartition"
|
130
116
|
end
|
131
117
|
response = request(:get, method_url)
|
132
|
-
|
133
|
-
parse_feed(doc, LogicalPartition)
|
118
|
+
FeedParser.new(response.body).objects(:LogicalPartition)
|
134
119
|
end
|
135
120
|
|
136
121
|
##
|
@@ -149,15 +134,14 @@ module IbmPowerHmc
|
|
149
134
|
method_url += "?group=#{group_name}" unless group_name.nil?
|
150
135
|
|
151
136
|
response = request(:get, method_url)
|
152
|
-
|
153
|
-
entry = doc.elements["entry"]
|
154
|
-
LogicalPartition.new(entry)
|
137
|
+
Parser.new(response.body).object(:LogicalPartition)
|
155
138
|
end
|
156
139
|
|
157
140
|
##
|
158
141
|
# @!method lpar_quick_property(lpar_uuid, property_name)
|
159
142
|
# Retrieve a quick property of a logical partition.
|
160
143
|
# @param lpar_uuid [String] The UUID of the logical partition.
|
144
|
+
# @param property_name [String] The quick property name.
|
161
145
|
# @return [String] The quick property value.
|
162
146
|
def lpar_quick_property(lpar_uuid, property_name)
|
163
147
|
method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/quick/#{property_name}"
|
@@ -167,19 +151,35 @@ module IbmPowerHmc
|
|
167
151
|
end
|
168
152
|
|
169
153
|
##
|
170
|
-
# @!method
|
154
|
+
# @!method rename_lpar(lpar_uuid, newname)
|
155
|
+
# Rename a logical partition.
|
156
|
+
# @param lpar_uuid [String] The UUID of the logical partition.
|
157
|
+
# @param newname [String] The new name of the logical partition.
|
158
|
+
def rename_lpar(lpar_uuid, newname)
|
159
|
+
method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}"
|
160
|
+
headers = {
|
161
|
+
:content_type => "application/vnd.ibm.powervm.uom+xml; type=LogicalPartition",
|
162
|
+
}
|
163
|
+
modify_object(method_url, headers) do |lpar|
|
164
|
+
lpar.xml.elements["PartitionName"].text = newname
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# @!method vioses(sys_uuid = nil, search = {})
|
171
170
|
# Retrieve the list of virtual I/O servers managed by the HMC.
|
172
171
|
# @param sys_uuid [String] The UUID of the managed system.
|
172
|
+
# @param search [Hash] The optional property name and value to match.
|
173
173
|
# @return [Array<IbmPowerHmc::VirtualIOServer>] The list of virtual I/O servers.
|
174
|
-
def vioses(sys_uuid = nil)
|
174
|
+
def vioses(sys_uuid = nil, search = {})
|
175
175
|
if sys_uuid.nil?
|
176
176
|
method_url = "/rest/api/uom/VirtualIOServer"
|
177
|
+
search.each { |key, value| method_url += "/search/(#{key}==#{value})" }
|
177
178
|
else
|
178
179
|
method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/VirtualIOServer"
|
179
180
|
end
|
180
181
|
response = request(:get, method_url)
|
181
|
-
|
182
|
-
parse_feed(doc, VirtualIOServer)
|
182
|
+
FeedParser.new(response.body).objects(:VirtualIOServer)
|
183
183
|
end
|
184
184
|
|
185
185
|
##
|
@@ -198,9 +198,7 @@ module IbmPowerHmc
|
|
198
198
|
method_url += "?group=#{group_name}" unless group_name.nil?
|
199
199
|
|
200
200
|
response = request(:get, method_url)
|
201
|
-
|
202
|
-
entry = doc.elements["entry"]
|
203
|
-
VirtualIOServer.new(entry)
|
201
|
+
Parser.new(response.body).object(:VirtualIOServer)
|
204
202
|
end
|
205
203
|
|
206
204
|
##
|
@@ -293,6 +291,21 @@ module IbmPowerHmc
|
|
293
291
|
job
|
294
292
|
end
|
295
293
|
|
294
|
+
##
|
295
|
+
# @!method remove_connection(hmc_uuid, sys_uuid, sync = true)
|
296
|
+
# Remove a managed system from the management console.
|
297
|
+
# @param hmc_uuid [String] The UUID of the management console.
|
298
|
+
# @param sys_uuid [String] The UUID of the managed system.
|
299
|
+
# @param sync [Boolean] Start the job and wait for its completion.
|
300
|
+
# @return [IbmPowerHmc::HmcJob] The HMC job.
|
301
|
+
def remove_connection(hmc_uuid, sys_uuid, sync = true)
|
302
|
+
method_url = "/rest/api/uom/ManagementConsole/#{hmc_uuid}/ManagedSystem/#{sys_uuid}/do/RemoveConnection"
|
303
|
+
|
304
|
+
job = HmcJob.new(self, method_url, "RemoveConnection", "ManagedSystem")
|
305
|
+
job.run if sync
|
306
|
+
job
|
307
|
+
end
|
308
|
+
|
296
309
|
##
|
297
310
|
# @!method cli_run(hmc_uuid, cmd, sync = true)
|
298
311
|
# Run a CLI command on the HMC as a job.
|
@@ -326,8 +339,7 @@ module IbmPowerHmc
|
|
326
339
|
# No need to sleep as the HMC already waits a bit before returning 204
|
327
340
|
break if response.code != 204 || !wait
|
328
341
|
end
|
329
|
-
|
330
|
-
parse_feed(doc, Event)
|
342
|
+
FeedParser.new(response.body).objects(:Event)
|
331
343
|
end
|
332
344
|
|
333
345
|
##
|
@@ -356,10 +368,8 @@ module IbmPowerHmc
|
|
356
368
|
|
357
369
|
# Try to parse body as an HttpErrorResponse
|
358
370
|
unless err.response.nil?
|
359
|
-
|
360
|
-
|
361
|
-
unless entry.nil?
|
362
|
-
resp = HttpErrorResponse.new(entry)
|
371
|
+
resp = Parser.new(err.response.body).object(:HttpErrorResponse)
|
372
|
+
unless resp.nil?
|
363
373
|
@uri = resp.uri
|
364
374
|
@reason = resp.reason
|
365
375
|
@message = resp.message
|
@@ -368,7 +378,7 @@ module IbmPowerHmc
|
|
368
378
|
end
|
369
379
|
|
370
380
|
def to_s
|
371
|
-
"msg
|
381
|
+
"msg=\"#{@message}\" status=\"#{@status}\" reason=\"#{@reason}\" uri=#{@uri}"
|
372
382
|
end
|
373
383
|
end
|
374
384
|
|
@@ -386,7 +396,7 @@ module IbmPowerHmc
|
|
386
396
|
# Check for relative URLs
|
387
397
|
url = "https://#{@hostname}#{url}" if url.start_with?("/")
|
388
398
|
begin
|
389
|
-
headers = headers.merge(
|
399
|
+
headers = headers.merge("X-API-Session" => @api_session_token)
|
390
400
|
RestClient::Request.execute(
|
391
401
|
:method => method,
|
392
402
|
:url => url,
|
@@ -405,5 +415,27 @@ module IbmPowerHmc
|
|
405
415
|
raise HttpError.new(e), "REST request failed"
|
406
416
|
end
|
407
417
|
end
|
418
|
+
|
419
|
+
private
|
420
|
+
|
421
|
+
def modify_object(method_url, headers = {}, attempts = 5)
|
422
|
+
while attempts > 0
|
423
|
+
response = request(:get, method_url)
|
424
|
+
obj = Parser.new(response.body).object
|
425
|
+
|
426
|
+
yield obj
|
427
|
+
|
428
|
+
# Use ETag to ensure object has not changed.
|
429
|
+
headers = headers.merge("If-Match" => obj.etag)
|
430
|
+
begin
|
431
|
+
request(:post, method_url, headers, obj.xml.to_s)
|
432
|
+
break
|
433
|
+
rescue HttpError => e
|
434
|
+
attempts -= 1
|
435
|
+
# Will get 412 ("Precondition Failed" if ETag mismatches)
|
436
|
+
raise if e.status != 412 || attempts == 0
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
408
440
|
end
|
409
441
|
end
|
data/lib/ibm_power_hmc/job.rb
CHANGED
@@ -24,7 +24,7 @@ module IbmPowerHmc
|
|
24
24
|
end
|
25
25
|
|
26
26
|
##
|
27
|
-
# @!method
|
27
|
+
# @!method start
|
28
28
|
# Start the job asynchronously.
|
29
29
|
# @return [String] The ID of the job.
|
30
30
|
def start
|
@@ -32,25 +32,22 @@ module IbmPowerHmc
|
|
32
32
|
:content_type => "application/vnd.ibm.powervm.web+xml; type=JobRequest"
|
33
33
|
}
|
34
34
|
doc = REXML::Document.new("")
|
35
|
-
doc.add_element("JobRequest:JobRequest",
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
})
|
40
|
-
op = doc.root.add_element("RequestedOperation", {"schemaVersion" => "V1_1_0"})
|
35
|
+
doc.add_element("JobRequest:JobRequest", "schemaVersion" => "V1_1_0")
|
36
|
+
doc.root.add_namespace("http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/")
|
37
|
+
doc.root.add_namespace("JobRequest", "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/")
|
38
|
+
op = doc.root.add_element("RequestedOperation", "schemaVersion" => "V1_1_0")
|
41
39
|
op.add_element("OperationName").text = @operation
|
42
40
|
op.add_element("GroupName").text = @group
|
43
|
-
|
44
|
-
jobparams = doc.root.add_element("JobParameters",
|
41
|
+
|
42
|
+
jobparams = doc.root.add_element("JobParameters", "schemaVersion" => "V1_1_0")
|
45
43
|
@params.each do |key, value|
|
46
|
-
jobparam = jobparams.add_element("JobParameter",
|
44
|
+
jobparam = jobparams.add_element("JobParameter", "schemaVersion" => "V1_1_0")
|
47
45
|
jobparam.add_element("ParameterName").text = key
|
48
46
|
jobparam.add_element("ParameterValue").text = value
|
49
47
|
end
|
50
48
|
response = @conn.request(:put, @method_url, headers, doc.to_s)
|
51
|
-
|
52
|
-
|
53
|
-
@id = info.elements["JobID"].text
|
49
|
+
jobresp = Parser.new(response.body).object(:JobResponse)
|
50
|
+
@id = jobresp.id
|
54
51
|
end
|
55
52
|
|
56
53
|
# @return [Hash] The job results returned by the HMC.
|
@@ -68,20 +65,9 @@ module IbmPowerHmc
|
|
68
65
|
:content_type => "application/vnd.ibm.powervm.web+xml; type=JobRequest"
|
69
66
|
}
|
70
67
|
response = @conn.request(:get, method_url, headers)
|
71
|
-
|
72
|
-
|
73
|
-
status
|
74
|
-
# Damien: also retrieve "ResponseException/Message"?
|
75
|
-
|
76
|
-
# Gather Job results returned by the HMC.
|
77
|
-
@results = {}
|
78
|
-
info.each_element("Results/JobParameter") do |result|
|
79
|
-
name = result.elements["ParameterName"].text.strip
|
80
|
-
value = result.elements["ParameterValue"].text.strip
|
81
|
-
@results[name] = value
|
82
|
-
end
|
83
|
-
|
84
|
-
status
|
68
|
+
jobresp = Parser.new(response.body).object(:JobResponse)
|
69
|
+
@results = jobresp.results
|
70
|
+
jobresp.status
|
85
71
|
end
|
86
72
|
|
87
73
|
##
|
@@ -112,8 +98,7 @@ module IbmPowerHmc
|
|
112
98
|
# @return [String] The status of the job.
|
113
99
|
def run(timeout = 120, poll_interval = 0)
|
114
100
|
start
|
115
|
-
|
116
|
-
status
|
101
|
+
wait(timeout, poll_interval)
|
117
102
|
ensure
|
118
103
|
delete if defined?(@id)
|
119
104
|
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module IbmPowerHmc
|
7
|
+
# Parser for HMC feeds and entries.
|
8
|
+
class Parser
|
9
|
+
def initialize(body)
|
10
|
+
@doc = REXML::Document.new(body)
|
11
|
+
end
|
12
|
+
|
13
|
+
def entry
|
14
|
+
@doc.elements["entry"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def object(filter_type = nil)
|
18
|
+
self.class.to_obj(entry, filter_type)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.to_obj(entry, filter_type = nil)
|
22
|
+
return if entry.nil?
|
23
|
+
|
24
|
+
content = entry.elements["content"]
|
25
|
+
return if content.nil?
|
26
|
+
|
27
|
+
type = content.attributes["type"]
|
28
|
+
return if type.nil?
|
29
|
+
|
30
|
+
type = type.split("=").last
|
31
|
+
return unless filter_type.nil? || filter_type.to_s == type
|
32
|
+
|
33
|
+
Module.const_get("IbmPowerHmc::#{type}").new(entry)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class FeedParser < Parser
|
38
|
+
def entries
|
39
|
+
objs = []
|
40
|
+
@doc.each_element("feed/entry") do |entry|
|
41
|
+
objs << yield(entry)
|
42
|
+
end
|
43
|
+
objs
|
44
|
+
end
|
45
|
+
|
46
|
+
def objects(filter_type = nil)
|
47
|
+
entries do |entry|
|
48
|
+
self.class.to_obj(entry, filter_type)
|
49
|
+
end.compact
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private_constant :Parser
|
54
|
+
private_constant :FeedParser
|
55
|
+
|
56
|
+
# HMC generic XML entry
|
57
|
+
class AbstractRest
|
58
|
+
ATTRS = {}.freeze
|
59
|
+
attr_reader :uuid, :published, :etag, :xml
|
60
|
+
|
61
|
+
def initialize(doc)
|
62
|
+
@uuid = doc.elements["id"]&.text
|
63
|
+
@published = Time.xmlschema(doc.elements["published"]&.text)
|
64
|
+
@etag = doc.elements["etag:etag"]&.text&.strip
|
65
|
+
type = self.class.name.split("::").last
|
66
|
+
@xml = doc.elements["content/#{type}:#{type}"]
|
67
|
+
define_attrs(self.class::ATTRS)
|
68
|
+
end
|
69
|
+
|
70
|
+
def define_attr(varname, xpath)
|
71
|
+
value = text_element(xpath)
|
72
|
+
self.class.__send__(:attr_reader, varname)
|
73
|
+
instance_variable_set("@#{varname}", value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def define_attrs(hash)
|
77
|
+
hash.each do |key, value|
|
78
|
+
define_attr(key, value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def text_element(xpath)
|
83
|
+
xml.elements[xpath]&.text&.strip
|
84
|
+
end
|
85
|
+
|
86
|
+
def extract_uuid_from_href(href)
|
87
|
+
URI(href).path.split('/').last
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# HMC information
|
92
|
+
class ManagementConsole < AbstractRest
|
93
|
+
ATTRS = {
|
94
|
+
:name => "ManagementConsoleName",
|
95
|
+
:build_level => "VersionInfo/BuildLevel",
|
96
|
+
:version => "BaseVersion"
|
97
|
+
}.freeze
|
98
|
+
|
99
|
+
def managed_systems_uuids
|
100
|
+
xml.get_elements("ManagedSystems/link").map do |link|
|
101
|
+
extract_uuid_from_href(link.attributes["href"])
|
102
|
+
end.compact
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Managed System information
|
107
|
+
class ManagedSystem < AbstractRest
|
108
|
+
ATTRS = {
|
109
|
+
:name => "SystemName",
|
110
|
+
:state => "State",
|
111
|
+
:hostname => "Hostname",
|
112
|
+
:ipaddr => "PrimaryIPAddress",
|
113
|
+
:fwversion => "SystemFirmware",
|
114
|
+
:memory => "AssociatedSystemMemoryConfiguration/InstalledSystemMemory",
|
115
|
+
:avail_mem => "AssociatedSystemMemoryConfiguration/CurrentAvailableSystemMemory",
|
116
|
+
:cpus => "AssociatedSystemProcessorConfiguration/InstalledSystemProcessorUnits",
|
117
|
+
:avail_cpus => "AssociatedSystemProcessorConfiguration/CurrentAvailableSystemProcessorUnits",
|
118
|
+
:mtype => "MachineTypeModelAndSerialNumber/MachineType",
|
119
|
+
:model => "MachineTypeModelAndSerialNumber/Model",
|
120
|
+
:serial => "MachineTypeModelAndSerialNumber/SerialNumber"
|
121
|
+
}.freeze
|
122
|
+
|
123
|
+
def lpars_uuids
|
124
|
+
xml.get_elements("AssociatedLogicalPartitions/link").map do |link|
|
125
|
+
extract_uuid_from_href(link.attributes["href"])
|
126
|
+
end.compact
|
127
|
+
end
|
128
|
+
|
129
|
+
def vioses_uuids
|
130
|
+
xml.get_elements("AssociatedVirtualIOServers/link").map do |link|
|
131
|
+
extract_uuid_from_href(link.attributes["href"])
|
132
|
+
end.compact
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Common class for LPAR and VIOS
|
137
|
+
class BasePartition < AbstractRest
|
138
|
+
ATTRS = {
|
139
|
+
:name => "PartitionName",
|
140
|
+
:id => "PartitionID",
|
141
|
+
:state => "PartitionState",
|
142
|
+
:type => "PartitionType",
|
143
|
+
:memory => "PartitionMemoryConfiguration/CurrentMemory",
|
144
|
+
:dedicated => "PartitionProcessorConfiguration/HasDedicatedProcessors",
|
145
|
+
:rmc_state => "ResourceMonitoringControlState",
|
146
|
+
:rmc_ipaddr => "ResourceMonitoringIPAddress",
|
147
|
+
:ref_code => "ReferenceCode"
|
148
|
+
}.freeze
|
149
|
+
|
150
|
+
def sys_uuid
|
151
|
+
sys_href = xml.elements["AssociatedManagedSystem"].attributes["href"]
|
152
|
+
extract_uuid_from_href(sys_href)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Logical Partition information
|
157
|
+
class LogicalPartition < BasePartition
|
158
|
+
end
|
159
|
+
|
160
|
+
# VIOS information
|
161
|
+
class VirtualIOServer < BasePartition
|
162
|
+
end
|
163
|
+
|
164
|
+
# HMC Event
|
165
|
+
class Event < AbstractRest
|
166
|
+
ATTRS = {
|
167
|
+
:id => "EventID",
|
168
|
+
:type => "EventType",
|
169
|
+
:data => "EventData",
|
170
|
+
:detail => "EventDetail"
|
171
|
+
}.freeze
|
172
|
+
end
|
173
|
+
|
174
|
+
# Error response from HMC
|
175
|
+
class HttpErrorResponse < AbstractRest
|
176
|
+
ATTRS = {
|
177
|
+
:status => "HTTPStatus",
|
178
|
+
:uri => "RequestURI",
|
179
|
+
:reason => "ReasonCode",
|
180
|
+
:message => "Message"
|
181
|
+
}.freeze
|
182
|
+
end
|
183
|
+
|
184
|
+
# Job Response
|
185
|
+
class JobResponse < AbstractRest
|
186
|
+
ATTRS = {
|
187
|
+
:id => "JobID",
|
188
|
+
:status => "Status",
|
189
|
+
:message => "ResponseException/Message"
|
190
|
+
}.freeze
|
191
|
+
|
192
|
+
def results
|
193
|
+
results = {}
|
194
|
+
xml.each_element("Results/JobParameter") do |result|
|
195
|
+
name = result.elements["ParameterName"]&.text&.strip
|
196
|
+
value = result.elements["ParameterValue"]&.text&.strip
|
197
|
+
results[name] = value unless name.nil?
|
198
|
+
end
|
199
|
+
results
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
data/lib/ibm_power_hmc/pcm.rb
CHANGED
@@ -5,26 +5,62 @@ require 'uri'
|
|
5
5
|
|
6
6
|
module IbmPowerHmc
|
7
7
|
class Connection
|
8
|
+
def pcm_preferences
|
9
|
+
method_url = "/rest/api/pcm/preferences"
|
10
|
+
|
11
|
+
response = request(:get, method_url)
|
12
|
+
REXML::Document.new(response.body)
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# @!method phyp_metrics(sys_uuid:, start_ts: nil, end_ts: nil, short_term: false)
|
17
|
+
# Retrieve PowerVM metrics for a given managed system.
|
18
|
+
# @param sys_uuid [String] The managed system UUID.
|
19
|
+
# @param start_ts [Time] Start timestamp.
|
20
|
+
# @param end_ts [Time] End timestamp.
|
21
|
+
# @param short_term [Boolean] Retrieve short term monitor metrics (default to long term).
|
22
|
+
# @return [Array<Hash>] The PowerVM metrics for the managed system.
|
23
|
+
def phyp_metrics(sys_uuid:, start_ts: nil, end_ts: nil, short_term: false)
|
24
|
+
type = short_term ? "ShortTermMonitor" : "LongTermMonitor"
|
25
|
+
method_url = "/rest/api/pcm/ManagedSystem/#{sys_uuid}/RawMetrics/#{type}"
|
26
|
+
query = {}
|
27
|
+
query["StartTS"] = self.class.format_time(start_ts) unless start_ts.nil?
|
28
|
+
query["EndTS"] = self.class.format_time(end_ts) unless end_ts.nil?
|
29
|
+
method_url += "?" + query.map { |h| h.join("=") }.join("&") unless query.empty?
|
30
|
+
|
31
|
+
response = request(:get, method_url)
|
32
|
+
FeedParser.new(response.body).entries do |entry|
|
33
|
+
link = entry.elements["link"]
|
34
|
+
next if link.nil?
|
35
|
+
|
36
|
+
href = link.attributes["href"]
|
37
|
+
next if href.nil?
|
38
|
+
|
39
|
+
response = request(:get, href)
|
40
|
+
JSON.parse(response.body)
|
41
|
+
end.compact
|
42
|
+
end
|
43
|
+
|
8
44
|
##
|
9
|
-
# @!method managed_system_metrics(sys_uuid:, start_ts: nil, end_ts: nil, no_samples: nil)
|
45
|
+
# @!method managed_system_metrics(sys_uuid:, start_ts: nil, end_ts: nil, no_samples: nil, aggregated: false)
|
10
46
|
# Retrieve metrics for a managed system.
|
11
47
|
# @param sys_uuid [String] The managed system UUID.
|
12
|
-
# @param start_ts [
|
13
|
-
# @param end_ts [
|
48
|
+
# @param start_ts [Time] Start timestamp.
|
49
|
+
# @param end_ts [Time] End timestamp.
|
14
50
|
# @param no_samples [Integer] Number of samples.
|
15
|
-
# @
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
query
|
21
|
-
query
|
22
|
-
|
51
|
+
# @param aggregated [Boolean] Retrieve aggregated metrics (default to Processed).
|
52
|
+
# @return [Array<Hash>] The metrics for the managed system.
|
53
|
+
def managed_system_metrics(sys_uuid:, start_ts: nil, end_ts: nil, no_samples: nil, aggregated: false)
|
54
|
+
type = aggregated ? "AggregatedMetrics" : "ProcessedMetrics"
|
55
|
+
method_url = "/rest/api/pcm/ManagedSystem/#{sys_uuid}/#{type}"
|
56
|
+
query = {}
|
57
|
+
query["StartTS"] = self.class.format_time(start_ts) unless start_ts.nil?
|
58
|
+
query["EndTS"] = self.class.format_time(end_ts) unless end_ts.nil?
|
59
|
+
query["NoOfSamples"] = no_samples unless no_samples.nil?
|
60
|
+
method_url += "?" + query.map { |h| h.join("=") }.join("&") unless query.empty?
|
23
61
|
|
24
62
|
response = request(:get, method_url)
|
25
|
-
|
26
|
-
metrics = []
|
27
|
-
doc.each_element("feed/entry") do |entry|
|
63
|
+
FeedParser.new(response.body).entries do |entry|
|
28
64
|
category = entry.elements["category"]
|
29
65
|
next if category.nil?
|
30
66
|
|
@@ -37,10 +73,50 @@ module IbmPowerHmc
|
|
37
73
|
href = link.attributes["href"]
|
38
74
|
next if href.nil?
|
39
75
|
|
40
|
-
response = request(:get, href
|
41
|
-
|
42
|
-
end
|
43
|
-
|
76
|
+
response = request(:get, href)
|
77
|
+
JSON.parse(response.body)
|
78
|
+
end.compact
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# @!method lpar_metrics(sys_uuid:, lpar_uuid:, start_ts: nil, end_ts: nil, no_samples: nil, aggregated: false)
|
83
|
+
# Retrieve metrics for a logical partition.
|
84
|
+
# @param sys_uuid [String] The managed system UUID.
|
85
|
+
# @param lpar_uuid [String] The logical partition UUID.
|
86
|
+
# @param start_ts [Time] Start timestamp.
|
87
|
+
# @param end_ts [Time] End timestamp.
|
88
|
+
# @param no_samples [Integer] Number of samples.
|
89
|
+
# @param aggregated [Boolean] Retrieve aggregated metrics (default to Processed).
|
90
|
+
# @return [Array<Hash>] The metrics for the logical partition.
|
91
|
+
def lpar_metrics(sys_uuid:, lpar_uuid:, start_ts: nil, end_ts: nil, no_samples: nil, aggregated: false)
|
92
|
+
type = aggregated ? "AggregatedMetrics" : "ProcessedMetrics"
|
93
|
+
method_url = "/rest/api/pcm/ManagedSystem/#{sys_uuid}/LogicalPartition/#{lpar_uuid}/#{type}"
|
94
|
+
query = {}
|
95
|
+
query["StartTS"] = self.class.format_time(start_ts) unless start_ts.nil?
|
96
|
+
query["EndTS"] = self.class.format_time(end_ts) unless end_ts.nil?
|
97
|
+
query["NoOfSamples"] = no_samples unless no_samples.nil?
|
98
|
+
method_url += "?" + query.map { |h| h.join("=") }.join("&") unless query.empty?
|
99
|
+
|
100
|
+
response = request(:get, method_url)
|
101
|
+
FeedParser(response.body).entries do |entry|
|
102
|
+
link = entry.elements["link"]
|
103
|
+
next if link.nil?
|
104
|
+
|
105
|
+
href = link.attributes["href"]
|
106
|
+
next if href.nil?
|
107
|
+
|
108
|
+
response = request(:get, href)
|
109
|
+
JSON.parse(response.body)
|
110
|
+
end.compact
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# @!method format_time(time)
|
115
|
+
# Convert ruby time to HMC time format.
|
116
|
+
# @param time [Time] The ruby time to convert.
|
117
|
+
# @return [String] The time in HMC format.
|
118
|
+
def self.format_time(time)
|
119
|
+
time.utc.xmlschema
|
44
120
|
end
|
45
121
|
end
|
46
122
|
end
|
data/lib/ibm_power_hmc.rb
CHANGED
@@ -7,7 +7,8 @@ require "ibm_power_hmc/version"
|
|
7
7
|
|
8
8
|
# Module for IBM HMC Rest API Client
|
9
9
|
module IbmPowerHmc
|
10
|
-
require_relative "./ibm_power_hmc/
|
10
|
+
require_relative "./ibm_power_hmc/parser.rb"
|
11
11
|
require_relative "./ibm_power_hmc/job.rb"
|
12
12
|
require_relative "./ibm_power_hmc/connection.rb"
|
13
|
+
require_relative "./ibm_power_hmc/pcm.rb"
|
13
14
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ibm_power_hmc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- IBM Power
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.1'
|
27
27
|
description: A Ruby gem for interacting with the IBM Hardware Management Console (HMC).
|
28
|
-
email:
|
28
|
+
email:
|
29
29
|
executables: []
|
30
30
|
extensions: []
|
31
31
|
extra_rdoc_files: []
|
@@ -45,7 +45,7 @@ files:
|
|
45
45
|
- lib/ibm_power_hmc.rb
|
46
46
|
- lib/ibm_power_hmc/connection.rb
|
47
47
|
- lib/ibm_power_hmc/job.rb
|
48
|
-
- lib/ibm_power_hmc/
|
48
|
+
- lib/ibm_power_hmc/parser.rb
|
49
49
|
- lib/ibm_power_hmc/pcm.rb
|
50
50
|
- lib/ibm_power_hmc/version.rb
|
51
51
|
homepage: http://github.com/IBM/ibm_power_hmc_sdk_ruby
|
@@ -56,7 +56,7 @@ metadata:
|
|
56
56
|
homepage_uri: http://github.com/IBM/ibm_power_hmc_sdk_ruby
|
57
57
|
source_code_uri: http://github.com/IBM/ibm_power_hmc_sdk_ruby
|
58
58
|
changelog_uri: http://github.com/IBM/ibm_power_hmc_sdk_ruby/blob/master/CHANGELOG.md
|
59
|
-
post_install_message:
|
59
|
+
post_install_message:
|
60
60
|
rdoc_options: []
|
61
61
|
require_paths:
|
62
62
|
- lib
|
@@ -71,8 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: '0'
|
73
73
|
requirements: []
|
74
|
-
rubygems_version: 3.
|
75
|
-
signing_key:
|
74
|
+
rubygems_version: 3.1.2
|
75
|
+
signing_key:
|
76
76
|
specification_version: 4
|
77
77
|
summary: IBM Power HMC Ruby gem.
|
78
78
|
test_files: []
|
@@ -1,150 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'uri'
|
4
|
-
|
5
|
-
# Module for IBM HMC Rest API Client
|
6
|
-
module IbmPowerHmc
|
7
|
-
# HMC generic object
|
8
|
-
class HmcObject
|
9
|
-
attr_reader :uuid, :xml
|
10
|
-
|
11
|
-
def initialize(doc)
|
12
|
-
@uuid = doc.elements["id"].text
|
13
|
-
@xml = doc
|
14
|
-
end
|
15
|
-
|
16
|
-
def get_value(doc, xpath, varname)
|
17
|
-
value = doc.elements[xpath]
|
18
|
-
value = value.text unless value.nil?
|
19
|
-
value = value.strip unless value.nil?
|
20
|
-
self.class.__send__(:attr_reader, varname)
|
21
|
-
instance_variable_set("@#{varname}", value)
|
22
|
-
end
|
23
|
-
|
24
|
-
def get_values(doc, hash)
|
25
|
-
hash.each do |key, value|
|
26
|
-
get_value(doc, key, value)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# HMC information
|
32
|
-
class ManagementConsole < HmcObject
|
33
|
-
XMLMAP = {
|
34
|
-
"ManagementConsoleName" => "name",
|
35
|
-
"VersionInfo/BuildLevel" => "build_level",
|
36
|
-
"BaseVersion" => "version"
|
37
|
-
}.freeze
|
38
|
-
|
39
|
-
def initialize(doc)
|
40
|
-
super(doc)
|
41
|
-
info = doc.elements["content/ManagementConsole:ManagementConsole"]
|
42
|
-
get_values(info, XMLMAP)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Managed System information
|
47
|
-
class ManagedSystem < HmcObject
|
48
|
-
XMLMAP = {
|
49
|
-
"SystemName" => "name",
|
50
|
-
"State" => "state",
|
51
|
-
"Hostname" => "hostname",
|
52
|
-
"PrimaryIPAddress" => "ipaddr",
|
53
|
-
"SystemFirmware" => "fwversion",
|
54
|
-
"AssociatedSystemMemoryConfiguration/InstalledSystemMemory" => "memory",
|
55
|
-
"AssociatedSystemMemoryConfiguration/CurrentAvailableSystemMemory" => "avail_mem",
|
56
|
-
"AssociatedSystemProcessorConfiguration/InstalledSystemProcessorUnits" => "cpus",
|
57
|
-
"AssociatedSystemProcessorConfiguration/CurrentAvailableSystemProcessorUnits" => "avail_cpus",
|
58
|
-
"MachineTypeModelAndSerialNumber/MachineType" => "mtype",
|
59
|
-
"MachineTypeModelAndSerialNumber/Model" => "model",
|
60
|
-
"MachineTypeModelAndSerialNumber/SerialNumber" => "serial",
|
61
|
-
}.freeze
|
62
|
-
|
63
|
-
def initialize(doc)
|
64
|
-
super(doc)
|
65
|
-
info = doc.elements["content/ManagedSystem:ManagedSystem"]
|
66
|
-
get_values(info, XMLMAP)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Logical Partition information
|
71
|
-
class LogicalPartition < HmcObject
|
72
|
-
attr_reader :sys_uuid
|
73
|
-
|
74
|
-
XMLMAP = {
|
75
|
-
"PartitionName" => "name",
|
76
|
-
"PartitionID" => "id",
|
77
|
-
"PartitionState" => "state",
|
78
|
-
"PartitionType" => "type",
|
79
|
-
"PartitionMemoryConfiguration/CurrentMemory" => "memory",
|
80
|
-
"PartitionProcessorConfiguration/HasDedicatedProcessors" => "dedicated",
|
81
|
-
"ResourceMonitoringControlState" => "rmc_state",
|
82
|
-
"ResourceMonitoringIPAddress" => "rmc_ipaddr"
|
83
|
-
}.freeze
|
84
|
-
|
85
|
-
def initialize(doc)
|
86
|
-
super(doc)
|
87
|
-
info = doc.elements["content/LogicalPartition:LogicalPartition"]
|
88
|
-
sys_href = info.elements["AssociatedManagedSystem"].attributes["href"]
|
89
|
-
@sys_uuid = URI(sys_href).path.split('/').last
|
90
|
-
get_values(info, XMLMAP)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# VIOS information
|
95
|
-
class VirtualIOServer < HmcObject
|
96
|
-
attr_reader :sys_uuid
|
97
|
-
|
98
|
-
XMLMAP = {
|
99
|
-
"PartitionName" => "name",
|
100
|
-
"PartitionID" => "id",
|
101
|
-
"PartitionState" => "state",
|
102
|
-
"PartitionType" => "type",
|
103
|
-
"PartitionMemoryConfiguration/CurrentMemory" => "memory",
|
104
|
-
"PartitionProcessorConfiguration/HasDedicatedProcessors" => "dedicated"
|
105
|
-
}.freeze
|
106
|
-
|
107
|
-
def initialize(doc)
|
108
|
-
super(doc)
|
109
|
-
info = doc.elements["content/VirtualIOServer:VirtualIOServer"]
|
110
|
-
sys_href = info.elements["AssociatedManagedSystem"].attributes["href"]
|
111
|
-
@sys_uuid = URI(sys_href).path.split('/').last
|
112
|
-
get_values(info, XMLMAP)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# HMC Event
|
117
|
-
class Event < HmcObject
|
118
|
-
attr_reader :published
|
119
|
-
|
120
|
-
XMLMAP = {
|
121
|
-
"EventID" => "id",
|
122
|
-
"EventType" => "type",
|
123
|
-
"EventData" => "data",
|
124
|
-
"EventDetail" => "detail",
|
125
|
-
}.freeze
|
126
|
-
|
127
|
-
def initialize(doc)
|
128
|
-
super(doc)
|
129
|
-
@published = doc.elements["published"].text
|
130
|
-
info = doc.elements["content/Event:Event"]
|
131
|
-
get_values(info, XMLMAP)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# Error response from HMC
|
136
|
-
class HttpErrorResponse < HmcObject
|
137
|
-
XMLMAP = {
|
138
|
-
"HTTPStatus" => "status",
|
139
|
-
"RequestURI" => "uri",
|
140
|
-
"ReasonCode" => "reason",
|
141
|
-
"Message" => "message",
|
142
|
-
}.freeze
|
143
|
-
|
144
|
-
def initialize(doc)
|
145
|
-
super(doc)
|
146
|
-
info = doc.elements["content/HttpErrorResponse:HttpErrorResponse"]
|
147
|
-
get_values(info, XMLMAP)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|