Class: Puppet::Provider::Junos::L2InterfaceBridgeDomain

Inherits:
Puppet::Provider::Junos
  • Object
show all
Defined in:
lib/puppet/provider/junos/junos_l2_interface_bd.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.ac_ac_nountg(this, xml) ⇒ Object


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




419
420
421
422
423
424
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 419

def ac_ac_nountg( this, xml )
  NetdevJunos::Log.debug "ac_ac_nountg"                        
  # @@@ a port *MUST* be assigned to a vlan in access mode on MX.
  # @@@ generate an error!      
  Kernel.raise Puppet::DevError, "untagged_vlan missing, port must be assigned to a VLAN"      
end

.ac_ac_untg(this, xml) ⇒ Object



443
444
445
446
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 443

def ac_ac_untg( this, xml )
  NetdevJunos::Log.debug "ac_ac_untg"                  
  set_vlan_id( this, xml )
end

.ac_tr_nountg(this, xml) ⇒ Object



426
427
428
429
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 426

def ac_tr_nountg( this, xml )      
  NetdevJunos::Log.debug "ac_tr_nountg"                             
  ## no action needed; handled already
end

.ac_tr_untg(this, xml) ⇒ Object



448
449
450
451
452
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 448

def ac_tr_untg( this, xml )      
  NetdevJunos::Log.debug "ac_tr_untg"            
  set_vlan_id( this, xml, :delete ) if this.ndev_res[:untagged_vlan]
  set_native_vlan_id( this, xml )
end

.change_untagged_vlan(this, xml) ⇒ Object

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



409
410
411
412
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 409

def change_untagged_vlan( this, xml )
  proc = @@untgv_jmptbl[this.is_trunk?][this.should_trunk?][this.resource[:untagged_vlan].empty?]
  proc.call( this, xml )
end

.initcvar_for_untagged_vlanObject

initialize the jump table once as a class variable this is called from #init_resource



402
403
404
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 402

def initcvar_for_untagged_vlan    
  @@untgv_jmptbl ||= initcvar_jmptbl_untagged_vlan
end

.initcvar_jmptbl_untagged_vlanObject

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 :-)



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 374

def initcvar_jmptbl_untagged_vlan
  
  # auto-hash table
  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

.initcvar_vlanxrefs(resource) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 135

def initcvar_vlanxrefs( resource )
  
  @@rpc ||= Puppet::Provider::Junos.netdev.netconf.rpc
  @@catalog ||= resource.catalog
  @@catalog_netdev_vlan ||= @@catalog.resources.select{ |r| r.type == :netdev_vlan }
        
  @@vlan_name_hash ||= {}
  @@vlan_tag_hash ||= {}
  @@vlan_rewrite ||= {}
  
  # note: resource[:tagged_vlans] is stored as Array-of-Arrays.  ugh ...
  # so need to grab the .to_s for just the string name...
  
  all_vlan_names = resource[:tagged_vlans].clone      
  all_vlan_names << resource[:untagged_vlan] unless resource[:untagged_vlan].empty?            
  all_vlan_names.each{ |vlan_name| vlanxrefs_addbyname( vlan_name.to_s ) }
  
  # load the table of currently used VLANs from the device      
  vlanxrefs_from_junos( resource )
  
end

.set_ifd_trunking(xml, should_trunk) ⇒ Object



494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 494

def set_ifd_trunking( xml, should_trunk )
  par = xml.instance_variable_get(:@parent)     
  Nokogiri::XML::Builder.with( par.at_xpath( 'ancestor::interface' )) do |dot|
    if should_trunk
      dot.send( :'flexible-vlan-tagging' )
      dot.send( :'encapsulation', 'flexible-ethernet-services' )
    else
      dot.send( :'flexible-vlan-tagging', Netconf::JunosConfig::DELETE )
      dot.send( :'encapsulation', Netconf::JunosConfig::DELETE )
    end
  end       
end

.set_native_vlan_id(this, xml, delete = :no) ⇒ Object



478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 478

def set_native_vlan_id( this, xml, delete = :no )
  par = xml.instance_variable_get(:@parent)     
  vlan_id = vlan_names_to_tags( this.resource[:untagged_vlan] )
  
  Nokogiri::XML::Builder.with( par.at_xpath( 'ancestor::interface' )) do |dot|
    if delete == :delete
      # vlan-id-list is removed by another routine :-)
      dot.send( :'native-vlan-id', Netconf::JunosConfig::DELETE )       
    else
      xml.send( :'vlan-id-list', vlan_id )
      dot.send( :'native-vlan-id', vlan_id )
    end
  end    
  
end

.set_vlan_id(this, xml, delete = :no) ⇒ Object


helper methods, re-usable for each of the transitions




469
470
471
472
473
474
475
476
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 469

def set_vlan_id( this, xml, delete = :no )
  vlan_id = vlan_names_to_tags( this.resource[:untagged_vlan] )
  if delete == :delete 
    xml.send( :'vlan-id', Netconf::JunosConfig::DELETE )
  else
    xml.send( :'vlan-id', vlan_id )
  end
end

.tr_ac_nountg(this, xml) ⇒ Object



431
432
433
434
435
436
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 431

def tr_ac_nountg( this, xml )
  NetdevJunos::Log.debug "tr_ac_nountg"     
  # @@@ a port *MUST* be assigned to a vlan in access mode on MX.
  # @@@ generate an error!      
  Kernel.raise Puppet::DevError, "untagged_vlan missing, port must be assigned to a VLAN"
end

.tr_ac_untg(this, xml) ⇒ Object



454
455
456
457
458
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 454

def tr_ac_untg( this, xml )
  NetdevJunos::Log.debug "tr_ac_untg"      
  set_native_vlan_id( this, xml, :delete )
  set_vlan_id( this, xml )      
end

.tr_tr_nountg(this, xml) ⇒ Object



438
439
440
441
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 438

def tr_tr_nountg( this, xml )
  NetdevJunos::Log.debug "tr_tr_nountg"                  
  set_native_vlan_id( this, xml, :delete )
end

.tr_tr_untg(this, xml) ⇒ Object



460
461
462
463
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 460

def tr_tr_untg( this, xml )
  NetdevJunos::Log.debug "tr_tr_untg"
  set_native_vlan_id( this, xml )
end

.vlan_names_to_tags(names_a) ⇒ Object


vlan_names_to_tags is called when this provider is writing the configuration back to the device via the XML routines below …




254
255
256
257
258
259
260
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 254

def vlan_names_to_tags( names_a )
  if names_a.class == Array
    tags_a = names_a.collect{ |name| @@vlan_name_hash[name] }
  else
    @@vlan_name_hash[names_a]
  end
end

.vlan_tags_to_names(tagid_a) ⇒ Object



240
241
242
243
244
245
246
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 240

def vlan_tags_to_names( tagid_a )      
  if tagid_a.class == Array
    tagid_a.collect{ |tag_id| @@vlan_tag_hash[tag_id] || vlanxrefs_addbytag( 'default-switch', tag_id ) }
  else
    @@vlan_tag_hash[tagid_a] || vlanxrefs_addbytag( 'default-switch', tagid_a )
  end
end

.vlanxrefs_addbyname(vlan_name) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 182

def vlanxrefs_addbyname( vlan_name )
  return if @@vlan_name_hash[vlan_name]              

  # let's see if Puppet knows about this vlan_name ...
  # we snarf the tilde (~) in case this is a triggered vlan_name
  # change; and the vlan_names in the catalog don't have a tilde.  Yo!
  
  if vlan_res = @@catalog.resource( :netdev_vlan, vlan_name.sub( '~',''))
    vlan_id = vlan_res[:vlan_id]          
    @@vlan_name_hash[vlan_name] = vlan_id
    @@vlan_tag_hash[vlan_id] = vlan_name
    return
  end
  
  # Pupept doesn't know, so we need to go to the config 
  # and retrieve what we need ...
  
  bd_cfg = @@rpc.get_configuration{|cfg|
    cfg.send(:'bridge-domains') {
      cfg.domain { cfg.name vlan_name
        cfg.send(:'vlan-id')
      }
  }}
  
  vlan_id = bd_cfg.xpath('//vlan-id').text.chomp
  if vlan_id.empty?
    Kernel.raise Puppet::DevError, "requested VLAN #{vlan_name} does not exist!"
    return
  end
  
  @@vlan_name_hash[vlan_name] = vlan_id
  @@vlan_tag_hash[vlan_id] = vlan_name        
  
end

.vlanxrefs_addbytag(switch_name, tag_id) ⇒ Object


vlanxrefs_addbytag and vlan_tags_to_names is called by the routines when the configuration is loaded from the device.




222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 222

def vlanxrefs_addbytag( switch_name, tag_id )   # returns the vlan name
  
  # resource[:vlan_id] is a Fixnum, and tag_id is String. So
  # convert to Fixnum now for comparison ...
  tag_id_i = tag_id.to_i            
        
  p_ndev_vlan = @@catalog_netdev_vlan.select{ |v| v[:vlan_id].to_i == tag_id_i  }[0]
  
  if p_ndev_vlan
    vlan_name = p_ndev_vlan[:name]
    @@vlan_name_hash[vlan_name] = tag_id
    @@vlan_tag_hash[tag_id] = vlan_name
    vlan_name
  else             
    Kernel.raise Puppet::DevError, "Unknown VLAN by tag-id: #{tag_id} !"      
  end
end

.vlanxrefs_from_junos(resource) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 157

def vlanxrefs_from_junos( resource )
  
  bd_if_info = @@rpc.get_bridge_instance_information(:interface => resource[:name] + ".0")
  
  bd_names = bd_if_info.xpath('l2ald-bd-ifbd-entry/l2ald-ifbd-entry/l2ifbd-bd-name')
  bd_names.each do |name|
    vlan_name = name.text
            
    bd_info = @@rpc.get_bridge_instance_information( :bridge_domain_name => vlan_name, :brief => true )
    dev_vlan_id = bd_info.xpath('//l2rtb-bridge-vlan').text.chomp
    
    if pp_vlan_id = @@vlan_name_hash[vlan_name]
      # then Puppet already knows about this vlan, need to see if the vlan-id
      # has changed as a result of a netdev_vlan update
      if dev_vlan_id != pp_vlan_id
        @@vlan_name_hash['~' + vlan_name] = pp_vlan_id
      end
    else
      # Puppet didn't know abou this vlan, so add it to the managed list ...
      @@vlan_name_hash[vlan_name] = dev_vlan_id
    end
    @@vlan_tag_hash[dev_vlan_id] = vlan_name        
  end # each: bd_name      
end

Instance Method Details

#default_descriptionObject



93
94
95
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 93

def default_description
  "Puppet created netdev_l2_interface: #{resource[:name]}"
end

#init_ndev_resObject


called from #netdev_exists?




78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 78

def init_ndev_res
  
  @ndev_res ||= NetdevJunos::Resource.new( self, "interfaces", "interface" )
   
  ndev_config = @ndev_res.getconfig    
  @ifd_config = ndev_config.xpath('//interface')[0]
  return false unless @ifd_config
  
  @ifl_config = @ifd_config.xpath('unit')[0]    
  return false unless @ifl_config
  
  @ndev_res.set_active_state( @ifl_config )      
  return true
end

#is_trunk?Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 117

def is_trunk?
  @ndev_res[:vlan_tagging] == :enable
end

#mode_changed?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 125

def mode_changed?
  @ndev_res[:name].nil? or (resource[:vlan_tagging] != @ndev_res[:vlan_tagging])
end

#netdev_res_exists?Boolean


triggered from Provider #exists?


Returns:

  • (Boolean)


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 46

def netdev_res_exists?
   
  resource[:description] ||= default_description
  resource[:tagged_vlans] = resource[:tagged_vlans].to_a || []     
  resource[:untagged_vlan] ||= ''     # if not set in manifest, it is nil   
  resource[:vlan_tagging] = :enable unless resource[:tagged_vlans].empty?   
  resource[:tagged_vlans] += [resource[:untagged_vlan]] unless resource[:untagged_vlan].empty?
  
  self.class.initcvar_for_untagged_vlan      
  self.class.initcvar_vlanxrefs( resource )    
  
  return false unless init_ndev_res

  @ndev_res[:description] = ''
  @ndev_res[:vlan_tagging] = :disable
  @ndev_res[:untagged_vlan] = ''
  @ndev_res[:tagged_vlans] = []         
  
  @ndev_res[:description] = @ifl_config.xpath('description').text.chomp    
  fam_eth_cfg = @ifl_config.xpath('family/bridge')      
  
  return false if fam_eth_cfg.empty?
  
  netdev_retrieve_fam_eth_info( fam_eth_cfg )
  
  return true
end

#netdev_resxml_edit(xml) ⇒ Object

override default ‘edit’ method to place ‘dot’ inside the family bridge stanza



270
271
272
273
274
275
276
277
278
279
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 270

def netdev_resxml_edit( xml )
  xml.unit {
    xml.name '0' 
    xml.family { 
      xml.send(:'bridge') {
        return xml
      }
    }
  }
end

#netdev_retrieve_fam_eth_info(fam_eth_cfg) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 97

def netdev_retrieve_fam_eth_info( fam_eth_cfg )
  
  @ndev_res[:vlan_tagging] = fam_eth_cfg.xpath('interface-mode').text.chomp == 'trunk' ? :enable : :disable
  
  # --- access port      
  
  if @ndev_res[:vlan_tagging] == :disable
    vlan_id = fam_eth_cfg.xpath('vlan-id').text.chomp || ''
    @ndev_res[:untagged_vlan] = self.class.vlan_tags_to_names( vlan_id )
    return
  end
  
  # --- trunk port       
  native_vlan_id = @ifd_config.xpath('native-vlan-id').text.chomp;
  @ndev_res[:untagged_vlan] = native_vlan_id.empty? ? '' : self.class.vlan_tags_to_names( native_vlan_id ) 
  
  vlan_id_list = fam_eth_cfg.xpath('vlan-id-list').collect { |v| v.text.chomp }       
  @ndev_res[:tagged_vlans] = self.class.vlan_tags_to_names( vlan_id_list )
end

#should_trunk?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 121

def should_trunk?
  resource[:vlan_tagging] == :enable
end

#upd_tagged_vlans(xml) ⇒ Object



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 328

def upd_tagged_vlans( xml )
  
  return unless should_trunk?
  
  should = resource[:tagged_vlans] || []
  has = @ndev_res[:tagged_vlans] || []    
    
  has = has.map(&:to_s)    
  should = should.map(&:to_s)        
  
  del = self.class.vlan_names_to_tags( has - should )
  add = self.class.vlan_names_to_tags( should - has )    
      
  if add or del
    Puppet.debug "#{resource[:name]}: Adding VLANS: [#{add.join(',')}]" unless add.empty?
    Puppet.debug "#{resource[:name]}: Deleting VLANS: [#{del.join(',')}]" unless del.empty?      
    del.each{|tag_id|  xml.send( :'vlan-id-list', tag_id, Netconf::JunosConfig::DELETE )}
    add.each{|tag_id|  xml.send( :'vlan-id-list', tag_id )}
  end
  
end

#upd_untagged_vlan(xml) ⇒ Object



359
360
361
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 359

def upd_untagged_vlan( xml )
  self.class.change_untagged_vlan( self, xml )
end

#xml_change_description(xml) ⇒ Object

:description



285
286
287
288
289
290
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 285

def xml_change_description( xml )    
  par = xml.instance_variable_get(:@parent)        
  Nokogiri::XML::Builder.with( par.at_xpath( 'ancestor::unit' )) do |dot|
    dot.description resource[:description]
  end    
end

#xml_change_tagged_vlans(xml) ⇒ Object


XML:tagged_vlans




322
323
324
325
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 322

def xml_change_tagged_vlans( xml )  
  return if mode_changed?  
  upd_tagged_vlans( xml )
end

#xml_change_untagged_vlan(xml) ⇒ Object


XML:untagged_vlan




354
355
356
357
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 354

def xml_change_untagged_vlan( xml )           
  return if mode_changed?         
  upd_untagged_vlan( xml )
end

#xml_change_vlan_tagging(xml) ⇒ Object

:vlan_tagging



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/puppet/provider/junos/junos_l2_interface_bd.rb', line 296

def xml_change_vlan_tagging( xml )
  
  port_mode = should_trunk? ? 'trunk' : 'access'
  xml.send :"interface-mode", port_mode
  
  if is_trunk? and not should_trunk?
    # trunk --> access
    self.class.set_ifd_trunking( xml, false )
  elsif should_trunk? and not is_trunk?
    # access --> trunk
    self.class.set_ifd_trunking( xml, true )
  end    
  
  # when the vlan_tagging value changes then this method
  # will trigger updates to the untagged_vlan and tagged_vlans
  # resource values as well.
  
  upd_untagged_vlan( xml )
  upd_tagged_vlans( xml )
  
end