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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6aae673197b8e5426c2f75250ef521db9d7e8eed79a20c70089612a10d189cfc
4
- data.tar.gz: f7b5cd95629fedf835a97eebd33874edf777527cb8af2c4c5ebdbaaf9364d4d8
3
+ metadata.gz: 9c95e9629a205e4276acce5737764da0da1cda5f5eb31dc7eef6adb72c12b3f4
4
+ data.tar.gz: 8b6c5e4f244cdfe42a317eaa95c992913aab9c387b90de04829fcfa9a6446775
5
5
  SHA512:
6
- metadata.gz: 793385e1153eff3f9d4bdb8eafe62365a92f0d7fcde75452c1327c36de86b99b2ffd011bf05a57ec9101b4d2d6e84139bc4e86e6cb83347aadef1f0fe5e10b1c
7
- data.tar.gz: 3eedcfd6693b0ac13c725488c1f13bb6433e94b136eaebf1c48f4118582b7ed937ad0e6fe1d06f8c74d209eb67f885e181cc26b7b60683f837628f9fc5ed4f3c
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
@@ -2,6 +2,6 @@ AllCops:
2
2
  Exclude:
3
3
  - '*.gemspec'
4
4
  Layout/HashAlignment:
5
- EnforcedHashRocketStyle: key
5
+ Enabled: false
6
6
  Style/ConditionalAssignment:
7
- EnforcedStyle: assign_inside_condition
7
+ Enabled: false
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
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
- "xmlns" => "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/",
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
- parse_feed(doc, ManagementConsole).first
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
- doc = REXML::Document.new(response.body)
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 logical partition.
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
- doc = REXML::Document.new(response.body)
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
- doc = REXML::Document.new(response.body)
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
- doc = REXML::Document.new(response.body)
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 vioses(sys_uuid = nil)
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
- doc = REXML::Document.new(response.body)
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
- doc = REXML::Document.new(response.body)
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
- doc = REXML::Document.new(response.body)
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
- doc = REXML::Document.new(err.response.body)
360
- entry = doc.elements["entry"]
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=#{@message} status=#{@status} reason=#{@reason} uri=#{@uri}"
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({"X-API-Session" => @api_session_token})
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
@@ -24,7 +24,7 @@ module IbmPowerHmc
24
24
  end
25
25
 
26
26
  ##
27
- # @!method status
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
- "xmlns:JobRequest" => "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/",
37
- "xmlns" => "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/",
38
- "schemaVersion" => "V1_1_0"
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
- # Damien: ProgressType?
44
- jobparams = doc.root.add_element("JobParameters", {"schemaVersion" => "V1_1_0"})
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", {"schemaVersion" => "V1_1_0"})
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
- doc = REXML::Document.new(response.body)
52
- info = doc.root.elements["content/JobResponse:JobResponse"]
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
- doc = REXML::Document.new(response.body)
72
- info = doc.root.elements["content/JobResponse:JobResponse"]
73
- status = info.elements["Status"].text
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
- status = wait(timeout, poll_interval)
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
@@ -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 [String] Start timestamp.
13
- # @param end_ts [String] End timestamp.
48
+ # @param start_ts [Time] Start timestamp.
49
+ # @param end_ts [Time] End timestamp.
14
50
  # @param no_samples [Integer] Number of samples.
15
- # @return [Array<Hash>] The processed metrics for the managed system.
16
- def managed_system_metrics(sys_uuid:, start_ts: nil, end_ts: nil, no_samples: nil)
17
- method_url = "/rest/api/pcm/ManagedSystem/#{sys_uuid}/ProcessedMetrics"
18
- query = []
19
- query << "StartTS=#{start_ts}" unless start_ts.nil?
20
- query << "EndTS=#{end_ts}" unless end_ts.nil?
21
- query << "NoOfSamples=#{no_samples}" unless no_samples.nil?
22
- method_url += "?" + query.compact.join('&') unless query.empty?
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
- doc = REXML::Document.new(response.body)
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.to_s)
41
- metrics << JSON.parse(response.body)
42
- end
43
- metrics
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IbmPowerHmc
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.1"
5
5
  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/objects.rb"
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.2
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-09-29 00:00:00.000000000 Z
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/objects.rb
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.0.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