rbvppc 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +302 -0
- data/Rakefile +8 -0
- data/documentation/hmc.odt +0 -0
- data/documentation/lpar.odt +0 -0
- data/documentation/lun.odt +0 -0
- data/documentation/network.odt +0 -0
- data/documentation/nim.odt +0 -0
- data/documentation/vio.odt +0 -0
- data/documentation/vnic.odt +0 -0
- data/documentation/vscsi.odt +0 -0
- data/examples/add_disk_any_size_to_lpar.rb +46 -0
- data/examples/add_disk_specifing_size_to_lpar.rb +47 -0
- data/examples/remove_disks_and_delete_lpar.rb +35 -0
- data/examples/remove_disks_from_lpar.rb +33 -0
- data/examples/test_lpar_build.rb +83 -0
- data/lib/rbvppc/command_failure.rb +18 -0
- data/lib/rbvppc/connectable_server.rb +95 -0
- data/lib/rbvppc/hmc.rb +892 -0
- data/lib/rbvppc/lpar.rb +1140 -0
- data/lib/rbvppc/lun.rb +23 -0
- data/lib/rbvppc/network.rb +54 -0
- data/lib/rbvppc/nim.rb +442 -0
- data/lib/rbvppc/version.rb +10 -0
- data/lib/rbvppc/vio.rb +720 -0
- data/lib/rbvppc/vnic.rb +34 -0
- data/lib/rbvppc/vscsi.rb +36 -0
- data/lib/rbvppc.rb +28 -0
- data/rbvppc.gemspec +26 -0
- metadata +117 -0
data/lib/rbvppc/lpar.rb
ADDED
|
@@ -0,0 +1,1140 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Authors: Christopher M Wood (<woodc@us.ibm.com>)
|
|
3
|
+
# John F Hutchinson (<jfhutchi@us.ibm.com)
|
|
4
|
+
# © Copyright IBM Corporation 2015.
|
|
5
|
+
#
|
|
6
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
|
7
|
+
#
|
|
8
|
+
=begin
|
|
9
|
+
Assumptions:
|
|
10
|
+
-operations on LPARs will be done simultaneously to both their current profile and
|
|
11
|
+
the LPAR's hardware itself, removing the need to abstract data into both LPAR attributes
|
|
12
|
+
and attributes of that LPAR's profile.
|
|
13
|
+
Future features:
|
|
14
|
+
-May split lpar_profile into a subclass of LPAR in the future, to allow greater levels of
|
|
15
|
+
customization.
|
|
16
|
+
=end
|
|
17
|
+
require_relative 'hmc'
|
|
18
|
+
require_relative 'vscsi'
|
|
19
|
+
require_relative 'network'
|
|
20
|
+
require_relative 'vnic'
|
|
21
|
+
|
|
22
|
+
class Lpar
|
|
23
|
+
|
|
24
|
+
attr_accessor :min_proc_units, :max_proc_units, :desired_proc_units,
|
|
25
|
+
:min_memory, :max_memory, :desired_memory,
|
|
26
|
+
:min_vcpu, :max_vcpu, :desired_vcpu,
|
|
27
|
+
:hostname, :uncap_weight, :max_virtual_slots
|
|
28
|
+
|
|
29
|
+
attr_reader :hmc, :id, :name, :proc_mode, :sharing_mode, :frame,
|
|
30
|
+
:current_profile, :default_profile
|
|
31
|
+
|
|
32
|
+
#Class variable to hold all 'valid' attributes that can be set on an LPAR
|
|
33
|
+
@@valid_attributes = ["min_mem", "desired_mem", "max_mem", "min_num_huge_pages", "desired_num_huge_pages", "max_num_huge_pages",
|
|
34
|
+
"mem_mode", "hpt_ratio", "proc_mode", "min_proc_units", "desired_proc_units", "max_proc_units", "min_procs",
|
|
35
|
+
"desired_procs", "max_procs", "sharing_mode", "uncap_weight", "shared_proc_pool_id", "shared_proc_pool_name",
|
|
36
|
+
"io_slots", "lpar_io_pool_ids", "max_virtual_slots", "hca_adapters", "boot_mode", "conn_monitoring", "auto_start",
|
|
37
|
+
"power_ctrl_lpar_ids", "work_group_id", "redundant_err_path_reporting", "bsr_arrays", "lhea_logical_ports", "lhea_capabilities", "lpar_proc_compat_mode", "electronic_err_reporting"]
|
|
38
|
+
#Small hash to handle translating HMC labels to Lpar class attributes
|
|
39
|
+
@@attr_mapping = {"min_mem" => "min_memory",
|
|
40
|
+
"max_mem" => "max_memory",
|
|
41
|
+
"desired_mem" => "desired_memory",
|
|
42
|
+
"min_proc_units" => "min_proc_units",
|
|
43
|
+
"max_proc_units" => "max_proc_units",
|
|
44
|
+
"desired_proc_units" => "desired_proc_units",
|
|
45
|
+
"min_procs" => "min_vcpu",
|
|
46
|
+
"max_procs" => "max_vcpu",
|
|
47
|
+
"desired_procs" => "desired_vcpu"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
def initialize(options_hash, disable_auto_reboot = false)
|
|
51
|
+
|
|
52
|
+
#Test for the explicitly required parameters
|
|
53
|
+
raise StandardError.new("An Lpar cannot be defined without a managing HMC") if options_hash[:hmc].nil? or !options_hash[:hmc].respond_to?(:execute_cmd)
|
|
54
|
+
raise StandardError.new("An Lpar cannot be defined without a name") if options_hash[:name].nil?
|
|
55
|
+
raise StandardError.new("An Lpar cannot be defined without specifying the frame it resides/will reside on") if options_hash[:frame].nil?
|
|
56
|
+
raise StandardError.new("An Lpar cannot be defined without specifying it's desired processing units") if options_hash[:des_proc].nil?
|
|
57
|
+
raise StandardError.new("An Lpar cannot be defined without specifying it's desired virtual CPUs") if options_hash[:des_vcpu].nil?
|
|
58
|
+
raise StandardError.new("An Lpar cannot be defined without specifying it's desired memory") if options_hash[:des_mem].nil?
|
|
59
|
+
|
|
60
|
+
#TODO: We should not really be storing the hostname (or vlan_id, or management_ip) as an attribute of LPAR, much less any network configuration stuff...
|
|
61
|
+
#Maybe we should consider a NetworkSettings class that is just an attribute of LPAR, which we leverage to find any network info we need here...?
|
|
62
|
+
raise StandardError.new("An Lpar cannot be defined without specifying it's FQDN") if options_hash[:hostname].nil? && options_hash[:name].nil?
|
|
63
|
+
|
|
64
|
+
#Parameters that are explicitly required to make an LPAR object
|
|
65
|
+
@hmc = options_hash[:hmc]
|
|
66
|
+
@desired_proc_units = options_hash[:des_proc].to_f
|
|
67
|
+
@desired_memory = options_hash[:des_mem].to_i
|
|
68
|
+
@desired_vcpu = options_hash[:des_vcpu].to_i
|
|
69
|
+
@frame = options_hash[:frame]
|
|
70
|
+
@name = options_hash[:name]
|
|
71
|
+
|
|
72
|
+
#Parameters that can be defaulted if they are not provided
|
|
73
|
+
!options_hash[:hostname].nil? ? @hostname = options_hash[:hostname] : @hostname = @name
|
|
74
|
+
!options_hash[:min_proc].nil? ? @min_proc_units = options_hash[:min_proc].to_f : @min_proc_units = @desired_proc_units
|
|
75
|
+
!options_hash[:max_proc].nil? ? @max_proc_units = options_hash[:max_proc].to_f : @max_proc_units = @desired_proc_units
|
|
76
|
+
!options_hash[:max_mem].nil? ? @max_memory = options_hash[:max_mem].to_i : @max_memory = @desired_memory
|
|
77
|
+
!options_hash[:min_mem].nil? ? @min_memory = options_hash[:min_mem].to_i : @min_memory = @desired_memory
|
|
78
|
+
!options_hash[:max_vcpu].nil? ? @max_vcpu = options_hash[:max_vcpu].to_i : @max_vcpu = @desired_vcpu
|
|
79
|
+
!options_hash[:min_vcpu].nil? ? @min_vcpu = options_hash[:min_vcpu].to_i : @min_vcpu = @desired_vcpu
|
|
80
|
+
!options_hash[:max_virt_slots].nil? ? @max_virtual_slots = options_hash[:max_virt_slots].to_i : @max_virtual_slots = 30
|
|
81
|
+
!options_hash[:current_profile].nil? ? @current_profile = options_hash[:current_profile] : @current_profile = @name + "_profile"
|
|
82
|
+
!options_hash[:default_profile].nil? ? @default_profile = options_hash[:default_profile] : @default_profile = @current_profile
|
|
83
|
+
!options_hash[:sharing_mode].nil? ? @sharing_mode = options_hash[:sharing_mode] : @sharing_mode = "cap"
|
|
84
|
+
@sharing_mode == "uncap" ? @uncap_weight = options_hash[:uncap_weight].to_i : @uncap_weight = nil
|
|
85
|
+
!options_hash[:proc_mode].nil? ? @proc_mode = options_hash[:proc_mode] : @proc_mode = "shared"
|
|
86
|
+
|
|
87
|
+
#Parameters that hold no value unless the LPAR already exists
|
|
88
|
+
#or create() is called
|
|
89
|
+
!options_hash[:id].nil? ? @id = options_hash[:id] : @id = nil
|
|
90
|
+
@disable_auto_reboot = disable_auto_reboot
|
|
91
|
+
#TODO: Implement the VIO pair as attributes of the LPAR???
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#Create an LPAR
|
|
95
|
+
def create
|
|
96
|
+
|
|
97
|
+
#Stop the create from proceeding if this LPAR already exists
|
|
98
|
+
raise StandardError.new("This LPAR already exists on #{frame}, cannot create #{name}") if exists?
|
|
99
|
+
|
|
100
|
+
command = "mksyscfg -r lpar -m #{@frame} -i name=#{@name}, profile_name=#{@current_profile},boot_mode=norm," +
|
|
101
|
+
"auto_start=0,lpar_env=aixlinux,max_virtual_slots=#{@max_virtual_slots},desired_mem=#{@desired_memory}," +
|
|
102
|
+
"min_mem=#{@min_memory},max_mem=#{@max_memory},desired_procs=#{@desired_vcpu},min_procs=#{@min_vcpu}," +
|
|
103
|
+
"max_procs=#{@max_vcpu},proc_mode=#{@proc_mode},sharing_mode=#{@sharing_mode},desired_proc_units=#{@desired_proc_units}," +
|
|
104
|
+
"max_proc_units=#{@max_proc_units},min_proc_units=#{@min_proc_units}"
|
|
105
|
+
command += ",uncap_weight=#{@uncap_weight}" if !@uncap_weight.nil?
|
|
106
|
+
|
|
107
|
+
hmc.execute_cmd(command)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
#Delete an LPAR
|
|
111
|
+
#Takes an optional array of Vio objects representing
|
|
112
|
+
#the VIO pair that serves storage to this LPAR.
|
|
113
|
+
def delete(vio_array = nil)
|
|
114
|
+
#Check that this LPAR exists before attempting to delete it.
|
|
115
|
+
#If the LPAR does not exist, simply output a warning stating such
|
|
116
|
+
if !exists?
|
|
117
|
+
warn "This LPAR (#{name}) does not currently exist on #{frame} to be deleted."
|
|
118
|
+
return
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
#Do a hard shutdown and then remove the LPAR definition
|
|
122
|
+
hard_shutdown unless not_activated?
|
|
123
|
+
sleep(10) until not_activated?
|
|
124
|
+
|
|
125
|
+
#If not passed, try to find the VIO servers by looking
|
|
126
|
+
#at this LPAR's vSCSI adapters
|
|
127
|
+
server_lpars = []
|
|
128
|
+
if vio_array.nil?
|
|
129
|
+
vscsis = get_vscsi_adapters
|
|
130
|
+
vscsis.each do |adapter|
|
|
131
|
+
server_lpars.push(adapter.remote_lpar_name)
|
|
132
|
+
end
|
|
133
|
+
server_lpars.uniq!
|
|
134
|
+
|
|
135
|
+
#Now if there are only two unique server LPARs
|
|
136
|
+
#that serve this LPAR, we have our VIO servers
|
|
137
|
+
if server_lpars.length == 2
|
|
138
|
+
vio_array = []
|
|
139
|
+
vio_array.push(Vio.new(hmc,frame,server_lpars[0]))
|
|
140
|
+
vio_array.push(Vio.new(hmc,frame,server_lpars[1]))
|
|
141
|
+
else
|
|
142
|
+
warn "Unable to determine this LPAR's VIO servers, proceeding without removing disks"
|
|
143
|
+
vio_array = nil
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
#Attempt to remove all of the LPAR's disks/vSCSIs before deleting
|
|
148
|
+
remove_storage(vio_array[0],vio_array[1]) if !vio_array.nil?
|
|
149
|
+
|
|
150
|
+
hmc.execute_cmd "rmsyscfg -r lpar -m #{frame} -n #{name}"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
#Rename an LPAR
|
|
154
|
+
def rename(newname)
|
|
155
|
+
hmc.execute_cmd "chsyscfg -r lpar -m #{frame} -i \'name=#{name},new_name=#{newname}\'"
|
|
156
|
+
@name = newname
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
#Active an LPAR using a profile
|
|
160
|
+
def activate(profile_name = @current_profile)
|
|
161
|
+
hmc.execute_cmd "chsysstate -r lpar -m #{frame} -o on -n #{name} -f #{profile_name}"
|
|
162
|
+
@current_profile = profile_name if @current_profile != profile_name
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
#Hard shutdown LPAR
|
|
166
|
+
def hard_shutdown
|
|
167
|
+
hmc.execute_cmd "chsysstate -r lpar -m #{frame} -o shutdown --immed -n #{name}"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#Soft shutdown an LPAR
|
|
171
|
+
def soft_shutdown
|
|
172
|
+
hmc.execute_cmd "chsysstate -r lpar -m #{frame} -o shutdown -n #{name}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
#Get LPAR state
|
|
176
|
+
def check_state
|
|
177
|
+
hmc.execute_cmd("lssyscfg -r lpar -m #{frame} --filter lpar_names=#{name} -F state").chomp
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
#Returns true if this LPAR actually exists on it's frame
|
|
181
|
+
#Returns false if it doesn't
|
|
182
|
+
def exists?
|
|
183
|
+
#List all LPARs residing underneath this frame
|
|
184
|
+
result = hmc.execute_cmd("lssyscfg -r lpar -m #{frame} -F name").chomp
|
|
185
|
+
#See if any of their names match this Lpar's name
|
|
186
|
+
result.each_line do |line|
|
|
187
|
+
line.chomp!
|
|
188
|
+
if line == name
|
|
189
|
+
return true
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
#Return false if none the names listed match this Lpar's name
|
|
193
|
+
return false
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
#Returns true/false value depending on if the LPAR is running or not
|
|
197
|
+
#Since an LPAR can have states such as "Not Activated", "Open Firmware", "Shutting Down",
|
|
198
|
+
#this function only helps for when we are explicitly looking for an LPAR to be either "Running" or not.
|
|
199
|
+
def is_running?
|
|
200
|
+
return check_state == "Running"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
#Similar to is_running? - only returns true if the LPAR's state is "Not Activated".
|
|
204
|
+
#Any other state is percieved as false
|
|
205
|
+
def not_activated?
|
|
206
|
+
return check_state == "Not Activated"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def get_info
|
|
210
|
+
info = hmc.execute_cmd "lssyscfg -r lpar -m \'#{frame}\' --filter lpar_names=\'#{name}\'"
|
|
211
|
+
return info.chomp
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
#Get the ID of an LPAR
|
|
215
|
+
def id
|
|
216
|
+
if @id.nil?
|
|
217
|
+
#Use an HMC command to pull the LPAR's ID if this is the first time that
|
|
218
|
+
#the LPAR's ID is being accessed
|
|
219
|
+
@id = hmc.execute_cmd("lssyscfg -r lpar -m #{frame} --filter lpar_names=#{name} -F lpar_id").chomp
|
|
220
|
+
end
|
|
221
|
+
return @id
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
#Get the Current Profile of an LPAR
|
|
225
|
+
def current_profile
|
|
226
|
+
if @current_profile.nil?
|
|
227
|
+
@current_profile = hmc.execute_cmd("lssyscfg -r lpar -m #{frame} --filter lpar_names=#{name} -F curr_profile").chomp
|
|
228
|
+
end
|
|
229
|
+
return @current_profile
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
#Get the Default Profile of an LPAR
|
|
233
|
+
def default_profile
|
|
234
|
+
if @default_profile.nil?
|
|
235
|
+
@default_profile = hmc.execute_cmd("lssyscfg -r lpar -m #{frame} --filter lpar_names=#{name} -F default_profile").chomp
|
|
236
|
+
end
|
|
237
|
+
return @default_profile
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
#Get the MAC address of an LPAR
|
|
241
|
+
def get_mac_address
|
|
242
|
+
result = hmc.execute_cmd("lshwres -r virtualio --rsubtype eth --level lpar -m #{frame} -F mac_addr --filter \"lpar_names=#{name}\" ")
|
|
243
|
+
return result.chomp
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
#Set an LPAR profile's attribute, specifying the units to set the attribute to and the HMC label for the attribute
|
|
247
|
+
def set_attr_profile(units,hmc_label)
|
|
248
|
+
cmd = "chsyscfg -m #{frame} -r prof -i \"name=#{current_profile}, lpar_name=#{name}, #{hmc_label}=#{units} \" "
|
|
249
|
+
hmc.execute_cmd(cmd)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
#Function to use for all Min/Max attribute changing
|
|
253
|
+
def set_attr_and_reactivate(units,hmc_label)
|
|
254
|
+
#Change the profile attribute
|
|
255
|
+
set_attr_profile(units,hmc_label)
|
|
256
|
+
reactivate unless @disable_auto_reboot
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Shutdown and reactivate the LPAR so that the attribute changes take effect
|
|
260
|
+
def reactivate
|
|
261
|
+
#Shut down the LPAR
|
|
262
|
+
soft_shutdown unless not_activated?
|
|
263
|
+
#Wait until it's state is "Not Activated"
|
|
264
|
+
sleep(10) until not_activated?
|
|
265
|
+
#Reactivate the LPAR so that the attribute changes take effect
|
|
266
|
+
activate
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
#Bulk modifies an LPAR's resources based on the provided hash.
|
|
270
|
+
#The Hash is required to have it's keys represent labels for HMC attributes (ie, min_mem, max_mem, etc)
|
|
271
|
+
#while it's values are what the user requests those attributes be set to for this LPAR.
|
|
272
|
+
#The LPAR is then reactivated once all of the changes are made for them to take effect.
|
|
273
|
+
# The Class Instance variable @@valid_attributes is used to determine if a key in options is a valid
|
|
274
|
+
# attribute. If an attribute in options is deemed invalid, nothing is done with respect to that attribute.
|
|
275
|
+
def modify_resources(options, reboot = true)
|
|
276
|
+
options.each do |key,val|
|
|
277
|
+
if @@valid_attributes.include?(key)
|
|
278
|
+
#Check for min/max/desired in the key to determine if
|
|
279
|
+
#some bound needs to be checked first
|
|
280
|
+
verify_and_handle_attr_bounds(options,key,val)
|
|
281
|
+
|
|
282
|
+
set_attr_profile(val,key)
|
|
283
|
+
|
|
284
|
+
#Handle setting of any instance variables that should change
|
|
285
|
+
#due to this
|
|
286
|
+
map_key_to_attr(key, val)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
reactivate if reboot
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
#####################################
|
|
293
|
+
# Processing Unit functions
|
|
294
|
+
#####################################
|
|
295
|
+
|
|
296
|
+
#Set the processing units for an LPAR
|
|
297
|
+
def desired_proc_units=(units)
|
|
298
|
+
|
|
299
|
+
raise StandardError.new("Processing unit value is lower than the Minimum Processing Units specified for this LPAR: #{min_proc_units}") if units < min_proc_units
|
|
300
|
+
raise StandardError.new("Processing unit value is higher than the Maximum Processing Units specified for this LPAR: #{max_proc_units}") if units > max_proc_units
|
|
301
|
+
|
|
302
|
+
#Validate that this value adheres to the vCPU:Proc_unit ratio of 10:1
|
|
303
|
+
raise StandardError.new("Desired processing unit value must be less than or equal to Desired vCPU value: #{desired_vcpu}") if units > desired_vcpu
|
|
304
|
+
raise StandardError.new("Desired processing unit value must be at least 1/10 the Desired vCPU value: #{desired_vcpu}") if desired_vcpu/units > 10
|
|
305
|
+
|
|
306
|
+
#Set processing units on the Profile
|
|
307
|
+
set_attr_profile(units,"desired_proc_units")
|
|
308
|
+
#Set processing units via DLPAR
|
|
309
|
+
set_proc_units_dlpar(units)
|
|
310
|
+
|
|
311
|
+
#After the Desired Proc units are set on the profile and hardware, set
|
|
312
|
+
#the private attribute
|
|
313
|
+
@desired_proc_units = units
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
#Set the max processing units for an LPAR
|
|
317
|
+
def max_proc_units=(units)
|
|
318
|
+
raise StandardError.new("Maximum processing unit value is lower than the Desired Processing Units specified for this LPAR") if units < desired_proc_units
|
|
319
|
+
|
|
320
|
+
#Validate that the value specified does not violate the 10:1 ratio requirement between max vCPU and max proc units.
|
|
321
|
+
raise StandardError.new("Maximum processing unit value must be less than or equal to Maximum vCPU value: #{max_vcpu}") if units > max_vcpu
|
|
322
|
+
raise StandardError.new("Maximum processing unit value must at least be 1/10 the Maximum vCPU value: #{max_vcpu}") if max_vcpu/units > 10
|
|
323
|
+
|
|
324
|
+
#Set the Max Proc Units on the LPAR profile
|
|
325
|
+
#and reactivate the LPAR
|
|
326
|
+
set_attr_and_reactivate(units,"max_proc_units")
|
|
327
|
+
|
|
328
|
+
#Set the private member
|
|
329
|
+
@max_proc_units = units
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
#Set the min processing units for an LPAR
|
|
333
|
+
def min_proc_units=(units)
|
|
334
|
+
raise StandardError.new("Minimum processing unit value is greater than the Desired Processing Units specified for this LPAR") if units > desired_proc_units
|
|
335
|
+
|
|
336
|
+
#Validate that this value adheres to the vCPU:Proc_unit ratio of 10:1
|
|
337
|
+
raise StandardError.new("Minimum processing unit value must be less than or equal to Minimum vCPU value: #{min_vcpu}") if units > min_vcpu
|
|
338
|
+
raise StandardError.new("Minimum processing unit value must be at least 1/10 the Minimum vCPU value: #{min_vcpu}") if min_vcpu/units > 10
|
|
339
|
+
|
|
340
|
+
#Set the Max Proc Units on the LPAR profile
|
|
341
|
+
#and reactivate the LPAR
|
|
342
|
+
set_attr_and_reactivate(units,"min_proc_units")
|
|
343
|
+
|
|
344
|
+
#Set the private member
|
|
345
|
+
@min_proc_units = units
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
#####################################
|
|
349
|
+
# Virtual CPU functions
|
|
350
|
+
#####################################
|
|
351
|
+
|
|
352
|
+
#Set the virtual CPUs for an LPAR
|
|
353
|
+
def desired_vcpu=(units)
|
|
354
|
+
raise StandardError.new("Virtual CPU value is lower than the Minimum Virtual CPU value specified for this LPAR: #{min_vcpu}") if units < min_vcpu
|
|
355
|
+
raise StandardError.new("Virtual CPU value is higher than the Maximum Virtual CPU value specified for this LPAR: #{max_vcpu}") if units > max_vcpu
|
|
356
|
+
|
|
357
|
+
#Validate that this value adheres to the vCPU:Proc_unit ratio of 10:1
|
|
358
|
+
raise StandardError.new("Desired vCPU value must be greater than or equal to Desired processing unit value: #{desired_proc_units}") if units < desired_proc_units
|
|
359
|
+
raise StandardError.new("Desired vCPU value must be at most 10 times as large as Desired processing unit value: #{desired_proc_units}") if units/desired_proc_units > 10
|
|
360
|
+
|
|
361
|
+
#Set processing units on the Profile
|
|
362
|
+
set_attr_profile(units,"desired_procs")
|
|
363
|
+
#Set processing units via DLPAR
|
|
364
|
+
set_vcpu_dlpar(units)
|
|
365
|
+
|
|
366
|
+
#After the Desired Proc units are set on the profile and hardware, set
|
|
367
|
+
#the private attribute
|
|
368
|
+
@desired_vcpu = units
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
#Set the minimum virtual CPUs for an LPAR
|
|
372
|
+
def min_vcpu=(units)
|
|
373
|
+
raise StandardError.new("Minimum vCPU value is higher than the Desired Virtual CPU specified for this LPAR: #{desired_vcpu}") if units > desired_vcpu
|
|
374
|
+
|
|
375
|
+
#Validate that this value adheres to the vCPU:Proc_unit ratio of 10:1
|
|
376
|
+
raise StandardError.new("Minimum vCPU value must be greater than or equal to Minimum processing unit value: #{min_proc_units}") if units < min_proc_units
|
|
377
|
+
raise StandardError.new("Minimum vCPU value must be at most 10 times as large as Minimum processing unit value: #{min_proc_units}") if units/min_proc_units > 10
|
|
378
|
+
|
|
379
|
+
#Set the Min vCPU on the LPAR profile
|
|
380
|
+
#and reactivate the LPAR
|
|
381
|
+
set_attr_and_reactivate(units,"min_procs")
|
|
382
|
+
|
|
383
|
+
#Set the private member
|
|
384
|
+
@min_vcpu = units
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
#Set the maximum virtual CPUs for an LPAR
|
|
388
|
+
def max_vcpu=(units)
|
|
389
|
+
raise StandardError.new("Maximum vCPU value is lower than the Desired Virtual CPU specified for this LPAR: #{desired_vcpu}") if units < desired_vcpu
|
|
390
|
+
|
|
391
|
+
#Validate that this value adheres to the vCPU:Proc_unit ratio of 10:1
|
|
392
|
+
raise StandardError.new("Maximum vCPU value must be greater than or equal to Maximum processing unit value: #{max_proc_units}") if units < max_proc_units
|
|
393
|
+
raise StandardError.new("Maximum vCPU value must be at most 10 times as large as Maximum processing unit value: #{max_proc_units}") if units/max_proc_units > 10
|
|
394
|
+
|
|
395
|
+
#Set the Max vCPU on the LPAR profile
|
|
396
|
+
#and reactivate the LPAR
|
|
397
|
+
set_attr_and_reactivate(units,"max_procs")
|
|
398
|
+
|
|
399
|
+
#Set the private member
|
|
400
|
+
@max_vcpu = units
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
############################################
|
|
404
|
+
# Memory allocation/deallocation functions
|
|
405
|
+
############################################
|
|
406
|
+
|
|
407
|
+
#Set the Memory allocated to an LPAR (in MB)
|
|
408
|
+
def desired_memory=(units)
|
|
409
|
+
|
|
410
|
+
raise StandardError.new("Memory value is lower than the Minimum Memory specified for this LPAR") if units < min_memory
|
|
411
|
+
raise StandardError.new("Memory value is higher than the Maximum Memory specified for this LPAR") if units > max_memory
|
|
412
|
+
|
|
413
|
+
#Set the desired memory of the LPAR in the profile
|
|
414
|
+
set_attr_profile(units,"desired_mem")
|
|
415
|
+
|
|
416
|
+
#Set the desired memory of the LPAR via DLPAR
|
|
417
|
+
set_memory_dlpar(units)
|
|
418
|
+
|
|
419
|
+
#After it has been set on the profile and the LPAR, set the attribute for the object
|
|
420
|
+
@desired_memory = units
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
#Set the minimum virtual CPUs for an LPAR
|
|
424
|
+
def min_memory=(units)
|
|
425
|
+
raise StandardError.new("Minimum Memory value is higher than the Desired Memory specified for this LPAR: #{desired_memory}") if units > desired_memory
|
|
426
|
+
|
|
427
|
+
#Set the Min Memory on the LPAR profile
|
|
428
|
+
#and reactivate
|
|
429
|
+
set_attr_and_reactivate(units,"min_mem")
|
|
430
|
+
|
|
431
|
+
#Set private member
|
|
432
|
+
@min_memory = units
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
#Set the maximum virtual CPUs for an LPAR
|
|
436
|
+
def max_memory=(units)
|
|
437
|
+
raise StandardError.new("Maximum Memory value is lower than the Desired Memory specified for this LPAR: #{desired_memory}") if units < desired_memory
|
|
438
|
+
|
|
439
|
+
#Set the Max vCPU on the LPAR profile
|
|
440
|
+
#and reactivate
|
|
441
|
+
set_attr_and_reactivate(units,"max_mem")
|
|
442
|
+
|
|
443
|
+
#Set private member
|
|
444
|
+
@max_memory = units
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
####################################
|
|
448
|
+
# Misc LPAR Attribute functions
|
|
449
|
+
####################################
|
|
450
|
+
|
|
451
|
+
#Set the Uncapped Processor Weight for this LPAR
|
|
452
|
+
#TODO: change set_attr_profile to set_attr_and_reactivate?
|
|
453
|
+
def uncap_weight=(units)
|
|
454
|
+
if sharing_mode == "uncap"
|
|
455
|
+
set_attr_profile(units,"uncap_weight")
|
|
456
|
+
#set_attr_and_reactivate(units,"uncap_weight")
|
|
457
|
+
@uncap_weight = units
|
|
458
|
+
else
|
|
459
|
+
#Warn user that the sharing mode doesn't permit modifying uncap_weight
|
|
460
|
+
warn "Cannot change uncap_weight on a capped LPAR"
|
|
461
|
+
return nil
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
#Set the Maximum number of virtual adapters for this LPAR
|
|
466
|
+
#TODO: change set_attr_profile to set_attr_and_reactivate?
|
|
467
|
+
def max_virtual_slots=(units)
|
|
468
|
+
if units < max_virtual_slots
|
|
469
|
+
#Test to make sure that any occupied slots are
|
|
470
|
+
#less than units
|
|
471
|
+
used_slots = get_used_virtual_slots
|
|
472
|
+
max = used_slots.sort[0]
|
|
473
|
+
raise StandardError.new("Cannot reduce the maximum number of virtual slots to #{units} because slot #{max} is currently in use") if units < max
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
set_attr_profile(units,"max_virtual_slots")
|
|
477
|
+
@max_virtual_slots = units
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
####################################
|
|
481
|
+
# vSCSI Adapter functions
|
|
482
|
+
####################################
|
|
483
|
+
|
|
484
|
+
#Returns array of output with vSCSI adapter information
|
|
485
|
+
#about the client LPAR
|
|
486
|
+
def get_vscsi_adapters
|
|
487
|
+
|
|
488
|
+
#Get vSCSI adapter info from this LPAR's profile
|
|
489
|
+
scsi_adapter_output = clean_vadapter_string(hmc.execute_cmd("lssyscfg -r prof -m #{frame} --filter 'lpar_names=#{name},profile_names=#{current_profile}' -F virtual_scsi_adapters").chomp)
|
|
490
|
+
vscsi_adapters = []
|
|
491
|
+
if scsi_adapter_output.include?(",")
|
|
492
|
+
scsi_adapters = scsi_adapter_output.split(/,/)
|
|
493
|
+
#split on /
|
|
494
|
+
#11/client/1/rslppc09a/17/0,12/client/2/rslppc09b/17/0
|
|
495
|
+
scsi_adapters.each do |scsi_adapter|
|
|
496
|
+
scsi_adapter = scsi_adapter.split("/")
|
|
497
|
+
vscsi = Vscsi.new(scsi_adapter[0],scsi_adapter[1],scsi_adapter[2],scsi_adapter[3],scsi_adapter[4],scsi_adapter[5])
|
|
498
|
+
vscsi_adapters.push(vscsi)
|
|
499
|
+
end
|
|
500
|
+
elsif !scsi_adapter_output.empty?
|
|
501
|
+
scsi_adapter = scsi_adapter_output
|
|
502
|
+
scsi_adapter = scsi_adapter.split("/")
|
|
503
|
+
vscsi = Vscsi.new(scsi_adapter[0],scsi_adapter[1],scsi_adapter[2],scsi_adapter[3],scsi_adapter[4],scsi_adapter[5])
|
|
504
|
+
vscsi_adapters.push(vscsi)
|
|
505
|
+
end
|
|
506
|
+
return vscsi_adapters
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
#Return array of used virtual adapter slots
|
|
510
|
+
#for an LPAR
|
|
511
|
+
def get_used_virtual_slots
|
|
512
|
+
#scsi_slot_output = execute_cmd "lshwres -r virtualio --rsubtype scsi -m #{frame} --level lpar --filter lpar_names=#{lpar} -F slot_num"
|
|
513
|
+
#eth_slot_output = execute_cmd "lshwres -r virtualio --rsubtype eth -m #{frame} --level lpar --filter lpar_names=#{lpar} -F slot_num"
|
|
514
|
+
#serial_slot_output = execute_cmd "lshwres -r virtualio --rsubtype serial -m #{frame} --level lpar --filter lpar_names=#{lpar} -F slot_num"
|
|
515
|
+
#lpar_prof = get_lpar_curr_profile(frame,lpar)
|
|
516
|
+
|
|
517
|
+
scsi_slot_output = clean_vadapter_string(hmc.execute_cmd "lssyscfg -r prof -m '#{frame}' --filter 'lpar_names=#{name},profile_names=#{current_profile}' -F virtual_scsi_adapters")
|
|
518
|
+
serial_slot_output = clean_vadapter_string(hmc.execute_cmd "lssyscfg -r prof -m '#{frame}' --filter 'lpar_names=#{name},profile_names=#{current_profile}' -F virtual_serial_adapters")
|
|
519
|
+
eth_slot_output = clean_vadapter_string(hmc.execute_cmd "lssyscfg -r prof -m '#{frame}' --filter 'lpar_names=#{name},profile_names=#{current_profile}' -F virtual_eth_adapters")
|
|
520
|
+
used_slots = []
|
|
521
|
+
|
|
522
|
+
if scsi_slot_output.include?(",")
|
|
523
|
+
scsi_slots = scsi_slot_output.split(/,/)
|
|
524
|
+
else
|
|
525
|
+
scsi_slots = [scsi_slot_output]
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
if serial_slot_output.include?(",")
|
|
529
|
+
serial_slots = serial_slot_output.split(/,/)
|
|
530
|
+
else
|
|
531
|
+
serial_slots = [serial_slot_output]
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
if eth_slot_output.include?(",")
|
|
535
|
+
eth_slots = eth_slot_output.split(/,/)
|
|
536
|
+
else
|
|
537
|
+
eth_slots = [eth_slot_output]
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
scsi_slots.each do |adapter_line|
|
|
541
|
+
if !adapter_line.empty?
|
|
542
|
+
parse_hash = parse_vscsi_syntax(adapter_line)
|
|
543
|
+
used_slots.push(parse_hash[:virtual_slot_num].to_i)
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
serial_slots.each do |adapter_line|
|
|
548
|
+
if !adapter_line.empty?
|
|
549
|
+
parse_hash = parse_vserial_syntax(adapter_line)
|
|
550
|
+
used_slots.push(parse_hash[:virtual_slot_num].to_i)
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
eth_slots.each do |adapter_line|
|
|
555
|
+
if !adapter_line.empty?
|
|
556
|
+
parse_hash = parse_vnic_syntax(adapter_line)
|
|
557
|
+
used_slots.push(parse_hash[:virtual_slot_num].to_i)
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
return used_slots
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
#Get next usable virtual slot on an LPAR
|
|
565
|
+
#Returns nil if no usable slots exist
|
|
566
|
+
def get_available_slot(type = nil)
|
|
567
|
+
max_slots = max_virtual_slots
|
|
568
|
+
used_slots = get_used_virtual_slots
|
|
569
|
+
lowest_slot=11
|
|
570
|
+
if !type.nil?
|
|
571
|
+
lowest_slot=2 if type == "eth"
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
lowest_slot.upto(max_slots) do |n|
|
|
575
|
+
if !used_slots.include?(n)
|
|
576
|
+
return n
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
return nil
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
#Remove vSCSI from LPAR
|
|
583
|
+
#Handles removing from the LPAR profiles as well as DLPAR
|
|
584
|
+
#Last parameter is optional and if it isn't specified
|
|
585
|
+
#then it looks for an adapter on lpar that is attached to server_lpar
|
|
586
|
+
#and removes that from the profile/hardware of both the client
|
|
587
|
+
#and server
|
|
588
|
+
#MAY BE DANGEROUS- if multiple vSCSI adapters on a single lpar pointing at the same VIO
|
|
589
|
+
def remove_vscsi(server_lpar,adapter_details=nil)
|
|
590
|
+
if adapter_details.nil?
|
|
591
|
+
adapters = get_vscsi_adapters
|
|
592
|
+
adapters.each do |adapter|
|
|
593
|
+
adapter_details = adapter if adapter.remote_lpar_name == server_lpar.name
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
#Remove this vSCSI from the lpar and server lpar profiles
|
|
598
|
+
remove_vscsi_from_profile(server_lpar,adapter_details)
|
|
599
|
+
|
|
600
|
+
#Remove this vSCSI from the actual hardware of lpar and server lpar
|
|
601
|
+
remove_vscsi_dlpar(server_lpar,adapter_details)
|
|
602
|
+
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
#Remove vSCSI from the LPAR profiles only
|
|
606
|
+
def remove_vscsi_from_profile(server_lpar,vscsi)
|
|
607
|
+
remote_lpar_profile = server_lpar.current_profile
|
|
608
|
+
client_lpar_id = id
|
|
609
|
+
|
|
610
|
+
client_slot = vscsi.virtual_slot_num
|
|
611
|
+
server_lpar_id = vscsi.remote_lpar_id
|
|
612
|
+
if server_lpar != vscsi.remote_lpar_name
|
|
613
|
+
#server_lpar and the LPAR cited in the
|
|
614
|
+
#vscsi hash aren't the same...
|
|
615
|
+
#error out or do something else here...?
|
|
616
|
+
end
|
|
617
|
+
server_slot = vscsi.remote_slot_num
|
|
618
|
+
is_req = vscsi.is_required
|
|
619
|
+
|
|
620
|
+
#Modify client LPAR's profile to no longer include the adapter
|
|
621
|
+
#whose details occupy the vscsi_hash
|
|
622
|
+
hmc.execute_cmd("chsyscfg -r prof -m #{frame} -i \"name=#{current_profile},lpar_name=#{name}," +
|
|
623
|
+
"virtual_scsi_adapters-=#{client_slot}/client/#{server_lpar_id}/#{server_lpar.name}/#{server_slot}/#{is_req}\" ")
|
|
624
|
+
|
|
625
|
+
#Modify the server LPAR's profile to no longer include the client
|
|
626
|
+
hmc.execute_cmd("chsyscfg -r prof -m #{server_lpar.frame} -i \"name=#{remote_lpar_profile},lpar_name=#{server_lpar.name}," +
|
|
627
|
+
"virtual_scsi_adapters-=#{server_slot}/server/#{client_lpar_id}/#{name}/#{client_slot}/#{is_req}\" ")
|
|
628
|
+
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
#Remove vSCSI from LPARs via DLPAR
|
|
632
|
+
def remove_vscsi_dlpar(server_lpar,vscsi)
|
|
633
|
+
|
|
634
|
+
client_slot = vscsi.virtual_slot_num
|
|
635
|
+
server_slot = vscsi.remote_slot_num
|
|
636
|
+
|
|
637
|
+
#If the client LPAR is running, we have to do DLPAR on it.
|
|
638
|
+
if is_running?
|
|
639
|
+
hmc.execute_cmd("chhwres -r virtualio -m #{frame} -p #{name} -o r --rsubtype scsi -s #{client_slot}")
|
|
640
|
+
#-a \"adapter_type=client,remote_lpar_name=#{server_lpar},remote_slot_num=#{server_slot}\" ")
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
#If the server LPAR is running, we have to do DLPAR on it.
|
|
644
|
+
if server_lpar.is_running?
|
|
645
|
+
hmc.execute_cmd("chhwres -r virtualio -m #{server_lpar.frame} -p #{server_lpar.name} -o r --rsubtype scsi -s #{server_slot}")
|
|
646
|
+
#-a \"adapter_type=server,remote_lpar_name=#{lpar},remote_slot_num=#{client_slot}\" ")
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
#Add vSCSI to LPAR
|
|
651
|
+
#Handles adding to profile and via DLPAR
|
|
652
|
+
def add_vscsi(server_lpar)
|
|
653
|
+
#Add vscsi to client and server LPAR profiles
|
|
654
|
+
#Save the adapter slots used
|
|
655
|
+
client_slot, server_slot = add_vscsi_to_profile(server_lpar)
|
|
656
|
+
|
|
657
|
+
#Run DLPAR commands against LPARs themselves (if necessary)
|
|
658
|
+
add_vscsi_dlpar(server_lpar, client_slot, server_slot)
|
|
659
|
+
|
|
660
|
+
return [client_slot, server_slot]
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
#Add vSCSI adapter to LPAR profile
|
|
664
|
+
def add_vscsi_to_profile(server_lpar)
|
|
665
|
+
virtual_slot_num = get_available_slot
|
|
666
|
+
remote_slot_num = server_lpar.get_available_slot
|
|
667
|
+
lpar_profile = current_profile
|
|
668
|
+
remote_lpar_profile = server_lpar.current_profile
|
|
669
|
+
|
|
670
|
+
raise StandardError.new("No available virtual adapter slots on client LPAR #{lpar}") if virtual_slot_num.nil?
|
|
671
|
+
raise StandardError.new("No available virtual adapter slots on server LPAR #{server_lpar}") if remote_slot_num.nil?
|
|
672
|
+
|
|
673
|
+
#Modify client LPAR's profile
|
|
674
|
+
hmc.execute_cmd("chsyscfg -r prof -m #{frame} -i \"name=#{lpar_profile},lpar_name=#{name},virtual_scsi_adapters+=#{virtual_slot_num}/client//#{server_lpar.name}/#{remote_slot_num}/0\" ")
|
|
675
|
+
#Modify server LPAR's profile
|
|
676
|
+
hmc.execute_cmd("chsyscfg -r prof -m #{server_lpar.frame} -i \"name=#{remote_lpar_profile},lpar_name=#{server_lpar.name},virtual_scsi_adapters+=#{remote_slot_num}/server//#{name}/#{virtual_slot_num}/0\" ")
|
|
677
|
+
|
|
678
|
+
#Return the client slot and server slot used in the LPAR profiles
|
|
679
|
+
return [virtual_slot_num, remote_slot_num]
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
#Add vSCSI adapter via DLPAR command
|
|
683
|
+
def add_vscsi_dlpar(server_lpar,client_slot_to_use = nil, server_slot_to_use = nil)
|
|
684
|
+
if client_slot_to_use.nil? or server_slot_to_use.nil?
|
|
685
|
+
client_slot_to_use = get_available_slot
|
|
686
|
+
server_slot_to_use = server_lpar.get_available_slot
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
#If the client LPAR is running, we have to do DLPAR on it.
|
|
690
|
+
if is_running?
|
|
691
|
+
hmc.execute_cmd("chhwres -r virtualio -m #{frame} -p #{name} -o a --rsubtype scsi -s #{client_slot_to_use} -a \"adapter_type=client,remote_lpar_name=#{server_lpar.name},remote_slot_num=#{server_slot_to_use}\" ")
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
#If the server LPAR is running, we have to do DLPAR on it.
|
|
695
|
+
if server_lpar.is_running?
|
|
696
|
+
hmc.execute_cmd("chhwres -r virtualio -m #{server_lpar.frame} -p #{server_lpar.name} -o a --rsubtype scsi -s #{server_slot_to_use} -a \"adapter_type=server,remote_lpar_name=#{name},remote_slot_num=#{client_slot_to_use}\" ")
|
|
697
|
+
end
|
|
698
|
+
#chhwres -r virtualio -m "FrameName" -p VioName -o a --rsubtype scsi -s 11 -a "adapter_type=server,remote_lpar_name=ClientLPAR,remote_slot_num=5"
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
#####################################
|
|
703
|
+
# Disk management functions
|
|
704
|
+
#####################################
|
|
705
|
+
|
|
706
|
+
#Adds storage to this LPAR using the provided Primary and Secondary VIOs
|
|
707
|
+
#and the amount of storage requested, in GB
|
|
708
|
+
def add_storage(primary_vio,secondary_vio,size_in_gb)
|
|
709
|
+
#Get info about all vSCSIs attached to this LPAR
|
|
710
|
+
attached_vscsis = get_vscsi_adapters
|
|
711
|
+
|
|
712
|
+
#Keep track of the number of vSCSI adapters that attach to the
|
|
713
|
+
#VIOs. This should be 2 after finding the vSCSI adapters that attach
|
|
714
|
+
#to each of the VIOs (one for each VIO). If it is more, then there must
|
|
715
|
+
#be more than one vSCSI attached to one or both of the VIOs.
|
|
716
|
+
adapter_count = 0
|
|
717
|
+
primary_vscsi = nil
|
|
718
|
+
secondary_vscsi = nil
|
|
719
|
+
#Find the vSCSI adapters for each VIO
|
|
720
|
+
attached_vscsis.each do |vscsi|
|
|
721
|
+
if vscsi.remote_lpar_name == primary_vio.name
|
|
722
|
+
primary_vscsi = vscsi
|
|
723
|
+
adapter_count += 1
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
if vscsi.remote_lpar_name == secondary_vio.name
|
|
727
|
+
secondary_vscsi = vscsi
|
|
728
|
+
adapter_count += 1
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
#If the adapter count is greater than 2, that means that at least one of the
|
|
733
|
+
#VIOs in this pair has more than one vSCSI that attaches to this LPAR.
|
|
734
|
+
#Fail out for now.
|
|
735
|
+
#TODO: Add better handling logic that can avoid this issue.
|
|
736
|
+
if adapter_count > 2
|
|
737
|
+
warn "This LPAR has multiple adapter connections to it's VIOs; unable to determine which adapter to attach new disks to..."
|
|
738
|
+
return nil
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
#If an adapter cannot not be found for either of the VIOs, fail out
|
|
742
|
+
#because a disk cannot be attached.
|
|
743
|
+
if primary_vscsi.nil? or secondary_vscsi.nil?
|
|
744
|
+
raise StandardError.new("Cannot attach storage to this LPAR. It does not have a vSCSI adapter defined to one of it's VIOs")
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
#Use the remote_slot_num attribute of the two vSCSIs that were found
|
|
748
|
+
#to find out the names of the vhosts they reference on each of the VIOs
|
|
749
|
+
primary_vhost = primary_vio.find_vhost_given_virtual_slot(primary_vscsi.remote_slot_num)
|
|
750
|
+
secondary_vhost = secondary_vio.find_vhost_given_virtual_slot(secondary_vscsi.remote_slot_num)
|
|
751
|
+
|
|
752
|
+
#Use Vio map_by_size function to map the appropriate disks to both VIOs
|
|
753
|
+
primary_vio.map_by_size(primary_vhost, secondary_vio, secondary_vhost, size_in_gb)
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
#Removes/deallocates all storage from this LPAR and unmaps all of these disks
|
|
757
|
+
#on the specified Primary and Secondary VIO servers. The disks attached to
|
|
758
|
+
#the LPAR are assumed to be supplied by the Primary and Secondary VIOs specified.
|
|
759
|
+
def remove_storage(primary_vio,secondary_vio)
|
|
760
|
+
#Deallocates all storage and vSCSI adapters from this LPAR
|
|
761
|
+
primary_vio.unmap_all_disks(secondary_vio, self)
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
#Removes/deallocates a disk from the LPAR specified by it's PVID.
|
|
765
|
+
#This disk is assumed to be supplied by the Primary and Secondary VIO specified
|
|
766
|
+
def remove_disk(primary_vio,secondary_vio,pvid)
|
|
767
|
+
#Use unmap_by_pvid Vio function to unmap a single disk from this LPAR.
|
|
768
|
+
primary_vio.unmap_by_pvid(secondary_vio, pvid)
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
#####################################
|
|
772
|
+
# vNIC functions
|
|
773
|
+
#####################################
|
|
774
|
+
|
|
775
|
+
#Gets a list of vNIC objects
|
|
776
|
+
def get_vnic_adapters
|
|
777
|
+
#Get vNIC adapter info from this LPARs profile
|
|
778
|
+
eth_adapter_output = clean_vadapter_string(hmc.execute_cmd("lssyscfg -r prof -m #{frame} --filter 'lpar_names=#{name},profile_names=#{current_profile}' -F virtual_eth_adapters").chomp)
|
|
779
|
+
eth_adapters = []
|
|
780
|
+
#If there are multiple vNICs,
|
|
781
|
+
#they must be split on ',' and handled
|
|
782
|
+
#individually
|
|
783
|
+
if eth_adapter_output.include?(",")
|
|
784
|
+
#TODO:
|
|
785
|
+
# => Test with vNICs that have Additional VLAN IDs.
|
|
786
|
+
# => If Additional VLAN IDs have commas too, re-evaluate the logic here.
|
|
787
|
+
adapters = eth_adapter_output.split(/,/)
|
|
788
|
+
adapters.each do |adapter|
|
|
789
|
+
split_adapter = adapter.split("/")
|
|
790
|
+
vnic = Vnic.new(split_adapter[0],split_adapter[1],split_adapter[2],split_adapter[3],split_adapter[4],split_adapter[5])
|
|
791
|
+
eth_adapters.push(vnic)
|
|
792
|
+
end
|
|
793
|
+
elsif !eth_adapter_output.empty?
|
|
794
|
+
#If there are no ','s assume the there is only one vNIC defined
|
|
795
|
+
split_adapter = eth_adapter_output.split("/")
|
|
796
|
+
vnic = Vnic.new(split_adapter[0],split_adapter[1],split_adapter[2],split_adapter[3],split_adapter[4],split_adapter[5])
|
|
797
|
+
eth_adapters.push(vnic)
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
return eth_adapters
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
#Create vNIC on LPAR
|
|
804
|
+
def create_vnic(vlan_id,addl_vlan_ids = "")
|
|
805
|
+
if validate_vlan_id(vlan_id)
|
|
806
|
+
#default value for is_trunk = 0
|
|
807
|
+
#default value for is_required = 1
|
|
808
|
+
slot_num = get_available_slot("eth")
|
|
809
|
+
create_vnic_profile(slot_num,vlan_id,addl_vlan_ids,0,1)
|
|
810
|
+
|
|
811
|
+
#TODO: Handle logic for dealing with an LPAR
|
|
812
|
+
#that isn't Not Activated, but also isn't
|
|
813
|
+
#Running
|
|
814
|
+
create_vnic_dlpar(slot_num,vlan_id)
|
|
815
|
+
|
|
816
|
+
#LPAR requires a power cycle in order to
|
|
817
|
+
#get a MAC address from this vNIC
|
|
818
|
+
if not_activated?
|
|
819
|
+
activate
|
|
820
|
+
sleep(10) until !not_activated?
|
|
821
|
+
soft_shutdown
|
|
822
|
+
end
|
|
823
|
+
else
|
|
824
|
+
raise StandardError.new("VLAN ID: #{vlan_id} not found on #{frame}")
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
#Create vNIC on LPAR profile
|
|
829
|
+
def create_vnic_profile(slot_number, vlan_id, addl_vlan_ids, is_trunk, is_required)
|
|
830
|
+
if validate_vlan_id(vlan_id)
|
|
831
|
+
##chsyscfg -m Server-9117-MMA-SNxxxxx -r prof -i 'name=server_name,lpar_id=xx,"virtual_eth_adapters=596/1/596//0/1,506/1/506//0/1,"'
|
|
832
|
+
#slot_number/is_ieee/port_vlan_id/"additional_vlan_id,additional_vlan_id"/is_trunk(number=priority)/is_required
|
|
833
|
+
lpar_prof = current_profile
|
|
834
|
+
|
|
835
|
+
#Going to assume adapter will always be ieee
|
|
836
|
+
#For is Trunk how do we determine the number for priority? Do we just let the user pass it?
|
|
837
|
+
hmc.execute_cmd("chsyscfg -m #{frame} -r prof -i \'name=#{lpar_prof},lpar_name=#{name},"+
|
|
838
|
+
"\"virtual_eth_adapters+=#{slot_number}/1/#{vlan_id}/\"#{addl_vlan_ids}" +
|
|
839
|
+
"\"/#{is_trunk}/#{is_required} \"\'")
|
|
840
|
+
else
|
|
841
|
+
raise StandardError.new("VLAN ID: #{vlan_id} not found on #{frame}")
|
|
842
|
+
end
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
#Create vNIC on LPAR via DLPAR
|
|
846
|
+
#As writen today defaulting ieee_virtual_eth=1 sets us to Not IEEE 802.1Q compatible. To add compatability set value to 1
|
|
847
|
+
def create_vnic_dlpar(slot_number,vlan_id)
|
|
848
|
+
if is_running?
|
|
849
|
+
if validate_vlan_id(vlan_id)
|
|
850
|
+
hmc.execute_cmd("chhwres -r virtualio -m #{frame} -o a -p #{name} --rsubtype eth -s #{slot_number} -a \"ieee_virtual_eth=1,port_vlan_id=#{vlan_id}\"")
|
|
851
|
+
else
|
|
852
|
+
raise StandardError.new("VLAN ID: #{vlan_id} not found on #{frame}")
|
|
853
|
+
end
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
#Change vlan id of vnic
|
|
858
|
+
def modify_vnic!(slot_number, vlan_id, is_trunk, is_required)
|
|
859
|
+
|
|
860
|
+
if validate_vlan_id(vlan_id)
|
|
861
|
+
#Power down
|
|
862
|
+
soft_shutdown unless not_activated?
|
|
863
|
+
sleep 5 until not_activated?
|
|
864
|
+
hmc.execute_cmd("chsyscfg -r prof -m #{frame} -i \'name=#{current_profile},lpar_name=#{name},\"virtual_eth_adapters=#{slot_number}/1//#{vlan_id}//#{is_trunk}/#{is_required}\"\'")
|
|
865
|
+
activate
|
|
866
|
+
else
|
|
867
|
+
raise StandardError.new("VLAN ID: #{vlan_id} not found on #{frame}")
|
|
868
|
+
end
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
#list available vlans
|
|
872
|
+
def list_vlans
|
|
873
|
+
vlans = []
|
|
874
|
+
vlans = hmc.list_vlans_on_frame(frame)
|
|
875
|
+
return vlans
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
#validate vlan exists on frame
|
|
879
|
+
def validate_vlan_id(vlan_id)
|
|
880
|
+
vlans = []
|
|
881
|
+
vlans = hmc.list_vlans_on_frame(frame)
|
|
882
|
+
count = 0
|
|
883
|
+
vlans_length = vlans.length
|
|
884
|
+
vlans.each do |vlan|
|
|
885
|
+
if vlan_id == vlan
|
|
886
|
+
puts "VLAN ID is valid for #{frame}"
|
|
887
|
+
return true
|
|
888
|
+
break
|
|
889
|
+
end
|
|
890
|
+
count+1
|
|
891
|
+
end
|
|
892
|
+
if count == vlans_length
|
|
893
|
+
puts "VLAN ID not valid for #{frame}"
|
|
894
|
+
return false
|
|
895
|
+
end
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
#Removes a vNIC adapter on an LPAR based on the
|
|
899
|
+
#slot number that the vNIC occupies
|
|
900
|
+
#TODO: Overload parameters to allow a different way to remove vNICs ???
|
|
901
|
+
def remove_vnic(slot_number)
|
|
902
|
+
#Find the vNIC that is desired to be
|
|
903
|
+
#removed
|
|
904
|
+
vnics = get_vnic_adapters
|
|
905
|
+
vnic = nil
|
|
906
|
+
vnics.each do |adapter|
|
|
907
|
+
if adapter.virtual_slot_num == slot_number
|
|
908
|
+
vnic = adapter
|
|
909
|
+
end
|
|
910
|
+
end
|
|
911
|
+
#If no vNIC occupies the slot specified, error out
|
|
912
|
+
raise StandardError.new("vNIC adapter does not currently occupy slot #{slot_number}") if vnic.nil?
|
|
913
|
+
#Remove the vNIC from this LPAR's profile
|
|
914
|
+
remove_vnic_profile(vnic)
|
|
915
|
+
#Remove the vNIC from the LPAR hardware if the LPAR is currently activated
|
|
916
|
+
remove_vnic_dlpar(slot_number)
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
#Remove a vNIC on the LPAR's profile denoted by
|
|
920
|
+
#the virtual slot number occupied by the vNIC
|
|
921
|
+
def remove_vnic_profile(vnic)
|
|
922
|
+
hmc.execute_cmd("chsyscfg -m #{frame} -r prof -i 'name=#{current_profile},lpar_name=#{name},"+
|
|
923
|
+
"\"virtual_eth_adapters-=#{vnic.virtual_slot_num}/#{vnic.is_ieee}/#{vnic.vlan_id}/#{vnic.additional_vlan_ids}" +
|
|
924
|
+
"/#{vnic.is_trunk}/#{vnic.is_required}\"'")
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
#Remove a vNIC on the LPAR via DLPAR denoted by
|
|
928
|
+
#the virtual slot number occupied by the vNIC
|
|
929
|
+
def remove_vnic_dlpar(slot_number)
|
|
930
|
+
if is_running?
|
|
931
|
+
hmc.execute_cmd("chhwres -r virtualio -m #{frame} -o r -p #{name} --rsubtype eth -s #{slot_number}")
|
|
932
|
+
end
|
|
933
|
+
end
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
#####################################################
|
|
937
|
+
# Private Methods
|
|
938
|
+
#####################################################
|
|
939
|
+
private
|
|
940
|
+
|
|
941
|
+
#Private function that handles bulk setting of instance variables
|
|
942
|
+
#Used by modify_resources() to handle setting attribute values
|
|
943
|
+
#on the Lpar object after modifying the value on the HMC.
|
|
944
|
+
def map_key_to_attr(key, value)
|
|
945
|
+
if @@attr_mapping.has_key?(key)
|
|
946
|
+
attr_name = @@attr_mapping[key]
|
|
947
|
+
#Use Object function instance_variable_set to take
|
|
948
|
+
#a string that is the name of an instance variable
|
|
949
|
+
#and change it's value
|
|
950
|
+
instance_variable_set("@" + attr_name, value)
|
|
951
|
+
end
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
#Private function that is used to ensure that the LPAR attribute key
|
|
955
|
+
#is set to value, while adhereing to any min, max, or desired qualification.
|
|
956
|
+
#options_hash represents a collection of other LPAR attributes that also will be changed.
|
|
957
|
+
#So this hash is checked to see if it contains any bounds shifts that would allow key to
|
|
958
|
+
#also be changed. If none of the bounds related to the attribute key are cited in the hash,
|
|
959
|
+
#the assumption that the attribute bounds should be changed to accomodate this is made.
|
|
960
|
+
def verify_and_handle_attr_bounds(options_hash, key, value)
|
|
961
|
+
split_key = key.split('_')
|
|
962
|
+
#Save the qualifier for the attribute
|
|
963
|
+
#as well it's the base name
|
|
964
|
+
qualifier = split_key[0]
|
|
965
|
+
split_key.delete_at(0)
|
|
966
|
+
base_attr = split_key.join('_')
|
|
967
|
+
fix_bounds = false
|
|
968
|
+
if ["min","max","desired"].include?(qualifier)
|
|
969
|
+
other_bounds = ["min","max","desired"].select { |x| x!=qualifier }
|
|
970
|
+
#Since there will only ever be 2 more array elements in other_bounds at this point,
|
|
971
|
+
#assign them, find their labels, find their attribute names,
|
|
972
|
+
#find their current values, and continue with validation
|
|
973
|
+
other_bound_a = other_bounds[0]
|
|
974
|
+
other_bound_b = other_bounds[1]
|
|
975
|
+
bound_a_label = [other_bound_a,base_attr].join('_')
|
|
976
|
+
bound_b_label = [other_bound_b,base_attr].join('_')
|
|
977
|
+
bound_a_instance_var = @@attr_mapping[bound_a_label]
|
|
978
|
+
bound_b_instance_var = @@attr_mapping[bound_b_label]
|
|
979
|
+
bound_a = instance_variable_get("@" + bound_a_instance_var)
|
|
980
|
+
bound_b = instance_variable_get("@" + bound_b_instance_var)
|
|
981
|
+
#Find out if this attribute change doesn't satisfy the current bounds
|
|
982
|
+
this_attr_label = key
|
|
983
|
+
this_attr_value = value
|
|
984
|
+
|
|
985
|
+
bound_a_new_val = nil
|
|
986
|
+
bound_b_new_val = nil
|
|
987
|
+
|
|
988
|
+
#If this value does not satisfy the current bounds, take note and
|
|
989
|
+
#rectify it later
|
|
990
|
+
if !satisfies_bounds?(qualifier, this_attr_value, bound_a, bound_b)
|
|
991
|
+
#Make the new bounds values be what is in the options hash, unless
|
|
992
|
+
#it isn't specified, then just make it the same as what we're trying to change.
|
|
993
|
+
if options_hash.has_key?(bound_a_label)
|
|
994
|
+
bound_a_new_val = options_hash[bound_a_label]
|
|
995
|
+
else
|
|
996
|
+
bound_a_new_val = value
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
if options_hash.has_key?(bound_b_label)
|
|
1000
|
+
bound_b_new_val = options_hash[bound_b_label]
|
|
1001
|
+
else
|
|
1002
|
+
bound_b_new_val = value
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
#Check if the bounds might be satisfied if *only one* of the bounds changed
|
|
1006
|
+
if satisfies_bounds?(qualifier, this_attr_value, bound_a_new_val, bound_b)
|
|
1007
|
+
bound_b_new_val = bound_b
|
|
1008
|
+
elsif satisfies_bounds?(qualifier, this_attr_value, bound_a, bound_b_new_val)
|
|
1009
|
+
bound_a_new_val = bound_a
|
|
1010
|
+
end
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
#If this is a vCPU or a Proc Units change, we need to ensure that
|
|
1014
|
+
#the new change adheres to the fact that the ratio between vCPUs and
|
|
1015
|
+
#Proc Units needs to be 10:1
|
|
1016
|
+
if ["procs","proc_units"].include?(base_attr)
|
|
1017
|
+
#TODO: Add logic that handles ensuring this 10:1 ratio remains in
|
|
1018
|
+
#place after this change.
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
if !bound_a_new_val.nil? and !bound_b_new_val.nil?
|
|
1022
|
+
#Based on how the other_bounds array is constructed earlier,
|
|
1023
|
+
#other_bound_a can either be "min" or "max", which helps determine the order
|
|
1024
|
+
#in which to set bound_a and bound_b. Also, if the new bound is less than or greater than
|
|
1025
|
+
#the old bound will further determine this order.
|
|
1026
|
+
|
|
1027
|
+
#If other_bound_a == 'min', and it's new value is less than the old one,
|
|
1028
|
+
#Change this one first, and then the second bound
|
|
1029
|
+
#Same for if bound_a is 'max' and it's new value is greater than the old
|
|
1030
|
+
if (other_bound_a == "min" and bound_a_new_val <= bound_a) or
|
|
1031
|
+
(other_bound_a == "max" and bound_a_new_val > bound_a)
|
|
1032
|
+
set_attr_profile(bound_a_new_val, bound_a_label)
|
|
1033
|
+
set_attr_profile(bound_b_new_val, bound_b_label)
|
|
1034
|
+
elsif (other_bound_a == "min" and bound_a_new_val > bound_a) or
|
|
1035
|
+
(other_bound_a == "max" and bound_a_new_val <= bound_a)
|
|
1036
|
+
set_attr_profile(bound_b_new_val, bound_b_label)
|
|
1037
|
+
set_attr_profile(bound_a_new_val, bound_a_label)
|
|
1038
|
+
end
|
|
1039
|
+
instance_variable_set("@" + bound_a_instance_var, bound_a_new_val)
|
|
1040
|
+
instance_variable_set("@" + bound_b_instance_var, bound_b_new_val)
|
|
1041
|
+
end
|
|
1042
|
+
end
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
def satisfies_bounds?(op, val1, val2, val3)
|
|
1046
|
+
if op == "min"
|
|
1047
|
+
return (val1 <= val2 and val1 <= val3 and val2 >= val3)
|
|
1048
|
+
elsif op == "max"
|
|
1049
|
+
return (val1 >= val2 and val1 >= val3 and val2 <= val3)
|
|
1050
|
+
elsif op == "desired"
|
|
1051
|
+
return (val1 >= val2 and val1 <= val3 and val2 <= val3)
|
|
1052
|
+
end
|
|
1053
|
+
end
|
|
1054
|
+
|
|
1055
|
+
#Set the processing units for an LPAR via DLPAR
|
|
1056
|
+
def set_proc_units_dlpar(units)
|
|
1057
|
+
#This command adds or removes, doesn't 'set'
|
|
1058
|
+
#TODO: add logic to make it behave like a 'set' and not an add/remove
|
|
1059
|
+
units > desired_proc_units ? op="a" : op="r"
|
|
1060
|
+
difference = (units-desired_proc_units).abs
|
|
1061
|
+
if is_running?
|
|
1062
|
+
if proc_mode == "shared"
|
|
1063
|
+
hmc.execute_cmd("chhwres -r proc -m #{frame} -o #{op} -p #{name} --procunits #{difference} ")
|
|
1064
|
+
elsif proc_mode == "dedicated"
|
|
1065
|
+
#Apparently if the proccessor sharing mode is 'dedicated',
|
|
1066
|
+
#then you need to use the --procs flag when changing processor units
|
|
1067
|
+
hmc.execute_cmd("chhwres -r proc -m #{frame} -o #{op} -p #{name} --procs #{difference} ")
|
|
1068
|
+
end
|
|
1069
|
+
end
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
#Set the desired number of virtual CPUs for an LPAR using DLPAR commands
|
|
1073
|
+
def set_vcpu_dlpar(units)
|
|
1074
|
+
#This command adds or removes, it doesn't 'set'
|
|
1075
|
+
units > desired_vcpu ? op="a" : op="r"
|
|
1076
|
+
difference = (units-desired_vcpu).abs
|
|
1077
|
+
if is_running?
|
|
1078
|
+
hmc.execute_cmd("chhwres -r proc -m #{frame} -o #{op} -p #{name} --procs #{difference}")
|
|
1079
|
+
end
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
#Set the Memory allocated to an LPAR via DLPAR (in MB)
|
|
1083
|
+
def set_memory_dlpar(units)
|
|
1084
|
+
|
|
1085
|
+
units > desired_memory ? op="a" : op="r"
|
|
1086
|
+
difference = (units-desired_memory).abs
|
|
1087
|
+
|
|
1088
|
+
if is_running?
|
|
1089
|
+
hmc.execute_cmd("chhwres -r mem -m #{frame} -o #{op} -p #{name} -q #{difference}")
|
|
1090
|
+
# chhwres -r mem -m Managed-System -o a -p Lpar_name -q 1024
|
|
1091
|
+
end
|
|
1092
|
+
end
|
|
1093
|
+
|
|
1094
|
+
#####################################
|
|
1095
|
+
# Utility Functions
|
|
1096
|
+
#####################################
|
|
1097
|
+
|
|
1098
|
+
#Handle strings of multiple vadapters that could be surrounded by
|
|
1099
|
+
#stray '"' or evaluate to "none" if there are no vadapters
|
|
1100
|
+
def clean_vadapter_string(vadapter_string)
|
|
1101
|
+
vadapter_string = "" if vadapter_string.chomp == "none"
|
|
1102
|
+
vadapter_string = vadapter_string[1..-1] if vadapter_string.start_with?('"')
|
|
1103
|
+
vadapter_string = vadapter_string[0..-2] if vadapter_string.end_with?('"')
|
|
1104
|
+
|
|
1105
|
+
return vadapter_string
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
#Three functions used to parse out vSCSI, vSerial
|
|
1110
|
+
#and vNIC adapter syntax
|
|
1111
|
+
|
|
1112
|
+
def parse_vscsi_syntax(vscsi_string)
|
|
1113
|
+
return parse_slash_delim_string(vscsi_string,
|
|
1114
|
+
[:virtual_slot_num, :client_or_server, :remote_lpar_id, :remote_lpar_name, :remote_slot_num, :is_required]) if !vscsi_string.empty?
|
|
1115
|
+
end
|
|
1116
|
+
|
|
1117
|
+
def parse_vserial_syntax(vserial_string)
|
|
1118
|
+
return parse_slash_delim_string(vserial_string,
|
|
1119
|
+
[:virtual_slot_num, :client_or_server, :supports_hmc, :remote_lpar_id, :remote_lpar_name, :remote_slot_num, :is_required]) if !vserial_string.empty?
|
|
1120
|
+
end
|
|
1121
|
+
|
|
1122
|
+
def parse_vnic_syntax(vnic_string)
|
|
1123
|
+
return parse_slash_delim_string(vnic_string,
|
|
1124
|
+
[:virtual_slot_num, :is_ieee, :port_vlan_id, :additional_vlan_ids, :is_trunk, :is_required]) if !vnic_string.empty?
|
|
1125
|
+
end
|
|
1126
|
+
|
|
1127
|
+
#Parse the slash delimited string (used for vadapters) by
|
|
1128
|
+
#separating the elements in the string into a hash
|
|
1129
|
+
#with keys based on what is specified in field_specs
|
|
1130
|
+
def parse_slash_delim_string(slash_string, field_specs)
|
|
1131
|
+
# slash_string = "596/1/596//0/1"
|
|
1132
|
+
# field_specs = [:virtual_slot_num, :client_or_server, :remote_lpar_id...]
|
|
1133
|
+
values = slash_string.split(/\//)
|
|
1134
|
+
result = {}
|
|
1135
|
+
field_specs.each_index do |i|
|
|
1136
|
+
result[field_specs[i]] = values[i]
|
|
1137
|
+
end
|
|
1138
|
+
return result
|
|
1139
|
+
end
|
|
1140
|
+
end
|