class COMStar
Defines a class capable of creating iSCSI shares using the new COMStar
framework. This classes uses the various command line tools, not the C API.
Public Class Methods
Walks over the list of Logical Units, working out where the ZFS
volume backing the LU is. Returns a hash, giving the correct backing store for each LU
# File lib/SANStore/iSCSI/comstar.rb, line 193 def self.LUToVolMap # Get the raw map SANStore::CLI::Logger.instance.log_level(:low, :info, "Finding the backing stores for the logical units") raw_list = %x[stmfadm list-lu -v] raw_map = raw_list.split(/$/) # Create a hash from this map map_hash = Hash.new map_index = nil map_entry = nil raw_index = 0 while raw_index < raw_map.length do # Is this line the start of a new LU entry if raw_map[raw_index].index(/LU Name\:/) then # Store the old entry unless map_entry.nil? then map_hash[map_index] = map_entry end # Create a new map entry map_entry = Hash.new map_index = raw_map[raw_index].partition(/LU Name\:/)[2].strip else # Split the line to find the key and value entry = raw_map[raw_index].partition(/\s?\:\s/) case entry[0].strip when "Alias" map_entry[:guid] = entry[2].strip when "Data File" map_entry[:data_file] = entry[2].strip end end raw_index += 1 end # Add the last entry unless map_entry.nil? then map_hash[map_index] = map_entry end # Return the hash map return map_hash end
Walks over the list of iSCSI targets, looking for the store GUID (stored in the target alias field). Returns a map of the target names and associated aliases
# File lib/SANStore/iSCSI/comstar.rb, line 139 def self.TargetToGUIDMap # Get the raw map SANStore::CLI::Logger.instance.log_level(:low, :info, "Finding the GUID's associated with iSCSI targets") raw_list = %x[stmfadm list-target -v] raw_map = raw_list.split(/$/) # Create a hash from this map map_hash = Hash.new map_index = nil map_entry = nil raw_index = 0 while raw_index < raw_map.length do # Is this line the start of a new target entry if raw_map[raw_index].index(/Target\:/) then # Store the old entry unless map_entry.nil? then map_hash[map_index] = map_entry end # Create a new map entry map_entry = String.new map_index = raw_map[raw_index].partition(/Target\:/)[2].strip else # Split the line to find the key and value entry = raw_map[raw_index].partition(/\s?\:\s/) case entry[0].strip when "Alias" map_entry = entry[2].strip end end raw_index += 1 end # Add the last entry unless map_entry.nil? then map_hash[map_index] = map_entry end # Return the hash map return map_hash end
Delete an iSCSI target. This returns the name of the underlying ZFS
store in case the caller wants to delete that as well
# File lib/SANStore/iSCSI/comstar.rb, line 69 def self.delete_target(target_name) # Before we kill the target, get the store GUID so that we can clean up properly target_map = self.TargetToGUIDMap target_guid = target_map[target_name] # Get the maps of the LU identifers to the underlying stores vol_map = self.LUToVolMap # Look for the store with the GUID of the target we want to delete SANStore::CLI::Logger.instance.log_level(:low, :info, "Looking for the name of the volume #{target_guid} backing #{target_name}") vol_name = "" vol_store = "" vol_map.each{|key, value| if value[:guid] == target_guid then # We have found the right entry, so update the name of the # volume store and the name of the volume backing it vol_name = key vol_store = value[:data_file] break end } # Abort if we can't find what we are looking for if vol_name.empty? or vol_store.empty? then SANStore::CLI::Logger.instance.log_level(:high, :error, "Could not delete the file system for the iSCSI target. The target has been removed, but the file system is still around!") return "" end # Delete the target (and force any clients off the soon to die share) SANStore::CLI::Logger.instance.log_level(:low, :warning, "Closing all sessions for #{target_name}") target = %x[itadm delete-target -f #{target_name}] # Now unlink the SCSI logical unit, so that we can free the underlying ZFS volume SANStore::CLI::Logger.instance.log_level(:low, :delete, "Removing logical units associated with the deleted target") disk_target = %x[sbdadm delete-lu #{vol_name}] # The file store is now ready for deletion. We will tell the caller what to remove, but we # don't actually do this ourselves (file systems are someone elses problem) return vol_store end
List the current iSCSI targets defined on this host
# File lib/SANStore/iSCSI/comstar.rb, line 112 def self.list_vols raw_list = %x[itadm list-target] # Create a hash for the final list of targets target_list = Array.new # Run through the raw list of targets target_array = raw_list.split(/$/) target_array.delete_at(0) target_array.each{|row| row_fragments = row.split row_hash = Hash.new row_hash[:name] = row_fragments[0] row_hash[:state] = row_fragments[1] row_hash[:sessions] = row_fragments[2] target_list << row_hash } # return the list to the caller return target_list end
Create a new, ready to use, iSCSI target. Functionally this is command is equivalent to the old “shareiscsi=on” ZFS
volume property.
# File lib/SANStore/iSCSI/comstar.rb, line 25 def self.new_target(volume_path, volume_guid) # Create a new disk target for the ZFS volume SANStore::CLI::Logger.instance.log_level(:low, :create, "New SCSI block device at /dev/zvol/rdsk/#{volume_path}") disk_target = %x[sbdadm create-lu /dev/zvol/rdsk/#{volume_path}] # Get the ID of the new disk target from the output of the # target creation command id = disk_target.split(/$/)[4].split[0] SANStore::CLI::Logger.instance.log_level(:low, :info, "Using #{id} as the logical unit identifier") # Modify the just created logical unit to include the path of the # volume backing it. This makes it much easier to get rid of the # relevant volume later SANStore::CLI::Logger.instance.log_level(:low, :update, "Storing the volume GUID as the logical unit alias") modify_lu = %x[stmfadm modify-lu --lu-prop alias=#{volume_guid} #{id}] # Create a new target group SANStore::CLI::Logger.instance.log_level(:low, :create, "Creating target group #{id}") %x[stmfadm create-tg #{id}] # Link the new disk target to the iSCSI framework SANStore::CLI::Logger.instance.log_level(:low, :update, "Attaching logical unit #{id} into the iSCSI framework") vol_frame = %x[stmfadm add-view --target-group #{id} #{id}] # Create the target... SANStore::CLI::Logger.instance.log_level(:low, :create, "iSCSI block target") target = %x[itadm create-target] target_name = target.split[1] # Store the volume GUID as the alias so we can find it later SANStore::CLI::Logger.instance.log_level(:low, :update, "Storing the volume GUID as the iSCSI target alias") %x[itadm modify-target --alias #{volume_guid} #{target_name}] # Add the new target to the correct target group SANStore::CLI::Logger.instance.log_level(:low, :update, "Adding the target #{target_name} to its target group") %x[svcadm disable stmf; sleep 2; stmfadm add-tg-member -g #{id} #{target_name}; svcadm enable stmf] # Return the target name to the caller return target_name end