ibm_power_hmc 0.1.2 → 0.2.1
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.
- 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
|