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
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
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
# 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
# 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
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
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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# File lib/junos-ez/l2_ports/vlan.rb, line 203 def upd_untagged_vlan( xml ) self.class.change_untagged_vlan( self, xml ) end
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 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 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
Junos::Ez::Provider::Parent#xml_build_change
# 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
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
: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
: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
: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 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
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
# 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
# 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