ibm_power_hmc 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 397feab84db9812185ab1125cd6778b52a1848519d6bae5950d69cb31e9b4845
4
- data.tar.gz: 27dd4d94cd61a19c66d0d6e438c17987ea5926af78b7677b5044a11a50acdb18
3
+ metadata.gz: e42aa4d6eaa8915b8c37ce96aab995801533b81d8fa70b1e351bc550cc6eaa02
4
+ data.tar.gz: 6022fb088c67eeb0c20e8435c20567ef62fb34e365419cfa20f6fb9bc1e769f5
5
5
  SHA512:
6
- metadata.gz: 1171816de48bed97b1837ab39d3bd639772928ebee98fb8f287c85006196bdf068320599b921a239d10d5ce74e98629cde754eca14b12c6cf6be85477e7a7fb3
7
- data.tar.gz: 10f7397e58acab288715283de98480caf915fb628021b2f8c5261b13b2c7b273cdec5e1d7a52b35560acbe5cae6dfed5c9e68516673d97ff5f91a9fb44daa370
6
+ metadata.gz: 7ca0280aaeff1a1a0ce0cf5c53c40b6f0ddfc94725536e53d19031b1b107de4c8b44919580eaf1716e60f302bf339363508597b9188634412511bcc7869e4f83
7
+ data.tar.gz: b0251d621a729e2b7d97c7655709fd68bd1e796466967f2021924ab7658a12c2dc13c34dfe71597f96f6ed2114e24c405362232c4dab2e88b653afbe2b7d679a
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ /Gemfile.lock
1
2
  /.bundle/
2
3
  /.yardoc
3
4
  /_yardoc/
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ inherit_gem:
2
+ manageiq-style: ".rubocop_base.yml"
3
+ inherit_from:
4
+ - ".rubocop_local.yml"
@@ -0,0 +1,7 @@
1
+ AllCops:
2
+ Exclude:
3
+ - '*.gemspec'
4
+ Layout/HashAlignment:
5
+ Enabled: false
6
+ Style/ConditionalAssignment:
7
+ Enabled: false
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
@@ -2,10 +2,21 @@
2
2
 
3
3
  # Module for IBM HMC Rest API Client
4
4
  module IbmPowerHmc
5
- # HMC REST Client connection
5
+ class Error < StandardError; end
6
+
7
+ ##
8
+ # HMC REST Client connection.
6
9
  class Connection
10
+ ##
11
+ # @!method initialize(host:, username: "hscroot", password:, port: 12_443, validate_ssl: true)
12
+ # Create a new HMC connection.
13
+ #
14
+ # @param host [String] Hostname of the HMC.
15
+ # @param username [String] User name.
16
+ # @param password [String] Password.
17
+ # @param port [Integer] TCP port number.
18
+ # @param validate_ssl [Boolean] Verify SSL certificates.
7
19
  def initialize(host:, username: "hscroot", password:, port: 12_443, validate_ssl: true)
8
- # Damien: use URI::HTTPS
9
20
  @hostname = "#{host}:#{port}"
10
21
  @username = username
11
22
  @password = password
@@ -13,72 +24,107 @@ module IbmPowerHmc
13
24
  @api_session_token = nil
14
25
  end
15
26
 
27
+ ##
28
+ # @!method logon
29
+ # Establish a trusted session with the Web Services APIs.
30
+ # @return [String] The X-API-Session token.
16
31
  def logon
17
32
  method_url = "/rest/api/web/Logon"
18
33
  headers = {
19
- content_type: "application/vnd.ibm.powervm.web+xml; type=LogonRequest"
34
+ :content_type => "application/vnd.ibm.powervm.web+xml; type=LogonRequest"
20
35
  }
21
36
  doc = REXML::Document.new("")
22
- doc.add_element("LogonRequest", {
23
- "xmlns" => "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/",
24
- "schemaVersion" => "V1_1_0"
25
- })
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/")
26
39
  doc.root.add_element("UserID").text = @username
27
40
  doc.root.add_element("Password").text = @password
28
41
 
29
- # Damien: begin/rescue
30
42
  @api_session_token = ""
31
43
  response = request(:put, method_url, headers, doc.to_s)
32
44
  doc = REXML::Document.new(response.body)
33
- @api_session_token = doc.root.elements["X-API-Session"].text
45
+ elem = doc.elements["LogonResponse/X-API-Session"]
46
+ raise Error, "LogonResponse/X-API-Session not found" if elem.nil?
47
+
48
+ @api_session_token = elem.text
34
49
  end
35
50
 
51
+ ##
52
+ # @!method logoff
53
+ # Close the session.
36
54
  def logoff
55
+ # Don't want to trigger automatic logon here!
56
+ return if @api_session_token.nil?
57
+
37
58
  method_url = "/rest/api/web/Logon"
38
- request(:delete, method_url)
59
+ begin
60
+ request(:delete, method_url)
61
+ rescue
62
+ # Ignore exceptions as this is best effort attempt to log off.
63
+ end
39
64
  @api_session_token = nil
40
65
  end
41
66
 
67
+ ##
68
+ # @!method management_console
69
+ # Retrieve information about the management console.
70
+ # @return [IbmPowerHmc::ManagementConsole] The management console.
42
71
  def management_console
43
72
  method_url = "/rest/api/uom/ManagementConsole"
44
73
  response = request(:get, method_url)
45
- doc = REXML::Document.new(response.body)
46
- entry = doc.root.elements["entry"]
47
- ManagementConsole.new(entry)
74
+ # This request returns a feed with a single entry.
75
+ FeedParser.new(response.body).objects(:ManagementConsole).first
48
76
  end
49
77
 
50
- def managed_systems
78
+ ##
79
+ # @!method managed_systems(search = {})
80
+ # Retrieve the list of systems managed by the HMC.
81
+ # @param search [Hash] The optional property name and value to match.
82
+ # @return [Array<IbmPowerHmc::ManagedSystem>] The list of managed systems.
83
+ def managed_systems(search = {})
51
84
  method_url = "/rest/api/uom/ManagedSystem"
85
+ search.each { |key, value| method_url += "/search/(#{key}==#{value})" }
52
86
  response = request(:get, method_url)
53
- doc = REXML::Document.new(response.body)
54
- systems = []
55
- return systems if doc.root.nil?
87
+ FeedParser.new(response.body).objects(:ManagedSystem)
88
+ end
56
89
 
57
- doc.root.each_element("entry") do |entry|
58
- system = ManagedSystem.new(entry)
59
- systems += [system]
60
- end
61
- systems
90
+ ##
91
+ # @!method managed_system(lpar_uuid, sys_uuid = nil, group_name = nil)
92
+ # Retrieve information about a managed system.
93
+ # @param sys_uuid [String] The UUID of the managed system.
94
+ # @param group_name [String] The extended group attributes.
95
+ # @return [IbmPowerHmc::ManagedSystem] The managed system.
96
+ def managed_system(sys_uuid, group_name = nil)
97
+ method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}"
98
+ method_url += "?group=#{group_name}" unless group_name.nil?
99
+
100
+ response = request(:get, method_url)
101
+ Parser.new(response.body).object(:ManagedSystem)
62
102
  end
63
103
 
64
- def lpars(sys_uuid = nil)
104
+ ##
105
+ # @!method lpars(sys_uuid = nil, search = {})
106
+ # Retrieve the list of logical partitions managed by the HMC.
107
+ # @param sys_uuid [String] The UUID of the managed system.
108
+ # @param search [Hash] The optional property name and value to match.
109
+ # @return [Array<IbmPowerHmc::LogicalPartition>] The list of logical partitions.
110
+ def lpars(sys_uuid = nil, search = {})
65
111
  if sys_uuid.nil?
66
112
  method_url = "/rest/api/uom/LogicalPartition"
113
+ search.each { |key, value| method_url += "/search/(#{key}==#{value})" }
67
114
  else
68
115
  method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/LogicalPartition"
69
116
  end
70
117
  response = request(:get, method_url)
71
- doc = REXML::Document.new(response.body)
72
- lpars = []
73
- return lpars if doc.root.nil?
74
-
75
- doc.root.each_element("entry") do |entry|
76
- lpar = LogicalPartition.new(entry)
77
- lpars += [lpar]
78
- end
79
- lpars
118
+ FeedParser.new(response.body).objects(:LogicalPartition)
80
119
  end
81
120
 
121
+ ##
122
+ # @!method lpar(lpar_uuid, sys_uuid = nil, group_name = nil)
123
+ # Retrieve information about a logical partition.
124
+ # @param lpar_uuid [String] The UUID of the logical partition.
125
+ # @param sys_uuid [String] The UUID of the managed system.
126
+ # @param group_name [String] The extended group attributes.
127
+ # @return [IbmPowerHmc::LogicalPartition] The logical partition.
82
128
  def lpar(lpar_uuid, sys_uuid = nil, group_name = nil)
83
129
  if sys_uuid.nil?
84
130
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}"
@@ -88,11 +134,15 @@ module IbmPowerHmc
88
134
  method_url += "?group=#{group_name}" unless group_name.nil?
89
135
 
90
136
  response = request(:get, method_url)
91
- doc = REXML::Document.new(response.body)
92
- entry = doc.elements["entry"]
93
- LogicalPartition.new(entry)
137
+ Parser.new(response.body).object(:LogicalPartition)
94
138
  end
95
139
 
140
+ ##
141
+ # @!method lpar_quick_property(lpar_uuid, property_name)
142
+ # Retrieve a quick property of a logical partition.
143
+ # @param lpar_uuid [String] The UUID of the logical partition.
144
+ # @param property_name [String] The quick property name.
145
+ # @return [String] The quick property value.
96
146
  def lpar_quick_property(lpar_uuid, property_name)
97
147
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/quick/#{property_name}"
98
148
 
@@ -100,141 +150,292 @@ module IbmPowerHmc
100
150
  response.body[1..-2]
101
151
  end
102
152
 
103
- def vioses(sys_uuid = nil)
153
+ ##
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 = {})
170
+ # Retrieve the list of virtual I/O servers managed by the HMC.
171
+ # @param sys_uuid [String] The UUID of the managed system.
172
+ # @param search [Hash] The optional property name and value to match.
173
+ # @return [Array<IbmPowerHmc::VirtualIOServer>] The list of virtual I/O servers.
174
+ def vioses(sys_uuid = nil, search = {})
104
175
  if sys_uuid.nil?
105
176
  method_url = "/rest/api/uom/VirtualIOServer"
177
+ search.each { |key, value| method_url += "/search/(#{key}==#{value})" }
106
178
  else
107
179
  method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/VirtualIOServer"
108
180
  end
109
- begin
110
- response = request(:get, method_url)
111
- rescue StandardError
112
- return []
113
- end
114
- doc = REXML::Document.new(response.body)
115
- vioses = []
116
- return vioses if doc.root.nil?
117
-
118
- doc.root.each_element("entry") do |entry|
119
- vios = VirtualIOServer.new(entry)
120
- vioses += [vios]
121
- end
122
- vioses
181
+ response = request(:get, method_url)
182
+ FeedParser.new(response.body).objects(:VirtualIOServer)
123
183
  end
124
184
 
125
- # Damien: share the same method for VIOS and LPAR?
126
- def lpar_profiles(lpar_uuid)
127
- method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/LogicalPartitionProfile"
128
- begin
129
- response = request(:get, method_url)
130
- rescue StandardError
131
- return []
185
+ ##
186
+ # @!method vios(vios_uuid, sys_uuid = nil, group_name = nil)
187
+ # Retrieve information about a virtual I/O server.
188
+ # @param vios_uuid [String] The UUID of the virtual I/O server.
189
+ # @param sys_uuid [String] The UUID of the managed system.
190
+ # @param group_name [String] The extended group attributes.
191
+ # @return [IbmPowerHmc::VirtualIOServer] The virtual I/O server.
192
+ def vios(vios_uuid, sys_uuid = nil, group_name = nil)
193
+ if sys_uuid.nil?
194
+ method_url = "/rest/api/uom/VirtualIOServer/#{vios_uuid}"
195
+ else
196
+ method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/VirtualIOServer/#{vios_uuid}"
132
197
  end
133
- doc = REXML::Document.new(response.body)
134
- profiles = []
135
- return profiles if doc.root.nil?
198
+ method_url += "?group=#{group_name}" unless group_name.nil?
136
199
 
137
- doc.root.each_element("entry") do |entry|
138
- profile = LogicalPartitionProfile.new(lpar_uuid, entry)
139
- profiles += [profile]
140
- end
141
- profiles
200
+ response = request(:get, method_url)
201
+ Parser.new(response.body).object(:VirtualIOServer)
142
202
  end
143
203
 
144
- def poweron_lpar(lpar_uuid, params = {})
204
+ ##
205
+ # @!method poweron_lpar(lpar_uuid, params = {}, sync = true)
206
+ # Power on a logical partition.
207
+ # @param lpar_uuid [String] The UUID of the logical partition.
208
+ # @param params [Hash] Job parameters.
209
+ # @param sync [Boolean] Start the job and wait for its completion.
210
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
211
+ def poweron_lpar(lpar_uuid, params = {}, sync = true)
145
212
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/do/PowerOn"
146
213
 
147
214
  job = HmcJob.new(self, method_url, "PowerOn", "LogicalPartition", params)
148
- job.start
149
- job.wait
150
- job.delete
215
+ job.run if sync
216
+ job
151
217
  end
152
218
 
153
- def poweroff_lpar(lpar_uuid, params = {})
219
+ ##
220
+ # @!method poweroff_lpar(lpar_uuid, params = {}, sync = true)
221
+ # Power off a logical partition.
222
+ # @param lpar_uuid [String] The UUID of the logical partition.
223
+ # @param params [Hash] Job parameters.
224
+ # @param sync [Boolean] Start the job and wait for its completion.
225
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
226
+ def poweroff_lpar(lpar_uuid, params = {}, sync = true)
154
227
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/do/PowerOff"
155
228
 
156
229
  job = HmcJob.new(self, method_url, "PowerOff", "LogicalPartition", params)
157
- job.start
158
- job.wait
159
- job.delete
230
+ job.run if sync
231
+ job
160
232
  end
161
233
 
162
- # Damien: share with poweron_lpar?
163
- def poweron_vios(vios_uuid, params = {})
234
+ ##
235
+ # @!method poweron_vios(vios_uuid, params = {}, sync = true)
236
+ # Power on a virtual I/O server.
237
+ # @param vios_uuid [String] The UUID of the virtual I/O server.
238
+ # @param params [Hash] Job parameters.
239
+ # @param sync [Boolean] Start the job and wait for its completion.
240
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
241
+ def poweron_vios(vios_uuid, params = {}, sync = true)
164
242
  method_url = "/rest/api/uom/VirtualIOServer/#{vios_uuid}/do/PowerOn"
165
243
 
166
244
  job = HmcJob.new(self, method_url, "PowerOn", "VirtualIOServer", params)
167
- job.start
168
- job.wait
169
- job.delete
245
+ job.run if sync
246
+ job
170
247
  end
171
248
 
172
- # Damien: share with poweroff_lpar?
173
- def poweroff_vios(vios_uuid, params = {})
249
+ ##
250
+ # @!method poweroff_vios(vios_uuid, params = {}, sync = true)
251
+ # Power off a virtual I/O server.
252
+ # @param vios_uuid [String] The UUID of the virtual I/O server.
253
+ # @param params [Hash] Job parameters.
254
+ # @param sync [Boolean] Start the job and wait for its completion.
255
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
256
+ def poweroff_vios(vios_uuid, params = {}, sync = true)
174
257
  method_url = "/rest/api/uom/VirtualIOServer/#{vios_uuid}/do/PowerOff"
175
258
 
176
259
  job = HmcJob.new(self, method_url, "PowerOff", "VirtualIOServer", params)
177
- job.start
178
- job.wait
179
- job.delete
260
+ job.run if sync
261
+ job
180
262
  end
181
263
 
182
- def poweron_managed_system(sys_uuid, params = {})
264
+ ##
265
+ # @!method poweron_managed_system(sys_uuid, params = {}, sync = true)
266
+ # Power on a managed system.
267
+ # @param sys_uuid [String] The UUID of the managed system.
268
+ # @param params [Hash] Job parameters.
269
+ # @param sync [Boolean] Start the job and wait for its completion.
270
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
271
+ def poweron_managed_system(sys_uuid, params = {}, sync = true)
183
272
  method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/do/PowerOn"
184
273
 
185
274
  job = HmcJob.new(self, method_url, "PowerOn", "ManagedSystem", params)
186
- job.start
187
- job.wait
188
- job.delete
275
+ job.run if sync
276
+ job
189
277
  end
190
278
 
191
- def poweroff_managed_system(sys_uuid, params = {})
279
+ ##
280
+ # @!method poweroff_managed_system(sys_uuid, params = {}, sync = true)
281
+ # Power off a managed system.
282
+ # @param sys_uuid [String] The UUID of the managed system.
283
+ # @param params [Hash] Job parameters.
284
+ # @param sync [Boolean] Start the job and wait for its completion.
285
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
286
+ def poweroff_managed_system(sys_uuid, params = {}, sync = true)
192
287
  method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/do/PowerOff"
193
288
 
194
289
  job = HmcJob.new(self, method_url, "PowerOff", "ManagedSystem", params)
195
- job.start
196
- job.wait
197
- job.delete
290
+ job.run if sync
291
+ job
292
+ end
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
198
307
  end
199
308
 
200
- # Blocks until new events occur.
201
- def next_events
309
+ ##
310
+ # @!method cli_run(hmc_uuid, cmd, sync = true)
311
+ # Run a CLI command on the HMC as a job.
312
+ # @param hmc_uuid [String] The UUID of the management console.
313
+ # @param cmd [String] The command to run.
314
+ # @param sync [Boolean] Start the job and wait for its completion.
315
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
316
+ def cli_run(hmc_uuid, cmd, sync = true)
317
+ method_url = "/rest/api/uom/ManagementConsole/#{hmc_uuid}/do/CLIRunner"
318
+
319
+ params = {
320
+ "cmd" => cmd,
321
+ "acknowledgeThisAPIMayGoAwayInTheFuture" => "true",
322
+ }
323
+ job = HmcJob.new(self, method_url, "CLIRunner", "ManagementConsole", params)
324
+ job.run if sync
325
+ job
326
+ end
327
+
328
+ ##
329
+ # @!method next_events(wait = true)
330
+ # Retrieve a list of events that occured since last call.
331
+ # @param wait [Boolean] If no event is available, block until new events occur.
332
+ # @return [Array<IbmPowerHmc::Event>] The list of events.
333
+ def next_events(wait = true)
202
334
  method_url = "/rest/api/uom/Event"
203
335
 
204
- events = []
336
+ response = nil
205
337
  loop do
206
338
  response = request(:get, method_url)
207
- next if response.code == 204
339
+ # No need to sleep as the HMC already waits a bit before returning 204
340
+ break if response.code != 204 || !wait
341
+ end
342
+ FeedParser.new(response.body).objects(:Event)
343
+ end
344
+
345
+ ##
346
+ # @!method schema(type)
347
+ # Retrieve the XML schema file for a given object type.
348
+ # @param type [String] The object type (e.g. "LogicalPartition", "inc/Types")
349
+ # @return [REXML::Document] The XML schema file.
350
+ def schema(type)
351
+ method_url = "/rest/api/web/schema/#{type}.xsd"
352
+ response = request(:get, method_url)
353
+ REXML::Document.new(response.body)
354
+ end
208
355
 
209
- doc = REXML::Document.new(response.body)
210
- doc.root.each_element("entry") do |entry|
211
- event = Event.new(entry)
212
- events += [event]
356
+ class HttpError < Error
357
+ attr_reader :status, :uri, :reason, :message, :original_exception
358
+
359
+ ##
360
+ # @!method initialize(err)
361
+ # Create a new HttpError exception.
362
+ # @param err [RestClient::Exception] The REST client exception.
363
+ def initialize(err)
364
+ super
365
+ @original_exception = err
366
+ @status = err.http_code
367
+ @message = err.message
368
+
369
+ # Try to parse body as an HttpErrorResponse
370
+ unless err.response.nil?
371
+ resp = Parser.new(err.response.body).object(:HttpErrorResponse)
372
+ unless resp.nil?
373
+ @uri = resp.uri
374
+ @reason = resp.reason
375
+ @message = resp.message
376
+ end
213
377
  end
214
- break
215
378
  end
216
- events
379
+
380
+ def to_s
381
+ "msg=\"#{@message}\" status=\"#{@status}\" reason=\"#{@reason}\" uri=#{@uri}"
382
+ end
217
383
  end
218
384
 
385
+ ##
386
+ # @!method request(method, url, headers = {}, payload = nil)
387
+ # Perform a REST API request.
388
+ # @param method [String] The HTTP method.
389
+ # @param url [String] The method URL.
390
+ # @param headers [Hash] HTTP headers.
391
+ # @param payload [String] HTTP request payload.
392
+ # @return [RestClient::Response] The response from the HMC.
219
393
  def request(method, url, headers = {}, payload = nil)
220
394
  logon if @api_session_token.nil?
395
+ reauth = false
396
+ # Check for relative URLs
397
+ url = "https://#{@hostname}#{url}" if url.start_with?("/")
398
+ begin
399
+ headers = headers.merge("X-API-Session" => @api_session_token)
400
+ RestClient::Request.execute(
401
+ :method => method,
402
+ :url => url,
403
+ :verify_ssl => @verify_ssl,
404
+ :payload => payload,
405
+ :headers => headers
406
+ )
407
+ rescue RestClient::Exception => e
408
+ # Do not retry on failed logon attempts
409
+ if e.http_code == 401 && @api_session_token != "" && !reauth
410
+ # Try to reauth
411
+ reauth = true
412
+ logon
413
+ retry
414
+ end
415
+ raise HttpError.new(e), "REST request failed"
416
+ end
417
+ end
221
418
 
222
- headers = headers.merge({ "X-API-Session" => @api_session_token })
223
- # Damien: use URI module and prepare in initialize?
224
- response = RestClient::Request.execute(
225
- method: method,
226
- url: "https://" + @hostname + url,
227
- verify_ssl: @verify_ssl,
228
- payload: payload,
229
- headers: headers
230
- )
231
- if response.code == 403
232
- # Damien: if token expires, reauth?
233
- @api_session_token = nil
234
- logon
235
- # Damien: retry TBD
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
236
438
  end
237
- response
238
439
  end
239
440
  end
240
441
  end
@@ -1,70 +1,116 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Module for IBM HMC Rest API Client
4
3
  module IbmPowerHmc
5
- # HMC Job for long running operations
4
+ ##
5
+ # HMC Job for long running operations.
6
6
  class HmcJob
7
- def initialize(hc, method_url, operation, group, params)
8
- @hc = hc
7
+ class JobNotStarted < StandardError; end
8
+
9
+ ##
10
+ # @!method initialize(conn, method_url, operation, group, params = {})
11
+ # Construct a new HMC Job.
12
+ #
13
+ # @param conn [IbmPowerHmc::Connection] The connection to the HMC.
14
+ # @param method_url [String] The method URL.
15
+ # @param operation [String] The name of the requested operation.
16
+ # @param group [String] The name of the group.
17
+ # @param params [Hash] The job name/value parameters.
18
+ def initialize(conn, method_url, operation, group, params = {})
19
+ @conn = conn
9
20
  @method_url = method_url
10
21
  @operation = operation
11
22
  @group = group
12
23
  @params = params
13
24
  end
14
25
 
26
+ ##
27
+ # @!method start
28
+ # Start the job asynchronously.
29
+ # @return [String] The ID of the job.
15
30
  def start
16
31
  headers = {
17
- content_type: "application/vnd.ibm.powervm.web+xml; type=JobRequest"
32
+ :content_type => "application/vnd.ibm.powervm.web+xml; type=JobRequest"
18
33
  }
19
34
  doc = REXML::Document.new("")
20
- doc.add_element("JobRequest:JobRequest", {
21
- "xmlns:JobRequest" => "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/",
22
- "xmlns" => "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/",
23
- "schemaVersion" => "V1_1_0"
24
- })
25
- 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")
26
39
  op.add_element("OperationName").text = @operation
27
40
  op.add_element("GroupName").text = @group
28
- # Damien: ProgressType?
29
- jobparams = doc.root.add_element("JobParameters", { "schemaVersion" => "V1_1_0" })
41
+
42
+ jobparams = doc.root.add_element("JobParameters", "schemaVersion" => "V1_1_0")
30
43
  @params.each do |key, value|
31
- jobparam = jobparams.add_element("JobParameter", { "schemaVersion" => "V1_1_0" })
44
+ jobparam = jobparams.add_element("JobParameter", "schemaVersion" => "V1_1_0")
32
45
  jobparam.add_element("ParameterName").text = key
33
46
  jobparam.add_element("ParameterValue").text = value
34
47
  end
35
- response = @hc.request(:put, @method_url, headers, doc.to_s)
36
- doc = REXML::Document.new(response.body)
37
- info = doc.root.elements["content/JobResponse:JobResponse"]
38
- @id = info.elements["JobID"].text
48
+ response = @conn.request(:put, @method_url, headers, doc.to_s)
49
+ jobresp = Parser.new(response.body).object(:JobResponse)
50
+ @id = jobresp.id
39
51
  end
40
52
 
53
+ # @return [Hash] The job results returned by the HMC.
54
+ attr_reader :results
55
+
56
+ ##
57
+ # @!method status
58
+ # Return the status of the job.
59
+ # @return [String] The status of the job.
41
60
  def status
42
- # Damien: check id is defined
61
+ raise JobNotStarted unless defined?(@id)
62
+
43
63
  method_url = "/rest/api/uom/jobs/#{@id}"
44
64
  headers = {
45
- content_type: "application/vnd.ibm.powervm.web+xml; type=JobRequest"
65
+ :content_type => "application/vnd.ibm.powervm.web+xml; type=JobRequest"
46
66
  }
47
- response = @hc.request(:get, method_url, headers)
48
- doc = REXML::Document.new(response.body)
49
- info = doc.root.elements["content/JobResponse:JobResponse"]
50
- status = info.elements["Status"].text
51
- # Damien: also retrieve "ResponseException/Message"
52
- status
67
+ response = @conn.request(:get, method_url, headers)
68
+ jobresp = Parser.new(response.body).object(:JobResponse)
69
+ @results = jobresp.results
70
+ jobresp.status
53
71
  end
54
72
 
55
- def wait(timeout = 120, poll_interval = 30)
56
- endtime = Time.now + timeout
57
- while Time.now < endtime do
73
+ ##
74
+ # @!method wait(timeout = 120, poll_interval = 0)
75
+ # Wait for the job to complete.
76
+ # @param timeout [Integer] The maximum time in seconds to wait for the job to complete.
77
+ # @param poll_interval [Integer] The interval in seconds between status queries (0 means auto).
78
+ # @return [String] The status of the job.
79
+ def wait(timeout = 120, poll_interval = 0)
80
+ endtime = Time.now.utc + timeout
81
+ auto = poll_interval == 0
82
+ poll_interval = 1 if auto
83
+ while Time.now.utc < endtime
58
84
  status = self.status
59
- break if status != "RUNNING" # Damien: and != "STARTING"?
85
+ return status if status != "RUNNING" && status != "NOT_STARTED"
86
+
87
+ poll_interval *= 2 if auto && poll_interval < 30
60
88
  sleep(poll_interval)
61
89
  end
90
+ "TIMEDOUT"
91
+ end
92
+
93
+ ##
94
+ # @!method run(timeout = 120, poll_interval = 0)
95
+ # Run the job synchronously.
96
+ # @param timeout [Integer] The maximum time in seconds to wait for the job to complete.
97
+ # @param poll_interval [Integer] The interval in seconds between status queries (0 means auto).
98
+ # @return [String] The status of the job.
99
+ def run(timeout = 120, poll_interval = 0)
100
+ start
101
+ wait(timeout, poll_interval)
102
+ ensure
103
+ delete if defined?(@id)
62
104
  end
63
105
 
106
+ ##
107
+ # @!method delete
108
+ # Delete the job from the HMC.
64
109
  def delete
65
- # Damien: check id is defined
110
+ raise JobNotStarted unless defined?(@id)
111
+
66
112
  method_url = "/rest/api/uom/jobs/#{@id}"
67
- @hc.request(:delete, method_url)
113
+ @conn.request(:delete, method_url)
68
114
  # Returns HTTP 204 if ok
69
115
  end
70
116
  end
@@ -0,0 +1,203 @@
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
+ :os => "OperatingSystemVersion",
140
+ :name => "PartitionName",
141
+ :id => "PartitionID",
142
+ :state => "PartitionState",
143
+ :type => "PartitionType",
144
+ :memory => "PartitionMemoryConfiguration/CurrentMemory",
145
+ :dedicated => "PartitionProcessorConfiguration/HasDedicatedProcessors",
146
+ :rmc_state => "ResourceMonitoringControlState",
147
+ :rmc_ipaddr => "ResourceMonitoringIPAddress",
148
+ :ref_code => "ReferenceCode"
149
+ }.freeze
150
+
151
+ def sys_uuid
152
+ sys_href = xml.elements["AssociatedManagedSystem"].attributes["href"]
153
+ extract_uuid_from_href(sys_href)
154
+ end
155
+ end
156
+
157
+ # Logical Partition information
158
+ class LogicalPartition < BasePartition
159
+ end
160
+
161
+ # VIOS information
162
+ class VirtualIOServer < BasePartition
163
+ end
164
+
165
+ # HMC Event
166
+ class Event < AbstractRest
167
+ ATTRS = {
168
+ :id => "EventID",
169
+ :type => "EventType",
170
+ :data => "EventData",
171
+ :detail => "EventDetail"
172
+ }.freeze
173
+ end
174
+
175
+ # Error response from HMC
176
+ class HttpErrorResponse < AbstractRest
177
+ ATTRS = {
178
+ :status => "HTTPStatus",
179
+ :uri => "RequestURI",
180
+ :reason => "ReasonCode",
181
+ :message => "Message"
182
+ }.freeze
183
+ end
184
+
185
+ # Job Response
186
+ class JobResponse < AbstractRest
187
+ ATTRS = {
188
+ :id => "JobID",
189
+ :status => "Status",
190
+ :message => "ResponseException/Message"
191
+ }.freeze
192
+
193
+ def results
194
+ results = {}
195
+ xml.each_element("Results/JobParameter") do |result|
196
+ name = result.elements["ParameterName"]&.text&.strip
197
+ value = result.elements["ParameterValue"]&.text&.strip
198
+ results[name] = value unless name.nil?
199
+ end
200
+ results
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'uri'
5
+
6
+ module IbmPowerHmc
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
+
44
+ ##
45
+ # @!method managed_system_metrics(sys_uuid:, start_ts: nil, end_ts: nil, no_samples: nil, aggregated: false)
46
+ # Retrieve metrics for a managed system.
47
+ # @param sys_uuid [String] The managed system UUID.
48
+ # @param start_ts [Time] Start timestamp.
49
+ # @param end_ts [Time] End timestamp.
50
+ # @param no_samples [Integer] Number of samples.
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?
61
+
62
+ response = request(:get, method_url)
63
+ FeedParser.new(response.body).entries do |entry|
64
+ category = entry.elements["category"]
65
+ next if category.nil?
66
+
67
+ term = category.attributes["term"]
68
+ next if term.nil? || term != "ManagedSystem"
69
+
70
+ link = entry.elements["link"]
71
+ next if link.nil?
72
+
73
+ href = link.attributes["href"]
74
+ next if href.nil?
75
+
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
120
+ end
121
+ end
122
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IbmPowerHmc
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
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.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - IBM Power
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-06 00:00:00.000000000 Z
11
+ date: 2021-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -31,9 +31,10 @@ extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
33
  - ".gitignore"
34
+ - ".rubocop.yml"
35
+ - ".rubocop_local.yml"
34
36
  - CHANGELOG.md
35
37
  - Gemfile
36
- - Gemfile.lock
37
38
  - LICENSE
38
39
  - README.md
39
40
  - Rakefile
@@ -43,7 +44,8 @@ files:
43
44
  - lib/ibm_power_hmc.rb
44
45
  - lib/ibm_power_hmc/connection.rb
45
46
  - lib/ibm_power_hmc/job.rb
46
- - lib/ibm_power_hmc/objects.rb
47
+ - lib/ibm_power_hmc/parser.rb
48
+ - lib/ibm_power_hmc/pcm.rb
47
49
  - lib/ibm_power_hmc/version.rb
48
50
  homepage: http://github.com/IBM/ibm_power_hmc_sdk_ruby
49
51
  licenses:
data/Gemfile.lock DELETED
@@ -1,37 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- ibm_power_hmc (0.1.0)
5
- rest-client (~> 2.1)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- domain_name (0.5.20190701)
11
- unf (>= 0.0.5, < 1.0.0)
12
- http-accept (1.7.0)
13
- http-cookie (1.0.4)
14
- domain_name (~> 0.5)
15
- mime-types (3.3.1)
16
- mime-types-data (~> 3.2015)
17
- mime-types-data (3.2021.0704)
18
- netrc (0.11.0)
19
- rake (12.3.3)
20
- rest-client (2.1.0)
21
- http-accept (>= 1.7.0, < 2.0)
22
- http-cookie (>= 1.0.2, < 2.0)
23
- mime-types (>= 1.16, < 4.0)
24
- netrc (~> 0.8)
25
- unf (0.1.4)
26
- unf_ext
27
- unf_ext (0.0.7.7)
28
-
29
- PLATFORMS
30
- ruby
31
-
32
- DEPENDENCIES
33
- ibm_power_hmc!
34
- rake (~> 12.0)
35
-
36
- BUNDLED WITH
37
- 2.1.4
@@ -1,157 +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
10
-
11
- def initialize(doc)
12
- @uuid = doc.elements["id"].text
13
- end
14
-
15
- def get_value(doc, xpath, varname)
16
- value = doc.elements[xpath]
17
- value = value.text unless value.nil?
18
- value = value.strip unless value.nil?
19
- self.class.__send__(:attr_reader, "#{varname}")
20
- instance_variable_set("@#{varname}", value)
21
- end
22
-
23
- def get_values(doc, hash)
24
- hash.each do |key, value|
25
- get_value(doc, key, value)
26
- end
27
- end
28
-
29
- def to_s
30
- "uuid=#{@uuid}"
31
- end
32
- end
33
-
34
- # HMC information
35
- class ManagementConsole < HmcObject
36
- XMLMAP = {
37
- "ManagementConsoleName" => "name",
38
- "VersionInfo/BuildLevel" => "build_level",
39
- "BaseVersion" => "version"
40
- }.freeze
41
-
42
- def initialize(doc)
43
- super(doc)
44
- info = doc.elements["content/ManagementConsole:ManagementConsole"]
45
- get_values(info, XMLMAP)
46
- end
47
-
48
- def to_s
49
- "hmc name=#{@name} version=#{@version} build_level=#{@build_level}"
50
- end
51
- end
52
-
53
- # Managed System information
54
- class ManagedSystem < HmcObject
55
- XMLMAP = {
56
- "SystemName" => "name",
57
- "State" => "state",
58
- "Hostname" => "hostname",
59
- "PrimaryIPAddress" => "ipaddr",
60
- "AssociatedSystemMemoryConfiguration/InstalledSystemMemory" => "memory",
61
- "AssociatedSystemMemoryConfiguration/CurrentAvailableSystemMemory" => "avail_mem",
62
- "AssociatedSystemProcessorConfiguration/InstalledSystemProcessorUnits" => "cpus",
63
- "AssociatedSystemProcessorConfiguration/CurrentAvailableSystemProcessorUnits" => "avail_cpus"
64
- }.freeze
65
-
66
- def initialize(doc)
67
- super(doc)
68
- info = doc.elements["content/ManagedSystem:ManagedSystem"]
69
- get_values(info, XMLMAP)
70
- end
71
-
72
- def to_s
73
- "sys name=#{@name} state=#{@state} ip=#{@ipaddr} mem=#{@memory}MB avail=#{@avail_mem}MB CPUs=#{@cpus} avail=#{@avail_cpus}"
74
- end
75
- end
76
-
77
- # Logical Partition information
78
- class LogicalPartition < HmcObject
79
- attr_reader :sys_uuid
80
-
81
- XMLMAP = {
82
- "PartitionName" => "name",
83
- "PartitionID" => "id",
84
- "PartitionState" => "state",
85
- "PartitionType" => "type",
86
- "PartitionMemoryConfiguration/CurrentMemory" => "memory",
87
- "PartitionProcessorConfiguration/HasDedicatedProcessors" => "dedicated",
88
- "ResourceMonitoringControlState" => "rmc_state",
89
- "ResourceMonitoringIPAddress" => "rmc_ipaddr"
90
- }.freeze
91
-
92
- def initialize(doc)
93
- super(doc)
94
- info = doc.elements["content/LogicalPartition:LogicalPartition"]
95
- sys_href = info.elements["AssociatedManagedSystem"].attributes["href"]
96
- @sys_uuid = URI(sys_href).path.split('/').last
97
- get_values(info, XMLMAP)
98
- end
99
-
100
- def to_s
101
- "lpar name=#{@name} id=#{@id} state=#{@state} type=#{@type} memory=#{@memory}MB dedicated cpus=#{@dedicated}"
102
- end
103
- end
104
-
105
- # VIOS information
106
- class VirtualIOServer < HmcObject
107
- attr_reader :sys_uuid
108
-
109
- XMLMAP = {
110
- "PartitionName" => "name",
111
- "PartitionID" => "id",
112
- "PartitionState" => "state",
113
- "PartitionType" => "type",
114
- "PartitionMemoryConfiguration/CurrentMemory" => "memory",
115
- "PartitionProcessorConfiguration/HasDedicatedProcessors" => "dedicated"
116
- }.freeze
117
-
118
- def initialize(doc)
119
- super(doc)
120
- info = doc.elements["content/VirtualIOServer:VirtualIOServer"]
121
- sys_href = info.elements["AssociatedManagedSystem"].attributes["href"]
122
- @sys_uuid = URI(sys_href).path.split('/').last
123
- get_values(info, XMLMAP)
124
- end
125
-
126
- def to_s
127
- "vios name=#{@name} id=#{@id} state=#{@state} type=#{@type} memory=#{@memory}MB dedicated cpus=#{@dedicated}"
128
- end
129
- end
130
-
131
- # LPAR profile
132
- class LogicalPartitionProfile < HmcObject
133
- attr_reader :lpar_uuid
134
-
135
- # Damien: TBD
136
- end
137
-
138
- # HMC Event
139
- class Event < HmcObject
140
- XMLMAP = {
141
- "EventID" => "id",
142
- "EventType" => "type",
143
- "EventData" => "data",
144
- "EventDetail" => "detail",
145
- }.freeze
146
-
147
- def initialize(doc)
148
- super(doc)
149
- info = doc.elements["content/Event:Event"]
150
- get_values(info, XMLMAP)
151
- end
152
-
153
- def to_s
154
- "event id=#{@id} type=#{@type} data=#{@data} detail=#{@detail}"
155
- end
156
- end
157
- end