ibm_power_hmc 0.3.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,16 +4,26 @@ require 'time'
4
4
  require 'uri'
5
5
 
6
6
  module IbmPowerHmc
7
- # Parser for HMC feeds and entries.
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
- # HMC generic XML entry
57
- class AbstractRest
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 :uuid, :published, :etag, :xml
86
+ attr_reader :xml
60
87
 
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)
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 = text_element(xpath)
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 define_attrs(hash)
77
- hash.each do |key, value|
78
- define_attr(key, value)
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 text_element(xpath)
83
- xml.elements[xpath]&.text&.strip
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 extract_uuid_from_href(href)
87
- URI(href).path.split('/').last
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
- xml.get_elements("ManagedSystems/link").map do |link|
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 lpars_uuids
124
- xml.get_elements("AssociatedLogicalPartitions/link").map do |link|
125
- extract_uuid_from_href(link.attributes["href"])
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
- xml.get_elements("AssociatedVirtualIOServers/link").map do |link|
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
- :ref_code => "ReferenceCode"
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 = xml.elements["AssociatedManagedSystem"].attributes["href"]
153
- extract_uuid_from_href(sys_href)
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 |result|
196
- name = result.elements["ParameterName"]&.text&.strip
197
- value = result.elements["ParameterValue"]&.text&.strip
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