Class: Brocade::SAN::Switch

Inherits:
Object
  • Object
show all
Includes:
SshDevice
Defined in:
lib/brocadesan/switch.rb,
lib/brocadesan/switch.rb,
lib/brocadesan/switch.rb,
lib/meta_methods.rb

Overview

Class to model SAN switch from Brocade

Direct Known Subclasses

Provisioning::Agent

Defined Under Namespace

Classes: Error, Response

Constant Summary collapse

CMD_MAPPING =

Maps each method name to command to be run to obtain it and to hash key where it ill be stored. As well sets the format of the returned value. This is used only for documentation purposes.

See lib/config/brocade/san/switch_cmd_mapping.yml for details

Example:

:name:
 :cmd: switchshow
 :attr: switch_name
 :format: string

This will cause that class will have instance method called name(forced=true). When the method is called first time or forced is true the switchshow command will be queried on the switch. The query response will be then parsed and stored in Response parsed hash under :switch_name key. The parsed hash is then merged into switch configuration hash. At the end the :switch_name key is returned from configuration hash.

The parser needs to ensure that it parses the cmd output and stores the proper value into Response parsed under :attr key.

YAML.load(File.read(Configuration::cmd_mapping_path(self)))
PARSER_MAPPING =

Maps each command to the parser method to use

See lib/config/parser_mapping.yml for details

YAML.load(File.read(Configuration::parser_path))
NAME_RULE =

zone configuration, zone and zone aliases naming rule must start with an alphabetic character and may contain alphanumeric characters and the underscore ( _ ) character.

'^[a-z][a-z_\d]*$'

Constants included from SshDevice

SshDevice::DEFAULT_QUERY_PROMPT

Instance Attribute Summary collapse

Attributes included from SshDevice

#prompt

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SshDevice

#get_mode, #interactive_mode, #script_mode, #session, #set_mode

Constructor Details

#initialize(*params) ⇒ Switch

Creates a Switch instance and tests a connection.

Checks as well if the switch is virtual fabric enabled since that defines the way it will be queried further.


77
78
79
80
81
# File 'lib/brocadesan/switch.rb', line 77

def initialize(*params)
  super(*params)
  @configuration={}
  vf
end

Instance Attribute Details

#configurationObject (readonly)

Returns the value of attribute configuration


110
111
112
# File 'lib/brocadesan/switch.rb', line 110

def configuration
  @configuration
end

#fidObject (readonly)

Fabric id of the switch to be queried. Can be set using set_context.

If the given fid does not exist default switch for the provided account will be queried.


117
118
119
# File 'lib/brocadesan/switch.rb', line 117

def fid
  @fid
end

Class Method Details

.attributes(args) ⇒ Object

Used to dynamically create named methods based on CMD_MAPPING


58
59
60
61
62
63
64
# File 'lib/brocadesan/switch.rb', line 58

def self.attributes(args)
  args.each do |arg|
   define_method arg do |forced=false|
     self.get(arg,forced)
   end
  end
end

.verify_name(name) ⇒ Object

verifies if name matches convetion defined in NAME_RULE raises Switch::Error: Incorrect name format if not this method is used internally mostly


70
71
72
# File 'lib/brocadesan/switch.rb', line 70

def self.verify_name(name)
  raise Switch::Error.incorrect(name) if !name.match(/#{NAME_RULE}/i)
end

Instance Method Details

#aliases(forced = false) ⇒ Object

returns all aliases defined on the switch including aliases created in ongoing transaction as array of Alias


202
203
204
# File 'lib/brocadesan/switch.rb', line 202

def aliases(forced=false)
  get_configshow(true,forced)[:aliases]
end

#effective_configuration(full = false, forced = false) ⇒ Object

Returns effective ZoneConfiguration

If full is set to true it loads full effective configuration with zones and aliases, otherwise it gets just the name


190
191
192
# File 'lib/brocadesan/switch.rb', line 190

def effective_configuration(full=false,forced=false)
  zone_configurations(full,forced).select {|z| z.effective == true}.first
end

#fabric(forced = false) ⇒ Object

returns switches in the fabric in hash form


156
157
158
159
160
# File 'lib/brocadesan/switch.rb', line 156

def fabric(forced=false)
  cmd="fabricshow"
  refresh(cmd,"",forced)
  @configuration[:fabric]
end

#find(str, opts = {}) ⇒ Object

finds configuration object by str. Case insensitive. If the object option is not specified it searches :zone objects. It finds only saved objects. If the object was created but the transaction is not confirmed it will not find it.

opts

:object

:zones (default) - finds zones

:aliases - finds aliases

:find_mode

:partial - find partial matches

:exact(default) - finds exact matches

Example:

switch.find(“zone1”,:object=>:zone)


279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/brocadesan/switch.rb', line 279

def find(str,opts={})
  # do not change the following 3 lines without writing test for it     
  obj = !opts[:object].nil? && [:zone,:alias].include?(opts[:object]) ? opts[:object] : :zone
  mode = !opts[:find_mode].nil? && [:partial,:exact].include?(opts[:find_mode]) ? opts[:find_mode] : :exact
  grep_exp = mode==:exact ? " | grep -i -E ^#{obj}\.#{str}:" : " | grep -i -E ^#{obj}\..*#{str}.*:"  
  
  response = script_mode do
    query("configshow"+grep_exp)
  end
  response.parse
  
  #output of configshow is stored to find_results
  
  objs=response.parsed[:find_results]
  objs||=[]
  
  result=[]
  
  objs.each do |item|
     i = obj==:zone ? Zone.new(item[:obj]) : Alias.new(item[:obj]) 
     item[:members].split(";").each do |member|
       i.add_member(member)
     end
     result<<i
  end
  # result is array of Zone or Alias instances
  result
end

#find_alias(str) ⇒ Object

returns Alias with name of str if exists, nil otherwise


221
222
223
# File 'lib/brocadesan/switch.rb', line 221

def find_alias(str)
  al = find(str,:object=>:alias)
end

#find_aliases(regexp) ⇒ Object

returns Alias array of Aliases with name matching regexp if exists, [] otherwise

find is case insesitive


228
229
230
231
232
# File 'lib/brocadesan/switch.rb', line 228

def find_aliases(regexp)
  aliases = find(regexp,:object=>:alias,:find_mode=>:partial)
  return [] if aliases==[nil]
  aliases
end

#find_by_member(str, opts = {}) ⇒ Object

finds configuration objects that have member specified by str. Case insensitive. If the object option is not specified it searches :zone objects. See find_by_member_from_cfgshow.

opts

:object

:all (default) - finds all objects (zones, configs, aliases)

:aliases - finds aliases

:zones - finds zones

:find_mode

:partial - find partial matches

:exact(default) - finds exact matches

:transaction

false (defualt) - ignores object in ongoing transaction

true - includes objects in ongoing transaction

Example:

switch.find_by_member(“zone1”,:object=>:cfg)

Note:

Zone can be only members of zone configuration and alias can be only members of zones so finding object that have them as members works with default :all :object. However WWNs can be part both of zones and aliases so that is why there is option to speficy the object


337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/brocadesan/switch.rb', line 337

def find_by_member(str,opts={})
  obj = !opts[:object].nil? && [:zone,:alias,:all].include?(opts[:object]) ? opts[:object] : :all
  obj = "zone|alias|cfg" if obj==:all
  mode = !opts[:find_mode].nil? && [:partial,:exact].include?(opts[:find_mode]) ? opts[:find_mode] : :exact
  
  trans_inc = !opts[:transaction].nil? && [true,false].include?(opts[:transaction]) ? opts[:transaction] : false
  
  base_grep1 = "^#{obj}\."
  base_grep2 = mode==:exact ? "(:|;)#{str}(;|$)" : ":.*#{str}"

  if trans_inc
    grep_exp1 = /#{base_grep1}/i
    grep_exp2 = /#{base_grep2}/i
    response = script_mode do
      query("cfgshow")
    end
    response.send :cfgshow_to_configshow, grep_exp1, grep_exp2
  else
    grep_exp = " | grep -i -E \"#{base_grep1}\""
    grep_exp += " | grep -i -E \"#{base_grep2}\""
    response = script_mode do
      query("configshow"+grep_exp)
    end
  end
  
  response.parse
  #output of configshow is stored to find_results
  
  objs=response.parsed[:find_results]
  objs||=[]
  
  result=[]
  
  objs.each do |item|
     i = case item[:type]
     when :zone
        Zone.new(item[:obj])
     when :alias
        Alias.new(item[:obj])
     when :cfg
       ZoneConfiguration.new(item[:obj])
     end 
     item[:members].split(";").each do |member|
       i.add_member(member)
     end
     result<<i
  end
  # result is array of Zone, Alias, and ZoneConfiguration instances
  result
end

#find_wwn(value, forced = true, opts = {:fabric_wide=>false}) ⇒ Object

returns WWN of given value if exists, nil if not

if forced is true it will load the data from switch instead of the cache

opts

:fabric_wide

searches whole fabric


259
260
261
262
# File 'lib/brocadesan/switch.rb', line 259

def find_wwn(value,forced=true,opts={:fabric_wide=>false})
  objs = opts[:fabric_wide]==true ? get_ns(true,forced,:local=>true).concat(get_ns(true,forced,:remote=>true)) : get_ns(true,forced,:local=>true)
  objs.find {|k| value.downcase == k.value.downcase}
end

#find_zone(str) ⇒ Object

returns Zone with name of str if exists, nil otherwise


207
208
209
# File 'lib/brocadesan/switch.rb', line 207

def find_zone(str)
  find(str,:object=>:zone)
end

#find_zones(regexp) ⇒ Object

returns Zone array of Zones with name matching regexp if exists, [] otherwise

find is case insesitive


214
215
216
217
218
# File 'lib/brocadesan/switch.rb', line 214

def find_zones(regexp)
  zones = find(regexp,:object=>:zone,:find_mode=>:partial)
  return [] if zones==[nil]
  zones
end

#get(attr, forced = false) ⇒ Object

gets the attr

attr has to be speficied in the CMD_MAPPING

named methods are wrappers around this method so you should not use this directly


144
145
146
147
148
149
150
151
152
# File 'lib/brocadesan/switch.rb', line 144

def get(attr,forced=false)
  raise Switch::Error.unknown if CMD_MAPPING[attr.to_sym].nil?
  
  cmd=CMD_MAPPING[attr.to_sym][:cmd]
  
  refresh(cmd,"",forced)
  
  @configuration[CMD_MAPPING[attr.to_sym][:attr].to_sym]
end

#override_vfObject

override VF settings all commands will run only on base switch this is to allow to run certain commands on VF enabled switches untill the fosexec is fixed


136
137
138
# File 'lib/brocadesan/switch.rb', line 136

def override_vf
  @configuration[:override_vf]=true
end

#query(*cmds) ⇒ Object

:nodoc


388
389
390
391
392
393
394
395
# File 'lib/brocadesan/switch.rb', line 388

def query(*cmds) #:nodoc
  if get_mode=="interactive"
    cmds[0]=fullcmd(cmds[0])
  else
    cmds.map! {|cmd| fullcmd(cmd)}
  end
  super(*cmds)
end

#set_context(fid = 128) ⇒ Object

Sets the FID of the switch to be queried and clears cache. Next queries will be done directly on switch.

If not fid is given it will set it to default 128. If the switch does not support virtual fabrics this will be ignored.

Returns the fid that was set


128
129
130
131
# File 'lib/brocadesan/switch.rb', line 128

def set_context(fid=128)
  @loaded={}
  @fid = fid.to_i==0 ? 128 : fid.to_i
end

#vf(forced = false) ⇒ Object

If called with true argument it will get the virtual_fabric from the switch instead of cache

Returns value in (string) format


166
167
168
169
170
171
172
173
174
175
176
# File 'lib/brocadesan/switch.rb', line 166

def vf(forced=false)
  if !@configuration[:vf] || forced
    # using this instead of fosconfig --show as that command does not work everywhere
    # we could user #ls_attributes method but that loaded whole switchshow os this will be a bit faster, especially with big switches
    # it needs to be faster as vf is called during initialization
    # if the switch is vf there will be LS Attributes line, otherwise it will be empty
    response=query("switchshow|grep \"^LS Attributes\"")
    @configuration[:vf] = response.data.split("\n").size == 2 ? "enabled" : "disabled"
  end
  @configuration[:vf]
end

#wwns(forced = false, mode = :local) ⇒ Object

returns all WWNs

mode

:local

returns all local WWNs

:cached

returns wwns cached from remote switches

:all

returns all local and remote wwns


242
243
244
245
246
247
248
249
250
# File 'lib/brocadesan/switch.rb', line 242

def wwns(forced=false,mode=:local)
  if mode==:local
    get_ns(true,forced,:local=>true)
  elsif mode==:cached
    get_ns(true,forced,:remote=>true)
  else
    get_ns(true,forced,:local=>true).concat get_ns(true,forced,:remote=>true)
  end 
end

#zone_configurations(full = false, forced = false) ⇒ Object

Returns ZoneConfigurations array

If full is set to true it loads full configurations with zones and aliases, otherwise it gets just the names.

It laods even zone configurations that were create as part of ongoing transaction.


183
184
185
# File 'lib/brocadesan/switch.rb', line 183

def zone_configurations(full=false,forced=false)
  get_configshow(full,forced)[:zone_configurations]
end

#zones(forced = false) ⇒ Object

returns all zones defined on the switch including zones created in ongoing transaction as array of Zone


196
197
198
# File 'lib/brocadesan/switch.rb', line 196

def zones(forced=false)
  get_configshow(true,forced)[:zones]
end