ibm_power_hmc 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|