rbeapi 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +25 -2
  4. data/Gemfile +13 -7
  5. data/Rakefile +8 -7
  6. data/lib/rbeapi/api/alias.rb +160 -0
  7. data/lib/rbeapi/api/bgp.rb +9 -9
  8. data/lib/rbeapi/api/dns.rb +3 -1
  9. data/lib/rbeapi/api/interfaces.rb +194 -32
  10. data/lib/rbeapi/api/ipinterfaces.rb +5 -3
  11. data/lib/rbeapi/api/managementdefaults.rb +119 -0
  12. data/lib/rbeapi/api/mlag.rb +6 -6
  13. data/lib/rbeapi/api/ntp.rb +1 -1
  14. data/lib/rbeapi/api/ospf.rb +171 -12
  15. data/lib/rbeapi/api/prefixlists.rb +19 -9
  16. data/lib/rbeapi/api/radius.rb +5 -5
  17. data/lib/rbeapi/api/routemaps.rb +12 -12
  18. data/lib/rbeapi/api/snmp.rb +6 -4
  19. data/lib/rbeapi/api/stp.rb +24 -24
  20. data/lib/rbeapi/api/switchports.rb +15 -9
  21. data/lib/rbeapi/api/tacacs.rb +1 -1
  22. data/lib/rbeapi/api/users.rb +4 -4
  23. data/lib/rbeapi/api/varp.rb +7 -3
  24. data/lib/rbeapi/api/vlans.rb +2 -2
  25. data/lib/rbeapi/api/vrrp.rb +61 -61
  26. data/lib/rbeapi/client.rb +9 -6
  27. data/lib/rbeapi/eapilib.rb +3 -3
  28. data/lib/rbeapi/netdev/snmp.rb +8 -6
  29. data/lib/rbeapi/switchconfig.rb +9 -10
  30. data/lib/rbeapi/version.rb +1 -1
  31. data/spec/support/fixtures.rb +4 -4
  32. data/spec/support/matchers/switch_config_sections.rb +2 -2
  33. data/spec/system/rbeapi/api/acl_spec.rb +2 -4
  34. data/spec/system/rbeapi/api/alias_spec.rb +168 -0
  35. data/spec/system/rbeapi/api/bgp_spec.rb +1 -2
  36. data/spec/system/rbeapi/api/interfaces_base_spec.rb +7 -8
  37. data/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +36 -3
  38. data/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +35 -3
  39. data/spec/system/rbeapi/api/interfaces_vlan_spec.rb +90 -0
  40. data/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +3 -4
  41. data/spec/system/rbeapi/api/managementdefaults_spec.rb +31 -0
  42. data/spec/system/rbeapi/api/ospf_interfaces_spec.rb +36 -11
  43. data/spec/system/rbeapi/api/ospf_spec.rb +240 -17
  44. data/spec/system/rbeapi/api/prefixlists_spec.rb +105 -89
  45. data/spec/system/rbeapi/api/routemaps_spec.rb +15 -10
  46. data/spec/system/rbeapi/api/users_spec.rb +4 -5
  47. data/spec/system/rbeapi/api/vrrp_spec.rb +2 -5
  48. data/spec/system/rbeapi/client_spec.rb +1 -2
  49. data/spec/unit/rbeapi/api/acl/default_spec.rb +1 -2
  50. data/spec/unit/rbeapi/api/alias/default_spec.rb +119 -0
  51. data/spec/unit/rbeapi/api/alias/fixture_alias.text +3 -0
  52. data/spec/unit/rbeapi/api/bgp/bgp_neighbors_spec.rb +1 -2
  53. data/spec/unit/rbeapi/api/bgp/bgp_spec.rb +1 -2
  54. data/spec/unit/rbeapi/api/interfaces/base_spec.rb +1 -1
  55. data/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +35 -1
  56. data/spec/unit/rbeapi/api/interfaces/fixture_interfaces.text +68 -0
  57. data/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +41 -4
  58. data/spec/unit/rbeapi/api/interfaces/vlan_spec.rb +72 -0
  59. data/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb +2 -2
  60. data/spec/unit/rbeapi/api/managementdefaults/default_spec.rb +50 -0
  61. data/spec/unit/rbeapi/api/managementdefaults/fixture_managementdefaults.yaml +1 -0
  62. data/spec/unit/rbeapi/api/prefixlists/default_spec.rb +98 -80
  63. data/spec/unit/rbeapi/api/prefixlists/fixture_prefixlists.text +9 -4
  64. data/spec/unit/rbeapi/api/users/default_spec.rb +2 -4
  65. data/spec/unit/rbeapi/api/vrrp/default_spec.rb +2 -5
  66. data/spec/unit/rbeapi/client_spec.rb +21 -14
  67. data/spec/unit/rbeapi/switchconfig_spec.rb +10 -3
  68. metadata +49 -59
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1dc55f02164a2136033dc85beedb95892b9c4123
4
+ data.tar.gz: 834b6277842521fb9fbfd47a00364dd1ac30457b
5
+ SHA512:
6
+ metadata.gz: 6af640792253a287f6fc05cb940e1783c06c767d1bb592a61497e35a2c0b6db59ce5d11b0d26178219797d33554c5626e68506a0173ce1f9a43ee4fc73325442
7
+ data.tar.gz: 7571e8a5ebe5cb10b0f0c77f5c2011958d3f5cfeea568d5542a13d3cc56edb1ae30309dba4053bffe5ecc83b49bb252168554ae0ba3c60cbd5f06f8fef7e1d8a
@@ -19,3 +19,6 @@ Metrics/AbcSize:
19
19
 
20
20
  Metrics/ClassLength:
21
21
  Max: 130
22
+
23
+ Metrics/BlockLength:
24
+ Enabled: False
@@ -1,7 +1,28 @@
1
1
  # Change Log
2
2
 
3
- ## [1.0](https://github.com/arista-eosplus/rbeapi/tree/1.0) (2016-09-22)
4
- [Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.5.1...1.0)
3
+ ## [1.1](https://github.com/arista-eosplus/rbeapi/tree/1.1) (2016-12-06)
4
+ [Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v1.0...1.1)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - add subinterface functionality [\#161](https://github.com/arista-eosplus/rbeapi/pull/161) ([mmailand](https://github.com/mmailand))
9
+ - add support to set aliases [\#160](https://github.com/arista-eosplus/rbeapi/pull/160) ([mmailand](https://github.com/mmailand))
10
+ - added support for setting the crypto in managementdefaults [\#159](https://github.com/arista-eosplus/rbeapi/pull/159) ([mmailand](https://github.com/mmailand))
11
+ - added support for autostate [\#158](https://github.com/arista-eosplus/rbeapi/pull/158) ([mmailand](https://github.com/mmailand))
12
+ - add support for multi/single-line prefix list output [\#155](https://github.com/arista-eosplus/rbeapi/pull/155) ([mrvinti](https://github.com/mrvinti))
13
+
14
+ **Fixed bugs:**
15
+
16
+ - Fix multiline alias support [\#165](https://github.com/arista-eosplus/rbeapi/pull/165) ([jerearista](https://github.com/jerearista))
17
+ - extend and fix ospf features [\#156](https://github.com/arista-eosplus/rbeapi/pull/156) ([rknaus](https://github.com/rknaus))
18
+
19
+ **Merged pull requests:**
20
+
21
+ - Style updates for Rubocop 0.45 [\#163](https://github.com/arista-eosplus/rbeapi/pull/163) ([jerearista](https://github.com/jerearista))
22
+ - fix for rspec failure on current develop [\#162](https://github.com/arista-eosplus/rbeapi/pull/162) ([mmailand](https://github.com/mmailand))
23
+
24
+ ## [v1.0](https://github.com/arista-eosplus/rbeapi/tree/v1.0) (2016-09-26)
25
+ [Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.5.1...v1.0)
5
26
 
6
27
  **Implemented enhancements:**
7
28
 
@@ -24,6 +45,8 @@
24
45
 
25
46
  **Merged pull requests:**
26
47
 
48
+ - Release 1.0 [\#153](https://github.com/arista-eosplus/rbeapi/pull/153) ([jerearista](https://github.com/jerearista))
49
+ - Release 1.0 [\#152](https://github.com/arista-eosplus/rbeapi/pull/152) ([jerearista](https://github.com/jerearista))
27
50
  - Add json option to get\_config [\#151](https://github.com/arista-eosplus/rbeapi/pull/151) ([jerearista](https://github.com/jerearista))
28
51
  - Handle more multiline config commands [\#150](https://github.com/arista-eosplus/rbeapi/pull/150) ([jerearista](https://github.com/jerearista))
29
52
  - Ensure get\_config, running\_config, and startup\_config return sane output [\#149](https://github.com/arista-eosplus/rbeapi/pull/149) ([jerearista](https://github.com/jerearista))
data/Gemfile CHANGED
@@ -1,5 +1,9 @@
1
1
  source ENV['GEM_SOURCE'] || 'https://rubygems.org'
2
2
 
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rbeapi/version'
6
+
3
7
  gem 'inifile'
4
8
  gem 'net_http_unix'
5
9
  gem 'netaddr'
@@ -12,20 +16,20 @@ group :development do
12
16
  end
13
17
 
14
18
  group :development, :test do
19
+ gem 'ci_reporter_rspec', require: false
15
20
  gem 'listen', '<=3.0.3'
21
+ gem 'pry', require: false
22
+ gem 'pry-doc', require: false
23
+ gem 'pry-stack_explorer', require: false
16
24
  gem 'rake', '~> 10.1.0'
25
+ gem 'rbeapi', Rbeapi::VERSION, path: '.'
26
+ gem 'redcarpet', '~> 3.1.2'
17
27
  gem 'rspec', '~> 3.0.0'
18
28
  gem 'rspec-mocks', '~> 3.0.0'
19
29
  gem 'simplecov'
20
- gem 'yard'
21
- gem 'redcarpet', '~> 3.1.2'
22
- gem 'pry', require: false
23
- gem 'pry-doc', require: false
24
- gem 'pry-stack_explorer', require: false
25
- gem 'rbeapi', '1.0', path: '.'
26
- gem 'ci_reporter_rspec', require: false
27
30
  gem 'simplecov-json', require: false
28
31
  gem 'simplecov-rcov', require: false
32
+ gem 'yard'
29
33
  end
30
34
 
31
35
  # Rubocop > 0.37 requires a gem that only works with ruby 2.x
@@ -35,6 +39,8 @@ if RUBY_VERSION.to_f < 2.0
35
39
  gem 'rubocop', '>=0.35.1', '< 0.38'
36
40
  end
37
41
  else
42
+ # Rubocop thinks these are duplicates.
43
+ # rubocop:disable Bundler/DuplicatedGem
38
44
  gem 'json'
39
45
  group :development, :test do
40
46
  gem 'rubocop', '>=0.35.1'
data/Rakefile CHANGED
@@ -9,13 +9,14 @@ end
9
9
 
10
10
  RPM_OPTS = '--define "_topdir %(pwd)/rpmbuild" --define "_builddir ' \
11
11
  '%{_topdir}" --define "_rpmdir %(pwd)/rpms" --define "_srcrpmdir ' \
12
- '%{_rpmdir}" --define "_sourcedir %(pwd)" --define "_specdir %(pwd)" -bb'
12
+ '%{_rpmdir}" --define "_sourcedir %(pwd)" --define "_specdir %(pwd)" '\
13
+ '-bb'.freeze
13
14
  desc 'Generate regular and puppet-enterprise rbeapi RPMs for EOS'
14
15
  task rpm: :build do
15
16
  system "sed -e 's/^Version:.*/Version: #{Rbeapi::VERSION}/g' " \
16
17
  'rbeapi.spec.tmpl > rbeapi.spec'
17
18
  system "rpmbuild #{RPM_OPTS} rbeapi.spec"
18
- RPMS = `find rpms/noarch -name "*rbeapi*rpm"`
19
+ RPMS = `find rpms/noarch -name "*rbeapi*rpm"`.freeze
19
20
  puts "\n################################################\n#"
20
21
  puts "Created the following in rpms/noarch/\n#{RPMS}"
21
22
  puts "#\n################################################\n\n"
@@ -32,7 +33,7 @@ task :inifile do
32
33
  system "sed -e 's/^Version:.*/Version: #{INIFILE_VERSION}/g' " \
33
34
  'gems/inifile/inifile.spec.tmpl > gems/inifile/inifile.spec'
34
35
  system "rpmbuild #{RPM_OPTS} gems/inifile/inifile.spec"
35
- RPMS = `find rpms/noarch -name "*inifile*rpm"`
36
+ RPMS = `find rpms/noarch -name "*inifile*rpm"`.freeze
36
37
  puts "\n################################################\n#"
37
38
  puts "Created the following in rpms/noarch/\n#{RPMS}"
38
39
  puts "#\n################################################\n\n"
@@ -50,7 +51,7 @@ task :net_http_unix do
50
51
  'gems/net_http_unix/net_http_unix.spec.tmpl > ' \
51
52
  'gems/net_http_unix/net_http_unix.spec'
52
53
  system "rpmbuild #{RPM_OPTS} gems/net_http_unix/net_http_unix.spec"
53
- RPMS = `find rpms/noarch -name "*net_http_unix*rpm"`
54
+ RPMS = `find rpms/noarch -name "*net_http_unix*rpm"`.freeze
54
55
  puts "\n################################################\n#"
55
56
  puts "Created the following in rpms/noarch/\n#{RPMS}"
56
57
  puts "#\n################################################\n\n"
@@ -67,7 +68,7 @@ task :netaddr do
67
68
  system "sed -e 's/^Version:.*/Version: #{NETADDR_VERSION}/g' " \
68
69
  'gems/netaddr/netaddr.spec.tmpl > gems/netaddr/netaddr.spec'
69
70
  system "rpmbuild #{RPM_OPTS} gems/netaddr/netaddr.spec"
70
- RPMS = `find rpms/noarch -name "*netaddr*rpm"`
71
+ RPMS = `find rpms/noarch -name "*netaddr*rpm"`.freeze
71
72
  puts "\n################################################\n#"
72
73
  puts "Created the following in rpms/noarch/\n#{RPMS}"
73
74
  puts "#\n################################################\n\n"
@@ -114,7 +115,7 @@ end
114
115
  desc 'Generate SWIX files from RPMs'
115
116
  task swix: :all_rpms do
116
117
  SWIX = 'PYTHONPATH=${PYTHONPATH}:/nfs/misc/tools/swix \
117
- /nfs/misc/tools/swix/swix'
118
+ /nfs/misc/tools/swix/swix'.freeze
118
119
  system "(cd rpms/noarch;
119
120
  rm -f rbeapi-#{Rbeapi::VERSION}-1.swix;
120
121
  #{SWIX} create rbeapi-#{Rbeapi::VERSION}-1.swix \
@@ -141,7 +142,7 @@ task swix: :all_rpms do
141
142
  rubygem-inifile-puppet-aio-3.0.0-5.eos4.noarch.rpm \
142
143
  rubygem-netaddr-puppet-aio-1.5.1-4.eos4.noarch.rpm \
143
144
  rubygem-net_http_unix-puppet-aio-0.2.2-5.eos4.noarch.rpm)"
144
- SWIXS = `find rpms/noarch -name "rbeapi*swix" -ls`
145
+ SWIXS = `find rpms/noarch -name "rbeapi*swix" -ls`.freeze
145
146
  puts "\n################################################\n#"
146
147
  puts "The following artifacts are in rpms/noarch/\n#{SWIXS}"
147
148
  puts "#\n################################################\n\n"
@@ -0,0 +1,160 @@
1
+ #
2
+ ## Copyright (c) 2016, Arista Networks, Inc.
3
+ ## All rights reserved.
4
+ ##
5
+ ## Redistribution and use in source and binary forms, with or without
6
+ ## modification, are permitted provided that the following conditions are
7
+ ## met:
8
+ ##
9
+ ## Redistributions of source code must retain the above copyright notice,
10
+ ## this list of conditions and the following disclaimer.
11
+ ##
12
+ ## Redistributions in binary form must reproduce the above copyright
13
+ ## notice, this list of conditions and the following disclaimer in the
14
+ ## documentation and/or other materials provided with the distribution.
15
+ ##
16
+ ## Neither the name of Arista Networks nor the names of its
17
+ ## contributors may be used to endorse or promote products derived from
18
+ ## this software without specific prior written permission.
19
+ ##
20
+ ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ ## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ ## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS
24
+ ## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27
+ ## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
+ ## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29
+ ## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30
+ ## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ ##
32
+ require 'rbeapi/api'
33
+
34
+ ##
35
+ # Rbeapi toplevel namespace.
36
+ module Rbeapi
37
+ ##
38
+ # Api is module namespace for working with the EOS command API.
39
+ module Api
40
+ ##
41
+ # The Alias class manages aliass entries on an EOS node.
42
+ class Alias < Entity
43
+ ##
44
+ # get returns the current alias configuration hash extracted from the
45
+ # nodes running configuration.
46
+ #
47
+ # @example
48
+ # {
49
+ # alias: array<strings>
50
+ # }
51
+ #
52
+ # @return [Hash<Symbol, Object>] Returns the alias resource as a hash
53
+ # object from the nodes current configuration.
54
+ def get(name)
55
+ # Complex regex handles the following cases:
56
+ # All aliases start with 'alian <name>' followed by
57
+ # <space><single-line command>
58
+ # <carriage return><multiple lines of commands>
59
+ pattern = /^alias #{name}((?:(?= )(?:.+?)(?=\n)|\n(?:.+?)(?=\n\!)))/m
60
+ aliases = config.scan(pattern)
61
+ return nil unless aliases[0]
62
+ parse_alias_entry(name, aliases[0])
63
+ end
64
+
65
+ ##
66
+ # getall returns a collection of alias resource hashes from the nodes
67
+ # running configuration. The alias resource collection hash is keyed
68
+ # by the unique alias name.
69
+ #
70
+ # @example
71
+ # [
72
+ # <alias>: {
73
+ # command: <string>
74
+ # },
75
+ # <alias>: {
76
+ # command: <string>
77
+ # },
78
+ # ...
79
+ # ]
80
+ #
81
+ # @return [Hash<Symbol, Object>] Returns a hash that represents the
82
+ # entire alias collection from the nodes running configuration. If
83
+ # there are no aliass configured, this method will return an empty
84
+ # hash.
85
+ def getall
86
+ entries = config.scan(/^alias (\w+)(.+)?/)
87
+ entries.inspect
88
+ response = {}
89
+ entries.each do |aliases|
90
+ response[aliases[0]] = get aliases[0]
91
+ end
92
+ response
93
+ end
94
+
95
+ ##
96
+ # parse_alias_entry maps the tokens found to the hash entries.
97
+ #
98
+ # @api private
99
+ #
100
+ # @param alias [Array] An array of values returned from the regular
101
+ # expression scan of the aliass configuration.
102
+ #
103
+ # @return [Hash<Symbol, Object>] Returns the resource hash attribute.
104
+ def parse_alias_entry(name, command)
105
+ hsh = {}
106
+ hsh[:name] = name
107
+ com = command[0]
108
+ hsh[:command] = com.strip
109
+ hsh
110
+ end
111
+ private :parse_alias_entry
112
+
113
+ ##
114
+ # create will create a alias entry in the nodes current
115
+ # configuration with the specified address.
116
+ #
117
+ # @since eos_version 4.13.7M
118
+ #
119
+ # ===Commands
120
+ # alias <name> <address>
121
+ #
122
+ # @param name [String] The name of the alias.
123
+ #
124
+ # @param opts [hash] Optional keyword arguments.
125
+ #
126
+ # @option opts command [String] Configures the alias ip address
127
+ #
128
+ # @return [Boolean] Returns true if the command completed successfully.
129
+ def create(name, opts = {})
130
+ raise ArgumentError, 'a command must be provided' unless \
131
+ opts[:command] =~ /.+/
132
+ command = opts.fetch(:command)
133
+ cmd = ["alias #{name} "]
134
+ if command =~ /\\n/
135
+ command.split('\\n').each { |a| cmd << a }
136
+ else
137
+ cmd[0] << command
138
+ end
139
+ configure(cmd)
140
+ end
141
+
142
+ ##
143
+ # delete will delete an existing alias entry from the nodes current
144
+ # running configuration. If the delete method is called and the alias
145
+ # entry does not exist, this method will succeed.
146
+ #
147
+ # @since eos_version 4.13.7M
148
+ #
149
+ # ===Commands
150
+ # no alias <name>
151
+ #
152
+ # @param name [String] The alias name entry to delete from the node.
153
+ #
154
+ # @return [Boolean] Returns true if the command completed successfully.
155
+ def delete(name)
156
+ configure("no alias #{name}")
157
+ end
158
+ end
159
+ end
160
+ end
@@ -227,7 +227,7 @@ module Rbeapi
227
227
  def create(bgp_as, opts = {})
228
228
  if opts[:maximum_ecmp_paths] && !opts[:maximum_paths]
229
229
  message = 'maximum_paths must be set if maximum_ecmp_paths is set'
230
- fail ArgumentError, message
230
+ raise ArgumentError, message
231
231
  end
232
232
  cmds = ["router bgp #{bgp_as}"]
233
233
  if opts.key?(:enable)
@@ -284,7 +284,7 @@ module Rbeapi
284
284
  # @return [Boolean] Returns true if the command complete successfully.
285
285
  def configure_bgp(cmd)
286
286
  config = get_block('^router bgp .*')
287
- fail 'BGP router is not configured' unless config
287
+ raise 'BGP router is not configured' unless config
288
288
  bgp_as = Bgp.parse_bgp_as(config)
289
289
  cmds = ["router bgp #{bgp_as[:bgp_as]}", cmd]
290
290
  configure(cmds)
@@ -341,10 +341,10 @@ module Rbeapi
341
341
  #
342
342
  # @return [Boolean] Returns true if the command complete successfully.
343
343
  def set_shutdown(opts = {})
344
- fail 'set_shutdown has the value option set' if opts[:value]
344
+ raise 'set_shutdown has the value option set' if opts[:value]
345
345
  # Shutdown semantics are opposite of enable semantics so invert enable
346
346
  value = !opts[:enable]
347
- opts.merge!(enable: value)
347
+ opts[:enable] = value
348
348
  configure_bgp(command_builder('shutdown', opts))
349
349
  end
350
350
 
@@ -697,7 +697,7 @@ module Rbeapi
697
697
  # @return [Boolean] Returns true if the command complete successfully.
698
698
  def configure_bgp(cmd)
699
699
  config = get_block('^router bgp .*')
700
- fail 'BGP router is not configured' unless config
700
+ raise 'BGP router is not configured' unless config
701
701
  bgp_as = Bgp.parse_bgp_as(config)
702
702
  cmds = ["router bgp #{bgp_as[:bgp_as]}", cmd]
703
703
  configure(cmds)
@@ -831,10 +831,10 @@ module Rbeapi
831
831
  #
832
832
  # @return [Boolean] Returns true if the command complete successfully.
833
833
  def set_shutdown(name, opts = {})
834
- fail 'set_shutdown has value option set' if opts[:value]
834
+ raise 'set_shutdown has value option set' if opts[:value]
835
835
  # Shutdown semantics are opposite of enable semantics so invert enable.
836
836
  value = !opts[:enable]
837
- opts.merge!(enable: value)
837
+ opts[:enable] = value
838
838
  configure_bgp(neigh_command_builder(name, 'shutdown', opts))
839
839
  end
840
840
 
@@ -859,7 +859,7 @@ module Rbeapi
859
859
  #
860
860
  # @return [Boolean] Returns true if the command complete successfully.
861
861
  def set_send_community(name, opts = {})
862
- fail 'send_community has the value option set' if opts[:value]
862
+ raise 'send_community has the value option set' if opts[:value]
863
863
  configure_bgp(neigh_command_builder(name, 'send-community', opts))
864
864
  end
865
865
 
@@ -885,7 +885,7 @@ module Rbeapi
885
885
  #
886
886
  # @return [Boolean] Returns true if the command complete successfully.
887
887
  def set_next_hop_self(name, opts = {})
888
- fail 'set_next_hop_self has the value option set' if opts[:value]
888
+ raise 'set_next_hop_self has the value option set' if opts[:value]
889
889
  configure_bgp(neigh_command_builder(name, 'next-hop-self', opts))
890
890
  end
891
891
 
@@ -213,7 +213,9 @@ module Rbeapi
213
213
  default = opts[:default] || false
214
214
 
215
215
  if value
216
- fail ArgumentError, 'value must be an Array' unless value.is_a?(Array)
216
+ unless value.is_a?(Array)
217
+ raise ArgumentError, 'value must be an Array'
218
+ end
217
219
  end
218
220
 
219
221
  cmds = []
@@ -55,6 +55,7 @@ module Rbeapi
55
55
  # name: <string>,
56
56
  # type: <string>,
57
57
  # description: <string>,
58
+ # encapsulation: <integer>,
58
59
  # shutdown: <boolean>
59
60
  # }
60
61
  #
@@ -77,6 +78,7 @@ module Rbeapi
77
78
  # name: <string>,
78
79
  # type: <string>,
79
80
  # description: <string>,
81
+ # encapsulation: <integer>,
80
82
  # shutdown: <boolean>,
81
83
  # ...
82
84
  # },
@@ -84,6 +86,7 @@ module Rbeapi
84
86
  # name: <string>,
85
87
  # type: <string>,
86
88
  # description: <string>,
89
+ # encapsulation: <integer>,
87
90
  # shutdown: <boolean>,
88
91
  # ...
89
92
  # },
@@ -110,16 +113,18 @@ module Rbeapi
110
113
  # @return [Object] Returns the interface instance as an Object.
111
114
  def get_instance(name)
112
115
  name = name[0, 2].upcase
113
- case name
114
- when 'ET'
115
- cls = 'Rbeapi::Api::EthernetInterface'
116
- when 'PO'
117
- cls = 'Rbeapi::Api::PortchannelInterface'
118
- when 'VX'
119
- cls = 'Rbeapi::Api::VxlanInterface'
120
- else
121
- cls = 'Rbeapi::Api::BaseInterface'
122
- end
116
+ cls = case name
117
+ when 'ET'
118
+ 'Rbeapi::Api::EthernetInterface'
119
+ when 'PO'
120
+ 'Rbeapi::Api::PortchannelInterface'
121
+ when 'VX'
122
+ 'Rbeapi::Api::VxlanInterface'
123
+ when 'VL'
124
+ 'Rbeapi::Api::VlanInterface'
125
+ else
126
+ 'Rbeapi::Api::BaseInterface'
127
+ end
123
128
 
124
129
  return @instances[name] if @instances.include?(cls)
125
130
  instance = Rbeapi::Utils.class_from_string(cls).new(@node)
@@ -127,10 +132,12 @@ module Rbeapi
127
132
  instance
128
133
  end
129
134
 
135
+ # rubocop:disable Style/MethodMissing
130
136
  def method_missing(method_name, *args, &block)
131
137
  instance = get_instance(args[0])
132
138
  instance.send(method_name.to_sym, *args, &block)
133
139
  end
140
+ # rubocop:enable Style/MethodMissing
134
141
 
135
142
  def respond_to?(method_name, name = nil)
136
143
  return super unless name
@@ -143,8 +150,9 @@ module Rbeapi
143
150
  # The BaseInterface class extends Entity and provides an implementation
144
151
  # that is common to all interfaces configured in EOS.
145
152
  class BaseInterface < Entity
146
- DEFAULT_INTF_DESCRIPTION = ''
147
- DEFAULT_LOAD_INTERVAL = ''
153
+ DEFAULT_INTF_DESCRIPTION = ''.freeze
154
+ DEFAULT_INTF_ENCAPSULATION = ''.freeze
155
+ DEFAULT_LOAD_INTERVAL = ''.freeze
148
156
 
149
157
  ##
150
158
  # get returns the specified interface resource hash that represents the
@@ -157,6 +165,7 @@ module Rbeapi
157
165
  # name: <string>
158
166
  # type: 'generic'
159
167
  # description: <string>
168
+ # encapsulation: <integer>
160
169
  # shutdown: [true, false]
161
170
  # load_interval: <string>
162
171
  # }
@@ -173,6 +182,7 @@ module Rbeapi
173
182
 
174
183
  response = { name: name, type: 'generic' }
175
184
  response.merge!(parse_description(config))
185
+ response.merge!(parse_encapsulation(config))
176
186
  response.merge!(parse_shutdown(config))
177
187
  response.merge!(parse_load_interval(config))
178
188
  response
@@ -197,6 +207,26 @@ module Rbeapi
197
207
  end
198
208
  private :parse_description
199
209
 
210
+ ##
211
+ # parse_encapsulation scans the provided configuration block and parses
212
+ # the encapsulation value if it exists in the configuration. If the
213
+ # encapsulation value is not configured, then the
214
+ # DEFALT_INTF_ENCAPSULATION value is returned. The hash returned by this
215
+ # method is intended to be merged into the interface resource hash
216
+ # returned by the get method.
217
+ #
218
+ # @api private
219
+ #
220
+ # @param config [String] The configuration block retrieved from the
221
+ # nodes current running configuration.
222
+ #
223
+ # @return [Hash<Symbol, Object>] Returns the resource hash attribute.
224
+ def parse_encapsulation(config)
225
+ mdata = /^\s{3}encapsulation dot1q vlan\s(.+)$/.match(config)
226
+ { encapsulation: mdata.nil? ? DEFAULT_INTF_ENCAPSULATION : mdata[1] }
227
+ end
228
+ private :parse_encapsulation
229
+
200
230
  ##
201
231
  # parse_shutdown scans the provided configuration block and parses
202
232
  # the shutdown value. If the shutdown value is configured then true
@@ -315,6 +345,44 @@ module Rbeapi
315
345
  configure_interface(name, commands)
316
346
  end
317
347
 
348
+ ##
349
+ # set_encapsulation configures the VLAN ID value for the specified
350
+ # interface name in the nodes running configuration. If the enable
351
+ # keyword is false then the encapsulation value is negated using the no
352
+ # keyword. If the default keyword is set to true, then the encapsulation
353
+ # value is defaulted using the default keyword. The default keyword takes
354
+ # precedence over the enable keyword if both are provided.
355
+ #
356
+ # @since eos_version X.XX.XM
357
+ #
358
+ # @param name [String] The interface name to apply the configuration
359
+ # to. The name value must be the full interface identifier.
360
+ #
361
+ # @param opts [hash] Optional keyword arguments.
362
+ #
363
+ # @option opts value [String] The value to configure the VLAN ID to be
364
+ # used in the encapsulation dot1q vlan setting for a subinterface.
365
+ #
366
+ # @option opts enable [Boolean] If false then the command is
367
+ # negated. Default is true.
368
+ #
369
+ # @option opts default [Boolean] Configure the interface encapsulation
370
+ # using the default keyword.
371
+ #
372
+ # @return [Boolean] Returns true if the command completed successfully.
373
+ def set_encapsulation(name, opts = {})
374
+ unless name =~ /\./
375
+ raise ArgumentError, 'Parameter encapsulation can be set only on '\
376
+ 'subinterfaces'
377
+ end
378
+ unless name.downcase =~ /et|po/
379
+ raise ArgumentError, 'Parameter encapsulation can be set only on '\
380
+ 'Ethernet and PostChannel interfaces'
381
+ end
382
+ commands = command_builder('encapsulation dot1q vlan', opts)
383
+ configure_interface(name, commands)
384
+ end
385
+
318
386
  ##
319
387
  # set_shutdown configures the administrative state of the specified
320
388
  # interface in the node. If the enable keyword is false, then the
@@ -340,10 +408,10 @@ module Rbeapi
340
408
  #
341
409
  # @return [Boolean] Returns true if the command completed successfully.
342
410
  def set_shutdown(name, opts = {})
343
- fail 'set_shutdown has the value option set' if opts[:value]
411
+ raise 'set_shutdown has the value option set' if opts[:value]
344
412
  # Shutdown semantics are opposite of enable semantics so invert enable.
345
413
  value = !opts[:enable]
346
- opts.merge!(enable: value)
414
+ opts[:enable] = value
347
415
  commands = command_builder('shutdown', opts)
348
416
  configure_interface(name, commands)
349
417
  end
@@ -374,9 +442,9 @@ module Rbeapi
374
442
  # The EthernetInterface class manages all Ethernet interfaces on an
375
443
  # EOS node.
376
444
  class EthernetInterface < BaseInterface
377
- DEFAULT_ETH_FLOWC_TX = 'off'
378
- DEFAULT_ETH_FLOWC_RX = 'off'
379
- DEFAULT_SPEED = 'default'
445
+ DEFAULT_ETH_FLOWC_TX = 'off'.freeze
446
+ DEFAULT_ETH_FLOWC_RX = 'off'.freeze
447
+ DEFAULT_SPEED = 'default'.freeze
380
448
  DEFAULT_LACP_PRIORITY = 32_768
381
449
 
382
450
  ##
@@ -388,6 +456,7 @@ module Rbeapi
388
456
  # name: <string>,
389
457
  # type: <string>,
390
458
  # description: <string>,
459
+ # encapsulation: <integer>,
391
460
  # shutdown: <boolean>,
392
461
  # load_interval: <string>
393
462
  # speed: <string>,
@@ -509,14 +578,19 @@ module Rbeapi
509
578
  ##
510
579
  # create overrides the create method from the BaseInterface and raises
511
580
  # an exception because Ethernet interface creation is not supported.
581
+ # This doesn't happen for Ethernet subinterfaces
512
582
  #
513
- # @param _name [String] The name of the interface.
583
+ # @param name [String] The name of the interface.
514
584
  #
515
585
  # @raise [NotImplementedError] Creation of physical Ethernet interfaces
516
- # is not supported.
517
- def create(_name)
518
- fail NotImplementedError, 'creating Ethernet interfaces is '\
519
- 'not supported'
586
+ # is not supported. Only subinterfaces are allowed.
587
+ def create(name)
588
+ if name !~ /\./
589
+ raise NotImplementedError, 'creating Ethernet interfaces is '\
590
+ 'not supported'
591
+ else
592
+ configure("interface #{name}")
593
+ end
520
594
  end
521
595
 
522
596
  ##
@@ -524,13 +598,17 @@ module Rbeapi
524
598
  # raises an exception because Ethernet interface deletion is not
525
599
  # supported.
526
600
  #
527
- # @param _name [String] The name of the interface.
601
+ # @param name [String] The name of the interface.
528
602
  #
529
603
  # @raise [NotImplementedError] Deletion of physical Ethernet interfaces
530
604
  # is not supported.
531
- def delete(_name)
532
- fail NotImplementedError, 'deleting Ethernet interfaces is '\
533
- 'not supported'
605
+ def delete(name)
606
+ if name !~ /\./
607
+ raise NotImplementedError, 'deleting Ethernet interfaces is '\
608
+ 'not supported'
609
+ else
610
+ configure("no interface #{name}")
611
+ end
534
612
  end
535
613
 
536
614
  ##
@@ -720,9 +798,9 @@ module Rbeapi
720
798
  # The PortchannelInterface class manages all port channel interfaces on an
721
799
  # EOS node.
722
800
  class PortchannelInterface < BaseInterface
723
- DEFAULT_LACP_FALLBACK = 'disabled'
724
- DEFAULT_LACP_MODE = 'on'
725
- DEFAULT_MIN_LINKS = '0'
801
+ DEFAULT_LACP_FALLBACK = 'disabled'.freeze
802
+ DEFAULT_LACP_MODE = 'on'.freeze
803
+ DEFAULT_MIN_LINKS = '0'.freeze
726
804
 
727
805
  ##
728
806
  # get returns the specified port-channel interface configuration from
@@ -734,6 +812,7 @@ module Rbeapi
734
812
  # {
735
813
  # type: 'portchannel'
736
814
  # description: <string>
815
+ # encapsulation: <integer>
737
816
  # shutdown: [true, false]
738
817
  # load_interval: <string>
739
818
  # members: array[<strings>]
@@ -861,6 +940,7 @@ module Rbeapi
861
940
  # @return [Hash<Symbol, Object>] Returns the resource hash attribute.
862
941
  def parse_lacp_timeout(config)
863
942
  mdata = /lacp fallback timeout (\d+)$/.match(config)
943
+ return { lacp_timeout: [] } unless defined? mdata[1]
864
944
  { lacp_timeout: mdata[1] }
865
945
  end
866
946
  private :parse_lacp_timeout
@@ -925,7 +1005,7 @@ module Rbeapi
925
1005
  #
926
1006
  # @return [Boolean] Returns true if the command completed successfully.
927
1007
  def set_members(name, members, mode = nil)
928
- fail ArgumentError, 'members must be an Array' unless
1008
+ raise ArgumentError, 'members must be an Array' unless
929
1009
  members.is_a?(Array)
930
1010
 
931
1011
  current_members = Set.new parse_members(name)[:members]
@@ -1091,8 +1171,8 @@ module Rbeapi
1091
1171
  ##
1092
1172
  # The VxlanInterface class manages all Vxlan interfaces on an EOS node.
1093
1173
  class VxlanInterface < BaseInterface
1094
- DEFAULT_SRC_INTF = ''
1095
- DEFAULT_MCAST_GRP = ''
1174
+ DEFAULT_SRC_INTF = ''.freeze
1175
+ DEFAULT_MCAST_GRP = ''.freeze
1096
1176
 
1097
1177
  ##
1098
1178
  # Returns the Vxlan interface configuration as a Ruby hash of key/value
@@ -1105,6 +1185,7 @@ module Rbeapi
1105
1185
  # name: <string>,
1106
1186
  # type: <string>,
1107
1187
  # description: <string>,
1188
+ # encapsulation: <string>,
1108
1189
  # shutdown: <boolean>,
1109
1190
  # load_interval: <string>
1110
1191
  # source_interface: <string>,
@@ -1374,5 +1455,86 @@ module Rbeapi
1374
1455
  configure_interface(name, "no vxlan vlan #{vlan} vni")
1375
1456
  end
1376
1457
  end
1458
+
1459
+ ##
1460
+ # The VlanInterface class manages all Vlan interfaces on an EOS node.
1461
+ class VlanInterface < BaseInterface
1462
+ ##
1463
+ # Returns the Vlan interface configuration as a Ruby hash of key/value
1464
+ # pairs from the nodes running configuration. This method extends the
1465
+ # BaseInterface get method and adds the Vlan specific attributes to
1466
+ # the hash.
1467
+ #
1468
+ # @example
1469
+ # {
1470
+ # name: <string>,
1471
+ # type: <string>,
1472
+ # description: <string>,
1473
+ # shutdown: <boolean>,
1474
+ # autostate: <boolean>
1475
+ # }
1476
+ #
1477
+ # @param name [String] The interface name to return from the nodes
1478
+ # configuration.
1479
+ #
1480
+ # @return [nil, Hash<String, String>] Returns the interface configuration
1481
+ # as a Ruby hash object. If the provided interface name is not found
1482
+ # then this method will return nil.
1483
+ def get(name)
1484
+ config = get_block("interface #{name}")
1485
+ return nil unless config
1486
+
1487
+ response = super(name)
1488
+ response[:type] = 'vlan'
1489
+ response.merge!(parse_autostate(config))
1490
+ response
1491
+ end
1492
+
1493
+ ##
1494
+ # parse_autostate scans the interface config block and returns the
1495
+ # value of the vlan autostate. If the autostate is not
1496
+ # configured then it's enabled, as by default. The hash
1497
+ # returned is intended to be merged into the interface resource hash
1498
+ #
1499
+ # @api private
1500
+ #
1501
+ # @param config [String] The interface configuration block to extract
1502
+ # the vlan autostate value from.
1503
+ #
1504
+ # @return [Hash<Symbol, Object>]
1505
+ def parse_autostate(config)
1506
+ mdata = /^\s{3}no\sautostate$/.match(config)
1507
+ { autostate: mdata.nil? ? :true : :false }
1508
+ end
1509
+ private :parse_autostate
1510
+
1511
+ ##
1512
+ # set_autostate configures the autostate on a vlan interface.
1513
+ # Default value is true, if set to false 'no autostate' is
1514
+ # configured on the interface.
1515
+ #
1516
+ # @since eos_version 4.13.7M
1517
+ #
1518
+ # @param name [String] The interface name to apply the configuration
1519
+ # values to. The name must be the full interface identifier.
1520
+ #
1521
+ # @param opts [Hash] Optional keyword arguments.
1522
+ #
1523
+ # @option opts value [Boolean] Enables or disables autotate for vlan
1524
+ # interfaces. Default is true.
1525
+ #
1526
+ # @option opts default [Boolean] Configures the autostate value
1527
+ # on the interface using the default value (true).
1528
+ #
1529
+ # @return [Boolean] Returns true if the command completed successfully.
1530
+ def set_autostate(name, opts = {})
1531
+ commands = if opts[:value] == :false
1532
+ command_builder('no autostate')
1533
+ else
1534
+ command_builder('autostate')
1535
+ end
1536
+ configure_interface(name, commands)
1537
+ end
1538
+ end
1377
1539
  end
1378
1540
  end