Class: COMStar

Inherits:
Object
  • Object
show all
Defined in:
lib/SANStore/iSCSI/comstar.rb

Overview

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.

Class Method Summary collapse

Class Method Details

.delete_target(target_name) ⇒ Object

Delete an iSCSI target. This returns the name of the underlying ZFS store in case the caller wants to delete that as well



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 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_volsObject

List the current iSCSI targets defined on this host



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 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

.LUToVolMapObject

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



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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# 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

.new_target(volume_path, volume_guid) ⇒ Object

Create a new, ready to use, iSCSI target. Functionally this is command is equivalent to the old “shareiscsi=on” ZFS volume property.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 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

.TargetToGUIDMapObject

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



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# 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