Class: Puppet::Provider::Junos::L2InterfaceL2NG

Inherits:
Puppet::Provider::Junos
  • Object
show all
Defined in:
lib/puppet/provider/junos/junos_l2_interface_l2ng.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




397
398
399
400
401
402
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 397

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



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

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

.ac_tr_nountg(this, xml) ⇒ Object



404
405
406
407
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 404

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

.ac_tr_untg(this, xml) ⇒ Object



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

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



387
388
389
390
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 387

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



380
381
382
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 380

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



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 352

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



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 132

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_native_vlan_id(this, xml, delete = :no) ⇒ Object



457
458
459
460
461
462
463
464
465
466
467
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 457

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
      dot.send( :'native-vlan-id', Netconf::JunosConfig::DELETE )
    else
      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




447
448
449
450
451
452
453
454
455
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 447

def set_vlan_id( this, xml, delete = :no )
  xml.vlan( Netconf::JunosConfig::REPLACE ) {
    if delete == :delete
      xml.members this.resource[:untagged_vlan], Netconf::JunosConfig::DELETE
    else
      xml.members this.resource[:untagged_vlan]
    end
  }
end

.tr_ac_nountg(this, xml) ⇒ Object



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

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



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

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



416
417
418
419
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 416

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



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

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



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

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



231
232
233
234
235
236
237
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 231

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



179
180
181
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
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 179

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 ...
  
  vlan_cfg = @@rpc.get_configuration{|cfg|
    cfg.vlans {
      cfg.vlan { cfg.name vlan_name
        cfg.send(:'vlan-id')
      }
  }}
  
  vlan_id = vlan_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

returns the vlan name



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 214

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, tag-id: #{tag_id} does not exist!"      
  end
end

.vlanxrefs_from_junos(resource) ⇒ Object



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

def vlanxrefs_from_junos( resource )
        
  vlan_if_info = @@rpc.get_vlan_information(:interface => resource[:name] + ".0")
  
  vlan_names = vlan_if_info.xpath('//l2ifbd-vlan-name')
  vlan_names.each do |name|
    vlan_name = name.text
            
    vlan_info = @@rpc.get_vlan_information( :vlan_name => vlan_name, :brief => true )
    dev_vlan_id = vlan_info.xpath('//l2ng-l2rtb-vlan-tag').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



91
92
93
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 91

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

#init_ndev_resObject


called from #netdev_exists?




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

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)


114
115
116
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 114

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

#mode_changed?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 122

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)


45
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
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 45

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? 
  
  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/ethernet-switching')      
  
  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



255
256
257
258
259
260
261
262
263
264
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 255

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

#netdev_retrieve_fam_eth_info(fam_eth_cfg) ⇒ Object



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

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
    @ndev_res[:untagged_vlan] = fam_eth_cfg.xpath('vlan/members').text.chomp || ''
    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 ) 
  
  @ndev_res[:tagged_vlans] = fam_eth_cfg.xpath('vlan/members').collect { |v| v.text.chomp }
end

#should_trunk?Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 118

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

#upd_tagged_vlans(xml) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 304

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 = has - should
  add = 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? 
    xml.vlan {
      del.each{|v| xml.members v, Netconf::JunosConfig::DELETE }
      add.each{|v| xml.members v }
    }
  end
  
end

#upd_untagged_vlan(xml) ⇒ Object



337
338
339
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 337

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

#xml_change_description(xml) ⇒ Object

:description



270
271
272
273
274
275
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 270

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




299
300
301
302
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 299

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

#xml_change_untagged_vlan(xml) ⇒ Object


XML:untagged_vlan




332
333
334
335
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 332

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

#xml_change_vlan_tagging(xml) ⇒ Object

:vlan_tagging



281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/puppet/provider/junos/junos_l2_interface_l2ng.rb', line 281

def xml_change_vlan_tagging( xml )
  
  port_mode = should_trunk? ? 'trunk' : 'access'
  xml.send :"interface-mode", port_mode
  
  # 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