rbeapi 1.0 → 1.1

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 (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