class Junos::Ez::L2ports::Provider::VLAN


Class methods for handling state-transitions between configurations (tagged/untagged)



Provider collection methods



!!!!! PRIVATE METHODS !!!!


edit vlans
  • for interfaces configured here …


Public Class Methods

ac_ac_nountg( this, xml ) click to toggle source

The following are all the change transition functions for each of the use-cases


# File lib/junos-ez/l2_ports/vlan.rb, line 266
def self.ac_ac_nountg( this, xml )
  this._xml_rm_ac_untagged_vlan( xml )
end
ac_ac_untg( this, xml ) click to toggle source

transition where port WILL-HAVE untagged-vlan


# File lib/junos-ez/l2_ports/vlan.rb, line 289
def self.ac_ac_untg( this, xml )
  this._xml_rm_ac_untagged_vlan( xml )
  xml.vlan {
    xml.members this.should[:untagged_vlan]
  }            
end
ac_tr_nountg( this, xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 270
def self.ac_tr_nountg( this, xml )      
  unless (untg_vlan = this.has[:untagged_vlan]).nil?
    this._xml_rm_ac_untagged_vlan( xml )
  end
end
ac_tr_untg( this, xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 296
def self.ac_tr_untg( this, xml )      
  # move untagged vlan to native-vlan-id ...
  was_untg_vlan = this.has[:untagged_vlan]
  xml.send :'native-vlan-id', this.should[:untagged_vlan]       
  this._xml_rm_ac_untagged_vlan( xml ) if was_untg_vlan   
end
change_untagged_vlan( this, xml ) click to toggle source

invoke the correct method from the jump table based on the three criteria to select the action

# File lib/junos-ez/l2_ports/vlan.rb, line 255
def self.change_untagged_vlan( this, xml )
  @@ez_l2_jmptbl ||= init_jump_table    
  proc = @@ez_l2_jmptbl[this.is_trunk?][this.should_trunk?][this.should[:untagged_vlan].nil?]
  proc.call( this, xml )
end
init_jump_table() click to toggle source

creating some class definitions … this is a bit complicated because we need to handle port-mode change transitions; basically dealing with the fact that trunk ports use 'native-vlan-id' and access ports have a vlan member definition; i.e. they don't use native-vlan-id, ugh. Rather than doing all this logic as if/then/else statements, I've opted to using a proc jump-table technique. Lessons learned from lots of embedded systems programming :-)

# File lib/junos-ez/l2_ports/vlan.rb, line 225
def self.init_jump_table
  
  # auto-hash table, majik!
  hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)}))
  
  # ------------------------------------------------------------------
  # -   jump table for handling various untagged vlan change use-cases
  # ------------------------------------------------------------------
  # There are three criteria for selection:
  # | is_trunk | will_trunk | no_untg |
  # ------------------------------------------------------------------
  
  # - will not have untagged vlan
  hash[false][false][true] = self.method(:ac_ac_nountg)
  hash[false][true][true] = self.method(:ac_tr_nountg)
  hash[true][false][true] = self.method(:tr_ac_nountg)
  hash[true][true][true] = self.method(:tr_tr_nountg)
  
  # - will have untagged vlan
  hash[false][false][false] = self.method(:ac_ac_untg)
  hash[false][true][false] = self.method(:ac_tr_untg)
  hash[true][false][false] = self.method(:tr_ac_untg)
  hash[true][true][false] = self.method(:tr_tr_untg)
  
  hash
end
tr_ac_nountg( this, xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 276
def self.tr_ac_nountg( this, xml )
  xml.send :'native-vlan-id', Netconf::JunosConfig::DELETE
  this._xml_rm_these_vlans( xml, this.has[:tagged_vlans ] ) if this.has[:tagged_vlans]    
end
tr_ac_untg( this, xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 303
def self.tr_ac_untg( this, xml )    
  xml.send :'native-vlan-id', Netconf::JunosConfig::DELETE 
  this._xml_rm_these_vlans( xml, this.has[:tagged_vlans ] ) if this.has[:tagged_vlans]         
  xml.vlan { xml.members this.should[:untagged_vlan] }
end
tr_tr_nountg( this, xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 281
def self.tr_tr_nountg( this, xml )
  xml.send :'native-vlan-id', Netconf::JunosConfig::DELETE              
end
tr_tr_untg( this, xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 309
def self.tr_tr_untg( this, xml )
  xml.send :'native-vlan-id', this.should[:untagged_vlan]              
end

Public Instance Methods

_xml_edit_under_vlans( xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 388
  def _xml_edit_under_vlans( xml )
  Nokogiri::XML::Builder.with( xml.doc.root ) do |dot|
    dot.vlans {
      return dot
    }
  end      
end
_xml_rm_ac_untagged_vlan( xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 408
def _xml_rm_ac_untagged_vlan( xml )
  if @under_vlans.empty?
    xml.vlan Netconf::JunosConfig::DELETE    
  else
    _xml_rm_under_vlans( xml, [ @has[:untagged_vlan ] ] )
    @under_vlans = []    
  end
end
_xml_rm_these_vlans( xml, vlans ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 417
def _xml_rm_these_vlans( xml, vlans )
  if @under_vlans.empty?
    xml.vlan( Netconf::JunosConfig::DELETE ) 
  else
    # could be a mix between [edit vlans] and [edit interfaces] ...
    v_has = vlans.to_set
    del_under_vlans = v_has & @under_vlans
    _xml_rm_under_vlans( xml, del_under_vlans )
    if v_has ^ @under_vlans
      xml.vlan( Netconf::JunosConfig::DELETE ) 
    end
    @under_vlans = []        
  end
end
_xml_rm_under_vlans( xml, vlans ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 396
def _xml_rm_under_vlans( xml, vlans )
  at_vlans = _xml_edit_under_vlans( xml )
  vlans.each do |vlan_name|
    Nokogiri::XML::Builder.with( at_vlans.parent ) do |this|
      this.vlan {
        this.name vlan_name
        this.interface( Netconf::JunosConfig::DELETE ) { this.name @name }
      }
    end
  end
end
build_catalog() click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 332
def build_catalog
  @catalog = {}    
  return @catalog if list!.empty?
  
  list.each do |ifs_name|
    @ndev.rpc.get_configuration{ |xml|
      xml.interfaces {
        xml.interface {
          xml.name ifs_name
          xml.unit { xml.name '0' }
        }
      }
    }.xpath('interfaces/interface').each do |ifs_xml|
      @catalog[ifs_name] = {}
      unit = ifs_xml.xpath('unit')[0]        
      xml_read_parser( unit, @catalog[ifs_name] )
    end
  end    
  
  @catalog
end
build_list() click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 320
def build_list
  
  begin
    got = @ndev.rpc.get_ethernet_switching_interface_information(:summary=>true)
  rescue => e
    # in this case, no ethernet-switching is enabled so return empty list
    return []
  end
  
  got.xpath('interface/interface-name').collect{ |ifn| ifn.text.split('.')[0] }
end
upd_tagged_vlans( xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 164
def upd_tagged_vlans( xml )        
  return false unless should_trunk?
  
  @should[:tagged_vlans] = @should[:tagged_vlans].to_set if @should[:tagged_vlans].kind_of? Array
  @has[:tagged_vlans] = @has[:tagged_vlans].to_set if @has[:tagged_vlans].kind_of? Array    

  v_should = @should[:tagged_vlans] || Set.new    
  v_has = @has[:tagged_vlans] || Set.new    
  
  del = v_has - v_should
  add = v_should - v_has 

  del_under_vlans = del & @under_vlans    

  unless del_under_vlans.empty?
    del = del ^ @under_vlans
    _xml_rm_under_vlans( xml, del_under_vlans )
    @under_vlans = []
  end

  if add or del
    xml.vlan {
      del.each { |v| xml.members v, Netconf::JunosConfig::DELETE }
      add.each { |v| xml.members v }
    }  
  end
  
  return true    
end
upd_untagged_vlan( xml ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 203
def upd_untagged_vlan( xml )
  self.class.change_untagged_vlan( self, xml )
end
xml_at_element_top( xml, name ) click to toggle source

set the edit anchor inside the ethernet-switching stanza we will need to 'up-out' when making changes to the unit information, like description

# File lib/junos-ez/l2_ports/vlan.rb, line 19
def xml_at_element_top( xml, name )
  xml.interface {
    xml.name name
    xml.unit { 
      xml.name '0'
      return xml
    }
  }    
end
xml_at_here( xml ) click to toggle source

XML property writers


# File lib/junos-ez/l2_ports/vlan.rb, line 104
def xml_at_here( xml )
  xml.family {
    xml.send(:'ethernet-switching') {
      return xml
    }
  }
end
xml_at_top() click to toggle source

XML top placement


# File lib/junos-ez/l2_ports/vlan.rb, line 7
def xml_at_top
  Nokogiri::XML::Builder.new {|xml| xml.configuration {
    xml.interfaces {
      return xml_at_element_top( xml, @name )
    }
  }}
end
xml_build_change( nop = nil ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 112
def xml_build_change( nop = nil )
  @under_vlans ||= []       # handles case for create'd port
  
  if mode_changed?
    @should[:untagged_vlan] ||= @has[:untagged_vlan]    
  end
  
  super xml_at_here( xml_at_top )
end
xml_change_description( xml ) click to toggle source

overload default method since we need to “up-out” of the ethernet-switching stanza

# File lib/junos-ez/l2_ports/vlan.rb, line 129
def xml_change_description( xml )
  unit = xml.parent.xpath('ancestor::unit')[0]
  Nokogiri::XML::Builder.with( unit ){ |x| 
    xml_set_or_delete( x, 'description', @should[:description] )
  }
end
xml_change_tagged_vlans( xml ) click to toggle source

:tagged_vlans


# File lib/junos-ez/l2_ports/vlan.rb, line 159
def xml_change_tagged_vlans( xml )  
  return false if mode_changed?  
  upd_tagged_vlans( xml )
end
xml_change_untagged_vlan( xml ) click to toggle source

:untagged_vlan


# File lib/junos-ez/l2_ports/vlan.rb, line 198
def xml_change_untagged_vlan( xml )   
  return false if mode_changed?         
  upd_untagged_vlan( xml )
end
xml_change_vlan_tagging( xml ) click to toggle source

:vlan_tagging


# File lib/junos-ez/l2_ports/vlan.rb, line 140
def xml_change_vlan_tagging( xml )    
  interface_mode = should_trunk? ? 'trunk' : 'access'
  xml.send(:'interface-mode', interface_mode )
  
  # when the vlan_tagging value changes then this method
  # will trigger updates to the untagged_vlan and tagged_vlans
  # resource values as well.
  # !!! DO NOT SWAP THIS ORDER untagged processing *MUST* BE FIRST!
  
  upd_untagged_vlan( xml )
  upd_tagged_vlans( xml ) 
  
  return true
end
xml_get_has_xml( xml ) click to toggle source

XML property readers


# File lib/junos-ez/l2_ports/vlan.rb, line 33
def xml_get_has_xml( xml )              
  # second unit contains the family/ethernet-switching stanza
  got = xml.xpath('//unit')[0]
  
  # if this resource doesn't exist we need to default some
  # values into has/should variables
  
  unless got
    @has[:vlan_tagging] = false
    @should = @has.clone
  end
  
  got
end
xml_on_delete( xml ) click to toggle source

overload the xml_on_delete method since we may need to do some cleanup work in the [edit vlans] stanza

# File lib/junos-ez/l2_ports/vlan.rb, line 93
def xml_on_delete( xml )
  return unless @under_vlans
  return if @under_vlans.empty?
  
  _xml_rm_under_vlans( xml, @under_vlans )
end
xml_read_parser( as_xml, as_hash ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 48
def xml_read_parser( as_xml, as_hash )    
  set_has_status( as_xml, as_hash )  
  
  xml_when_item(as_xml.xpath('description')){|i| as_hash[:description] = i.text}

  f_eth = as_xml.xpath('family/ethernet-switching')        
  as_hash[:vlan_tagging] = f_eth.xpath('interface-mode').text.chomp == 'trunk' 
  
  # obtain a copy of the running state, this is needed in case the config
  # is located under the [edit vlans] stanza vs. [edit interfaces]
  
  ifs_name = @name || as_xml.xpath('ancestor::interface/name').text.strip
  eth_port_vlans = _get_eth_port_vlans_h( ifs_name )
  @under_vlans = []
  
  # --- access port
  
  if as_hash[:vlan_tagging] == false
    xml_when_item(f_eth.xpath('vlan/members')){ |i| as_hash[:untagged_vlan] = i.text.chomp }
    unless as_hash[:untagged_vlan]
      as_hash[:untagged_vlan] = eth_port_vlans[:untagged]
      @under_vlans << eth_port_vlans[:untagged]
    end
    return
  end
  
  # --- trunk port
  
  xml_when_item(f_eth.xpath('native-vlan-id')){|i| as_hash[:untagged_vlan] = i.text.chomp }
  as_hash[:untagged_vlan] ||= eth_port_vlans[:untagged]    
  as_hash[:tagged_vlans] = f_eth.xpath('vlan/members').collect { |v| v.text.chomp }.to_set   
  (eth_port_vlans[:tagged] - as_hash[:tagged_vlans]).each do |vlan|
    as_hash[:tagged_vlans] << vlan
    @under_vlans << vlan
  end
  
end

Private Instance Methods

_get_eth_port_vlans_h( ifs_name ) click to toggle source
# File lib/junos-ez/l2_ports/vlan.rb, line 363
def _get_eth_port_vlans_h( ifs_name )
  
  got = @ndev.rpc.get_ethernet_switching_interface_information(:interface_name => ifs_name)
  ret_h = {:untagged => nil, :tagged => Set.new }
  got.xpath('//interface-vlan-member').each do |vlan|
    vlan_name = vlan.xpath('interface-vlan-name').text.strip      
    tgdy = vlan.xpath('interface-vlan-member-tagness').text.strip
    if tgdy == 'untagged'
      ret_h[:untagged] = vlan_name
    else
      ret_h[:tagged] << vlan_name
    end
  end
  ret_h
end