ibm_power_hmc 0.3.0 → 0.7.0
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 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +0 -0
- data/LICENSE +0 -0
- data/README.md +5 -5
- data/Rakefile +0 -0
- data/ibm_power_hmc.gemspec +0 -0
- data/lib/ibm_power_hmc/connection.rb +296 -24
- data/lib/ibm_power_hmc/job.rb +8 -9
- data/lib/ibm_power_hmc/parser.rb +703 -41
- data/lib/ibm_power_hmc/pcm.rb +0 -0
- data/lib/ibm_power_hmc/version.rb +1 -1
- data/lib/ibm_power_hmc.rb +4 -4
- metadata +7 -7
data/lib/ibm_power_hmc/parser.rb
CHANGED
@@ -4,16 +4,26 @@ require 'time'
|
|
4
4
|
require 'uri'
|
5
5
|
|
6
6
|
module IbmPowerHmc
|
7
|
-
|
7
|
+
##
|
8
|
+
# Generic parser for HMC K2 XML responses.
|
8
9
|
class Parser
|
9
10
|
def initialize(body)
|
10
11
|
@doc = REXML::Document.new(body)
|
11
12
|
end
|
12
13
|
|
14
|
+
##
|
15
|
+
# @!method entry
|
16
|
+
# Return the first K2 entry element in the response.
|
17
|
+
# @return [REXML::Element, nil] The first entry element.
|
13
18
|
def entry
|
14
19
|
@doc.elements["entry"]
|
15
20
|
end
|
16
21
|
|
22
|
+
##
|
23
|
+
# @!method object(filter_type = nil)
|
24
|
+
# Parse the first K2 entry element into an object.
|
25
|
+
# @param filter_type [String] Entry type must match the specified type.
|
26
|
+
# @return [IbmPowerHmc::AbstractRest, nil] The parsed object.
|
17
27
|
def object(filter_type = nil)
|
18
28
|
self.class.to_obj(entry, filter_type)
|
19
29
|
end
|
@@ -21,19 +31,28 @@ module IbmPowerHmc
|
|
21
31
|
def self.to_obj(entry, filter_type = nil)
|
22
32
|
return if entry.nil?
|
23
33
|
|
24
|
-
content = entry.elements["content"]
|
34
|
+
content = entry.elements["content[@type]"]
|
25
35
|
return if content.nil?
|
26
36
|
|
27
|
-
type = content.attributes["type"]
|
28
|
-
return if type.nil?
|
29
|
-
|
30
|
-
type = type.split("=").last
|
37
|
+
type = content.attributes["type"].split("=").last
|
31
38
|
return unless filter_type.nil? || filter_type.to_s == type
|
32
39
|
|
33
40
|
Module.const_get("IbmPowerHmc::#{type}").new(entry)
|
34
41
|
end
|
35
42
|
end
|
36
43
|
|
44
|
+
##
|
45
|
+
# Parser for HMC K2 feeds.
|
46
|
+
# A feed encapsulates a list of entries like this:
|
47
|
+
# <feed>
|
48
|
+
# <entry>
|
49
|
+
# <!-- entry #1 -->
|
50
|
+
# </entry>
|
51
|
+
# <entry>
|
52
|
+
# <!-- entry #2 -->
|
53
|
+
# </entry>
|
54
|
+
# ...
|
55
|
+
# </feed>
|
37
56
|
class FeedParser < Parser
|
38
57
|
def entries
|
39
58
|
objs = []
|
@@ -43,6 +62,11 @@ module IbmPowerHmc
|
|
43
62
|
objs
|
44
63
|
end
|
45
64
|
|
65
|
+
##
|
66
|
+
# @!method objects(filter_type = nil)
|
67
|
+
# Parse feed entries into objects.
|
68
|
+
# @param filter_type [String] Filter entries based on content type.
|
69
|
+
# @return [Array<IbmPowerHmc::AbstractRest>] The list of objects.
|
46
70
|
def objects(filter_type = nil)
|
47
71
|
entries do |entry|
|
48
72
|
self.class.to_obj(entry, filter_type)
|
@@ -53,38 +77,111 @@ module IbmPowerHmc
|
|
53
77
|
private_constant :Parser
|
54
78
|
private_constant :FeedParser
|
55
79
|
|
56
|
-
|
57
|
-
|
80
|
+
##
|
81
|
+
# HMC generic K2 non-REST object.
|
82
|
+
# @abstract
|
83
|
+
# @attr_reader [REXML::Document] xml The XML document representing this object.
|
84
|
+
class AbstractNonRest
|
58
85
|
ATTRS = {}.freeze
|
59
|
-
attr_reader :
|
86
|
+
attr_reader :xml
|
60
87
|
|
61
|
-
def initialize(
|
62
|
-
@
|
63
|
-
|
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)
|
88
|
+
def initialize(xml)
|
89
|
+
@xml = xml
|
90
|
+
self.class::ATTRS.each { |varname, xpath| define_attr(varname, xpath) }
|
68
91
|
end
|
69
92
|
|
93
|
+
##
|
94
|
+
# @!method define_attr(varname, xpath)
|
95
|
+
# Define an instance variable using the text of an XML element as value.
|
96
|
+
# @param varname [String] The name of the instance variable.
|
97
|
+
# @param xpath [String] The XPath of the XML element containing the text.
|
70
98
|
def define_attr(varname, xpath)
|
71
|
-
value =
|
99
|
+
value = singleton(xpath)
|
72
100
|
self.class.__send__(:attr_reader, varname)
|
73
101
|
instance_variable_set("@#{varname}", value)
|
74
102
|
end
|
103
|
+
private :define_attr
|
104
|
+
|
105
|
+
##
|
106
|
+
# @!method singleton(xpath, attr = nil)
|
107
|
+
# Get the text (or the value of a specified attribute) of an XML element.
|
108
|
+
# @param xpath [String] The XPath of the XML element.
|
109
|
+
# @param attr [String] The name of the attribute.
|
110
|
+
# @return [String, nil] The text or attribute value of the XML element or nil.
|
111
|
+
# @example lpar.singleton("PartitionProcessorConfiguration/*/MaximumVirtualProcessors").to_i
|
112
|
+
def singleton(xpath, attr = nil)
|
113
|
+
elem = xml.elements[xpath]
|
114
|
+
return if elem.nil?
|
115
|
+
|
116
|
+
attr.nil? ? elem.text&.strip : elem.attributes[attr]
|
117
|
+
end
|
75
118
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
119
|
+
def to_s
|
120
|
+
str = +"#{self.class.name}:\n"
|
121
|
+
self.class::ATTRS.each do |varname, _|
|
122
|
+
value = instance_variable_get("@#{varname}")
|
123
|
+
value = value.nil? ? "null" : "'#{value}'"
|
124
|
+
str << " #{varname}: #{value}\n"
|
79
125
|
end
|
126
|
+
str
|
127
|
+
end
|
128
|
+
|
129
|
+
def uuid_from_href(href, index = -1)
|
130
|
+
URI(href).path.split('/')[index]
|
80
131
|
end
|
81
132
|
|
82
|
-
def
|
83
|
-
xml.
|
133
|
+
def uuids_from_links(elem, index = -1)
|
134
|
+
xml.get_elements("#{elem}/link[@href]").map do |link|
|
135
|
+
uuid_from_href(link.attributes["href"], index)
|
136
|
+
end.compact
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# HMC generic K2 REST object.
|
142
|
+
# Encapsulate data for a single REST object.
|
143
|
+
# The XML looks like this:
|
144
|
+
# <entry>
|
145
|
+
# <id>uuid</id>
|
146
|
+
# <published>timestamp</published>
|
147
|
+
# <link rel="SELF" href="https://..."/>
|
148
|
+
# <etag:etag>ETag</etag:etag>
|
149
|
+
# <content type="type">
|
150
|
+
# <!-- actual content here -->
|
151
|
+
# </content>
|
152
|
+
# </entry>
|
153
|
+
#
|
154
|
+
# @abstract
|
155
|
+
# @attr_reader [String] uuid The UUID of the object contained in the entry.
|
156
|
+
# @attr_reader [Time] published The time at which the entry was published.
|
157
|
+
# @attr_reader [URI::HTTPS] href The URL of the object itself.
|
158
|
+
# @attr_reader [String] etag The entity tag of the entry.
|
159
|
+
# @attr_reader [String] content_type The content type of the object contained in the entry.
|
160
|
+
class AbstractRest < AbstractNonRest
|
161
|
+
attr_reader :uuid, :published, :href, :etag, :content_type
|
162
|
+
|
163
|
+
def initialize(entry)
|
164
|
+
if entry.name != "entry"
|
165
|
+
# We are inlined.
|
166
|
+
super(entry)
|
167
|
+
return
|
168
|
+
end
|
169
|
+
|
170
|
+
@uuid = entry.elements["id"]&.text
|
171
|
+
@published = Time.xmlschema(entry.elements["published"]&.text)
|
172
|
+
link = entry.elements["link[@rel='SELF']"]
|
173
|
+
@href = URI(link.attributes["href"]) unless link.nil?
|
174
|
+
@etag = entry.elements["etag:etag"]&.text&.strip
|
175
|
+
content = entry.elements["content"]
|
176
|
+
@content_type = content.attributes["type"]
|
177
|
+
super(content.elements.first)
|
84
178
|
end
|
85
179
|
|
86
|
-
def
|
87
|
-
|
180
|
+
def to_s
|
181
|
+
str = super
|
182
|
+
str << " uuid: '#{uuid}'\n" if defined?(@uuid)
|
183
|
+
str << " published: '#{published}'\n" if defined?(@published)
|
184
|
+
str
|
88
185
|
end
|
89
186
|
end
|
90
187
|
|
@@ -97,9 +194,7 @@ module IbmPowerHmc
|
|
97
194
|
}.freeze
|
98
195
|
|
99
196
|
def managed_systems_uuids
|
100
|
-
|
101
|
-
extract_uuid_from_href(link.attributes["href"])
|
102
|
-
end.compact
|
197
|
+
uuids_from_links("ManagedSystems")
|
103
198
|
end
|
104
199
|
end
|
105
200
|
|
@@ -117,26 +212,55 @@ module IbmPowerHmc
|
|
117
212
|
:avail_cpus => "AssociatedSystemProcessorConfiguration/CurrentAvailableSystemProcessorUnits",
|
118
213
|
:mtype => "MachineTypeModelAndSerialNumber/MachineType",
|
119
214
|
:model => "MachineTypeModelAndSerialNumber/Model",
|
120
|
-
:serial => "MachineTypeModelAndSerialNumber/SerialNumber"
|
215
|
+
:serial => "MachineTypeModelAndSerialNumber/SerialNumber",
|
216
|
+
:vtpm_version => "AssociatedSystemSecurity/VirtualTrustedPlatformModuleVersion",
|
217
|
+
:vtpm_lpars => "AssociatedSystemSecurity/AvailableVirtualTrustedPlatformModulePartitions"
|
121
218
|
}.freeze
|
122
219
|
|
123
|
-
def
|
124
|
-
xml.get_elements("
|
125
|
-
|
220
|
+
def cpu_compat_modes
|
221
|
+
xml.get_elements("AssociatedSystemProcessorConfiguration/SupportedPartitionProcessorCompatibilityModes").map do |elem|
|
222
|
+
elem.text&.strip
|
126
223
|
end.compact
|
127
224
|
end
|
128
225
|
|
226
|
+
def lpars_uuids
|
227
|
+
uuids_from_links("AssociatedLogicalPartitions")
|
228
|
+
end
|
229
|
+
|
129
230
|
def vioses_uuids
|
130
|
-
|
131
|
-
extract_uuid_from_href(link.attributes["href"])
|
132
|
-
end.compact
|
231
|
+
uuids_from_links("AssociatedVirtualIOServers")
|
133
232
|
end
|
233
|
+
|
234
|
+
def io_adapters
|
235
|
+
xml.get_elements("AssociatedSystemIOConfiguration/IOSlots/IOSlot/RelatedIOAdapter/IOAdapter").map do |elem|
|
236
|
+
IOAdapter.new(elem)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def vswitches_uuids
|
241
|
+
uuids_from_links("AssociatedSystemIOConfiguration/AssociatedSystemVirtualNetwork/VirtualSwitches")
|
242
|
+
end
|
243
|
+
|
244
|
+
def networks_uuids
|
245
|
+
uuids_from_links("AssociatedSystemIOConfiguration/AssociatedSystemVirtualNetwork/VirtualNetworks")
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# I/O Adapter information
|
250
|
+
class IOAdapter < AbstractNonRest
|
251
|
+
ATTRS = {
|
252
|
+
:id => "AdapterID",
|
253
|
+
:description => "Description",
|
254
|
+
:name => "DeviceName",
|
255
|
+
:type => "DeviceType",
|
256
|
+
:dr_name => "DynamicReconfigurationConnectorName",
|
257
|
+
:udid => "UniqueDeviceID"
|
258
|
+
}.freeze
|
134
259
|
end
|
135
260
|
|
136
261
|
# Common class for LPAR and VIOS
|
137
262
|
class BasePartition < AbstractRest
|
138
263
|
ATTRS = {
|
139
|
-
:os => "OperatingSystemVersion",
|
140
264
|
:name => "PartitionName",
|
141
265
|
:id => "PartitionID",
|
142
266
|
:state => "PartitionState",
|
@@ -145,25 +269,563 @@ module IbmPowerHmc
|
|
145
269
|
:dedicated => "PartitionProcessorConfiguration/HasDedicatedProcessors",
|
146
270
|
:rmc_state => "ResourceMonitoringControlState",
|
147
271
|
:rmc_ipaddr => "ResourceMonitoringIPAddress",
|
148
|
-
:
|
272
|
+
:os => "OperatingSystemVersion",
|
273
|
+
:ref_code => "ReferenceCode",
|
274
|
+
:procs => "PartitionProcessorConfiguration/CurrentDedicatedProcessorConfiguration/CurrentProcessors",
|
275
|
+
:proc_units => "PartitionProcessorConfiguration/CurrentSharedProcessorConfiguration/CurrentProcessingUnits",
|
276
|
+
:vprocs => "PartitionProcessorConfiguration/CurrentSharedProcessorConfiguration/AllocatedVirtualProcessors"
|
149
277
|
}.freeze
|
150
278
|
|
151
279
|
def sys_uuid
|
152
|
-
sys_href =
|
153
|
-
|
280
|
+
sys_href = singleton("AssociatedManagedSystem", "href")
|
281
|
+
uuid_from_href(sys_href)
|
282
|
+
end
|
283
|
+
|
284
|
+
def net_adap_uuids
|
285
|
+
uuids_from_links("ClientNetworkAdapters")
|
286
|
+
end
|
287
|
+
|
288
|
+
def lhea_ports
|
289
|
+
xml.get_elements("HostEthernetAdapterLogicalPorts/HostEthernetAdapterLogicalPort").map do |elem|
|
290
|
+
HostEthernetAdapterLogicalPort.new(elem)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def sriov_elp_uuids
|
295
|
+
uuids_from_links("SRIOVEthernetLogicalPorts")
|
296
|
+
end
|
297
|
+
|
298
|
+
# Setters
|
299
|
+
|
300
|
+
def name=(name)
|
301
|
+
xml.elements[ATTRS[:name]].text = name
|
302
|
+
@name = name
|
154
303
|
end
|
155
304
|
end
|
156
305
|
|
157
306
|
# Logical Partition information
|
158
307
|
class LogicalPartition < BasePartition
|
308
|
+
def vnic_dedicated_uuids
|
309
|
+
uuids_from_links("DedicatedVirtualNICs")
|
310
|
+
end
|
311
|
+
|
312
|
+
def vscsi_client_uuids
|
313
|
+
uuids_from_links("VirtualSCSIClientAdapters")
|
314
|
+
end
|
315
|
+
|
316
|
+
def vfc_client_uuids
|
317
|
+
uuids_from_links("VirtualFibreChannelClientAdapters")
|
318
|
+
end
|
159
319
|
end
|
160
320
|
|
161
321
|
# VIOS information
|
162
322
|
class VirtualIOServer < BasePartition
|
323
|
+
def pvs
|
324
|
+
xml.get_elements("PhysicalVolumes/PhysicalVolume").map do |elem|
|
325
|
+
PhysicalVolume.new(elem)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def rep
|
330
|
+
elem = xml.elements["MediaRepositories/VirtualMediaRepository"]
|
331
|
+
VirtualMediaRepository.new(elem) unless elem.nil?
|
332
|
+
end
|
333
|
+
|
334
|
+
def vscsi_mappings
|
335
|
+
xml.get_elements("VirtualSCSIMappings/VirtualSCSIMapping").map do |elem|
|
336
|
+
VirtualSCSIMapping.new(elem)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def vfc_mappings
|
341
|
+
xml.get_elements("VirtualFibreChannelMappings/VirtualFibreChannelMapping").map do |elem|
|
342
|
+
VirtualFibreChannelMapping.new(elem)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
# Empty parent class to match K2 schema definition
|
348
|
+
class VirtualSCSIStorage < AbstractNonRest; end
|
349
|
+
|
350
|
+
# Physical Volume information
|
351
|
+
class PhysicalVolume < VirtualSCSIStorage
|
352
|
+
ATTRS = {
|
353
|
+
:location => "LocationCode",
|
354
|
+
:description => "Description",
|
355
|
+
:is_available => "AvailableForUsage",
|
356
|
+
:capacity => "VolumeCapacity",
|
357
|
+
:name => "VolumeName",
|
358
|
+
:is_fc => "IsFibreChannelBacked",
|
359
|
+
:udid => "VolumeUniqueID"
|
360
|
+
}.freeze
|
361
|
+
end
|
362
|
+
|
363
|
+
# Logical Volume information
|
364
|
+
class VirtualDisk < VirtualSCSIStorage
|
365
|
+
ATTRS = {
|
366
|
+
:name => "DiskName",
|
367
|
+
:label => "DiskLabel",
|
368
|
+
:capacity => "DiskCapacity", # In GiB
|
369
|
+
:psize => "PartitionSize",
|
370
|
+
:vg => "VolumeGroup",
|
371
|
+
:udid => "UniqueDeviceID"
|
372
|
+
}.freeze
|
373
|
+
end
|
374
|
+
|
375
|
+
# Virtual CD-ROM information
|
376
|
+
class VirtualOpticalMedia < VirtualSCSIStorage
|
377
|
+
ATTRS = {
|
378
|
+
:name => "MediaName",
|
379
|
+
:udid => "MediaUDID",
|
380
|
+
:mount_opts => "MountType",
|
381
|
+
:size => "Size" # in GiB
|
382
|
+
}.freeze
|
383
|
+
end
|
384
|
+
|
385
|
+
# Virtual Media Repository information
|
386
|
+
class VirtualMediaRepository < AbstractNonRest
|
387
|
+
ATTRS = {
|
388
|
+
:name => "RepositoryName",
|
389
|
+
:size => "RepositorySize" # in GiB
|
390
|
+
}.freeze
|
391
|
+
|
392
|
+
def vopts
|
393
|
+
xml.get_elements("OpticalMedia/VirtualOpticalMedia").map do |elem|
|
394
|
+
VirtualOpticalMedia.new(elem)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Virtual Switch information
|
400
|
+
class VirtualSwitch < AbstractRest
|
401
|
+
ATTRS = {
|
402
|
+
:id => "SwitchID",
|
403
|
+
:mode => "SwitchMode", # "VEB", "VEPA"
|
404
|
+
:name => "SwitchName"
|
405
|
+
}.freeze
|
406
|
+
|
407
|
+
def sys_uuid
|
408
|
+
href.path.split('/')[-3]
|
409
|
+
end
|
410
|
+
|
411
|
+
def networks_uuids
|
412
|
+
uuids_from_links("VirtualNetworks")
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Virtual Network information
|
417
|
+
class VirtualNetwork < AbstractRest
|
418
|
+
ATTRS = {
|
419
|
+
:name => "NetworkName",
|
420
|
+
:vlan_id => "NetworkVLANID",
|
421
|
+
:vswitch_id => "VswitchID",
|
422
|
+
:tagged => "TaggedNetwork"
|
423
|
+
}.freeze
|
424
|
+
|
425
|
+
def vswitch_uuid
|
426
|
+
href = singleton("AssociatedSwitch", "href")
|
427
|
+
uuid_from_href(href)
|
428
|
+
end
|
429
|
+
|
430
|
+
def lpars_uuids
|
431
|
+
uuids_from_links("ConnectedPartitions")
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
# Virtual I/O Adapter information
|
436
|
+
class VirtualIOAdapter < AbstractRest
|
437
|
+
ATTRS = {
|
438
|
+
:type => "AdapterType", # "Server", "Client", "Unknown"
|
439
|
+
:location => "LocationCode",
|
440
|
+
:slot => "VirtualSlotNumber",
|
441
|
+
:required => "RequiredAdapter"
|
442
|
+
}.freeze
|
443
|
+
end
|
444
|
+
|
445
|
+
# Virtual Ethernet Adapter information
|
446
|
+
class VirtualEthernetAdapter < VirtualIOAdapter
|
447
|
+
ATTRS = ATTRS.merge({
|
448
|
+
:macaddr => "MACAddress",
|
449
|
+
:vswitch_id => "VirtualSwitchID",
|
450
|
+
:vlan_id => "PortVLANID",
|
451
|
+
:location => "LocationCode"
|
452
|
+
}.freeze)
|
453
|
+
|
454
|
+
def vswitch_uuid
|
455
|
+
uuids_from_links("AssociatedVirtualSwitch").first
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
# Client Network Adapter information
|
460
|
+
class ClientNetworkAdapter < VirtualEthernetAdapter
|
461
|
+
def networks_uuids
|
462
|
+
uuids_from_links("VirtualNetworks")
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
# LP-HEA information
|
467
|
+
class EthernetBackingDevice < IOAdapter; end
|
468
|
+
class HostEthernetAdapterLogicalPort < EthernetBackingDevice
|
469
|
+
ATTRS = ATTRS.merge({
|
470
|
+
:macaddr => "MACAddress",
|
471
|
+
:port_id => "LogicalPortID",
|
472
|
+
:state => "PortState",
|
473
|
+
:location => "HEALogicalPortPhysicalLocation"
|
474
|
+
}.freeze)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Virtual NIC dedicated information
|
478
|
+
class VirtualNICDedicated < VirtualIOAdapter
|
479
|
+
ATTRS = ATTRS.merge({
|
480
|
+
:location => "DynamicReconfigurationConnectorName", # overrides VirtualIOAdapter
|
481
|
+
:macaddr => "Details/MACAddress",
|
482
|
+
:os_devname => "Details/OSDeviceName",
|
483
|
+
:port_vlan_id => "Details/PortVLANID"
|
484
|
+
}.freeze)
|
485
|
+
end
|
486
|
+
|
487
|
+
# SR-IOV Configured Logical Port information
|
488
|
+
class SRIOVConfiguredLogicalPort < AbstractRest
|
489
|
+
ATTRS = {
|
490
|
+
:port_id => "LogicalPortID",
|
491
|
+
:port_vlan_id => "PortVLANID",
|
492
|
+
:location => "LocationCode",
|
493
|
+
:dr_name => "DynamicReconfigurationConnectorName",
|
494
|
+
:devname => "DeviceName",
|
495
|
+
:capacity => "ConfiguredCapacity"
|
496
|
+
}.freeze
|
497
|
+
|
498
|
+
def lpars_uuids
|
499
|
+
uuids_from_links("AssociatedLogicalPartitions")
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
# SR-IOV Ethernet Logical Port information
|
504
|
+
class SRIOVEthernetLogicalPort < SRIOVConfiguredLogicalPort
|
505
|
+
ATTRS = ATTRS.merge({
|
506
|
+
:macaddr => "MACAddress"
|
507
|
+
}.freeze)
|
508
|
+
end
|
509
|
+
|
510
|
+
# Virtual SCSI mapping information
|
511
|
+
class VirtualSCSIMapping < AbstractNonRest
|
512
|
+
def lpar_uuid
|
513
|
+
href = singleton("AssociatedLogicalPartition", "href")
|
514
|
+
uuid_from_href(href)
|
515
|
+
end
|
516
|
+
|
517
|
+
def client
|
518
|
+
elem = xml.elements["ClientAdapter"]
|
519
|
+
VirtualSCSIClientAdapter.new(elem) unless elem.nil?
|
520
|
+
end
|
521
|
+
|
522
|
+
def server
|
523
|
+
elem = xml.elements["ServerAdapter"]
|
524
|
+
VirtualSCSIServerAdapter.new(elem) unless elem.nil?
|
525
|
+
end
|
526
|
+
|
527
|
+
def storage
|
528
|
+
# Possible storage types are:
|
529
|
+
# LogicalUnit, PhysicalVolume, VirtualDisk, VirtualOpticalMedia
|
530
|
+
elem = xml.elements["Storage/*[1]"]
|
531
|
+
Module.const_get("IbmPowerHmc::#{elem.name}").new(elem) unless elem.nil?
|
532
|
+
end
|
533
|
+
|
534
|
+
def device
|
535
|
+
# Possible backing device types are:
|
536
|
+
# LogicalVolumeVirtualTargetDevice, PhysicalVolumeVirtualTargetDevice,
|
537
|
+
# SharedStoragePoolLogicalUnitVirtualTargetDevice, VirtualOpticalTargetDevice
|
538
|
+
elem = xml.elements["TargetDevice/*[1]"]
|
539
|
+
Module.const_get("IbmPowerHmc::#{elem.name}").new(elem) unless elem.nil?
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
# Virtual SCSI adapter (common class for Client and Server)
|
544
|
+
class VirtualSCSIAdapter < VirtualIOAdapter
|
545
|
+
ATTRS = ATTRS.merge({
|
546
|
+
:name => "AdapterName",
|
547
|
+
:backdev => "BackingDeviceName",
|
548
|
+
:remote_backdev => "RemoteBackingDeviceName",
|
549
|
+
:remote_lpar_id => "RemoteLogicalPartitionID",
|
550
|
+
:remote_slot => "RemoteSlotNumber",
|
551
|
+
:server_location => "ServerLocationCode",
|
552
|
+
:udid => "UniqueDeviceID"
|
553
|
+
}.freeze)
|
554
|
+
end
|
555
|
+
|
556
|
+
# Virtual SCSI client adapter information
|
557
|
+
class VirtualSCSIClientAdapter < VirtualSCSIAdapter
|
558
|
+
def server
|
559
|
+
elem = xml.elements["ServerAdapter"]
|
560
|
+
VirtualSCSIServerAdapter.new(elem) unless elem.nil?
|
561
|
+
end
|
562
|
+
|
563
|
+
def vios_uuid
|
564
|
+
href = singleton("ConnectingPartition", "href")
|
565
|
+
uuid_from_href(href)
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
# Virtual SCSI server adapter information
|
570
|
+
class VirtualSCSIServerAdapter < VirtualSCSIAdapter; end
|
571
|
+
|
572
|
+
# Virtual target device information
|
573
|
+
class VirtualTargetDevice < AbstractNonRest
|
574
|
+
ATTRS = {
|
575
|
+
:lun => "LogicalUnitAddress",
|
576
|
+
:parent => "ParentName",
|
577
|
+
:target => "TargetName",
|
578
|
+
:udid => "UniqueDeviceID"
|
579
|
+
}.freeze
|
580
|
+
end
|
581
|
+
|
582
|
+
# LV backing device information
|
583
|
+
class LogicalVolumeVirtualTargetDevice < VirtualTargetDevice; end
|
584
|
+
|
585
|
+
# PV backing device information
|
586
|
+
class PhysicalVolumeVirtualTargetDevice < VirtualTargetDevice; end
|
587
|
+
|
588
|
+
# LU backing device information
|
589
|
+
class SharedStoragePoolLogicalUnitVirtualTargetDevice < VirtualTargetDevice
|
590
|
+
ATTRS = ATTRS.merge({
|
591
|
+
:cluster_id => "ClusterID",
|
592
|
+
:path => "PathName",
|
593
|
+
:raid_level => "RAIDLevel"
|
594
|
+
}.freeze)
|
595
|
+
end
|
596
|
+
|
597
|
+
# Virtual CD backing device information
|
598
|
+
class VirtualOpticalTargetDevice < VirtualTargetDevice
|
599
|
+
def media
|
600
|
+
elem = xml.elements["VirtualOpticalMedia"]
|
601
|
+
VirtualOpticalMedia.new(elem) unless elem.nil?
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
# VFC mapping information
|
606
|
+
class VirtualFibreChannelMapping < AbstractNonRest
|
607
|
+
def lpar_uuid
|
608
|
+
href = singleton("AssociatedLogicalPartition", "href")
|
609
|
+
uuid_from_href(href)
|
610
|
+
end
|
611
|
+
|
612
|
+
def client
|
613
|
+
elem = xml.elements["ClientAdapter"]
|
614
|
+
VirtualFibreChannelClientAdapter.new(elem) unless elem.nil?
|
615
|
+
end
|
616
|
+
|
617
|
+
def server
|
618
|
+
elem = xml.elements["ServerAdapter"]
|
619
|
+
VirtualFibreChannelServerAdapter.new(elem) unless elem.nil?
|
620
|
+
end
|
621
|
+
|
622
|
+
def port
|
623
|
+
elem = xml.elements["Port"]
|
624
|
+
PhysicalFibreChannelPort.new(elem) unless elem.nil?
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
# VFC adapter information
|
629
|
+
class VirtualFibreChannelAdapter < VirtualIOAdapter
|
630
|
+
ATTRS = ATTRS.merge({
|
631
|
+
:name => "AdapterName",
|
632
|
+
:lpar_id => "ConnectingPartitionID",
|
633
|
+
:slot => "ConnectingVirtualSlotNumber",
|
634
|
+
:udid => "UniqueDeviceID"
|
635
|
+
}.freeze)
|
636
|
+
|
637
|
+
def lpar_uuid
|
638
|
+
href = singleton("ConnectingPartition", "href")
|
639
|
+
uuid_from_href(href)
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
# VFC client information
|
644
|
+
class VirtualFibreChannelClientAdapter < VirtualFibreChannelAdapter
|
645
|
+
def nport_loggedin
|
646
|
+
xml.get_elements("NportLoggedInStatus/VirtualFibreChannelNPortLoginStatus").map do |elem|
|
647
|
+
VirtualFibreChannelNPortLoginStatus.new(elem)
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
def server
|
652
|
+
elem = xml.elements["ServerAdapter"]
|
653
|
+
VirtualFibreChannelServerAdapter.new(elem) unless elem.nil?
|
654
|
+
end
|
655
|
+
|
656
|
+
def wwpns
|
657
|
+
singleton("WWPNs")&.split
|
658
|
+
end
|
659
|
+
|
660
|
+
def os_disks
|
661
|
+
xml.get_elements("OperatingSystemDisks/OperatingSystemDisk/Name").map do |elem|
|
662
|
+
elem.text&.strip
|
663
|
+
end.compact
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
# VFC port status
|
668
|
+
class VirtualFibreChannelNPortLoginStatus < AbstractNonRest
|
669
|
+
ATTRS = {
|
670
|
+
:wwpn => "WWPN",
|
671
|
+
:wwpn_status => "WWPNStatus",
|
672
|
+
:loggedin_by => "LoggedInBy",
|
673
|
+
:reason => "StatusReason"
|
674
|
+
}.freeze
|
675
|
+
end
|
676
|
+
|
677
|
+
# VFC server information
|
678
|
+
class VirtualFibreChannelServerAdapter < VirtualFibreChannelAdapter
|
679
|
+
ATTRS = ATTRS.merge({
|
680
|
+
:map_port => "MapPort"
|
681
|
+
}.freeze)
|
682
|
+
|
683
|
+
def port
|
684
|
+
elem = xml.elements["PhysicalPort"]
|
685
|
+
PhysicalFibreChannelPort.new(elem) unless elem.nil?
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
# FC port information
|
690
|
+
class PhysicalFibreChannelPort < AbstractNonRest
|
691
|
+
ATTRS = {
|
692
|
+
:location => "LocationCode",
|
693
|
+
:name => "PortName",
|
694
|
+
:udid => "UniqueDeviceID",
|
695
|
+
:wwpn => "WWPN",
|
696
|
+
:wwnn => "WWNN",
|
697
|
+
:avail_ports => "AvailablePorts",
|
698
|
+
:total_ports => "TotalPorts"
|
699
|
+
}.freeze
|
700
|
+
|
701
|
+
def pvs
|
702
|
+
xml.get_elements("PhysicalVolumes/PhysicalVolume").map do |elem|
|
703
|
+
PhysicalVolume.new(elem)
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
# Cluster information
|
709
|
+
class Cluster < AbstractRest
|
710
|
+
ATTRS = {
|
711
|
+
:name => "ClusterName",
|
712
|
+
:id => "ClusterID",
|
713
|
+
:tier_capable => "ClusterCapabilities/IsTierCapable"
|
714
|
+
}.freeze
|
715
|
+
|
716
|
+
def ssp_uuid
|
717
|
+
href = singleton("ClusterSharedStoragePool", "href")
|
718
|
+
uuid_from_href(href)
|
719
|
+
end
|
720
|
+
|
721
|
+
def nodes
|
722
|
+
xml.get_elements("Node/Node").map do |elem|
|
723
|
+
Node.new(elem)
|
724
|
+
end
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
# Cluster node information
|
729
|
+
class Node < AbstractNonRest
|
730
|
+
ATTRS = {
|
731
|
+
:hostname => "HostName",
|
732
|
+
:lpar_id => "PartitionID",
|
733
|
+
:state => "State",
|
734
|
+
:ioslevel => "VirtualIOServerLevel"
|
735
|
+
}.freeze
|
736
|
+
|
737
|
+
def vios_uuid
|
738
|
+
href = singleton("VirtualIOServer", "href")
|
739
|
+
uuid_from_href(href)
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
# SSP information
|
744
|
+
class SharedStoragePool < AbstractRest
|
745
|
+
ATTRS = {
|
746
|
+
:name => "StoragePoolName",
|
747
|
+
:udid => "UniqueDeviceID",
|
748
|
+
:capacity => "Capacity",
|
749
|
+
:free_space => "FreeSpace",
|
750
|
+
:overcommit => "OverCommitSpace",
|
751
|
+
:total_lu_size => "TotalLogicalUnitSize",
|
752
|
+
:alert_threshold => "AlertThreshold"
|
753
|
+
}.freeze
|
754
|
+
|
755
|
+
def cluster_uuid
|
756
|
+
href = singleton("AssociatedCluster", "href")
|
757
|
+
uuid_from_href(href)
|
758
|
+
end
|
759
|
+
|
760
|
+
def pvs
|
761
|
+
xml.get_elements("PhysicalVolumes/PhysicalVolume").map do |elem|
|
762
|
+
PhysicalVolume.new(elem)
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
def tiers_uuids
|
767
|
+
uuids_from_links("AssociatedTiers")
|
768
|
+
end
|
769
|
+
|
770
|
+
def lus
|
771
|
+
xml.get_elements("LogicalUnits/LogicalUnit").map do |elem|
|
772
|
+
LogicalUnit.new(elem)
|
773
|
+
end
|
774
|
+
end
|
775
|
+
end
|
776
|
+
|
777
|
+
# SSP tier information
|
778
|
+
class Tier < AbstractRest
|
779
|
+
ATTRS = {
|
780
|
+
:name => "Name",
|
781
|
+
:udid => "UniqueDeviceID",
|
782
|
+
:type => "Type",
|
783
|
+
:capacity => "Capacity",
|
784
|
+
:total_lu_size => "TotalLogicalUnitSize",
|
785
|
+
:is_default => "IsDefault",
|
786
|
+
:free_space => "FreeSpace"
|
787
|
+
}.freeze
|
788
|
+
|
789
|
+
def ssp_uuid
|
790
|
+
href = singleton("AssociatedSharedStoragePool", "href")
|
791
|
+
uuid_from_href(href)
|
792
|
+
end
|
793
|
+
|
794
|
+
def lus_uuids
|
795
|
+
uuids_from_links("AssociatedLogicalUnits")
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
# SSP LU information
|
800
|
+
class LogicalUnit < VirtualSCSIStorage
|
801
|
+
ATTRS = {
|
802
|
+
:name => "UnitName",
|
803
|
+
:capacity => "UnitCapacity",
|
804
|
+
:udid => "UniqueDeviceID",
|
805
|
+
:thin => "ThinDevice",
|
806
|
+
:type => "LogicalUnitType",
|
807
|
+
:in_use => "InUse"
|
808
|
+
}.freeze
|
809
|
+
end
|
810
|
+
|
811
|
+
class PartitionTemplateSummary < AbstractRest
|
812
|
+
ATTRS = {
|
813
|
+
:name => "partitionTemplateName"
|
814
|
+
}.freeze
|
815
|
+
end
|
816
|
+
|
817
|
+
class PartitionTemplate < AbstractRest
|
818
|
+
ATTRS = {
|
819
|
+
:name => "partitionTemplateName",
|
820
|
+
:description => "description",
|
821
|
+
:os => "logicalPartitionConfig/osVersion",
|
822
|
+
:memory => "logicalPartitionConfig/memoryConfiguration/currMemory"
|
823
|
+
}.freeze
|
163
824
|
end
|
164
825
|
|
165
826
|
# HMC Event
|
166
827
|
class Event < AbstractRest
|
828
|
+
attr_accessor :usertask
|
167
829
|
ATTRS = {
|
168
830
|
:id => "EventID",
|
169
831
|
:type => "EventType",
|
@@ -192,9 +854,9 @@ module IbmPowerHmc
|
|
192
854
|
|
193
855
|
def results
|
194
856
|
results = {}
|
195
|
-
xml.each_element("Results/JobParameter") do |
|
196
|
-
name =
|
197
|
-
value =
|
857
|
+
xml.each_element("Results/JobParameter") do |jobparam|
|
858
|
+
name = jobparam.elements["ParameterName"]&.text&.strip
|
859
|
+
value = jobparam.elements["ParameterValue"]&.text&.strip
|
198
860
|
results[name] = value unless name.nil?
|
199
861
|
end
|
200
862
|
results
|