junos-ez-stdlib 0.0.10

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.
Files changed (52) hide show
  1. data/LICENSE +26 -0
  2. data/README.md +181 -0
  3. data/docs/Config_Utils.md +3 -0
  4. data/docs/Facts.md +106 -0
  5. data/docs/Filesys_Utils.md +3 -0
  6. data/docs/IPports.md +3 -0
  7. data/docs/L1ports.md +3 -0
  8. data/docs/L2ports.md +3 -0
  9. data/docs/Providers_Resources.md +304 -0
  10. data/docs/RE_utils.md +3 -0
  11. data/docs/StaticHosts.md +3 -0
  12. data/docs/StaticRoutes.md +3 -0
  13. data/docs/Vlans.md +3 -0
  14. data/examples/config/config_file.rb +72 -0
  15. data/examples/config/config_template_object.rb +81 -0
  16. data/examples/config/config_template_simple.rb +76 -0
  17. data/examples/config/multi_config.rb +60 -0
  18. data/examples/fs_utils.rb +31 -0
  19. data/examples/re_upgrade.rb +90 -0
  20. data/examples/re_utils.rb +30 -0
  21. data/examples/simple.rb +47 -0
  22. data/examples/st_hosts.rb +33 -0
  23. data/examples/vlans.rb +25 -0
  24. data/junos-ez-stdlib.gemspec +15 -0
  25. data/lib/junos-ez/facts/chassis.rb +45 -0
  26. data/lib/junos-ez/facts/ifd_style.rb +14 -0
  27. data/lib/junos-ez/facts/personality.rb +22 -0
  28. data/lib/junos-ez/facts/switch_style.rb +22 -0
  29. data/lib/junos-ez/facts/version.rb +32 -0
  30. data/lib/junos-ez/facts.rb +85 -0
  31. data/lib/junos-ez/ip_ports/classic.rb +149 -0
  32. data/lib/junos-ez/ip_ports.rb +28 -0
  33. data/lib/junos-ez/l1_ports/classic.rb +87 -0
  34. data/lib/junos-ez/l1_ports/switch.rb +134 -0
  35. data/lib/junos-ez/l1_ports.rb +81 -0
  36. data/lib/junos-ez/l2_ports/bridge_domain.rb +0 -0
  37. data/lib/junos-ez/l2_ports/vlan.rb +317 -0
  38. data/lib/junos-ez/l2_ports/vlan_l2ng.rb +0 -0
  39. data/lib/junos-ez/l2_ports.rb +57 -0
  40. data/lib/junos-ez/provider.rb +608 -0
  41. data/lib/junos-ez/stdlib.rb +16 -0
  42. data/lib/junos-ez/system/st_hosts.rb +74 -0
  43. data/lib/junos-ez/system/st_routes.rb +135 -0
  44. data/lib/junos-ez/system/syscfg.rb +103 -0
  45. data/lib/junos-ez/system.rb +98 -0
  46. data/lib/junos-ez/utils/config.rb +205 -0
  47. data/lib/junos-ez/utils/fs.rb +376 -0
  48. data/lib/junos-ez/utils/re.rb +371 -0
  49. data/lib/junos-ez/vlans/bridge_domain.rb +85 -0
  50. data/lib/junos-ez/vlans/vlan.rb +112 -0
  51. data/lib/junos-ez/vlans.rb +31 -0
  52. metadata +111 -0
@@ -0,0 +1,32 @@
1
+ Junos::Ez::Facts::Keeper.define( :version ) do |ndev, facts|
2
+
3
+ f_master, f_persona = uses :master, :personality
4
+
5
+ case f_persona
6
+ when :MX
7
+ swver = ndev.rpc.command "show version invoke-on all-routing-engines"
8
+ when :SWITCH
9
+ swver = ndev.rpc.command "show version all-members"
10
+ else
11
+ swver = ndev.rpc.command "show version"
12
+ end
13
+
14
+ if swver.name == 'multi-routing-engine-results'
15
+ swver_infos = swver.xpath('//software-information')
16
+ swver_infos.each do |re_sw|
17
+ re_name = re_sw.xpath('preceding-sibling::re-name').text.upcase
18
+ re_sw.xpath('package-information[1]/comment').text =~ /\[(.*)\]/
19
+ ver_key = ('version_' + re_name).to_sym
20
+ facts[ver_key] = $1
21
+ end
22
+ master_id = f_master
23
+ facts[:version] =
24
+ facts[("version_" + "RE" + master_id).to_sym] ||
25
+ facts[('version_' + "FPC" + master_id).to_sym]
26
+ else
27
+ junos = swver.xpath('//package-information[name = "junos"]/comment').text
28
+ junos =~ /\[(.*)\]/
29
+ facts[:version] = $1
30
+ end
31
+
32
+ end
@@ -0,0 +1,85 @@
1
+ require 'junos-ez/provider'
2
+
3
+ ### -----------------------------------------------------------------
4
+ ### Junos::Ez module devices the toplevel Provider and associated
5
+ ### Facts class & methods
6
+ ### -----------------------------------------------------------------
7
+
8
+ module Junos::Ez
9
+
10
+ attr_accessor :providers, :facts
11
+
12
+ def self.Provider( ndev )
13
+ ndev.extend Junos::Ez
14
+ ndev.providers = []
15
+ ndev.facts = Junos::Ez::Facts::Keeper.new( ndev )
16
+ ndev.facts.read!
17
+ true
18
+ end
19
+
20
+ def fact( name ); facts[name] end
21
+ end;
22
+
23
+ module Junos::Ez::Facts
24
+
25
+ class Keeper
26
+ attr_accessor :known
27
+
28
+ def initialize( ndev )
29
+ @ndev = ndev
30
+ @known = Hash.new
31
+ end
32
+
33
+ def clear; @known.clear end
34
+
35
+ def list; @known.keys end
36
+ def list!; read!; list; end
37
+
38
+ def catalog; @known end
39
+ def catalog!; read!; catalog end
40
+
41
+ def uses( *facts )
42
+ values = facts.collect do |f|
43
+ self.send( "fact_read_#{f}", @ndev, @known ) unless @known[f]
44
+ self[f]
45
+ end
46
+ (values.count == 1) ? values[0] : values
47
+ end
48
+
49
+ def self.define( fact, &block )
50
+ define_method( "fact_read_#{fact}".to_sym, block )
51
+ end
52
+
53
+ def []=(key,value)
54
+ @known[key] = value
55
+ end
56
+
57
+ def [](key)
58
+ @known[key]
59
+ end
60
+
61
+ def read!
62
+ @known.clear
63
+ fact_readers = self.methods.grep /^fact_read_/
64
+ fact_readers.each do |getter|
65
+ getter =~ /^fact_read_(\w+)/
66
+ fact = $1.to_sym
67
+ self.send( getter, @ndev, @known ) unless @known[fact]
68
+ end
69
+ end
70
+
71
+ end # class
72
+ end
73
+
74
+ ### -----------------------------------------------------------------
75
+ ### Load all of the fact files
76
+ ### -----------------------------------------------------------------
77
+
78
+ Dir[File.dirname(__FILE__) + "/facts/*.rb"].each do |file|
79
+ require file
80
+ end
81
+
82
+
83
+
84
+
85
+
@@ -0,0 +1,149 @@
1
+ class Junos::Ez::IPports::Provider::CLASSIC < Junos::Ez::IPports::Provider
2
+
3
+ ### ---------------------------------------------------------------
4
+ ### XML top placement
5
+ ### ---------------------------------------------------------------
6
+
7
+ def xml_at_top
8
+
9
+ # if just the IFD is given as the name, default to unit "0"
10
+ @ifd, @ifl = @name.split '.'
11
+ @ifl ||= "0"
12
+
13
+ Nokogiri::XML::Builder.new{ |x| x.configuration{
14
+ x.interfaces { x.interface { x.name @ifd
15
+ x.unit {
16
+ x.name @ifl
17
+ return x
18
+ }
19
+ }}
20
+ }}
21
+ end
22
+
23
+ def xml_element_rename( new_name )
24
+
25
+ # if just the IFD is given as the name, default to unit "0"
26
+ n_ifd, n_ifl = new_name.split '.'
27
+ n_ifl ||= "0"
28
+
29
+ # do not allow rename to different IFD.
30
+ return false unless @ifd == n_ifd
31
+
32
+ # return the new element name
33
+ return n_ifl
34
+ end
35
+
36
+ ### ---------------------------------------------------------------
37
+ ### XML readers
38
+ ### ---------------------------------------------------------------
39
+
40
+ def xml_get_has_xml( xml )
41
+ xml.xpath('//unit')[0]
42
+ end
43
+
44
+ def xml_read_parser( as_xml, as_hash )
45
+ set_has_status( as_xml, as_hash )
46
+
47
+ ifa_inet = as_xml.xpath('family/inet')
48
+
49
+ as_hash[:tag_id] = as_xml.xpath('vlan-id').text.to_i
50
+ as_hash[:description] = as_xml.xpath('description').text
51
+ as_hash[:mtu] = ifa_inet.xpath('mtu').text.to_i || nil
52
+ as_hash[:address] = ifa_inet.xpath('address/name').text || nil
53
+ as_hash[:admin] = as_xml.xpath('disable').empty? ? :up : :down
54
+
55
+ return true
56
+ end
57
+
58
+ ### ---------------------------------------------------------------
59
+ ### XML writers
60
+ ### ---------------------------------------------------------------
61
+
62
+ def xml_change_address( xml )
63
+ xml.family { xml.inet {
64
+ if @has[:address]
65
+ xml.address( Netconf::JunosConfig::DELETE ) {
66
+ xml.name @has[:address]
67
+ }
68
+ end
69
+ xml.address {
70
+ xml.name @should[:address]
71
+ }
72
+ }}
73
+ end
74
+
75
+ def xml_change_tag_id( xml )
76
+ xml_set_or_delete( xml, 'vlan-id', @should[:tag_id] )
77
+ end
78
+
79
+ def xml_change_mtu( xml )
80
+ xml.family { xml.inet {
81
+ xml_set_or_delete( xml, 'mtu', @should[:mtu] )
82
+ }}
83
+ end
84
+
85
+ end
86
+
87
+ ##### ---------------------------------------------------------------
88
+ ##### Provider collection methods
89
+ ##### ---------------------------------------------------------------
90
+
91
+ class Junos::Ez::IPports::Provider::CLASSIC
92
+
93
+ def build_list
94
+ from_junos_get_ifa_xml.collect do |ifa|
95
+ ifa.xpath('name').text.strip
96
+ end
97
+ end
98
+
99
+ def build_catalog
100
+ @catalog = {}
101
+
102
+ ## do the equivalent of "show interfaces ..." to retrieve the list
103
+ ## of known interfaces that have an IFA == 'inet'. Note that this
104
+ ## list will *not* include anything that has been deactivated.
105
+
106
+ ifa_list = from_junos_get_ifa_xml
107
+
108
+ ## from this list of IFA, retrieve the configurations
109
+
110
+ got_xml_cfg = @ndev.rpc.get_configuration do |cfg|
111
+ cfg.interfaces {
112
+ ifa_list.each do |ifa|
113
+ ifa_name = ifa.xpath('name').text.strip
114
+ ifa_ifd, ifa_ifl = ifa_name.split '.'
115
+ cfg.interface {
116
+ cfg.name ifa_ifd
117
+ cfg.unit { cfg.name ifa_ifl }
118
+ }
119
+ end
120
+ }
121
+ end
122
+
123
+ ## now create the object property hashes for each of the instances
124
+
125
+ got_xml_cfg.xpath('interfaces/interface/unit').each do |ifl|
126
+ ifd = ifl.xpath('preceding-sibling::name').text.strip
127
+ unit = ifl.xpath('name').text.strip
128
+ obj_name = ifd + '.' + unit
129
+
130
+ @catalog[obj_name] = {}
131
+ xml_read_parser( ifl, @catalog[obj_name] )
132
+ end
133
+
134
+ return @catalog
135
+ end
136
+
137
+ private
138
+
139
+ def from_junos_get_ifa_xml
140
+
141
+ xml_data = @ndev.rpc.get_interface_information(
142
+ :terse => true,
143
+ :interface_name => '[xgf]e-*/*/*.*' )
144
+
145
+ ifa_list = xml_data.xpath('logical-interface[normalize-space(address-family/address-family-name) = "inet"]')
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,28 @@
1
+
2
+ require "junos-ez/provider"
3
+
4
+ module Junos::Ez::IPports
5
+
6
+ PROPERTIES = [
7
+ :admin, # [:up, :down]
8
+ :description, # general description text
9
+ :tag_id, # VLAN tag-id for vlan-tag enabled ports
10
+ :mtu, # MTU value as number
11
+ :address # ip/prefix as text, e.g. "192.168.10.22/24"
12
+ ]
13
+
14
+ def self.Provider( ndev, varsym )
15
+ newbie = Junos::Ez::IPports::Provider::CLASSIC.new( ndev )
16
+ newbie.properties = Junos::Ez::Provider::PROPERTIES + PROPERTIES
17
+ Junos::Ez::Provider.attach_instance_variable( ndev, varsym, newbie )
18
+ end
19
+
20
+ class Provider < Junos::Ez::Provider::Parent
21
+ # common parenting goes here ...
22
+ end
23
+
24
+ end
25
+
26
+ require 'junos-ez/ip_ports/classic'
27
+
28
+
@@ -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,81 @@
1
+ require "junos-ez/provider"
2
+
3
+ module Junos::Ez::L1ports
4
+
5
+ PROPERTIES = [
6
+ :admin, # [ :up, :down ]
7
+ :description, # string
8
+ :mtu, # number
9
+ :speed, # [ :auto, '10m', '100m', '1g', '10g' ]
10
+ :duplex, # [ :auto, :half, :full ]
11
+ :unit_count, # number of configured units
12
+ ]
13
+
14
+ def self.Provider( ndev, varsym )
15
+ newbie = case ndev.fact( :ifd_style )
16
+ when :SWITCH
17
+ Junos::Ez::L1ports::Provider::SWITCH.new( ndev )
18
+ when :CLASSIC
19
+ Junos::Ez::L1ports::Provider::CLASSIC.new( ndev )
20
+ end
21
+
22
+ newbie.properties = Junos::Ez::Provider::PROPERTIES + PROPERTIES
23
+ Junos::Ez::Provider.attach_instance_variable( ndev, varsym, newbie )
24
+ end
25
+
26
+ end
27
+
28
+ class Junos::Ez::L1ports::Provider < Junos::Ez::Provider::Parent
29
+
30
+ ### ---------------------------------------------------------------
31
+ ### XML readers
32
+ ### ---------------------------------------------------------------
33
+
34
+ def xml_get_has_xml( xml )
35
+ xml.xpath('//interface')[0]
36
+ end
37
+
38
+ def xml_change_mtu( xml )
39
+ xml_set_or_delete( xml, 'mtu', @should[:mtu] )
40
+ end
41
+
42
+ ### ---------------------------------------------------------------
43
+ ### Collection methods
44
+ ### ---------------------------------------------------------------
45
+
46
+ def build_list
47
+ @ndev.rpc.get_interface_information({
48
+ :media => true,
49
+ :terse => true,
50
+ :interface_name => '[fgx]e-*'
51
+ }).xpath('physical-interface/name').collect do |ifs|
52
+ ifs.text.strip
53
+ end
54
+ end
55
+
56
+ def build_catalog
57
+ @catalog = {}
58
+
59
+ @ndev.rpc.get_configuration{|xml|
60
+ xml.interfaces {
61
+ list!.each do |ifs|
62
+ xml.interface {
63
+ xml.name ifs
64
+ xml_read_filter( xml )
65
+ }
66
+ end
67
+ }
68
+ }.xpath('interfaces/interface').each do |ifs_xml|
69
+ ifs_name = ifs_xml.xpath('name').text
70
+ @catalog[ifs_name] = {}
71
+ xml_read_parser( ifs_xml, @catalog[ifs_name] )
72
+ end
73
+
74
+ return @catalog
75
+ end
76
+
77
+ end
78
+
79
+ require 'junos-ez/l1_ports/switch'
80
+ require 'junos-ez/l1_ports/classic'
81
+
File without changes