shopify-junos-ez-stdlib 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +91 -0
- data/LICENSE +26 -0
- data/README.md +199 -0
- data/docs/Facts.md +192 -0
- data/docs/Providers/Group.md +61 -0
- data/docs/Providers/IPports.md +61 -0
- data/docs/Providers/L1ports.md +29 -0
- data/docs/Providers/L2ports.md +43 -0
- data/docs/Providers/LAGports.md +57 -0
- data/docs/Providers/StaticHosts.md +26 -0
- data/docs/Providers/StaticRoutes.md +37 -0
- data/docs/Providers/UserAuths.md +32 -0
- data/docs/Providers/Users.md +122 -0
- data/docs/Providers/Vlans.md +43 -0
- data/docs/Providers_Resources.md +353 -0
- data/docs/README_FIRST.md +27 -0
- data/docs/Utils/Config.md +160 -0
- data/docs/Utils/Filesystem.md +360 -0
- data/docs/Utils/Routing-Engine.md +379 -0
- data/docs/Utils/SCP.md +24 -0
- data/examples/config/config_file.rb +72 -0
- data/examples/config/config_template_object.rb +81 -0
- data/examples/config/config_template_simple.rb +76 -0
- data/examples/config/multi_config.rb +60 -0
- data/examples/fs_utils.rb +31 -0
- data/examples/lag_port.rb +27 -0
- data/examples/re_upgrade.rb +99 -0
- data/examples/re_utils.rb +33 -0
- data/examples/simple.rb +46 -0
- data/examples/st_hosts.rb +33 -0
- data/examples/user.rb +32 -0
- data/examples/vlans.rb +31 -0
- data/junos-ez-stdlib.gemspec +15 -0
- data/lib/junos-ez/exceptions.rb +3 -0
- data/lib/junos-ez/facts.rb +83 -0
- data/lib/junos-ez/facts/chassis.rb +51 -0
- data/lib/junos-ez/facts/ifd_style.rb +17 -0
- data/lib/junos-ez/facts/personality.rb +25 -0
- data/lib/junos-ez/facts/switch_style.rb +31 -0
- data/lib/junos-ez/facts/version.rb +58 -0
- data/lib/junos-ez/group.rb +206 -0
- data/lib/junos-ez/ip_ports.rb +30 -0
- data/lib/junos-ez/ip_ports/classic.rb +188 -0
- data/lib/junos-ez/l1_ports.rb +121 -0
- data/lib/junos-ez/l1_ports/classic.rb +87 -0
- data/lib/junos-ez/l1_ports/switch.rb +134 -0
- data/lib/junos-ez/l2_ports.rb +66 -0
- data/lib/junos-ez/l2_ports/bridge_domain.rb +499 -0
- data/lib/junos-ez/l2_ports/vlan.rb +433 -0
- data/lib/junos-ez/l2_ports/vlan_l2ng.rb +502 -0
- data/lib/junos-ez/lag_ports.rb +268 -0
- data/lib/junos-ez/provider.rb +619 -0
- data/lib/junos-ez/stdlib.rb +18 -0
- data/lib/junos-ez/system.rb +48 -0
- data/lib/junos-ez/system/st_hosts.rb +92 -0
- data/lib/junos-ez/system/st_routes.rb +159 -0
- data/lib/junos-ez/system/syscfg.rb +103 -0
- data/lib/junos-ez/system/userauths.rb +84 -0
- data/lib/junos-ez/system/users.rb +217 -0
- data/lib/junos-ez/utils/config.rb +236 -0
- data/lib/junos-ez/utils/fs.rb +385 -0
- data/lib/junos-ez/utils/re.rb +558 -0
- data/lib/junos-ez/version.rb +6 -0
- data/lib/junos-ez/vlans.rb +38 -0
- data/lib/junos-ez/vlans/bridge_domain.rb +89 -0
- data/lib/junos-ez/vlans/vlan.rb +119 -0
- data/lib/junos-ez/vlans/vlan_l2ng.rb +126 -0
- data/shipit.yml +4 -0
- data/tmp +7 -0
- metadata +129 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
class Junos::Ez::L1ports::Provider::CLASSIC < Junos::Ez::L1ports::Provider
|
2
|
+
|
3
|
+
### ---------------------------------------------------------------
|
4
|
+
### XML top placement
|
5
|
+
### ---------------------------------------------------------------
|
6
|
+
|
7
|
+
def xml_at_top
|
8
|
+
xml = Nokogiri::XML::Builder.new {|xml| xml.configuration {
|
9
|
+
xml.interfaces {
|
10
|
+
xml.interface {
|
11
|
+
xml.name @name
|
12
|
+
return xml
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}}
|
16
|
+
end
|
17
|
+
|
18
|
+
### ---------------------------------------------------------------
|
19
|
+
### XML property readers
|
20
|
+
### ---------------------------------------------------------------
|
21
|
+
|
22
|
+
def xml_read_filter( xml )
|
23
|
+
xml.description
|
24
|
+
xml.disable
|
25
|
+
xml.mtu
|
26
|
+
xml.speed
|
27
|
+
xml.send(:'link-mode')
|
28
|
+
xml.unit({:recurse => 'false'})
|
29
|
+
end
|
30
|
+
|
31
|
+
def xml_config_read!
|
32
|
+
xml = xml_at_top
|
33
|
+
xml_read_filter( xml )
|
34
|
+
@ndev.rpc.get_configuration( xml )
|
35
|
+
end
|
36
|
+
|
37
|
+
def xml_read_parser( as_xml, as_hash )
|
38
|
+
set_has_status( as_xml, as_hash )
|
39
|
+
|
40
|
+
as_hash[:admin] = as_xml.xpath('disable').empty? ? :up : :down
|
41
|
+
|
42
|
+
unless (desc = as_xml.xpath('description').text.chomp).empty?
|
43
|
+
as_hash[:description] = desc
|
44
|
+
end
|
45
|
+
|
46
|
+
if mtu = as_xml.xpath('mtu')[0]; as_hash[:mtu] = mtu.text.to_i end
|
47
|
+
|
48
|
+
as_hash[:duplex] = case as_xml.xpath('link-mode').text.chomp
|
49
|
+
when 'full-duplex' then :full
|
50
|
+
when 'half-duplex' then :half
|
51
|
+
else :auto
|
52
|
+
end
|
53
|
+
|
54
|
+
as_hash[:speed] = ( speed = as_xml.xpath('speed')[0] ) ? speed.text : :auto
|
55
|
+
as_hash[:unit_count] = as_xml.xpath('unit').count
|
56
|
+
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
|
60
|
+
### ---------------------------------------------------------------
|
61
|
+
### XML property writers
|
62
|
+
### ---------------------------------------------------------------
|
63
|
+
|
64
|
+
def xml_change_speed( xml )
|
65
|
+
if @should[:speed] == :auto
|
66
|
+
if is_new?
|
67
|
+
xml.speed Netconf::JunosConfig::DELETE
|
68
|
+
end
|
69
|
+
else
|
70
|
+
xml.speed @should[:speed]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def xml_change_duplex( xml )
|
75
|
+
if @should[:duplex] == :auto
|
76
|
+
unless is_new?
|
77
|
+
xml.send( :'link-mode', Netconf::JunosConfig::DELETE )
|
78
|
+
end
|
79
|
+
else
|
80
|
+
xml.send( :'link-mode', case @should[:duplex]
|
81
|
+
when :full then 'full-duplex'
|
82
|
+
when :half then 'half-duplex'
|
83
|
+
end )
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
class Junos::Ez::L1ports::Provider::SWITCH < Junos::Ez::L1ports::Provider
|
2
|
+
|
3
|
+
### ---------------------------------------------------------------
|
4
|
+
### XML top placement
|
5
|
+
### ---------------------------------------------------------------
|
6
|
+
|
7
|
+
def xml_at_top
|
8
|
+
xml = Nokogiri::XML::Builder.new {|xml| xml.configuration {
|
9
|
+
xml.interfaces {
|
10
|
+
xml.interface {
|
11
|
+
xml.name @name
|
12
|
+
return xml
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}}
|
16
|
+
end
|
17
|
+
|
18
|
+
### ---------------------------------------------------------------
|
19
|
+
### XML property readers
|
20
|
+
### ---------------------------------------------------------------
|
21
|
+
|
22
|
+
def xml_read_filter( xml )
|
23
|
+
xml.description
|
24
|
+
xml.disable
|
25
|
+
xml.mtu
|
26
|
+
xml.send(:'ether-options')
|
27
|
+
xml.unit({:recurse => 'false'})
|
28
|
+
end
|
29
|
+
|
30
|
+
def xml_config_read!
|
31
|
+
xml = xml_at_top
|
32
|
+
xml_read_filter( xml )
|
33
|
+
@ndev.rpc.get_configuration( xml )
|
34
|
+
end
|
35
|
+
|
36
|
+
def xml_read_parser( as_xml, as_hash )
|
37
|
+
set_has_status( as_xml, as_hash )
|
38
|
+
|
39
|
+
xml_when_item(as_xml.xpath('description')){|i| as_hash[:description] = i.text}
|
40
|
+
as_hash[:admin] = as_xml.xpath('disable').empty? ? :up : :down
|
41
|
+
xml_when_item(as_xml.xpath('mtu')){|i| as_hash[:mtu] = i.text.to_i }
|
42
|
+
|
43
|
+
phy_options = as_xml.xpath('ether-options')
|
44
|
+
if phy_options.empty?
|
45
|
+
as_hash[:speed] = :auto
|
46
|
+
as_hash[:duplex] = :auto
|
47
|
+
else
|
48
|
+
## :duplex
|
49
|
+
as_hash[:duplex] = case phy_options.xpath('link-mode').text.chomp
|
50
|
+
when 'full-duplex' then :full
|
51
|
+
when 'half-duplex' then :half
|
52
|
+
else :auto
|
53
|
+
end
|
54
|
+
## :speed
|
55
|
+
if speed = phy_options.xpath('speed')[0]
|
56
|
+
as_hash[:speed] = _speed_from_junos_( speed.first_element_child.name )
|
57
|
+
else
|
58
|
+
as_hash[:speed] = :auto
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
as_hash[:unit_count] = as_xml.xpath('unit').count
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
|
66
|
+
### ---------------------------------------------------------------
|
67
|
+
### XML property writers
|
68
|
+
### ---------------------------------------------------------------
|
69
|
+
|
70
|
+
def xml_change_speed( xml )
|
71
|
+
xml.send(:'ether-options') {
|
72
|
+
xml.speed {
|
73
|
+
if @should[:speed] == :auto
|
74
|
+
unless @has[:speed] == :auto
|
75
|
+
xml.send( _speed_to_junos_( @has[:speed] ), Netconf::JunosConfig::DELETE )
|
76
|
+
end
|
77
|
+
else
|
78
|
+
xml.send( _speed_to_junos_( @should[:speed] ))
|
79
|
+
end
|
80
|
+
}
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def xml_change_duplex( xml )
|
85
|
+
xml.send(:'ether-options') {
|
86
|
+
if @should[:duplex] == :auto
|
87
|
+
unless @has[:duplex] == :auto
|
88
|
+
xml.send( :'link-mode', Netconf::JunosConfig::DELETE )
|
89
|
+
end
|
90
|
+
else
|
91
|
+
xml.send( :'link-mode', case @should[:duplex]
|
92
|
+
when :full then 'full-duplex'
|
93
|
+
when :half then 'half-duplex'
|
94
|
+
end )
|
95
|
+
end
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
### -----------------------------------------------------------------
|
103
|
+
### PRIVATE METHODS
|
104
|
+
### -----------------------------------------------------------------
|
105
|
+
|
106
|
+
class Junos::Ez::L1ports::Provider::SWITCH
|
107
|
+
private
|
108
|
+
|
109
|
+
def _speed_to_junos_( pval )
|
110
|
+
# @@@ TODO: could remove case-statement and to
|
111
|
+
# @@@ string processing ...
|
112
|
+
case pval
|
113
|
+
when '10g' then :'ethernet-10g'
|
114
|
+
when '1g' then :'ethernet-1g'
|
115
|
+
when '100m' then :'ethernet-100m'
|
116
|
+
when '10m' then :'ethernet-10m'
|
117
|
+
else :auto
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def _speed_from_junos_( jval )
|
122
|
+
# @@@ TODO: could remove case-statement and to
|
123
|
+
# @@@ string processing ...
|
124
|
+
case jval
|
125
|
+
when 'ethernet-100m' then '100m'
|
126
|
+
when 'ethernet-10m' then '10m'
|
127
|
+
when 'ethernet-1g' then '1g'
|
128
|
+
when 'ethernet-10g' then '10g'
|
129
|
+
else :auto
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
require "junos-ez/provider"
|
3
|
+
|
4
|
+
module Junos::Ez::L2ports
|
5
|
+
|
6
|
+
PROPERTIES = [
|
7
|
+
:description, # String | nil
|
8
|
+
:untagged_vlan, # String | nil
|
9
|
+
:tagged_vlans, # Set of String | nil
|
10
|
+
:vlan_tagging # true | false
|
11
|
+
]
|
12
|
+
|
13
|
+
def self.Provider( ndev, varsym )
|
14
|
+
|
15
|
+
newbie = case ndev.fact( :switch_style )
|
16
|
+
when :VLAN
|
17
|
+
Junos::Ez::L2ports::Provider::VLAN.new( ndev )
|
18
|
+
when :VLAN_L2NG
|
19
|
+
Junos::Ez::L2ports::Provider::VLAN_L2NG.new( ndev )
|
20
|
+
when :BRIDGE_DOMAIN
|
21
|
+
Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN.new(ndev)
|
22
|
+
#raise ArgumentError, "under development"
|
23
|
+
# Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN.new( ndev )
|
24
|
+
end
|
25
|
+
|
26
|
+
newbie.properties = Junos::Ez::Provider::PROPERTIES + PROPERTIES
|
27
|
+
Junos::Ez::Provider.attach_instance_variable( ndev, varsym, newbie )
|
28
|
+
end
|
29
|
+
|
30
|
+
class Provider < Junos::Ez::Provider::Parent
|
31
|
+
# common parenting ...
|
32
|
+
|
33
|
+
def is_trunk?
|
34
|
+
@has[:vlan_tagging] == true
|
35
|
+
end
|
36
|
+
|
37
|
+
def should_trunk?
|
38
|
+
(@should[:vlan_tagging].nil?) ? @has[:vlan_tagging] : @should[:vlan_tagging]
|
39
|
+
end
|
40
|
+
|
41
|
+
def mode_changed?
|
42
|
+
return true if is_new?
|
43
|
+
return false if @should[:vlan_tagging].nil?
|
44
|
+
@should[:vlan_tagging] != @has[:vlan_tagging]
|
45
|
+
end
|
46
|
+
|
47
|
+
### ---------------------------------------------------------------
|
48
|
+
### XML overload 'activate/deactivate' since we need to modify
|
49
|
+
### this at the 'unit' level and not at the 'family' level
|
50
|
+
### ---------------------------------------------------------------
|
51
|
+
|
52
|
+
def xml_change__active( xml )
|
53
|
+
par = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface')
|
54
|
+
value = @should[:_active] ? 'active' : 'inactive'
|
55
|
+
par[value] = value # attribute name is same as value
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
require 'junos-ez/l2_ports/vlan'
|
63
|
+
require 'junos-ez/l2_ports/vlan_l2ng'
|
64
|
+
require 'junos-ez/l2_ports/bridge_domain'
|
65
|
+
|
66
|
+
|
@@ -0,0 +1,499 @@
|
|
1
|
+
class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN< Junos::Ez::L2ports::Provider
|
2
|
+
|
3
|
+
### ---------------------------------------------------------------
|
4
|
+
### XML top placement
|
5
|
+
### ---------------------------------------------------------------
|
6
|
+
|
7
|
+
def xml_at_top
|
8
|
+
Nokogiri::XML::Builder.new {|xml| xml.configuration {
|
9
|
+
xml.interfaces {
|
10
|
+
return xml_at_element_top( xml, @name )
|
11
|
+
}
|
12
|
+
}}
|
13
|
+
end
|
14
|
+
|
15
|
+
# set the edit anchor inside bridge-domains stanza
|
16
|
+
# we will need to 'up-out' when making changes to the
|
17
|
+
# unit information, like description
|
18
|
+
|
19
|
+
def xml_at_element_top( xml, name )
|
20
|
+
xml.interface {
|
21
|
+
xml.name name
|
22
|
+
xml.send(:'native-vlan-id')
|
23
|
+
xml.unit {
|
24
|
+
xml.name '0'
|
25
|
+
return xml
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
### ---------------------------------------------------------------
|
31
|
+
### XML property readers
|
32
|
+
### ---------------------------------------------------------------
|
33
|
+
|
34
|
+
def xml_get_has_xml( xml )
|
35
|
+
# second unit contains the family/bridge-domains stanza
|
36
|
+
got = xml.xpath('//unit')[0]
|
37
|
+
# if this resource doesn't exist we need to default some
|
38
|
+
# values into has/should variables
|
39
|
+
unless got
|
40
|
+
@has[:vlan_tagging] = false
|
41
|
+
@should = @has.clone
|
42
|
+
end
|
43
|
+
got
|
44
|
+
end
|
45
|
+
|
46
|
+
def xml_read_parser( as_xml, as_hash )
|
47
|
+
## reading is anchored at the [... unit 0 ...] level
|
48
|
+
set_has_status( as_xml, as_hash )
|
49
|
+
|
50
|
+
xml_when_item(as_xml.xpath('description')){|i| as_hash[:description] = i.text}
|
51
|
+
|
52
|
+
f_eth = as_xml.xpath('family/bridge')
|
53
|
+
as_hash[:vlan_tagging] = f_eth.xpath('interface-mode').text.chomp == 'trunk'
|
54
|
+
|
55
|
+
# obtain a copy of the running state, this is needed in case the config
|
56
|
+
# is located under the [edit vlans] stanza vs. [edit interfaces]
|
57
|
+
|
58
|
+
ifs_name = @name || as_xml.xpath('ancestor::interface/name').text.strip
|
59
|
+
eth_port_vlans = _get_eth_port_vlans_h( ifs_name )
|
60
|
+
@under_vlans = []
|
61
|
+
|
62
|
+
# --- access port
|
63
|
+
|
64
|
+
if as_hash[:vlan_tagging] == false
|
65
|
+
xml_when_item(f_eth.xpath('domain/vlan-id')){ |i| as_hash[:untagged_vlan] = i.text.chomp }
|
66
|
+
unless as_hash[:untagged_vlan]
|
67
|
+
as_hash[:untagged_vlan] = eth_port_vlans[:untagged]
|
68
|
+
@under_vlans << eth_port_vlans[:untagged]
|
69
|
+
end
|
70
|
+
return
|
71
|
+
end
|
72
|
+
|
73
|
+
# --- trunk port
|
74
|
+
as_hash[:untagged_vlan] ||= eth_port_vlans[:untagged]
|
75
|
+
as_hash[:tagged_vlans] = f_eth.xpath('//bridge/vlan-id-list').collect { |v| v.text.chomp }.to_set
|
76
|
+
(eth_port_vlans[:tagged] - as_hash[:tagged_vlans]).each do |vlan|
|
77
|
+
as_hash[:tagged_vlans] << vlan
|
78
|
+
@under_vlans << vlan
|
79
|
+
end
|
80
|
+
# native-vlan-id is set at the interface level, and is the VLAN-ID, not the vlan
|
81
|
+
# name. So we need to do a bit of translating here. The *ASSUMPTION* is that the
|
82
|
+
# native-vlan-id value is a given VLAN in the tagged_vlan list. So we will use
|
83
|
+
# that list to do the reverse lookup on the tag-id => name
|
84
|
+
as_hash[:tagged_vlans]= as_hash[:tagged_vlans].collect {|x| _vlan_tag_id_to_name(x)}
|
85
|
+
xml_when_item(f_eth.xpath('ancestor::interface/native-vlan-id')){ |i|
|
86
|
+
as_hash[:untagged_vlan] = _vlan_tag_id_to_name( i.text.chomp)
|
87
|
+
}
|
88
|
+
as_hash[:tagged_vlans].delete(as_hash[:untagged_vlan])
|
89
|
+
end
|
90
|
+
|
91
|
+
### ---------------------------------------------------------------
|
92
|
+
### XML on_create, on_delete handlers
|
93
|
+
### ---------------------------------------------------------------
|
94
|
+
|
95
|
+
## overload the xml_on_delete method since we may need
|
96
|
+
## to do some cleanup work in the [edit vlans] stanza
|
97
|
+
|
98
|
+
def xml_on_delete( xml )
|
99
|
+
@ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface')
|
100
|
+
@ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config
|
101
|
+
## need to add check if any native-vlan-id is present or not (untagged vlan)#####
|
102
|
+
if is_trunk? and @ifd.xpath('//native-vlan-id')
|
103
|
+
_delete_native_vlan_id( xml )
|
104
|
+
end
|
105
|
+
|
106
|
+
return unless @under_vlans
|
107
|
+
return if @under_vlans.empty?
|
108
|
+
|
109
|
+
_xml_rm_under_vlans( xml, @under_vlans )
|
110
|
+
end
|
111
|
+
|
112
|
+
### ---------------------------------------------------------------
|
113
|
+
### XML property writers
|
114
|
+
### ---------------------------------------------------------------
|
115
|
+
|
116
|
+
def xml_at_here( xml )
|
117
|
+
@ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface')
|
118
|
+
@ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config
|
119
|
+
xml.family {
|
120
|
+
xml.send(:'bridge') {
|
121
|
+
return xml
|
122
|
+
}
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def xml_build_change( nop = nil )
|
127
|
+
@under_vlans ||= [] # handles case for create'd port
|
128
|
+
if mode_changed?
|
129
|
+
@should[:untagged_vlan] ||= @has[:untagged_vlan]
|
130
|
+
end
|
131
|
+
super xml_at_here( xml_at_top )
|
132
|
+
end
|
133
|
+
|
134
|
+
## ----------------------------------------------------------------
|
135
|
+
## :description
|
136
|
+
## ----------------------------------------------------------------
|
137
|
+
|
138
|
+
## overload default method since we need to "up-out" of the
|
139
|
+
|
140
|
+
def xml_change_description( xml )
|
141
|
+
unit = xml.parent.xpath('ancestor::unit')[0]
|
142
|
+
Nokogiri::XML::Builder.with( unit ){ |x|
|
143
|
+
xml_set_or_delete( x, 'description', @should[:description] )
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
## ----------------------------------------------------------------
|
148
|
+
## :vlan_tagging
|
149
|
+
## ----------------------------------------------------------------
|
150
|
+
|
151
|
+
def xml_change_vlan_tagging( xml )
|
152
|
+
port_mode = should_trunk? ? 'trunk' : 'access'
|
153
|
+
xml.send(:'interface-mode', port_mode )
|
154
|
+
|
155
|
+
# when the vlan_tagging value changes then this method
|
156
|
+
# will trigger updates to the untagged_vlan and tagged_vlans
|
157
|
+
# resource values as well.
|
158
|
+
# !!! DO NOT SWAP THIS ORDER untagged processing *MUST* BE FIRST!
|
159
|
+
|
160
|
+
upd_untagged_vlan( xml )
|
161
|
+
upd_tagged_vlans( xml )
|
162
|
+
|
163
|
+
return true
|
164
|
+
end
|
165
|
+
|
166
|
+
def set_ifd_trunking( xml, should_trunk )
|
167
|
+
par = xml.instance_variable_get(:@parent)
|
168
|
+
Nokogiri::XML::Builder.with( par.at_xpath( 'ancestor::interface' )) do |dot|
|
169
|
+
if should_trunk
|
170
|
+
dot.send( :'flexible-vlan-tagging' )
|
171
|
+
dot.send( :'encapsulation', 'flexible-ethernet-services' )
|
172
|
+
else
|
173
|
+
dot.send( :'flexible-vlan-tagging', Netconf::JunosConfig::DELETE )
|
174
|
+
dot.send( :'encapsulation', Netconf::JunosConfig::DELETE )
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
## ----------------------------------------------------------------
|
180
|
+
## :tagged_vlans
|
181
|
+
## ----------------------------------------------------------------
|
182
|
+
|
183
|
+
def xml_change_tagged_vlans( xml )
|
184
|
+
return false if mode_changed?
|
185
|
+
upd_tagged_vlans( xml )
|
186
|
+
end
|
187
|
+
|
188
|
+
def upd_tagged_vlans( xml )
|
189
|
+
return false unless should_trunk?
|
190
|
+
|
191
|
+
@should[:tagged_vlans] = @should[:tagged_vlans].to_set if @should[:tagged_vlans].kind_of? Array
|
192
|
+
@has[:tagged_vlans] = @has[:tagged_vlans].to_set if @has[:tagged_vlans].kind_of? Array
|
193
|
+
|
194
|
+
v_should = @should[:tagged_vlans] || Set.new
|
195
|
+
v_has = @has[:tagged_vlans] || Set.new
|
196
|
+
|
197
|
+
del = v_has - v_should
|
198
|
+
add = v_should - v_has
|
199
|
+
|
200
|
+
del_under_vlans = del & @under_vlans
|
201
|
+
unless del_under_vlans.empty?
|
202
|
+
del = del ^ @under_vlans
|
203
|
+
_xml_rm_under_vlans( xml, del_under_vlans )
|
204
|
+
@under_vlans = []
|
205
|
+
end
|
206
|
+
|
207
|
+
if add or del
|
208
|
+
del.each{|v| xml.send(:'vlan-id-list', _vlan_name_to_tag_id( v ), Netconf::JunosConfig::DELETE)}
|
209
|
+
add.each{|v| xml.send( :'vlan-id-list', _vlan_name_to_tag_id(v) )}
|
210
|
+
end
|
211
|
+
return true
|
212
|
+
end
|
213
|
+
|
214
|
+
## ----------------------------------------------------------------
|
215
|
+
## :untagged_vlan
|
216
|
+
## ----------------------------------------------------------------
|
217
|
+
|
218
|
+
def xml_change_untagged_vlan( xml )
|
219
|
+
return false if mode_changed?
|
220
|
+
upd_untagged_vlan( xml )
|
221
|
+
end
|
222
|
+
|
223
|
+
def upd_untagged_vlan( xml )
|
224
|
+
self.class.change_untagged_vlan( self, xml )
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
##### ---------------------------------------------------------------
|
230
|
+
##### Class methods for handling state-transitions between
|
231
|
+
##### configurations (tagged/untagged)
|
232
|
+
##### ---------------------------------------------------------------
|
233
|
+
|
234
|
+
class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN
|
235
|
+
|
236
|
+
# creating some class definitions ...
|
237
|
+
# this is a bit complicated because we need to handle port-mode
|
238
|
+
# change transitions; basically dealing with the fact that
|
239
|
+
# trunk ports use 'native-vlan-id' and access ports have a
|
240
|
+
# vlan member definition; i.e. they don't use native-vlan-id, ugh.
|
241
|
+
# Rather than doing all this logic as if/then/else statements,
|
242
|
+
# I've opted to using a proc jump-table technique. Lessons
|
243
|
+
# learned from lots of embedded systems programming :-)
|
244
|
+
|
245
|
+
def self.init_jump_table
|
246
|
+
|
247
|
+
# auto-hash table, majik!
|
248
|
+
hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)}))
|
249
|
+
|
250
|
+
# ------------------------------------------------------------------
|
251
|
+
# - jump table for handling various untagged vlan change use-cases
|
252
|
+
# ------------------------------------------------------------------
|
253
|
+
# There are three criteria for selection:
|
254
|
+
# | is_trunk | will_trunk | no_untg |
|
255
|
+
# ------------------------------------------------------------------
|
256
|
+
|
257
|
+
# - will not have untagged vlan
|
258
|
+
hash[false][false][true] = self.method(:ac_ac_nountg)
|
259
|
+
hash[false][true][true] = self.method(:ac_tr_nountg)
|
260
|
+
hash[true][false][true] = self.method(:tr_ac_nountg)
|
261
|
+
hash[true][true][true] = self.method(:tr_tr_nountg)
|
262
|
+
|
263
|
+
# - will have untagged vlan
|
264
|
+
hash[false][false][false] = self.method(:ac_ac_untg)
|
265
|
+
hash[false][true][false] = self.method(:ac_tr_untg)
|
266
|
+
hash[true][false][false] = self.method(:tr_ac_untg)
|
267
|
+
hash[true][true][false] = self.method(:tr_tr_untg)
|
268
|
+
|
269
|
+
hash
|
270
|
+
end
|
271
|
+
|
272
|
+
### invoke the correct method from the jump table
|
273
|
+
### based on the three criteria to select the action
|
274
|
+
|
275
|
+
def self.change_untagged_vlan( this, xml )
|
276
|
+
@@ez_l2_jmptbl ||= init_jump_table
|
277
|
+
proc = @@ez_l2_jmptbl[this.is_trunk?][this.should_trunk?][this.should[:untagged_vlan].nil?]
|
278
|
+
proc.call( this, xml )
|
279
|
+
end
|
280
|
+
|
281
|
+
### -------------------------------------------------------------
|
282
|
+
### The following are all the change transition functions for
|
283
|
+
### each of the use-cases
|
284
|
+
### -------------------------------------------------------------
|
285
|
+
|
286
|
+
def self.ac_ac_nountg( this, xml )
|
287
|
+
#NetdevJunos::Log.debug "ac_ac_nountg"
|
288
|
+
# @@@ a port *MUST* be assigned to a vlan in access mode on MX.
|
289
|
+
# @@@ generate an error!
|
290
|
+
raise Junos::Ez::NoProviderError, "a port *MUST* be assigned to a vlan in access mode on MX."
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.ac_tr_nountg( this, xml )
|
294
|
+
#no action needed handled already
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.tr_ac_nountg( this, xml )
|
298
|
+
# @@@ a port *MUST* be assigned to a vlan in access mode on MX.
|
299
|
+
# @@@ generate an error!
|
300
|
+
raise Junos::Ez::NoProviderError, "a port *MUST* be assigned to vlan in access mode on MX"
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.tr_tr_nountg( this, xml )
|
304
|
+
this._delete_native_vlan_id( xml )
|
305
|
+
end
|
306
|
+
|
307
|
+
## ----------------------------------------------------------------
|
308
|
+
## transition where port WILL-HAVE untagged-vlan
|
309
|
+
## ----------------------------------------------------------------
|
310
|
+
|
311
|
+
def self.ac_ac_untg( this, xml )
|
312
|
+
vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] )
|
313
|
+
xml.send :'vlan-id', vlan_id
|
314
|
+
end
|
315
|
+
|
316
|
+
def self.ac_tr_untg( this, xml )
|
317
|
+
was_untg_vlan = this.has[:untagged_vlan]
|
318
|
+
this._set_native_vlan_id( xml, this.should[:untagged_vlan] )
|
319
|
+
this._xml_rm_ac_untagged_vlan( xml ) if was_untg_vlan
|
320
|
+
end
|
321
|
+
|
322
|
+
def self.tr_ac_untg( this, xml )
|
323
|
+
this._delete_native_vlan_id( xml )
|
324
|
+
vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] )
|
325
|
+
xml.send( :'vlan-id', vlan_id )
|
326
|
+
end
|
327
|
+
|
328
|
+
def self.tr_tr_untg( this, xml )
|
329
|
+
this._set_native_vlan_id(xml, this.should[:untagged_vlan])
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
##### ---------------------------------------------------------------
|
335
|
+
##### Provider collection methods
|
336
|
+
##### ---------------------------------------------------------------
|
337
|
+
|
338
|
+
class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN
|
339
|
+
|
340
|
+
def build_list
|
341
|
+
begin
|
342
|
+
got = @ndev.rpc.get_bridge_instance_information( :brief => true)
|
343
|
+
rescue => e
|
344
|
+
# in this case, no ethernet-switching is enabled so return empty list
|
345
|
+
return []
|
346
|
+
end
|
347
|
+
got.xpath('//l2iff-interface-name').collect{ |ifn| ifn.text.split('.')[0] }
|
348
|
+
end
|
349
|
+
|
350
|
+
def build_catalog
|
351
|
+
@catalog = {}
|
352
|
+
return @catalog if list!.empty?
|
353
|
+
list.each do |ifs_name|
|
354
|
+
@ndev.rpc.get_configuration{ |xml|
|
355
|
+
xml.interfaces {
|
356
|
+
xml_at_element_top( xml, ifs_name )
|
357
|
+
}
|
358
|
+
}.xpath('interfaces/interface').each do |ifs_xml|
|
359
|
+
@catalog[ifs_name] = {}
|
360
|
+
unit = xml_get_has_xml( ifs_xml )
|
361
|
+
xml_read_parser( unit, @catalog[ifs_name] )
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
@catalog
|
366
|
+
end
|
367
|
+
|
368
|
+
end
|
369
|
+
|
370
|
+
##### ---------------------------------------------------------------
|
371
|
+
##### !!!!! PRIVATE METHODS !!!!
|
372
|
+
##### ---------------------------------------------------------------
|
373
|
+
|
374
|
+
class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN
|
375
|
+
private
|
376
|
+
|
377
|
+
def _get_eth_port_vlans_h( ifs_name )
|
378
|
+
got = @ndev.rpc.get_bridge_instance_information(:interface => ifs_name)
|
379
|
+
ret_h = {:untagged => nil, :tagged => Set.new }
|
380
|
+
got.xpath('//l2ng-l2ald-iff-interface-entry').each do |vlan|
|
381
|
+
# one of the node-set elements (the first one?) contains the interface name.
|
382
|
+
# this doesn't have any VLAN information, so skip it.
|
383
|
+
next if vlan.xpath('l2iff-interface-name')
|
384
|
+
|
385
|
+
vlan_name = vlan.xpath('//l2rtb-bridge-vlan').text.strip
|
386
|
+
if vlan.xpath('//l2rtb-interface-vlan-member-tagness')
|
387
|
+
tgdy = vlan.xpath('//l2rtb-interface-vlan-member-tagness').text.strip
|
388
|
+
if tgdy == 'untagged'
|
389
|
+
ret_h[:untagged] = vlan_name
|
390
|
+
else
|
391
|
+
ret_h[:tagged] << vlan_name
|
392
|
+
end
|
393
|
+
else
|
394
|
+
ret_h[:tagged]<<vlan_name
|
395
|
+
end
|
396
|
+
end
|
397
|
+
ret_h
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
### ---------------------------------------------------------------
|
402
|
+
### [edit vlans] - for interfaces configured here ...
|
403
|
+
### ---------------------------------------------------------------
|
404
|
+
|
405
|
+
class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN
|
406
|
+
|
407
|
+
def _xml_edit_under_vlans( xml )
|
408
|
+
Nokogiri::XML::Builder.with( xml.doc.root ) do |dot|
|
409
|
+
dot.send(:'vlan-id'){
|
410
|
+
return dot
|
411
|
+
}
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
def _xml_rm_under_vlans( xml, vlans )
|
416
|
+
if vlans.any?
|
417
|
+
at_vlans = _xml_edit_under_vlans( xml )
|
418
|
+
vlans.each do |vlan_id|
|
419
|
+
Nokogiri::XML::Builder.with( at_vlans.parent ) do |this|
|
420
|
+
this.domain {
|
421
|
+
this.vlan_id vlan_id
|
422
|
+
this.interface( Netconf::JunosConfig::DELETE ) { this.name @name }
|
423
|
+
}
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def _xml_rm_ac_untagged_vlan( xml )
|
430
|
+
if @under_vlans.empty?
|
431
|
+
xml.send :'vlan-id', Netconf::JunosConfig::DELETE
|
432
|
+
else
|
433
|
+
_xml_rm_under_vlans( xml, [ @has[:untagged_vlan ] ] )
|
434
|
+
@under_vlans = []
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
def _xml_rm_these_vlans( xml, vlans )
|
439
|
+
if @under_vlans.empty?
|
440
|
+
xml.send :'vlan-id', ( Netconf::JunosConfig::DELETE )
|
441
|
+
else
|
442
|
+
# could be a mix between [edit vlans] and [edit interfaces] ...
|
443
|
+
v_has = vlans.to_set
|
444
|
+
del_under_vlans = v_has & @under_vlans
|
445
|
+
_xml_rm_under_vlans( xml, del_under_vlans )
|
446
|
+
if v_has ^ @under_vlans
|
447
|
+
xml.send :'vlan-id', ( Netconf::JunosConfig::DELETE )
|
448
|
+
end
|
449
|
+
@under_vlans = []
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
end
|
454
|
+
|
455
|
+
|
456
|
+
class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN
|
457
|
+
|
458
|
+
def _vlan_name_to_tag_id( vlan_name )
|
459
|
+
tag_id = @ndev.rpc.get_configuration { |xml|
|
460
|
+
xml.send(:'bridge-domains') { xml.domain { xml.name vlan_name }}
|
461
|
+
}.xpath('//vlan-id').text.chomp
|
462
|
+
raise ArgumentError, "VLAN '#{vlan_name}' not found" if tag_id.empty?
|
463
|
+
return tag_id
|
464
|
+
end
|
465
|
+
|
466
|
+
|
467
|
+
def _vlan_tag_id_to_name( vlan_id )
|
468
|
+
tag_name = @ndev.rpc.get_configuration { |xml|
|
469
|
+
xml.send(:'bridge-domains') { xml.domain { xml.send(:'vlan-id', vlan_id)}}
|
470
|
+
}.xpath('//name').text.chomp
|
471
|
+
raise ArgumentError, "VLAN '#{vlan_id}' not found" if tag_name.empty?
|
472
|
+
return tag_name
|
473
|
+
end
|
474
|
+
|
475
|
+
|
476
|
+
end
|
477
|
+
|
478
|
+
class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN
|
479
|
+
def _at_native_vlan_id( xml )
|
480
|
+
ifd
|
481
|
+
end
|
482
|
+
|
483
|
+
def _delete_native_vlan_id( xml )
|
484
|
+
Nokogiri::XML::Builder.with( @ifd ) do |dot|
|
485
|
+
dot.send :'native-vlan-id', Netconf::JunosConfig::DELETE
|
486
|
+
end
|
487
|
+
return true
|
488
|
+
end
|
489
|
+
|
490
|
+
def _set_native_vlan_id( xml, vlan_name )
|
491
|
+
Nokogiri::XML::Builder.with( @ifd ) do |dot|
|
492
|
+
dot.send :'native-vlan-id', _vlan_name_to_tag_id( vlan_name )
|
493
|
+
xml.send( :'vlan-id-list', _vlan_name_to_tag_id( vlan_name) )
|
494
|
+
end
|
495
|
+
return true
|
496
|
+
end
|
497
|
+
|
498
|
+
|
499
|
+
end
|