Class: Nim

Inherits:
ConnectableServer show all
Defined in:
lib/rbvppc/nim.rb

Instance Attribute Summary

Attributes inherited from ConnectableServer

#debug

Instance Method Summary collapse

Methods inherited from ConnectableServer

#connect, #connected?, #disconnect, #initialize, #toggle_debug

Constructor Details

This class inherits a constructor from ConnectableServer

Instance Method Details

#add_default_route(network_name, gateway) ⇒ Object



438
439
440
441
# File 'lib/rbvppc/nim.rb', line 438

def add_default_route(network_name,gateway)
   #TODO: Add more robust creation/management of NIM network routes, if necessary      
   execute_cmd("nim -o change -a routing1='default #{gateway}' #{network_name}")
end

#add_image(file_path, mksysb_name) ⇒ Object

Add a mksysb image to this NIM based on the name given and the local file path of the mksysb file on the NIM. Returns the name of the image that is created.



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/rbvppc/nim.rb', line 143

def add_image(file_path,mksysb_name)
   #Check to make sure a mksysb with this name doesn't already exist
   images = list_images
   if images.include?(mksysb_name)
      raise StandardError.new("A mksysb with the specified name #{mksysb_name} already exists, please specify another name")
   end

   #Add image to the NIM
   execute_cmd "nim -o define -t mksysb -F -a server=master -a location=#{file_path} -a mksysb_flags=XAe #{mksysb_name}"

   #Extract a SPOT from this mksysb
   extract_spot(mksysb_name)

   return mksysb_name
end

#add_network(network_name, network_addr, snm, gw) ⇒ Object

Add a NIM network object using the given name, network address, subnet mask, gateway

Raises:

  • (StandardError)


398
399
400
401
402
403
404
405
406
407
408
# File 'lib/rbvppc/nim.rb', line 398

def add_network(network_name,network_addr,snm,gw)
   #Ensure that network with this address doesn't already exist
   raise StandardError.new("Network #{network_name} already exists on this NIM") if network_exists?(network_name,network_addr)

   #Execute NIM command to create the network
   #It is assumed that the network addess and the gateway are the same
   execute_cmd("nim -o define -t ent -a net_addr=#{network_addr} -a snm=#{snm} #{network_name}")

   #Add default route to the specified gateway
   add_default_route(network_name,gw)
end

#bid_exists?(client_lpar) ⇒ Boolean

Checks if BID object exists on NIM for the Client LPAR

Returns:

  • (Boolean)


345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/rbvppc/nim.rb', line 345

def bid_exists?(client_lpar)
   defined_bids = list_objtype("bosinst_data")
   defined_bids.each do |obj_name|
      #Iterate through array elements returned by list_objtype
      #and check if any of them line up with the BID name for our LPAR
      if (obj_name == "#{client_lpar.name}_bid")
      #if (obj_name == "#{client_lpar}_bid")
         return true
      end
   end
   return false
end

#bos_install_finished?(lpar) ⇒ Boolean

Used in populating the BOS Install status message Returns true of the specified lpar is done with is BOS build. Sleeps for 15 seconds and returns false if otherwise.

Returns:

  • (Boolean)


230
231
232
233
234
235
236
237
# File 'lib/rbvppc/nim.rb', line 230

def bos_install_finished?(lpar)
   if check_install_status(lpar).match(/ready for a NIM operation/i)
      return true
   else
      sleep 15
      return false
   end
end

#capture_image(source_lpar, mksysb_name, path) ⇒ Object

Capture a mksysb image from a NIM client



132
133
134
135
136
137
138
# File 'lib/rbvppc/nim.rb', line 132

def capture_image(source_lpar,mksysb_name,path)
   #Pull mksysb from a NIM client, give it a name and place it in some location on the NIM
   execute_cmd "nim -o define -t mksysb -F -a server=master -a location=#{path} -a source=#{source_lpar.name} -a mk_image=yes -a mksysb_flags=XAe #{mksysb_name}"
         
   #Create SPOT resource from this mksysb, giving it a name and a location on the NIM to store it
   extract_spot(mksysb_name)     
end

#check_install_status(client_lpar) ⇒ Object

Check the install status of a NIM client Returns current Cstate attribute of NIM client



111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/rbvppc/nim.rb', line 111

def check_install_status(client_lpar)
   #lsnim -Z -a Cstate -a Mstate -a Cstate_result -a info nim_client_name
   result = execute_cmd "lsnim -Z -a Cstate -a Mstate -a Cstate_result -a info #{client_lpar.name}"
   #result = execute_cmd "lsnim -Z -a Cstate -a Mstate -a Cstate_result -a info #{client_lpar}"
   result.each_line do |line|
      line.match(/#{client_lpar.name}/) do |m|
      #line.match(/#{client_lpar}/) do |m|
         #Cstate is the 2nd column of the : delimited output
         cstate = line.split(/:/)[1]
         return cstate
      end
   end
   return nil
end

#client_defined?(client_lpar) ⇒ Boolean

Is the NIM Client defined?

Returns:

  • (Boolean)


54
55
56
57
58
59
60
# File 'lib/rbvppc/nim.rb', line 54

def client_defined?(client_lpar)
   #lsnim -Z lpar_name_here 2>/dev/null | awk '(NR==2) {print $1}' | awk -F: '{print $2}'
   #result = execute_cmd "lsnim -Z #{client_lpar} 2>/dev/null | " + 
   result = execute_cmd "lsnim -Z #{client_lpar.name} 2>/dev/null | " +
                          "awk '(NR==2) {print $1}' | awk -F: '{print $2}'"
   return result.chomp == "machines"
end

#create_bid(client_lpar) ⇒ Object

Creates a bosinst_data object for the client_lpar specified



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/rbvppc/nim.rb', line 303

def create_bid(client_lpar)
   if bid_exists?(client_lpar)
      #Force remove the BID and then continue to create a new one.
      remove_bid(client_lpar)
   end
   
   #Use heredoc to populate the bosinst_data file in a multiline string
   bid_contents = <<-EOS
   # bosinst_data file created for #{client_lpar.name}
   
   CONSOLE = Default
   RECOVER_DEVICES = no
   INSTALL_METHOD = overwrite
   PROMPT = no
   EXISTING_SYSTEM_OVERWRITE = any
   ACCEPT_LICENSES = yes
   
   locale:
   BOSINST_LANG = en_US
   CULTURAL_CONVENTION = en_US
   MESSAGES = en_US
   KEYBOARD = en_US
   EOS
   
   #Create bid contents file on NIM
   execute_cmd "mkdir -p /darwin; echo '#{bid_contents}' > /darwin/#{client_lpar.name}_bid"
   
   
   #Define the BID object
   execute_cmd "nim -o define -t bosinst_data -a location=/darwin/#{client_lpar.name}_bid -a server=master #{client_lpar.name}_bid"
   
   #Return the name of the BID created
   return "#{client_lpar.name}_bid"      
end

#deallocate_resources(client_lpar) ⇒ Object

Deallocates any/all NIM resources from the client manchine



99
100
101
# File 'lib/rbvppc/nim.rb', line 99

def deallocate_resources(client_lpar)
   execute_cmd "nim -o deallocate -a subclass=all #{client_lpar.name}"
end

#define_client(client_lpar) ⇒ Object

Define the NIM Client



63
64
65
66
67
68
69
# File 'lib/rbvppc/nim.rb', line 63

def define_client(client_lpar)
   if client_defined?(client_lpar)
      remove_client(client_lpar)
   end
   execute_cmd %Q{nim -o define -t standalone -a if1="find_net #{client_lpar.hostname} #{client_lpar.get_mac_address}" -a cable_type1="N/A" -a platform=chrp -a comments="Built by Darwin" -a net_settings1="auto auto" -a connect="shell" -a netboot_kernel=#{master_netboot_kernel} #{client_lpar.name}}
   #execute_cmd %Q{nim -o define -t standalone -a if1="find_net #{hostname} #{mac}" -a cable_type1="N/A" -a platform=chrp -a comments="Built by Darwin" -a net_settings1="auto auto" -a connect="shell" -a netboot_kernel=#{master_netboot_kernel} #{client_lpar}}
end

#deploy_image(client_lpar, mksysb_name, firstboot_script = nil, lpp_source = nil) {|nim_ip, gateway, subnetmask| ... } ⇒ Object

Deploy mksysb image to NIM client

Yields:

  • (nim_ip, gateway, subnetmask)


180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/rbvppc/nim.rb', line 180

def deploy_image(client_lpar, mksysb_name, firstboot_script = nil, lpp_source = nil)
   
   bosinst_data_obj = client_lpar.name+"_bid"
   
   #Create a NIM Client and a bosinst_data object if they don't
   #already exist for this LPAR.
   define_client(client_lpar) if !client_defined?(client_lpar)      
   create_bid(client_lpar) if !bid_exists?(client_lpar)

   if !lpp_source.nil?
      #TODO: Do something different if an lpp_source is specified...
   end

   #Get the SPOT to use for this image deployment
   spot_name = get_spot(mksysb_name)
   if spot_name.nil?
      #Extract the spot from this mksysb and use it
      spot_name = extract_spot(mksysb_name)
   end

   command = "nim -o bos_inst -a source=mksysb -a mksysb=#{mksysb_name} -a bosinst_data=#{bosinst_data_obj} -a no_nim_client=no " +
             "-a accept_licenses=yes -a boot_client=no"
   command += " -a spot=#{spot_name}" if !spot_name.nil?
   command += " -a fb_script=#{firstboot_script}" if !firstboot_script.nil?
   command += " -a lpp_source=#{lpp_source}" if !lpp_source.nil?
   command += " #{client_lpar.name}"
   #NIM command to start a remote mksysb install on NIM client
   execute_cmd(command)                        
   
   #Then, in order to actually start the install the HMC needs to netboot the LPAR
   #Should that be called from here or just utilized separately from the HMC object?
   #Maybe yeild to a block that should call the HMC LPAR netboot?
   #Then upon returning to this function, we poll the NIM client for Cstate statuses
   #until the build is finished?
   network_name = get_lpar_network_name(client_lpar)
   gateway = get_network_gateway(network_name)
   subnetmask = get_network_subnetmask(network_name)
   nim_ip = get_master_ip      
   
   yield(nim_ip,gateway,subnetmask)
   
   #Implemented nicer looking progress message for BOS installs
   print "Waiting for BOS install for #{client_lpar.name} to finish..."
   print "." until bos_install_finished?(client_lpar)
   puts "done"            
end

#execute_cmd(command) ⇒ Object

Execute commands on NIM, outputting the full command with puts first.



29
30
31
32
# File 'lib/rbvppc/nim.rb', line 29

def execute_cmd(command)
    puts "#{command}" if debug
    super "#{command}"
end

#extract_spot(mksysb_name) ⇒ Object

Extracts a SPOT from the mksysb image name specified. places the SPOT in a directory location adjacent to where the mksysb resides If a spot already exists for this mksysb, it’s name is simply returned.

Raises:

  • (StandardError)


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/rbvppc/nim.rb', line 260

def extract_spot(mksysb_name)
   #Find out if this mksysb exists on the NIM
   if !list_objtype("mksysb").include?(mksysb_name)
      #Mksysb not found - error out?
   end

   spot_name = mksysb_name+"_spot"
   #Find out if a SPOT already exists for this mksysb
   #if so, just return that name.
   temp_name = get_spot(mksysb_name)
   if !temp_name.nil?
      return temp_name
   end

   #Get the location of this mksysb
   mksysb_loc = get_mksysb_location(mksysb_name)

   #Make sure the mksysb location is non-null
   raise StandardError.new("Cannot locate where the image #{mksysb_name} exists on this NIM") if mksysb_loc.nil?

   #Split the mksysb location on '/', pop the mksysb name and directory it resides
   #in off of the array and push "spot" and the spot name onto the array to end up placing
   #the SPOT in ../spot/spot_name
   split_mksysb_path = mksysb_loc.split("/")
   split_mksysb_path.pop
   split_mksysb_path.pop
   split_mksysb_path.push("spot")
   split_mksysb_path.push(mksysb_name+"_spot")
   spot_path = split_mksysb_path.join("/")

   #Make a SPOT from this mksysb with the name <mksysb_name>_spot
   execute_cmd("nim -o define -t spot -a server=master -a source=#{mksysb_name} -a location=#{spot_path} -a auto_expand=yes #{spot_name}")

   #Return the name of the SPOT.
   return spot_name
end

#get_lpar_network_name(client_lpar) ⇒ Object

Find NIM interface settings for client LPAR



359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/rbvppc/nim.rb', line 359

def get_lpar_network_name(client_lpar)
   output = execute_cmd "lsnim -Z -a if1 #{client_lpar.name}"
   nim_network=""
   output.each_line do |line|
      line.chomp!
      if line.match(/^#{client_lpar.name}/)
         network_args = line.split(/:/)
         nim_network = network_args[1]
      end
   end
   return nim_network
end

#get_master_ipObject

Returns the IP address of the NIM master as a String



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rbvppc/nim.rb', line 78

def get_master_ip
   niminfo_line = execute_cmd("cat /etc/niminfo | grep NIM_MASTER_HOSTNAME")
   hostname = niminfo_line.split("=")[1].chomp

   ipaddr_line = execute_cmd("host #{hostname}")
   ip = ipaddr_line.split(" is ")[1].chomp

   if ip.empty?
      raise StandardError.new("Unable to determine the NIM Master's IP Address")
   end

   return ip
end

#get_mksysb_location(mksysb_name) ⇒ Object

Returns the filesystem location of the mksysb with the specified name



240
241
242
# File 'lib/rbvppc/nim.rb', line 240

def get_mksysb_location(mksysb_name)
   execute_cmd("lsnim -l #{mksysb_name} | awk '{if ($1 ~ /location/) print $3}'").chomp
end

#get_network_gateway(network_name) ⇒ Object

Find Gateway IP for NIM network



373
374
375
376
377
378
379
380
381
382
# File 'lib/rbvppc/nim.rb', line 373

def get_network_gateway(network_name)
   output = execute_cmd "lsnim -Z -a net_addr -a snm -a routing #{network_name}"
   output.each_line do |line|
      line.chomp!
      if line.match(/^#{network_name}/)
         network_fields = line.split(/:/)
         return network_fields[-1]
      end
   end
end

#get_network_subnetmask(network_name) ⇒ Object

Find Subnet mask for NIM network



385
386
387
388
389
390
391
392
393
394
# File 'lib/rbvppc/nim.rb', line 385

def get_network_subnetmask(network_name)
   output = execute_cmd "lsnim -Z -a net_addr -a snm -a routing #{network_name}"
   output.each_line do |line|
      line.chomp!
      if line.match(/^#{network_name}/)
         network_fields = line.split(/:/)
         return network_fields[2]
      end
   end
end

#get_spot(mksysb_name) ⇒ Object

Returns the name of the SPOT extracted from the supplied mksysb



246
247
248
249
250
251
252
253
# File 'lib/rbvppc/nim.rb', line 246

def get_spot(mksysb_name)
   spot = execute_cmd("lsnim -l #{mksysb_name} | awk '{if ($1 ~ /extracted_spot/) print $3}'").chomp
   if spot.empty?
      return nil
   else
      return spot
   end
end

#list_imagesObject

Return an array of names of mksysbs that exist on this NIM



127
128
129
# File 'lib/rbvppc/nim.rb', line 127

def list_images
   list_objtype("mksysb")
end

#list_objtype(type) ⇒ Object

list all defined objects of a specific type acceptable types are (standalone,ent,lpp_source,mksysb,spot,fb_script,script,bosinst_data,ent)



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rbvppc/nim.rb', line 36

def list_objtype(type)
   case type
   when "standalone","ent","lpp_source","mksysb","spot","fb_script","script","bosinst_data"
      output = execute_cmd "lsnim -t #{type}"
   else
      raise StandardError.new("Unknown type of NIM Object passed")
   end
   objects = []
   output.each_line do |line|
      line.chomp!
      columns = line.split(/[[:blank:]]+/)
      objects.push(columns[0]) if !columns[0].empty?
   end
   
   return objects
end

#master_netboot_kernelObject

Pull the netboot_kernel attribute from NIM master object



72
73
74
75
# File 'lib/rbvppc/nim.rb', line 72

def master_netboot_kernel
   result = execute_cmd "lsnim -l master | awk '{if ($1 ~ /netboot_kernel/) print $3}'"
   return result.chomp
end

#network_exists?(network_name, network_addr = nil) ⇒ Boolean

Returns true if a network object exists on the NIM with either the specified name or network address. Returns false otherwise.

Returns:

  • (Boolean)


423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/rbvppc/nim.rb', line 423

def network_exists?(network_name,network_addr=nil)
   network_names = list_objtype("ent")
   if network_names.include?(network_name)
      return true
   end
   network_names.each do |net_name|
      address = execute_cmd("lsnim -l #{net_name} | awk '{if ($1 ~ /net_addr/) print $3}'").chomp
      if address == network_addr
         return true
      end
   end

   return false
end

#remove_bid(client_lpar) ⇒ Object

Remove the NIM BID object for a client LPAR



339
340
341
342
# File 'lib/rbvppc/nim.rb', line 339

def remove_bid(client_lpar)
   execute_cmd "nim -F -o remove #{client_lpar.name}_bid"
   #execute_cmd "nim -F -o remove #{client_lpar}_bid"
end

#remove_client(client_lpar) ⇒ Object

Remove a NIM client



104
105
106
107
# File 'lib/rbvppc/nim.rb', line 104

def remove_client(client_lpar)
   deallocate_resources(client_lpar)
   execute_cmd "nim -F -o remove #{client_lpar.name}"
end

#remove_image(mksysb_name) ⇒ Object

Removes a mksysb from the NIM that identifies with the name specified. Attempts to remove the SPOT that was extracted from this mksysb first.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/rbvppc/nim.rb', line 161

def remove_image(mksysb_name)
   #Find if this mksysb actually exists on the NIM
   images = list_images
   if !images.include?(mksysb_name)
      warn "#{mksysb_name} does not exist on this NIM."
      return
   end

   #Find and remove the SPOT for this mksysb
   spot_name = get_spot(mksysb_name)
   if !spot_name.nil?
      remove_spot(spot_name)
   end

   #Remove the mksysb from the NIM (along with it's mksysb file)
   execute_cmd("nim -o remove -a rm_image=yes #{mksysb_name}")
end

#remove_network(network_name, network_addr = nil) ⇒ Object

Remove a NIM network given it’s name and/or it’s network address

Raises:

  • (StandardError)


412
413
414
415
416
417
418
# File 'lib/rbvppc/nim.rb', line 412

def remove_network(network_name,network_addr=nil)
   #Ensure that the network to remove is actually defined currently
   raise StandardError.new("Network #{network_name} does not exist on this NIM to be removed") if !network_exists?(network_name,network_addr)
   
   #Run command that removes this network from the NIM      
   execute_cmd("nim -Fo remove #{network_name}")
end

#remove_spot(spot_name) ⇒ Object

Removes a SPOT object from a NIM based on the name



298
299
300
# File 'lib/rbvppc/nim.rb', line 298

def remove_spot(spot_name)
   execute_cmd("nim -Fo remove #{spot_name}")
end

#reset_client(client_lpar) ⇒ Object

Reset a NIM client



93
94
95
96
# File 'lib/rbvppc/nim.rb', line 93

def reset_client(client_lpar)
    execute_cmd "nim -F -o reset #{client_lpar.name}"
    #execute_cmd "nim -F -o reset #{client_lpar}"
end