ibm_power_hmc 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 397feab84db9812185ab1125cd6778b52a1848519d6bae5950d69cb31e9b4845
4
- data.tar.gz: 27dd4d94cd61a19c66d0d6e438c17987ea5926af78b7677b5044a11a50acdb18
3
+ metadata.gz: 214dfa7f9a89d236f1f9bc4ee927b619596a0fabe59c2f596359637e891601ab
4
+ data.tar.gz: 2affd160febc3952014ab522bb9b0f89b0ebef6d785720d2d8d2a875cd1df918
5
5
  SHA512:
6
- metadata.gz: 1171816de48bed97b1837ab39d3bd639772928ebee98fb8f287c85006196bdf068320599b921a239d10d5ce74e98629cde754eca14b12c6cf6be85477e7a7fb3
7
- data.tar.gz: 10f7397e58acab288715283de98480caf915fb628021b2f8c5261b13b2c7b273cdec5e1d7a52b35560acbe5cae6dfed5c9e68516673d97ff5f91a9fb44daa370
6
+ metadata.gz: 3e6e6ae8b4c7d84eea70e3328ea44834a5b95ecd98fbe6a31c045e575951b6c17751ca7d6517d3ad58647b5c8b7e1321470c368c48018c31a450a28ba40463e5
7
+ data.tar.gz: f9139f2ea1a83d0abedc3c73832450e20fa4fcf7c56cc65c50ec5b14750bb5bb2eb17d7948ffc22d5887984d0f412ae8213a237892350e55f0cd55a49af80f30
data/.gitignore CHANGED
File without changes
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
+ EnforcedHashRocketStyle: key
6
+ Style/ConditionalAssignment:
7
+ EnforcedStyle: assign_inside_condition
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
File without changes
data/Rakefile CHANGED
File without changes
File without changes
@@ -2,8 +2,22 @@
2
2
 
3
3
  # Module for IBM HMC Rest API Client
4
4
  module IbmPowerHmc
5
- # HMC REST Client connection
5
+ require_relative 'pcm.rb'
6
+
7
+ class Error < StandardError; end
8
+
9
+ ##
10
+ # HMC REST Client connection.
6
11
  class Connection
12
+ ##
13
+ # @!method initialize(host:, username: "hscroot", password:, port: 12_443, validate_ssl: true)
14
+ # Create a new HMC connection.
15
+ #
16
+ # @param host [String] Hostname of the HMC.
17
+ # @param username [String] User name.
18
+ # @param password [String] Password.
19
+ # @param port [Integer] TCP port number.
20
+ # @param validate_ssl [Boolean] Verify SSL certificates.
7
21
  def initialize(host:, username: "hscroot", password:, port: 12_443, validate_ssl: true)
8
22
  # Damien: use URI::HTTPS
9
23
  @hostname = "#{host}:#{port}"
@@ -13,10 +27,14 @@ module IbmPowerHmc
13
27
  @api_session_token = nil
14
28
  end
15
29
 
30
+ ##
31
+ # @!method logon
32
+ # Establish a trusted session with the Web Services APIs.
33
+ # @return [String] The X-API-Session token.
16
34
  def logon
17
35
  method_url = "/rest/api/web/Logon"
18
36
  headers = {
19
- content_type: "application/vnd.ibm.powervm.web+xml; type=LogonRequest"
37
+ :content_type => "application/vnd.ibm.powervm.web+xml; type=LogonRequest"
20
38
  }
21
39
  doc = REXML::Document.new("")
22
40
  doc.add_element("LogonRequest", {
@@ -26,41 +44,84 @@ module IbmPowerHmc
26
44
  doc.root.add_element("UserID").text = @username
27
45
  doc.root.add_element("Password").text = @password
28
46
 
29
- # Damien: begin/rescue
30
47
  @api_session_token = ""
31
48
  response = request(:put, method_url, headers, doc.to_s)
32
49
  doc = REXML::Document.new(response.body)
33
- @api_session_token = doc.root.elements["X-API-Session"].text
50
+ elem = doc.elements["LogonResponse/X-API-Session"]
51
+ raise Error, "LogonResponse/X-API-Session not found" if elem.nil?
52
+
53
+ @api_session_token = elem.text
34
54
  end
35
55
 
56
+ ##
57
+ # @!method logoff
58
+ # Close the session.
36
59
  def logoff
60
+ # Don't want to trigger automatic logon here!
61
+ return if @api_session_token.nil?
62
+
37
63
  method_url = "/rest/api/web/Logon"
38
- request(:delete, method_url)
64
+ begin
65
+ request(:delete, method_url)
66
+ rescue
67
+ # Ignore exceptions as this is best effort attempt to log off.
68
+ end
39
69
  @api_session_token = nil
40
70
  end
41
71
 
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
+ ##
82
+ # @!method management_console
83
+ # Retrieve information about the management console.
84
+ # @return [IbmPowerHmc::ManagementConsole] The management console.
42
85
  def management_console
43
86
  method_url = "/rest/api/uom/ManagementConsole"
44
87
  response = request(:get, method_url)
45
88
  doc = REXML::Document.new(response.body)
46
- entry = doc.root.elements["entry"]
47
- ManagementConsole.new(entry)
89
+ # This request returns a feed with a single entry.
90
+ parse_feed(doc, ManagementConsole).first
48
91
  end
49
92
 
93
+ ##
94
+ # @!method managed_systems
95
+ # Retrieve the list of systems managed by the HMC.
96
+ # @return [Array<IbmPowerHmc::ManagedSystem>] The list of managed systems.
50
97
  def managed_systems
51
98
  method_url = "/rest/api/uom/ManagedSystem"
52
99
  response = request(:get, method_url)
53
100
  doc = REXML::Document.new(response.body)
54
- systems = []
55
- return systems if doc.root.nil?
101
+ parse_feed(doc, ManagedSystem)
102
+ end
56
103
 
57
- doc.root.each_element("entry") do |entry|
58
- system = ManagedSystem.new(entry)
59
- systems += [system]
60
- end
61
- systems
104
+ ##
105
+ # @!method managed_system(lpar_uuid, sys_uuid = nil, group_name = nil)
106
+ # Retrieve information about a managed system.
107
+ # @param sys_uuid [String] The UUID of the managed system.
108
+ # @param group_name [String] The extended group attributes.
109
+ # @return [IbmPowerHmc::ManagedSystem] The logical partition.
110
+ def managed_system(sys_uuid, group_name = nil)
111
+ method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}"
112
+ method_url += "?group=#{group_name}" unless group_name.nil?
113
+
114
+ response = request(:get, method_url)
115
+ doc = REXML::Document.new(response.body)
116
+ entry = doc.elements["entry"]
117
+ ManagedSystem.new(entry)
62
118
  end
63
119
 
120
+ ##
121
+ # @!method lpars(sys_uuid = nil)
122
+ # Retrieve the list of logical partitions managed by the HMC.
123
+ # @param sys_uuid [String] The UUID of the managed system.
124
+ # @return [Array<IbmPowerHmc::LogicalPartition>] The list of logical partitions.
64
125
  def lpars(sys_uuid = nil)
65
126
  if sys_uuid.nil?
66
127
  method_url = "/rest/api/uom/LogicalPartition"
@@ -69,16 +130,16 @@ module IbmPowerHmc
69
130
  end
70
131
  response = request(:get, method_url)
71
132
  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
133
+ parse_feed(doc, LogicalPartition)
80
134
  end
81
135
 
136
+ ##
137
+ # @!method lpar(lpar_uuid, sys_uuid = nil, group_name = nil)
138
+ # Retrieve information about a logical partition.
139
+ # @param lpar_uuid [String] The UUID of the logical partition.
140
+ # @param sys_uuid [String] The UUID of the managed system.
141
+ # @param group_name [String] The extended group attributes.
142
+ # @return [IbmPowerHmc::LogicalPartition] The logical partition.
82
143
  def lpar(lpar_uuid, sys_uuid = nil, group_name = nil)
83
144
  if sys_uuid.nil?
84
145
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}"
@@ -93,6 +154,11 @@ module IbmPowerHmc
93
154
  LogicalPartition.new(entry)
94
155
  end
95
156
 
157
+ ##
158
+ # @!method lpar_quick_property(lpar_uuid, property_name)
159
+ # Retrieve a quick property of a logical partition.
160
+ # @param lpar_uuid [String] The UUID of the logical partition.
161
+ # @return [String] The quick property value.
96
162
  def lpar_quick_property(lpar_uuid, property_name)
97
163
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/quick/#{property_name}"
98
164
 
@@ -100,141 +166,223 @@ module IbmPowerHmc
100
166
  response.body[1..-2]
101
167
  end
102
168
 
169
+ ##
170
+ # @!method vioses(sys_uuid = nil)
171
+ # Retrieve the list of virtual I/O servers managed by the HMC.
172
+ # @param sys_uuid [String] The UUID of the managed system.
173
+ # @return [Array<IbmPowerHmc::VirtualIOServer>] The list of virtual I/O servers.
103
174
  def vioses(sys_uuid = nil)
104
175
  if sys_uuid.nil?
105
176
  method_url = "/rest/api/uom/VirtualIOServer"
106
177
  else
107
178
  method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/VirtualIOServer"
108
179
  end
109
- begin
110
- response = request(:get, method_url)
111
- rescue StandardError
112
- return []
113
- end
180
+ response = request(:get, method_url)
114
181
  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
182
+ parse_feed(doc, 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
+ doc = REXML::Document.new(response.body)
202
+ entry = doc.elements["entry"]
203
+ VirtualIOServer.new(entry)
142
204
  end
143
205
 
144
- def poweron_lpar(lpar_uuid, params = {})
206
+ ##
207
+ # @!method poweron_lpar(lpar_uuid, params = {}, sync = true)
208
+ # Power on a logical partition.
209
+ # @param lpar_uuid [String] The UUID of the logical partition.
210
+ # @param params [Hash] Job parameters.
211
+ # @param sync [Boolean] Start the job and wait for its completion.
212
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
213
+ def poweron_lpar(lpar_uuid, params = {}, sync = true)
145
214
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/do/PowerOn"
146
215
 
147
216
  job = HmcJob.new(self, method_url, "PowerOn", "LogicalPartition", params)
148
- job.start
149
- job.wait
150
- job.delete
217
+ job.run if sync
218
+ job
151
219
  end
152
220
 
153
- def poweroff_lpar(lpar_uuid, params = {})
221
+ ##
222
+ # @!method poweroff_lpar(lpar_uuid, params = {}, sync = true)
223
+ # Power off a logical partition.
224
+ # @param lpar_uuid [String] The UUID of the logical partition.
225
+ # @param params [Hash] Job parameters.
226
+ # @param sync [Boolean] Start the job and wait for its completion.
227
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
228
+ def poweroff_lpar(lpar_uuid, params = {}, sync = true)
154
229
  method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}/do/PowerOff"
155
230
 
156
231
  job = HmcJob.new(self, method_url, "PowerOff", "LogicalPartition", params)
157
- job.start
158
- job.wait
159
- job.delete
232
+ job.run if sync
233
+ job
160
234
  end
161
235
 
162
- # Damien: share with poweron_lpar?
163
- def poweron_vios(vios_uuid, params = {})
236
+ ##
237
+ # @!method poweron_vios(vios_uuid, params = {}, sync = true)
238
+ # Power on a virtual I/O server.
239
+ # @param vios_uuid [String] The UUID of the virtual I/O server.
240
+ # @param params [Hash] Job parameters.
241
+ # @param sync [Boolean] Start the job and wait for its completion.
242
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
243
+ def poweron_vios(vios_uuid, params = {}, sync = true)
164
244
  method_url = "/rest/api/uom/VirtualIOServer/#{vios_uuid}/do/PowerOn"
165
245
 
166
246
  job = HmcJob.new(self, method_url, "PowerOn", "VirtualIOServer", params)
167
- job.start
168
- job.wait
169
- job.delete
247
+ job.run if sync
248
+ job
170
249
  end
171
250
 
172
- # Damien: share with poweroff_lpar?
173
- def poweroff_vios(vios_uuid, params = {})
251
+ ##
252
+ # @!method poweroff_vios(vios_uuid, params = {}, sync = true)
253
+ # Power off a virtual I/O server.
254
+ # @param vios_uuid [String] The UUID of the virtual I/O server.
255
+ # @param params [Hash] Job parameters.
256
+ # @param sync [Boolean] Start the job and wait for its completion.
257
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
258
+ def poweroff_vios(vios_uuid, params = {}, sync = true)
174
259
  method_url = "/rest/api/uom/VirtualIOServer/#{vios_uuid}/do/PowerOff"
175
260
 
176
261
  job = HmcJob.new(self, method_url, "PowerOff", "VirtualIOServer", params)
177
- job.start
178
- job.wait
179
- job.delete
262
+ job.run if sync
263
+ job
180
264
  end
181
265
 
182
- def poweron_managed_system(sys_uuid, params = {})
266
+ ##
267
+ # @!method poweron_managed_system(sys_uuid, params = {}, sync = true)
268
+ # Power on a managed system.
269
+ # @param sys_uuid [String] The UUID of the managed system.
270
+ # @param params [Hash] Job parameters.
271
+ # @param sync [Boolean] Start the job and wait for its completion.
272
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
273
+ def poweron_managed_system(sys_uuid, params = {}, sync = true)
183
274
  method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/do/PowerOn"
184
275
 
185
276
  job = HmcJob.new(self, method_url, "PowerOn", "ManagedSystem", params)
186
- job.start
187
- job.wait
188
- job.delete
277
+ job.run if sync
278
+ job
189
279
  end
190
280
 
191
- def poweroff_managed_system(sys_uuid, params = {})
281
+ ##
282
+ # @!method poweroff_managed_system(sys_uuid, params = {}, sync = true)
283
+ # Power off a managed system.
284
+ # @param sys_uuid [String] The UUID of the managed system.
285
+ # @param params [Hash] Job parameters.
286
+ # @param sync [Boolean] Start the job and wait for its completion.
287
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
288
+ def poweroff_managed_system(sys_uuid, params = {}, sync = true)
192
289
  method_url = "/rest/api/uom/ManagedSystem/#{sys_uuid}/do/PowerOff"
193
290
 
194
291
  job = HmcJob.new(self, method_url, "PowerOff", "ManagedSystem", params)
195
- job.start
196
- job.wait
197
- job.delete
292
+ job.run if sync
293
+ job
198
294
  end
199
295
 
200
- # Blocks until new events occur.
201
- def next_events
296
+ ##
297
+ # @!method cli_run(hmc_uuid, cmd, sync = true)
298
+ # Run a CLI command on the HMC as a job.
299
+ # @param hmc_uuid [String] The UUID of the management console.
300
+ # @param cmd [String] The command to run.
301
+ # @param sync [Boolean] Start the job and wait for its completion.
302
+ # @return [IbmPowerHmc::HmcJob] The HMC job.
303
+ def cli_run(hmc_uuid, cmd, sync = true)
304
+ method_url = "/rest/api/uom/ManagementConsole/#{hmc_uuid}/do/CLIRunner"
305
+
306
+ params = {
307
+ "cmd" => cmd,
308
+ "acknowledgeThisAPIMayGoAwayInTheFuture" => "true",
309
+ }
310
+ job = HmcJob.new(self, method_url, "CLIRunner", "ManagementConsole", params)
311
+ job.run if sync
312
+ job
313
+ end
314
+
315
+ ##
316
+ # @!method next_events(wait = true)
317
+ # Retrieve a list of events that occured since last call.
318
+ # @param wait [Boolean] If no event is available, block until new events occur.
319
+ # @return [Array<IbmPowerHmc::Event>] The list of events.
320
+ def next_events(wait = true)
202
321
  method_url = "/rest/api/uom/Event"
203
322
 
204
- events = []
323
+ response = nil
205
324
  loop do
206
325
  response = request(:get, method_url)
207
- next if response.code == 204
326
+ # No need to sleep as the HMC already waits a bit before returning 204
327
+ break if response.code != 204 || !wait
328
+ end
329
+ doc = REXML::Document.new(response.body)
330
+ parse_feed(doc, Event)
331
+ end
208
332
 
209
- doc = REXML::Document.new(response.body)
210
- doc.root.each_element("entry") do |entry|
211
- event = Event.new(entry)
212
- events += [event]
333
+ class HttpError < Error
334
+ attr_reader :status, :uri, :reason, :message
335
+
336
+ ##
337
+ # @!method initialize(err)
338
+ # Create a new HttpError exception.
339
+ # @param err [RestClient::Exception] The REST client exception.
340
+ def initialize(err)
341
+ super
342
+ @status = err.http_code
343
+
344
+ # Try to parse body as an HttpErrorResponse
345
+ doc = REXML::Document.new(err.response.body)
346
+ entry = doc.elements["entry"]
347
+ unless entry.nil?
348
+ resp = HttpErrorResponse.new(entry)
349
+ @uri = resp.uri
350
+ @reason = resp.reason
351
+ @message = resp.message
213
352
  end
214
- break
215
353
  end
216
- events
217
354
  end
218
355
 
356
+ ##
357
+ # @!method request(method, url, headers = {}, payload = nil)
358
+ # Perform a REST API request.
359
+ # @param method [String] The HTTP method.
360
+ # @param url [String] The method URL.
361
+ # @param headers [Hash] HTTP headers.
362
+ # @param payload [String] HTTP request payload.
363
+ # @return [RestClient::Response] The response from the HMC.
219
364
  def request(method, url, headers = {}, payload = nil)
220
365
  logon if @api_session_token.nil?
221
-
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
366
+ reauth = false
367
+ begin
368
+ headers = headers.merge({"X-API-Session" => @api_session_token})
369
+ RestClient::Request.execute(
370
+ :method => method,
371
+ :url => "https://" + @hostname + url,
372
+ :verify_ssl => @verify_ssl,
373
+ :payload => payload,
374
+ :headers => headers
375
+ )
376
+ rescue RestClient::Exception => e
377
+ # Do not retry on failed logon attempts
378
+ if e.http_code == 401 && @api_session_token != "" && !reauth
379
+ # Try to reauth
380
+ reauth = true
381
+ logon
382
+ retry
383
+ end
384
+ raise HttpError.new(e), "REST request failed"
236
385
  end
237
- response
238
386
  end
239
387
  end
240
388
  end
@@ -1,20 +1,35 @@
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 status
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
35
  doc.add_element("JobRequest:JobRequest", {
@@ -22,49 +37,95 @@ module IbmPowerHmc
22
37
  "xmlns" => "http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/",
23
38
  "schemaVersion" => "V1_1_0"
24
39
  })
25
- op = doc.root.add_element("RequestedOperation", { "schemaVersion" => "V1_1_0" })
40
+ op = doc.root.add_element("RequestedOperation", {"schemaVersion" => "V1_1_0"})
26
41
  op.add_element("OperationName").text = @operation
27
42
  op.add_element("GroupName").text = @group
28
43
  # Damien: ProgressType?
29
- jobparams = doc.root.add_element("JobParameters", { "schemaVersion" => "V1_1_0" })
44
+ jobparams = doc.root.add_element("JobParameters", {"schemaVersion" => "V1_1_0"})
30
45
  @params.each do |key, value|
31
- jobparam = jobparams.add_element("JobParameter", { "schemaVersion" => "V1_1_0" })
46
+ jobparam = jobparams.add_element("JobParameter", {"schemaVersion" => "V1_1_0"})
32
47
  jobparam.add_element("ParameterName").text = key
33
48
  jobparam.add_element("ParameterValue").text = value
34
49
  end
35
- response = @hc.request(:put, @method_url, headers, doc.to_s)
50
+ response = @conn.request(:put, @method_url, headers, doc.to_s)
36
51
  doc = REXML::Document.new(response.body)
37
52
  info = doc.root.elements["content/JobResponse:JobResponse"]
38
53
  @id = info.elements["JobID"].text
39
54
  end
40
55
 
56
+ # @return [Hash] The job results returned by the HMC.
57
+ attr_reader :results
58
+
59
+ ##
60
+ # @!method status
61
+ # Return the status of the job.
62
+ # @return [String] The status of the job.
41
63
  def status
42
- # Damien: check id is defined
64
+ raise JobNotStarted unless defined?(@id)
65
+
43
66
  method_url = "/rest/api/uom/jobs/#{@id}"
44
67
  headers = {
45
- content_type: "application/vnd.ibm.powervm.web+xml; type=JobRequest"
68
+ :content_type => "application/vnd.ibm.powervm.web+xml; type=JobRequest"
46
69
  }
47
- response = @hc.request(:get, method_url, headers)
70
+ response = @conn.request(:get, method_url, headers)
48
71
  doc = REXML::Document.new(response.body)
49
72
  info = doc.root.elements["content/JobResponse:JobResponse"]
50
73
  status = info.elements["Status"].text
51
- # Damien: also retrieve "ResponseException/Message"
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
+
52
84
  status
53
85
  end
54
86
 
55
- def wait(timeout = 120, poll_interval = 30)
56
- endtime = Time.now + timeout
57
- while Time.now < endtime do
87
+ ##
88
+ # @!method wait(timeout = 120, poll_interval = 0)
89
+ # Wait for the job to complete.
90
+ # @param timeout [Integer] The maximum time in seconds to wait for the job to complete.
91
+ # @param poll_interval [Integer] The interval in seconds between status queries (0 means auto).
92
+ # @return [String] The status of the job.
93
+ def wait(timeout = 120, poll_interval = 0)
94
+ endtime = Time.now.utc + timeout
95
+ auto = poll_interval == 0
96
+ poll_interval = 1 if auto
97
+ while Time.now.utc < endtime
58
98
  status = self.status
59
- break if status != "RUNNING" # Damien: and != "STARTING"?
99
+ return status if status != "RUNNING" && status != "NOT_STARTED"
100
+
101
+ poll_interval *= 2 if auto && poll_interval < 30
60
102
  sleep(poll_interval)
61
103
  end
104
+ "TIMEDOUT"
62
105
  end
63
106
 
107
+ ##
108
+ # @!method run(timeout = 120, poll_interval = 0)
109
+ # Run the job synchronously.
110
+ # @param timeout [Integer] The maximum time in seconds to wait for the job to complete.
111
+ # @param poll_interval [Integer] The interval in seconds between status queries (0 means auto).
112
+ # @return [String] The status of the job.
113
+ def run(timeout = 120, poll_interval = 0)
114
+ start
115
+ status = wait(timeout, poll_interval)
116
+ status
117
+ ensure
118
+ delete if defined?(@id)
119
+ end
120
+
121
+ ##
122
+ # @!method delete
123
+ # Delete the job from the HMC.
64
124
  def delete
65
- # Damien: check id is defined
125
+ raise JobNotStarted unless defined?(@id)
126
+
66
127
  method_url = "/rest/api/uom/jobs/#{@id}"
67
- @hc.request(:delete, method_url)
128
+ @conn.request(:delete, method_url)
68
129
  # Returns HTTP 204 if ok
69
130
  end
70
131
  end
@@ -16,7 +16,7 @@ module IbmPowerHmc
16
16
  value = doc.elements[xpath]
17
17
  value = value.text unless value.nil?
18
18
  value = value.strip unless value.nil?
19
- self.class.__send__(:attr_reader, "#{varname}")
19
+ self.class.__send__(:attr_reader, varname)
20
20
  instance_variable_set("@#{varname}", value)
21
21
  end
22
22
 
@@ -25,10 +25,6 @@ module IbmPowerHmc
25
25
  get_value(doc, key, value)
26
26
  end
27
27
  end
28
-
29
- def to_s
30
- "uuid=#{@uuid}"
31
- end
32
28
  end
33
29
 
34
30
  # HMC information
@@ -44,10 +40,6 @@ module IbmPowerHmc
44
40
  info = doc.elements["content/ManagementConsole:ManagementConsole"]
45
41
  get_values(info, XMLMAP)
46
42
  end
47
-
48
- def to_s
49
- "hmc name=#{@name} version=#{@version} build_level=#{@build_level}"
50
- end
51
43
  end
52
44
 
53
45
  # Managed System information
@@ -60,7 +52,10 @@ module IbmPowerHmc
60
52
  "AssociatedSystemMemoryConfiguration/InstalledSystemMemory" => "memory",
61
53
  "AssociatedSystemMemoryConfiguration/CurrentAvailableSystemMemory" => "avail_mem",
62
54
  "AssociatedSystemProcessorConfiguration/InstalledSystemProcessorUnits" => "cpus",
63
- "AssociatedSystemProcessorConfiguration/CurrentAvailableSystemProcessorUnits" => "avail_cpus"
55
+ "AssociatedSystemProcessorConfiguration/CurrentAvailableSystemProcessorUnits" => "avail_cpus",
56
+ "MachineTypeModelAndSerialNumber/MachineType" => "mtype",
57
+ "MachineTypeModelAndSerialNumber/Model" => "model",
58
+ "MachineTypeModelAndSerialNumber/SerialNumber" => "serial",
64
59
  }.freeze
65
60
 
66
61
  def initialize(doc)
@@ -68,10 +63,6 @@ module IbmPowerHmc
68
63
  info = doc.elements["content/ManagedSystem:ManagedSystem"]
69
64
  get_values(info, XMLMAP)
70
65
  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
66
  end
76
67
 
77
68
  # Logical Partition information
@@ -96,10 +87,6 @@ module IbmPowerHmc
96
87
  @sys_uuid = URI(sys_href).path.split('/').last
97
88
  get_values(info, XMLMAP)
98
89
  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
90
  end
104
91
 
105
92
  # VIOS information
@@ -122,21 +109,12 @@ module IbmPowerHmc
122
109
  @sys_uuid = URI(sys_href).path.split('/').last
123
110
  get_values(info, XMLMAP)
124
111
  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
112
  end
137
113
 
138
114
  # HMC Event
139
115
  class Event < HmcObject
116
+ attr_reader :published
117
+
140
118
  XMLMAP = {
141
119
  "EventID" => "id",
142
120
  "EventType" => "type",
@@ -146,12 +124,25 @@ module IbmPowerHmc
146
124
 
147
125
  def initialize(doc)
148
126
  super(doc)
127
+ @published = doc.elements["published"].text
149
128
  info = doc.elements["content/Event:Event"]
150
129
  get_values(info, XMLMAP)
151
130
  end
131
+ end
132
+
133
+ # Error response from HMC
134
+ class HttpErrorResponse < HmcObject
135
+ XMLMAP = {
136
+ "HTTPStatus" => "status",
137
+ "RequestURI" => "uri",
138
+ "ReasonCode" => "reason",
139
+ "Message" => "message",
140
+ }.freeze
152
141
 
153
- def to_s
154
- "event id=#{@id} type=#{@type} data=#{@data} detail=#{@detail}"
142
+ def initialize(doc)
143
+ super(doc)
144
+ info = doc.elements["content/HttpErrorResponse:HttpErrorResponse"]
145
+ get_values(info, XMLMAP)
155
146
  end
156
147
  end
157
148
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'uri'
5
+
6
+ module IbmPowerHmc
7
+ class Connection
8
+ ##
9
+ # @!method managed_system_metrics(sys_uuid:, start_ts: nil, end_ts: nil, no_samples: nil)
10
+ # Retrieve metrics for a managed system.
11
+ # @param sys_uuid [String] The managed system UUID.
12
+ # @param start_ts [String] Start timestamp.
13
+ # @param end_ts [String] End timestamp.
14
+ # @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?
23
+
24
+ response = request(:get, method_url)
25
+ doc = REXML::Document.new(response.body)
26
+ metrics = []
27
+ doc.each_element("feed/entry") do |entry|
28
+ category = entry.elements["category"]
29
+ next if category.nil?
30
+
31
+ term = category.attributes["term"]
32
+ next if term.nil? || term != "ManagedSystem"
33
+
34
+ link = entry.elements["link"]
35
+ next if link.nil?
36
+
37
+ href = link.attributes["href"]
38
+ next if href.nil?
39
+
40
+ # Validate URI
41
+ begin
42
+ href = URI(href)
43
+ rescue
44
+ next
45
+ end
46
+ # Remove https://hostname:port prefix.
47
+ href.scheme = href.host = href.port = nil
48
+
49
+ response = request(:get, href.to_s)
50
+ metrics << JSON.parse(response.body)
51
+ end
52
+ metrics
53
+ end
54
+ end
55
+ 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.1.1"
5
5
  end
data/lib/ibm_power_hmc.rb CHANGED
File without changes
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.1.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-06 00:00:00.000000000 Z
11
+ date: 2021-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -25,12 +25,14 @@ 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: []
32
32
  files:
33
33
  - ".gitignore"
34
+ - ".rubocop.yml"
35
+ - ".rubocop_local.yml"
34
36
  - CHANGELOG.md
35
37
  - Gemfile
36
38
  - Gemfile.lock
@@ -44,6 +46,7 @@ files:
44
46
  - lib/ibm_power_hmc/connection.rb
45
47
  - lib/ibm_power_hmc/job.rb
46
48
  - lib/ibm_power_hmc/objects.rb
49
+ - lib/ibm_power_hmc/pcm.rb
47
50
  - lib/ibm_power_hmc/version.rb
48
51
  homepage: http://github.com/IBM/ibm_power_hmc_sdk_ruby
49
52
  licenses:
@@ -53,7 +56,7 @@ metadata:
53
56
  homepage_uri: http://github.com/IBM/ibm_power_hmc_sdk_ruby
54
57
  source_code_uri: http://github.com/IBM/ibm_power_hmc_sdk_ruby
55
58
  changelog_uri: http://github.com/IBM/ibm_power_hmc_sdk_ruby/blob/master/CHANGELOG.md
56
- post_install_message:
59
+ post_install_message:
57
60
  rdoc_options: []
58
61
  require_paths:
59
62
  - lib
@@ -68,8 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
71
  - !ruby/object:Gem::Version
69
72
  version: '0'
70
73
  requirements: []
71
- rubygems_version: 3.1.2
72
- signing_key:
74
+ rubygems_version: 3.0.3
75
+ signing_key:
73
76
  specification_version: 4
74
77
  summary: IBM Power HMC Ruby gem.
75
78
  test_files: []