From 51c36cad643a0fca8c980b1655bbe658313ed02e Mon Sep 17 00:00:00 2001 From: Rick Sherman Date: Mon, 13 Nov 2017 15:57:06 -0600 Subject: [PATCH 01/34] (NETDEV-30) Enhance syslog, tacacs, radius (#558) * (maint) add net-telnet to gemspec Tests require net-telnet which was not specified * (NETDEV-30) syslog_server add port Added port to syslog_server Updated syslog server to operate as a single item vs multiple calls. Follows work previously done with ntp types * (NETDEV-30) Add source_interface to tacacs/radius_global Added source_interface to tacacs_global and radius_global Fixed handling of encryption key in tacacs_global Increased testing in radius_global * (NETDEV-30) Add console, monitor, source interface to syslog_settings * (NETDEV-30) Changelog --- CHANGELOG.md | 28 +++++++ cisco_node_utils.gemspec | 1 + .../cmd_ref/radius_global.yaml | 7 ++ .../cmd_ref/syslog_server.yaml | 5 +- .../cmd_ref/syslog_settings.yaml | 22 ++++- .../cmd_ref/tacacs_global.yaml | 7 ++ lib/cisco_node_utils/radius_global.rb | 26 +++++- lib/cisco_node_utils/syslog_server.rb | 80 +++++++++---------- lib/cisco_node_utils/syslog_settings.rb | 77 +++++++++++++++++- lib/cisco_node_utils/tacacs_global.rb | 47 ++++++++--- tests/test_radius_global.rb | 24 +++++- tests/test_syslog_server.rb | 42 +++------- tests/test_syslog_settings.rb | 51 ++++++++++-- tests/test_tacacs_global.rb | 53 ++++++++---- 14 files changed, 357 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24817152..639166f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,34 @@ Changelog * object_group (@saichint) * object_group_entry (@saichint) +### Added +* Extend syslog_server with attributes: + * `port` +* Extend syslog_settings with attributes: + * `console` + * `monitor` + * `source_interface` +* Extend radius_global with attributes: + * `source_interface` +* Extend tacacs_global with attributes: + * `source_interface` + +### Changed +* syslog_server initialize now uses options hash + * Prior to this release syslog_server accepted positional arguments for name, + level, and vrf. New behavior is to pass attributes as a hash. + + Example: + ``` + options = { 'name' => '1.1.1.1', 'level' => '4', 'port' => '2154', + 'vrf' => 'red' } + Cisco::SyslogServer.new(options, true) + ``` +* tacacs_global key removal fixed + * Prior to this release key removal was done by passing in a value of 8. A + nil value is now used. Added intelligence to determine key format + automatically for removal. + ## [v1.7.0] ### New feature support diff --git a/cisco_node_utils.gemspec b/cisco_node_utils.gemspec index 63a2a0ad..858f5511 100644 --- a/cisco_node_utils.gemspec +++ b/cisco_node_utils.gemspec @@ -31,6 +31,7 @@ Currently supports NX-OS nodes. spec.add_development_dependency 'bundler', '~> 1.7' spec.add_development_dependency 'kwalify', '~> 0.7.2' spec.add_development_dependency 'minitest', '~> 5.0' + spec.add_development_dependency 'net-telnet', '~> 0.1.1' spec.add_development_dependency 'rake', '~> 10.0' spec.add_development_dependency 'rspec', '~> 3.0' spec.add_development_dependency 'rubocop', '= 0.35.1' diff --git a/lib/cisco_node_utils/cmd_ref/radius_global.yaml b/lib/cisco_node_utils/cmd_ref/radius_global.yaml index f245a0f4..b5f6af0d 100644 --- a/lib/cisco_node_utils/cmd_ref/radius_global.yaml +++ b/lib/cisco_node_utils/cmd_ref/radius_global.yaml @@ -23,6 +23,13 @@ retransmit: ios_xr: default_value: 3 +source_interface: + default_value: ~ + get_value: '/^ip radius source-interface\s+(.*)$/' + set_value: ' ip radius source-interface ' + nexus: + get_command: "show running-config all | include '^ip radius source-interface'" + timeout: kind: int get_value: '/^radius-server timeout (\d+).*/' diff --git a/lib/cisco_node_utils/cmd_ref/syslog_server.yaml b/lib/cisco_node_utils/cmd_ref/syslog_server.yaml index 1b35f427..256b176a 100644 --- a/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +++ b/lib/cisco_node_utils/cmd_ref/syslog_server.yaml @@ -15,8 +15,9 @@ server: multiple: true nexus: get_command: "show running-config all | include '^logging server'" - get_value: '/^logging server (\S+).*/' - set_value: ' logging server ' + # Returns , , , + get_value: '/^(?:logging server )([^\s]+)(?: (\d+))?(?: port (\d+))?(?: use-vrf (\S+))?/' + set_value: ' logging server ' ios_xr: get_command: "show running-config logging" get_value: '/^logging (\S+).*/' diff --git a/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml b/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml index 83b5e2ad..c17966e7 100644 --- a/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +++ b/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml @@ -2,8 +2,28 @@ --- _exclude: [ios_xr] +console: + default_value: 2 + get_command: "show running-config all | include 'logging'" + # Returns and + get_value: '/^(no)?\s*logging console\s*(\d)?/' + set_value: ' logging console ' + +monitor: + default_value: 5 + get_command: "show running-config all | include 'logging'" + # Returns and + get_value: '/^(no)?\s*logging monitor\s*(\d)?/' + set_value: ' logging monitor ' + +source_interface: + default_value: ~ + get_command: "show running-config all | include 'logging'" + get_value: '/^logging source-interface\s+(.*)$/' + set_value: ' logging source-interface ' + timestamp: - get_command: "show running-config all | include '^logging timestamp'" + get_command: "show running-config all | include 'logging'" get_value: '/^logging timestamp (.*)$/' set_value: ' logging timestamp ' default_value: 'seconds' diff --git a/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml b/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml index 7c02d473..53c925a8 100644 --- a/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml +++ b/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml @@ -19,6 +19,13 @@ key_format: ios_xr: get_command: "show running-config tacacs-server" +source_interface: + default_value: ~ + get_value: '/^ip tacacs source-interface\s+(.*)$/' + set_value: ' ip tacacs source-interface ' + nexus: + get_command: "show running-config all | include '^ip tacacs source-interface'" + timeout: kind: int get_value: '/tacacs-server timeout\s+(\d+)/' diff --git a/lib/cisco_node_utils/radius_global.rb b/lib/cisco_node_utils/radius_global.rb index 6a950c02..2d15d73b 100644 --- a/lib/cisco_node_utils/radius_global.rb +++ b/lib/cisco_node_utils/radius_global.rb @@ -2,7 +2,7 @@ # Jonathan Tripathy et al., September 2015 -# Copyright (c) 2014-2016 Cisco and/or its affiliates. +# Copyright (c) 2014-2017 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -137,5 +137,29 @@ def key_set(value, format) key: "#{value}") end end + + # Get default source interface + def default_source_interface + config_get_default('radius_global', 'source_interface') + end + + # Set source interface + def source_interface=(name) + if name + config_set( + 'radius_global', 'source_interface', + state: '', source_interface: name) + else + config_set( + 'radius_global', 'source_interface', + state: 'no', source_interface: '') + end + end + + # Get source interface + def source_interface + i = config_get('radius_global', 'source_interface') + i.nil? ? default_source_interface : i.downcase + end end # class end # module diff --git a/lib/cisco_node_utils/syslog_server.rb b/lib/cisco_node_utils/syslog_server.rb index 8f7c7247..7f2e990f 100644 --- a/lib/cisco_node_utils/syslog_server.rb +++ b/lib/cisco_node_utils/syslog_server.rb @@ -2,7 +2,7 @@ # # Jonathan Tripathy et al., September 2015 # -# Copyright (c) 2014-2016 Cisco and/or its affiliates. +# Copyright (c) 2014-2017 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,11 +17,12 @@ # limitations under the License. require_relative 'node_util' +require 'resolv' module Cisco - # NtpServer - node utility class for NTP Server configuration management + # SyslogServer - node utility class for syslog server configuration management class SyslogServer < NodeUtil - attr_reader :name, :level, :vrf + attr_reader :name, :level, :port, :vrf, :severity_level LEVEL_TO_NUM = { 'emergencies' => 0, 'alerts' => 1, @@ -33,45 +34,38 @@ class SyslogServer < NodeUtil 'debugging' => 7 }.freeze NUM_TO_LEVEL = LEVEL_TO_NUM.invert.freeze - def initialize(name, - level=nil, - vrf=nil, - instantiate=true) - fail TypeError unless name.is_a?(String) - fail TypeError unless name.length > 0 - @name = name - - fail TypeError unless level.is_a?(Integer) || level.nil? - @level = level - - fail TypeError unless vrf.is_a?(String) || vrf.nil? - @vrf = vrf + def initialize(opts, instantiate=true) + @name = opts['name'] + @level = opts['level'] || opts['severity_level'] + @port = opts['port'] + @vrf = opts['vrf'] + @severity_level = opts['severity_level'] || opts['level'] + + hostname_regex = /^(?=.{1,255}$)[0-9A-Za-z] + (?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])? + (?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/x + + unless @name =~ Resolv::AddressRegex || + @name =~ hostname_regex + fail ArgumentError, + "Invalid value '#{@name}' \ + (Must be valid IPv4/IPv6 address or hostname)" + end create if instantiate end def self.syslogservers + keys = %w(name level port vrf severity_level) hash = {} syslogservers_list = config_get('syslog_server', 'server') return hash if syslogservers_list.nil? syslogservers_list.each do |id| - # The YAML regex isn't specific enough for some platforms, - # so we have to do further checking. - begin - IPAddr.new(id) - rescue - next - end - - level = config_get('syslog_server', 'level', id) - level = level[0] if level.is_a?(Array) - level = LEVEL_TO_NUM[level] if platform == :ios_xr - - vrf = config_get('syslog_server', 'vrf', id) - vrf = vrf[0] if vrf.is_a?(Array) - - hash[id] = SyslogServer.new(id, level, vrf, false) + value_hash = Hash[keys.zip(id)] + value_hash['severity_level'] = value_hash['level'] + value_hash['vrf'] = 'default' if value_hash['vrf'].nil? + hash[id[0]] = SyslogServer.new(value_hash, false) end hash @@ -92,17 +86,18 @@ def create config_set('syslog_server', 'server', state: '', - ip: "#{name}", - level: level.nil? ? '' : "severity #{NUM_TO_LEVEL[level]}", - vrf: vrf.nil? ? '' : "vrf #{vrf}", + ip: @name, + level: @level ? "severity #{NUM_TO_LEVEL[@level]}" : '', + vrf: @vrf ? "vrf #{@vrf}" : '', ) else config_set('syslog_server', 'server', state: '', - ip: "#{name}", - level: level.nil? ? '' : "#{level}", - vrf: vrf.nil? ? '' : "use-vrf #{vrf}", + ip: @name, + level: @level ? "#{@level}" : '', + port: @port ? "port #{@port}" : '', + vrf: @vrf ? "use-vrf #{@vrf}" : '', ) end end @@ -113,9 +108,9 @@ def destroy(duplicate_vrfs=[]) config_set('syslog_server', 'server', state: 'no', - ip: "#{name}", + ip: @name, level: '', - vrf: vrf.nil? ? '' : "vrf #{vrf}", + vrf: @vrf ? "vrf #{@vrf}" : '', ) else warn("#{name} is configured multiple times on the device" \ @@ -125,7 +120,7 @@ def destroy(duplicate_vrfs=[]) config_set('syslog_server', 'server', state: 'no', - ip: "#{name}", + ip: @name, level: '', vrf: "vrf #{dup}", ) @@ -135,8 +130,9 @@ def destroy(duplicate_vrfs=[]) config_set('syslog_server', 'server', state: 'no', - ip: "#{name}", + ip: @name, level: '', + port: '', vrf: '', ) end diff --git a/lib/cisco_node_utils/syslog_settings.rb b/lib/cisco_node_utils/syslog_settings.rb index 7c0dddaf..d91c39a0 100644 --- a/lib/cisco_node_utils/syslog_settings.rb +++ b/lib/cisco_node_utils/syslog_settings.rb @@ -2,7 +2,7 @@ # # Jonathan Tripathy et al., September 2015 # -# Copyright (c) 2014-2016 Cisco and/or its affiliates. +# Copyright (c) 2014-2017 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -42,14 +42,82 @@ def ==(other) name == other.name end + def default_console + config_get_default('syslog_settings', 'console') + end + + def console + console = config_get('syslog_settings', 'console') + if console.is_a?(Array) + console = console[0] == 'no' ? 'unset' : console[1] + end + console + end + + def console=(severity) + if severity + config_set( + 'syslog_settings', 'console', + state: '', severity: severity) + else + config_set( + 'syslog_settings', 'console', + state: 'no', severity: '') + end + end + + def default_monitor + config_get_default('syslog_settings', 'monitor') + end + + def monitor + monitor = config_get('syslog_settings', 'monitor') + if monitor.is_a?(Array) + monitor = monitor[0] == 'no' ? 'unset' : monitor[1] + end + monitor + end + + def monitor=(severity) + if severity + config_set( + 'syslog_settings', 'monitor', + state: '', severity: severity) + else + config_set( + 'syslog_settings', 'monitor', + state: 'no', severity: '') + end + end + + def default_source_interface + config_get_default('syslog_settings', 'source_interface') + end + + def source_interface + i = config_get('syslog_settings', 'source_interface') + i.nil? ? default_source_interface : i.downcase + end + + def source_interface=(name) + if name + config_set( + 'syslog_settings', 'source_interface', + state: '', source_interface: name) + else + config_set( + 'syslog_settings', 'source_interface', + state: 'no', source_interface: '') + end + end + def timestamp config_get('syslog_settings', 'timestamp') end def timestamp=(val) - fail TypeError unless val.is_a?(String) fail TypeError \ - unless %w(seconds milliseconds).include?(val) + unless %w(seconds milliseconds).include?(val.to_s) # There is no unset version as timestamp has a default value config_set('syslog_settings', @@ -57,5 +125,8 @@ def timestamp=(val) state: '', units: val) end + + alias_method :time_stamp_units, :timestamp + alias_method :time_stamp_units=, :timestamp= end # class end # module diff --git a/lib/cisco_node_utils/tacacs_global.rb b/lib/cisco_node_utils/tacacs_global.rb index 89f8ccff..2db86061 100644 --- a/lib/cisco_node_utils/tacacs_global.rb +++ b/lib/cisco_node_utils/tacacs_global.rb @@ -1,8 +1,8 @@ # Tacacs Global provider class -# TP HONEY et al., June 2014-2016 +# TP HONEY et al., June 2014-2017 -# Copyright (c) 2014-2016 Cisco and/or its affiliates. +# Copyright (c) 2014-2017 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,10 +20,6 @@ # Tacacs Global configuration management module Cisco - TACACS_GLOVAL_ENC_NONE = 0 - TACACS_GLOBAL_ENC_CISCO_TYPE_7 = 7 - TACACS_GLOBAL_ENC_UNKNOWN = 8 - # TacacsGlobal - node utility class for class TacacsGlobal < NodeUtil attr_reader :name @@ -92,14 +88,47 @@ def self.default_key end def encryption_key_set(key_format, key) - key = Utils.add_quotes(key) - if key_format == TACACS_GLOBAL_ENC_UNKNOWN + # If we get an empty key - remove default if configured + if key.nil? || key.to_s.empty? + key = self.key + return if key.empty? + key_format = self.key_format config_set('tacacs_server', 'encryption', state: 'no', option: key_format, key: key) else - config_set('tacacs_server', 'encryption', state: '', option: key_format, + key = Utils.add_quotes(key) + if key_format.nil? || key_format.to_s.empty? + config_set('tacacs_server', 'encryption', state: '', option: '', key: key) + else + config_set('tacacs_server', 'encryption', state: '', + option: key_format, key: key) + end + end + end + + # Get default source interface + def default_source_interface + config_get_default('tacacs_global', 'source_interface') + end + + # Set source interface + def source_interface=(name) + if name + config_set( + 'tacacs_global', 'source_interface', + state: '', source_interface: name) + else + config_set( + 'tacacs_global', 'source_interface', + state: 'no', source_interface: '') end end + + # Get source interface + def source_interface + i = config_get('tacacs_global', 'source_interface') + i.nil? ? default_source_interface : i.downcase + end end # class end # module diff --git a/tests/test_radius_global.rb b/tests/test_radius_global.rb index aa79213f..c9bba003 100644 --- a/tests/test_radius_global.rb +++ b/tests/test_radius_global.rb @@ -70,6 +70,12 @@ def test_radius_global global.key_set(key, nil) assert_match(/#{key}/, global.key) assert_match(/#{key}/, Cisco::RadiusGlobal.radius_global[id].key) + assert_equal(7, global.key_format) + # Change to type 6 + key = 'JDYkqyIFWeBvzpljSfWmRZrmRSRE8' + global.key_set(key, 6) + assert_match(/#{key}/, global.key) + assert_equal(6, global.key_format) elsif platform == :ios_xr global.key_set('QsEfThUkO', nil) assert(!global.key.nil?) @@ -77,9 +83,23 @@ def test_radius_global end # Setting back to default and re-checking - global.timeout = global.default_timeout - global.retransmit_count = global.default_retransmit_count + global.timeout = nil + global.retransmit_count = nil + global.key_set(nil, nil) assert_equal(global.timeout, global.default_timeout) assert_equal(global.retransmit_count, global.default_retransmit_count) + assert_nil(global.key) + + # Default source interface + assert_nil(global.source_interface) + + # Set source interface + interface = 'loopback0' + global.source_interface = interface + assert_equal(interface, global.source_interface) + + # Remove source interface + global.source_interface = nil + assert_nil(global.source_interface) end end diff --git a/tests/test_syslog_server.rb b/tests/test_syslog_server.rb index 772bc74c..c101e3bd 100644 --- a/tests/test_syslog_server.rb +++ b/tests/test_syslog_server.rb @@ -53,10 +53,9 @@ def test_create_destroy_single_ipv4 id = '1.2.3.4' refute_includes(Cisco::SyslogServer.syslogservers, id) - server = Cisco::SyslogServer.new(id, 2, 'default', true) + server = Cisco::SyslogServer.new({ 'name' => id, 'vrf' => 'default' }, true) assert_includes(Cisco::SyslogServer.syslogservers, id) assert_equal(server, Cisco::SyslogServer.syslogservers[id]) - assert_equal(2, Cisco::SyslogServer.syslogservers[id].level) server.destroy refute_includes(Cisco::SyslogServer.syslogservers, id) @@ -66,10 +65,9 @@ def test_create_destroy_single_ipv6 id = '2003::2' refute_includes(Cisco::SyslogServer.syslogservers, id) - server = Cisco::SyslogServer.new(id, 2, 'default', true) + server = Cisco::SyslogServer.new({ 'name' => id, 'vrf' => 'default' }, true) assert_includes(Cisco::SyslogServer.syslogservers, id) assert_equal(server, Cisco::SyslogServer.syslogservers[id]) - assert_equal(2, Cisco::SyslogServer.syslogservers[id].level) server.destroy refute_includes(Cisco::SyslogServer.syslogservers, id) @@ -81,14 +79,13 @@ def test_create_destroy_multiple refute_includes(Cisco::SyslogServer.syslogservers, id) refute_includes(Cisco::SyslogServer.syslogservers, id2) - server = Cisco::SyslogServer.new(id, 2, 'default', true) - server2 = Cisco::SyslogServer.new(id2, 3, 'default', true) + server = Cisco::SyslogServer.new({ 'name' => id, 'vrf' => 'default' }, true) + server2 = Cisco::SyslogServer.new({ 'name' => id2, 'vrf' => 'default' }, + true) assert_includes(Cisco::SyslogServer.syslogservers, id) assert_equal(server, Cisco::SyslogServer.syslogservers[id]) - assert_equal(2, Cisco::SyslogServer.syslogservers[id].level) assert_includes(Cisco::SyslogServer.syslogservers, id2) assert_equal(server2, Cisco::SyslogServer.syslogservers[id2]) - assert_equal(3, Cisco::SyslogServer.syslogservers[id2].level) server.destroy server2.destroy @@ -96,7 +93,7 @@ def test_create_destroy_multiple refute_includes(Cisco::SyslogServer.syslogservers, id2) end - def test_create_destroy_single_vrf_ipv4 + def test_create_options if platform == :ios_xr config('vrf red') else @@ -104,33 +101,16 @@ def test_create_destroy_single_vrf_ipv4 end id = '1.2.3.4' + options = { 'name' => id, 'level' => '4', 'port' => '2154', 'vrf' => 'red' } refute_includes(Cisco::SyslogServer.syslogservers, id) - server = Cisco::SyslogServer.new(id, 4, 'red', true) + server = Cisco::SyslogServer.new(options, true) assert_includes(Cisco::SyslogServer.syslogservers, id) assert_equal(server, Cisco::SyslogServer.syslogservers[id]) - assert_equal(4, Cisco::SyslogServer.syslogservers[id].level) - - server.destroy - refute_includes(Cisco::SyslogServer.syslogservers, id) - end - - def test_create_destroy_single_vrf_ipv6 - if platform == :ios_xr - config('vrf red') - else - config('vrf context red') - end - - id = '2003::2' - - refute_includes(Cisco::SyslogServer.syslogservers, id) - - server = Cisco::SyslogServer.new(id, 5, 'red', true) - assert_includes(Cisco::SyslogServer.syslogservers, id) - assert_equal(server, Cisco::SyslogServer.syslogservers[id]) - assert_equal(5, Cisco::SyslogServer.syslogservers[id].level) + assert_equal('4', Cisco::SyslogServer.syslogservers[id].level) + assert_equal('2154', Cisco::SyslogServer.syslogservers[id].port) + assert_equal('red', Cisco::SyslogServer.syslogservers[id].vrf) server.destroy refute_includes(Cisco::SyslogServer.syslogservers, id) diff --git a/tests/test_syslog_settings.rb b/tests/test_syslog_settings.rb index 98000368..542e3d54 100644 --- a/tests/test_syslog_settings.rb +++ b/tests/test_syslog_settings.rb @@ -24,24 +24,27 @@ def setup return if platform != :nexus # setup runs at the beginning of each test super - no_syslogsettings + default_syslogsettings end def teardown return if platform != :nexus # teardown runs at the end of each test - no_syslogsettings + default_syslogsettings super end - def no_syslogsettings + def default_syslogsettings # Turn the feature off for a clean test. - config('no logging timestamp seconds') + config('no logging timestamp seconds', + 'logging console 2', + 'logging monitor 5', + 'no logging source-interface') end # TESTS - def test_create + def test_timestamp syslog_setting = Cisco::SyslogSettings.new('default') if platform == :ios_xr @@ -62,6 +65,44 @@ def test_create assert_equal('milliseconds', syslog_setting.timestamp, ) + syslog_setting.time_stamp_units = 'seconds' + assert_equal('seconds', + syslog_setting.time_stamp_units, + ) end end + + def test_console + syslog_setting = Cisco::SyslogSettings.new('default') + + # Some systems return the value and othesr get it from yaml - normalize + assert_equal(syslog_setting.default_console, syslog_setting.console.to_i) + assert_equal(2, syslog_setting.console) + syslog_setting.console = '1' + assert_equal('1', syslog_setting.console) + syslog_setting.console = nil + assert_equal('unset', syslog_setting.console) + end + + def test_monitor + syslog_setting = Cisco::SyslogSettings.new('default') + + # Some systems return the value and othesr get it from yaml - normalize + assert_equal(syslog_setting.default_monitor, syslog_setting.monitor.to_i) + assert_equal('5', syslog_setting.monitor) + syslog_setting.monitor = '7' + assert_equal('7', syslog_setting.monitor) + syslog_setting.monitor = nil + assert_equal('unset', syslog_setting.monitor) + end + + def test_source_interface + syslog_setting = Cisco::SyslogSettings.new('default') + + assert_nil(syslog_setting.source_interface) + syslog_setting.source_interface = 'mgmt0' + assert_equal('mgmt0', syslog_setting.source_interface) + syslog_setting.source_interface = nil + assert_nil(syslog_setting.source_interface) + end end diff --git a/tests/test_tacacs_global.rb b/tests/test_tacacs_global.rb index 6b50f815..17f37c3f 100644 --- a/tests/test_tacacs_global.rb +++ b/tests/test_tacacs_global.rb @@ -1,7 +1,7 @@ # # Minitest for TacacsGlobal class # -# Copyright (c) 2014-2016 Cisco and/or its affiliates. +# Copyright (c) 2014-2017 Cisco and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -50,31 +50,50 @@ def test_tacacs_global assert_includes(Cisco::TacacsGlobal.tacacs_global, id) assert_equal(global, Cisco::TacacsGlobal.tacacs_global[id]) - # Default Checking + # Default timeout assert_equal(global.default_timeout, global.timeout) - global.timeout = 5 - assert_equal(5, Cisco::TacacsGlobal.tacacs_global[id].timeout) - assert_equal(5, global.timeout) + # Timeout update + global.timeout = 10 + assert_equal(10, Cisco::TacacsGlobal.tacacs_global[id].timeout) + assert_equal(10, global.timeout) - # first change - key_format = 0 + # Remove timeout + global.timeout = nil + assert_equal(global.default_timeout, global.timeout) + + # Check there is no default key + assert_equal('', global.key) + + # first key change - unencrypted key key = 'TEST_NEW' - global.encryption_key_set(key_format, key) - assert(!global.key.nil?) - assert(key_format, global.key_format) + global.encryption_key_set(nil, key) + # Device encypts key - verify return value + assert_equal(7, global.key_format) + assert_equal('"WAWY_NZB"', global.key) - # second change + # second key change - modify key to type6 key_format = 6 - # Must use a valid type6 password: CSCvb36266 key = 'JDYkqyIFWeBvzpljSfWmRZrmRSRE8' global.encryption_key_set(key_format, key) - assert(!global.key.nil?) - assert(key_format, global.key_format) + assert_equal(key_format, global.key_format) + assert_equal("\"#{key}\"", global.key) - # Setting back to default and re-checking - global.timeout = global.default_timeout - assert_equal(global.default_timeout, global.timeout) + # Remove global key + global.encryption_key_set('', '') + assert_equal('', global.key) + + # Default source interface + assert_nil(global.source_interface) + + # Set source interface + interface = 'loopback0' + global.source_interface = interface + assert_equal(interface, global.source_interface) + + # Remove source interface + global.source_interface = nil + assert_nil(global.source_interface) end end From a23980b8580718885cff9d747c29d331daee8db5 Mon Sep 17 00:00:00 2001 From: rahushen Date: Tue, 14 Nov 2017 17:57:05 -0500 Subject: [PATCH 02/34] Feature/evpn multisite (#565) * add multisite command reference * add tests and more logic to evpn_multisite * add evpn_stormcontrol NU module * add interface_evpn_multisite cmd_ref + nu + tests * add perr_type property for bgp_neighbor * add rewrite_rt_asn property to bgp_neighbor_af * add multisite_bg_interface property to vxlan_vtep * add multisite_ingress_replication property to vxlan_vtep_vni * recalibrate tests to skip for non-relevant platforms * Fix rubocop errors * Incorporate feedback comments * Update Changelog --- CHANGELOG.md | 21 +++++ lib/cisco_node_utils/bgp_neighbor.rb | 19 +++++ lib/cisco_node_utils/bgp_neighbor_af.rb | 14 ++++ .../cmd_ref/bgp_neighbor.yaml | 7 ++ .../cmd_ref/bgp_neighbor_af.yaml | 7 ++ .../cmd_ref/evpn_multisite.yaml | 17 ++++ .../cmd_ref/evpn_stormcontrol.yaml | 18 +++++ .../cmd_ref/interface_evpn_multisite.yaml | 12 +++ lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml | 6 ++ .../cmd_ref/vxlan_vtep_vni.yaml | 7 ++ lib/cisco_node_utils/evpn_multisite.rb | 70 ++++++++++++++++ lib/cisco_node_utils/evpn_stormcontrol.rb | 81 +++++++++++++++++++ .../interface_evpn_multisite.rb | 46 +++++++++++ lib/cisco_node_utils/vxlan_vtep.rb | 17 ++++ lib/cisco_node_utils/vxlan_vtep_vni.rb | 13 +++ tests/test_bgp_neighbor.rb | 15 ++++ tests/test_bgp_neighbor_af.rb | 27 +++++++ tests/test_evpn_multisite.rb | 70 ++++++++++++++++ tests/test_evpn_stormcontrol.rb | 56 +++++++++++++ tests/test_interface_evpn_multisite.rb | 59 ++++++++++++++ tests/test_vxlan_vtep.rb | 23 ++++++ tests/test_vxlan_vtep_vni.rb | 31 +++++++ 22 files changed, 636 insertions(+) create mode 100644 lib/cisco_node_utils/cmd_ref/evpn_multisite.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/evpn_stormcontrol.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/interface_evpn_multisite.yaml create mode 100644 lib/cisco_node_utils/evpn_multisite.rb create mode 100644 lib/cisco_node_utils/evpn_stormcontrol.rb create mode 100644 lib/cisco_node_utils/interface_evpn_multisite.rb create mode 100644 tests/test_evpn_multisite.rb create mode 100644 tests/test_evpn_stormcontrol.rb create mode 100644 tests/test_interface_evpn_multisite.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 639166f2..18772380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,27 @@ Changelog ## [Unreleased] +### New feature support + +#### Cisco Resources +* EVPN Multisite + * evpn_multisite (@rahushen) + * evpn_stormcontrol (@rahushen) + * interface_evpn_multisite (@rahushen) + +### Added +* Extend vxlan_vtep with attributes: + * `multisite_bg_interface` + +* Extend vxlan_vtep_vni with attributes: + * `multisite_ingress_replication` + +* Extend bgp_neighbor with attributes: + * `peer_type` + +* Extend bgp_neighbor_af with attributes: + * `rewrite_rt_asn` + #### Cisco Resources * ObjectGroup * object_group (@saichint) diff --git a/lib/cisco_node_utils/bgp_neighbor.rb b/lib/cisco_node_utils/bgp_neighbor.rb index ecf136f9..ac25c36e 100644 --- a/lib/cisco_node_utils/bgp_neighbor.rb +++ b/lib/cisco_node_utils/bgp_neighbor.rb @@ -503,5 +503,24 @@ def mode_cli_to_symbol(cli) fail KeyError end end + + def default_peer_type + config_get_default('bgp_neighbor', 'peer_type') + end + + def peer_type=(val) + if val == default_peer_type + @set_args[:state] = 'no' + else + Feature.nv_overlay_evpn_enable + @set_args[:peer_type] = val + @set_args[:state] = '' + end + config_set('bgp_neighbor', 'peer_type', @set_args) + end + + def peer_type + config_get('bgp_neighbor', 'peer_type', @get_args) + end end # class end # module diff --git a/lib/cisco_node_utils/bgp_neighbor_af.rb b/lib/cisco_node_utils/bgp_neighbor_af.rb index 15d3b5b4..ef38792f 100644 --- a/lib/cisco_node_utils/bgp_neighbor_af.rb +++ b/lib/cisco_node_utils/bgp_neighbor_af.rb @@ -756,5 +756,19 @@ def weight=(int) def default_weight config_get_default('bgp_neighbor_af', 'weight') end + + def rewrite_rt_asn + config_get('bgp_neighbor_af', 'rewrite_rt_asn', @get_args) + end + + def rewrite_rt_asn=(state) + Feature.nv_overlay_evpn_enable if state + set_args_keys(state: (state ? '' : 'no')) + config_set('bgp_neighbor_af', 'rewrite_rt_asn', @set_args) + end + + def default_rewrite_rt_asn + config_get_default('bgp_neighbor_af', 'rewrite_rt_asn') + end end end diff --git a/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml b/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml index 23aaeb62..231290de 100644 --- a/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +++ b/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml @@ -114,6 +114,13 @@ password_type: get_value: '/^password (\d+)/' default_value: 0 +peer_type: + _exclude: [ios_xr, N3k, N3k-F, N5k, N6k, N7k, N9k-F] + kind: string + get_value: '/^peer-type (\S+)$/' + set_value: ' peer-type ' + default_value: "" + remote_as: get_value: '/^remote-as (\d*?.?\d+?)$/' set_value: ' remote-as ' diff --git a/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml b/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml index 5cfc937d..eb3ce8c3 100644 --- a/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +++ b/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml @@ -146,6 +146,13 @@ prefix_list_out: set_value: ' prefix-list out' default_value: '' +rewrite_rt_asn: + _exclude: [ios_xr, N3k, N3k-F, N5k, N6k, N7k, N9k-F] + kind: boolean + get_value: '/^rewrite-rt-asn$/' + set_value: ' rewrite-rt-asn' + default_value: false + route_map_in: kind: string default_value: '' diff --git a/lib/cisco_node_utils/cmd_ref/evpn_multisite.yaml b/lib/cisco_node_utils/cmd_ref/evpn_multisite.yaml new file mode 100644 index 00000000..a0c8bd3b --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/evpn_multisite.yaml @@ -0,0 +1,17 @@ +# evpn_multisite.yaml +--- +_exclude: [ios_xr, N3k, N3k-F, N5k, N6k, N7k, N9k-F] + +_template: + get_command: "show running-config | section multisite" + +delay_restore: + get_context: ['/^evpn multisite border-gateway $/'] + get_value: '/^delay-restore\s+time\s+(\d+)$/' + set_context: ['evpn multisite border-gateway '] + set_value: " delay-restore time