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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +4 -0
- data/.rubocop_local.yml +7 -0
- data/README.md +6 -0
- data/lib/ibm_power_hmc/connection.rb +317 -116
- data/lib/ibm_power_hmc/job.rb +78 -32
- data/lib/ibm_power_hmc/parser.rb +203 -0
- data/lib/ibm_power_hmc/pcm.rb +122 -0
- data/lib/ibm_power_hmc/version.rb +1 -1
- data/lib/ibm_power_hmc.rb +2 -1
- metadata +6 -4
- data/Gemfile.lock +0 -37
- data/lib/ibm_power_hmc/objects.rb +0 -157
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e42aa4d6eaa8915b8c37ce96aab995801533b81d8fa70b1e351bc550cc6eaa02
|
4
|
+
data.tar.gz: 6022fb088c67eeb0c20e8435c20567ef62fb34e365419cfa20f6fb9bc1e769f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ca0280aaeff1a1a0ce0cf5c53c40b6f0ddfc94725536e53d19031b1b107de4c8b44919580eaf1716e60f302bf339363508597b9188634412511bcc7869e4f83
|
7
|
+
data.tar.gz: b0251d621a729e2b7d97c7655709fd68bd1e796466967f2021924ab7658a12c2dc13c34dfe71597f96f6ed2114e24c405362232c4dab2e88b653afbe2b7d679a
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
data/.rubocop_local.yml
ADDED
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
46
|
-
|
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
|
-
|
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
|
-
|
54
|
-
|
55
|
-
return systems if doc.root.nil?
|
87
|
+
FeedParser.new(response.body).objects(:ManagedSystem)
|
88
|
+
end
|
56
89
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
110
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
-
|
134
|
-
profiles = []
|
135
|
-
return profiles if doc.root.nil?
|
198
|
+
method_url += "?group=#{group_name}" unless group_name.nil?
|
136
199
|
|
137
|
-
|
138
|
-
|
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
|
-
|
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.
|
149
|
-
job
|
150
|
-
job.delete
|
215
|
+
job.run if sync
|
216
|
+
job
|
151
217
|
end
|
152
218
|
|
153
|
-
|
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.
|
158
|
-
job
|
159
|
-
job.delete
|
230
|
+
job.run if sync
|
231
|
+
job
|
160
232
|
end
|
161
233
|
|
162
|
-
|
163
|
-
|
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.
|
168
|
-
job
|
169
|
-
job.delete
|
245
|
+
job.run if sync
|
246
|
+
job
|
170
247
|
end
|
171
248
|
|
172
|
-
|
173
|
-
|
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.
|
178
|
-
job
|
179
|
-
job.delete
|
260
|
+
job.run if sync
|
261
|
+
job
|
180
262
|
end
|
181
263
|
|
182
|
-
|
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.
|
187
|
-
job
|
188
|
-
job.delete
|
275
|
+
job.run if sync
|
276
|
+
job
|
189
277
|
end
|
190
278
|
|
191
|
-
|
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.
|
196
|
-
job
|
197
|
-
|
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
|
-
|
201
|
-
|
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
|
-
|
336
|
+
response = nil
|
205
337
|
loop do
|
206
338
|
response = request(:get, method_url)
|
207
|
-
|
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
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
-
|
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
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
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
|
data/lib/ibm_power_hmc/job.rb
CHANGED
@@ -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
|
-
|
4
|
+
##
|
5
|
+
# HMC Job for long running operations.
|
6
6
|
class HmcJob
|
7
|
-
|
8
|
-
|
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
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
29
|
-
jobparams = doc.root.add_element("JobParameters",
|
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",
|
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 = @
|
36
|
-
|
37
|
-
|
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
|
-
|
61
|
+
raise JobNotStarted unless defined?(@id)
|
62
|
+
|
43
63
|
method_url = "/rest/api/uom/jobs/#{@id}"
|
44
64
|
headers = {
|
45
|
-
content_type
|
65
|
+
:content_type => "application/vnd.ibm.powervm.web+xml; type=JobRequest"
|
46
66
|
}
|
47
|
-
response = @
|
48
|
-
|
49
|
-
|
50
|
-
status
|
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
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
110
|
+
raise JobNotStarted unless defined?(@id)
|
111
|
+
|
66
112
|
method_url = "/rest/api/uom/jobs/#{@id}"
|
67
|
-
@
|
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
|
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/
|
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.
|
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-
|
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/
|
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
|