From 40d949ea95e41f3700a8cf19cbfc6f22344f85d1 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Wed, 24 Jun 2015 14:18:44 -0400 Subject: [PATCH 001/386] add AAA work-in-progress to feature/aaa branch --- lib/cisco_node_utils.rb | 3 + .../aaa_authentication_login.rb | 98 ++ .../aaa_authentication_login_service.rb | 131 +++ lib/cisco_node_utils/aaa_server_group.rb | 178 ++++ lib/cisco_node_utils/platform_info.yaml | 2 +- tests/test_aaa_authentication_login.rb | 342 +++++++ .../test_aaa_authentication_login_service.rb | 855 ++++++++++++++++++ tests/test_aaa_server_group.rb | 628 +++++++++++++ tests/test_all_cisco.rb | 3 + 9 files changed, 2239 insertions(+), 1 deletion(-) create mode 100644 lib/cisco_node_utils/aaa_authentication_login.rb create mode 100644 lib/cisco_node_utils/aaa_authentication_login_service.rb create mode 100644 lib/cisco_node_utils/aaa_server_group.rb create mode 100644 tests/test_aaa_authentication_login.rb create mode 100644 tests/test_aaa_authentication_login_service.rb create mode 100644 tests/test_aaa_server_group.rb diff --git a/lib/cisco_node_utils.rb b/lib/cisco_node_utils.rb index 9ea1e78c..7f51cdac 100644 --- a/lib/cisco_node_utils.rb +++ b/lib/cisco_node_utils.rb @@ -15,6 +15,9 @@ require "cisco_node_utils/cisco_cmn_utils" require "cisco_node_utils/command_reference" require "cisco_node_utils/configparser_lib" +require "cisco_node_utils/aaa_authentication_login" +require "cisco_node_utils/aaa_authentication_login_service" +require "cisco_node_utils/aaa_server_group" require "cisco_node_utils/interface" require "cisco_node_utils/interface_ospf" require "cisco_node_utils/node" diff --git a/lib/cisco_node_utils/aaa_authentication_login.rb b/lib/cisco_node_utils/aaa_authentication_login.rb new file mode 100644 index 00000000..8d095649 --- /dev/null +++ b/lib/cisco_node_utils/aaa_authentication_login.rb @@ -0,0 +1,98 @@ +# +# NXAPI implementation of AaaAuthenticationLogin class +# +# April 2015, Alex Hunsberger +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require File.join(File.dirname(__FILE__), 'node') + +module Cisco +class AaaAuthenticationLogin + @@node = Cisco::Node.instance + + # There is no "feature aaa" or "aaa new-model" on nxos, and only one + # instance which is always available + + # TODO: onep didn't implement mschap, mschapv2, chap, default fallback, console + # fallback. Should I? + + def AaaAuthenticationLogin.ascii_authentication + not @@node.config_get("aaa_authentication_login", "ascii_authentication").nil? + end + + def AaaAuthenticationLogin.ascii_authentication=(val) + no_cmd = val ? "" : "no" + @@node.config_set("aaa_authentication_login", "ascii_authentication", no_cmd) + end + + def AaaAuthenticationLogin.default_ascii_authentication + @@node.config_get_default("aaa_authentication_login", "ascii_authentication") + end + + def AaaAuthenticationLogin.chap + not @@node.config_get("aaa_authentication_login", "chap").nil? + end + + def AaaAuthenticationLogin.chap=(val) + no_cmd = val ? "" : "no" + @@node.config_set("aaa_authentication_login", "chap", no_cmd) + end + + def AaaAuthenticationLogin.default_chap + @@node.config_get_default("aaa_authentication_login", "chap") + end + + def AaaAuthenticationLogin.error_display + not @@node.config_get("aaa_authentication_login", "error_display").nil? + end + + def AaaAuthenticationLogin.error_display=(val) + no_cmd = val ? "" : "no" + @@node.config_set("aaa_authentication_login", "error_display", no_cmd) + end + + def AaaAuthenticationLogin.default_error_display + @@node.config_get_default("aaa_authentication_login", "error_display") + end + + def AaaAuthenticationLogin.mschap + not @@node.config_get("aaa_authentication_login", "mschap").nil? + end + + def AaaAuthenticationLogin.mschap=(val) + no_cmd = val ? "" : "no" + @@node.config_set("aaa_authentication_login", "mschap", no_cmd) + end + + def AaaAuthenticationLogin.default_mschap + @@node.config_get_default("aaa_authentication_login", "mschap") + end + + def AaaAuthenticationLogin.mschapv2 + not @@node.config_get("aaa_authentication_login", "mschapv2").nil? + end + + def AaaAuthenticationLogin.mschapv2=(val) + no_cmd = val ? "" : "no" + @@node.config_set("aaa_authentication_login", "mschapv2", no_cmd) + end + + def AaaAuthenticationLogin.default_mschapv2 + @@node.config_get_default("aaa_authentication_login", "mschapv2") + end +end +end diff --git a/lib/cisco_node_utils/aaa_authentication_login_service.rb b/lib/cisco_node_utils/aaa_authentication_login_service.rb new file mode 100644 index 00000000..29865673 --- /dev/null +++ b/lib/cisco_node_utils/aaa_authentication_login_service.rb @@ -0,0 +1,131 @@ +# +# NXAPI implementation of AaaAuthenticationLoginService class +# +# May 2015, Alex Hunsberger +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node') + +module Cisco +class AaaAuthenticationLoginService + @@node = Cisco::Node.instance + + attr_reader :name + + def initialize(name, create=true) + raise TypeError unless name.is_a? String + # only console and default are supported currently + raise ArgumentError unless %w(console default).include? name + @name = name + + # console needs to be explicitly created before it appears in + # "show run aaa all" but oddly not before it shows up in + # "show aaa authentication" + if create + m = default_method.to_s + @@node.config_set("aaa_auth_login_service", "method", "", name, m) + end + end + + def AaaAuthenticationLoginService.services + servs = {} + servs_arr = @@node.config_get("aaa_auth_login_service", "services") + unless servs_arr.nil? + servs_arr.each { |s| + servs[s] = AaaAuthenticationLoginService.new(s, false) + } + end + servs + end + + def destroy + # must specify exact current config string to unconfigure + m = method + m_str = m == :unselected ? "" : m.to_s + g_str = groups.join(" ") + + if g_str.empty? + @@node.config_set("aaa_auth_login_service", "method", + "no", @name, m_str) + else + @@node.config_set("aaa_auth_login_service", "groups", + "no", @name, g_str, m_str) + end + end + + # groups aren't retrieved via the usual CLI regex memory method because + # there can be an arbitrary number of groups and specifying a repeating + # memory regex only captures the last match + # ex: aaa authentication login default group group1 group2 group3 none + def groups + # config_get returns the following format: + # [{service:"default",method:"group group1 none "}, + # {service:"console",method:"local "}] + hsh_arr = @@node.config_get("aaa_auth_login_service", "groups", @name) + raise "unable to retrieve aaa groups information" if hsh_arr.nil? + hsh = hsh_arr.find { |x| x["service"] == @name } + # this should never happen unless @name is invalid + raise "no aaa info found for service #{@name}" if hsh.nil? + raise "no method found for #{@name} - api or feature change?" unless + hsh.key? "method" + # ex: ["group", "group1", "local"] or maybe ["none"] + grps = hsh["method"].strip.split + return [] if grps.size == 1 + # remove local, none, group keywords + grps -= %w(none local group) + grps + end + + # default is [] + def default_groups + @@node.config_get_default("aaa_auth_login_service", "groups") + end + + def method + m = @@node.config_get("aaa_auth_login_service", "method", @name) + m.nil? ? :unselected : m.first.to_sym + end + + # default is :local + def default_method + @@node.config_get_default("aaa_auth_login_service", "method") + end + + # groups and method must be set in the same CLI string + # aaa authentication login { console | default } / + # none | local | group [none] + def groups_method_set(grps, m) + raise TypeError unless grps.is_a? Array + raise TypeError unless m.is_a? Symbol + # only the following 3 are supported (unselected = blank) + raise ArgumentError unless [:none, :local, :unselected].include? m + + raise "method 'local' not allowed when groups are configured" if + m == :local and not grps.empty? + m_str = m == :unselected ? "" : m.to_s + g_str = grps.join(" ") + + # different config_set depending on whether we're setting groups or not + if g_str.empty? + @@node.config_set("aaa_auth_login_service", "method", + "", @name, m_str) + else + @@node.config_set("aaa_auth_login_service", "groups", + "", @name, g_str, m_str) + end + end +end +end diff --git a/lib/cisco_node_utils/aaa_server_group.rb b/lib/cisco_node_utils/aaa_server_group.rb new file mode 100644 index 00000000..91e4a7b1 --- /dev/null +++ b/lib/cisco_node_utils/aaa_server_group.rb @@ -0,0 +1,178 @@ +# +# NXAPI implementation of AaaServerGroup class +# +# April 2015, Alex Hunsberger +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node') +require File.join(File.dirname(__FILE__), 'tacacs_server') + +module Cisco +class AaaServerGroup + @@node = Cisco::Node.instance + + attr_reader :name, :type + + def initialize(name, type=:tacacs, create=true) + raise TypeError unless type.is_a? Symbol + raise TypeError unless name.is_a? String + @name = name + @type = type + if create + if type == :tacacs + TacacsServer.new.enable unless TacacsServer.enabled + @@node.config_set("aaa_server_group", "tacacs_group", "", name) + # elsif type == :radius ... + else + raise ArgumentError, "unsupported type #{type}" + end + end + end + + def destroy + if @type == :tacacs + @@node.config_set("aaa_server_group", "tacacs_group", "no", @name) + else + raise ArgumentError, "unsupported type #{@type}" + end + end + + def servers + servs = {} + if @type == :tacacs + tacservers = @@node.config_get("aaa_server_group", "tacacs_servers", @name) + unless tacservers.nil? + tacservers.each { |s| servs[s] = TacacsServerHost.new(s, false) } + end + else + raise ArgumentError, "unsupported type #{@type}" + end + servs + end + + def servers=(new_servs) + raise TypeError unless new_servs.is_a? Array + # just need the names of the current servers for comparison + current_servs = servers.keys + new_servs.each { |s| + # add any servers not yet configured + unless current_servs.include? s + if @type == :tacacs + @@node.config_set("aaa_server_group", "tacacs_server", @name, "", s) + else + raise ArgumentError, "unsupported type #{@type}" + end + end + } + current_servs.each { |s| + # remove any undesired existing servers + unless new_servs.include? s + if @type == :tacacs + @@node.config_set("aaa_server_group", "tacacs_server", @name, "no", s) + else + raise ArgumentError, "unsupported type #{@type}" + end + end + } + end + + def AaaServerGroup.default_servers + @@node.config_get_default("aaa_server_group", "servers") + end + + # allow optionally filtering on server type + def AaaServerGroup.groups(type=nil) + raise TypeError unless type.nil? or type.is_a? Symbol + grps = {} + tacgroups = @@node.config_get("aaa_server_group", "tacacs_groups") if + [nil, :tacacs].include? type and TacacsServer.enabled + unless tacgroups.nil? + tacgroups.each { |s| grps[s] = AaaServerGroup.new(s, :tacacs, false) } + end + grps + end + + def vrf + if @type == :tacacs + # vrf is always present in running config + v = @@node.config_get("aaa_server_group", "tacacs_vrf", @name) + return v.nil? ? AaaServerGroup.default_vrf : v.first + else + raise ArgumentError, "unsupported type #{@type}" + end + end + + def vrf=(v) + raise TypeError unless v.is_a? String + # vrf = "default" is equivalent to unconfiguring vrf + if @type == :tacacs + @@node.config_set("aaa_server_group", "tacacs_vrf", @name, "", v) + else + raise ArgumentError, "unsupported type #{@type}" + end + end + + def AaaServerGroup.default_vrf + @@node.config_get_default("aaa_server_group", "vrf") + end + + def deadtime + if @type == :tacacs + d = @@node.config_get("aaa_server_group", "tacacs_deadtime", @name) + return d.nil? ? AaaServerGroup.default_deadtime : d.first.to_i + else + raise ArgumentError, "unsupported type #{@type}" + end + end + + def deadtime=(t) + no_cmd = t == AaaServerGroup.default_deadtime ? "no" : "" + if @type == :tacacs + @@node.config_set("aaa_server_group", "tacacs_deadtime", @name, no_cmd, t) + else + raise ArgumentError, "unsupported type #{@type}" + end + end + + def AaaServerGroup.default_deadtime + @@node.config_get_default("aaa_server_group", "deadtime") + end + + def source_interface + if @type == :tacacs + i = @@node.config_get("aaa_server_group", "tacacs_source_interface", @name) + return i.nil? ? AaaServerGroup.default_source_interface : i.first + else + raise ArgumentError, "unsupported type #{@type}" + end + end + + def source_interface=(s) + raise TypeError unless s.is_a? String + no_cmd = s == AaaServerGroup.default_source_interface ? "no" : "" + if @type == :tacacs + @@node.config_set("aaa_server_group", "tacacs_source_interface", + @name, no_cmd, s) + else + raise ArgumentError, "unsupported type #{@type}" + end + end + + def AaaServerGroup.default_source_interface + @@node.config_get_default("aaa_server_group", "source_interface") + end +end +end diff --git a/lib/cisco_node_utils/platform_info.yaml b/lib/cisco_node_utils/platform_info.yaml index 206e98ff..4db30a0d 100644 --- a/lib/cisco_node_utils/platform_info.yaml +++ b/lib/cisco_node_utils/platform_info.yaml @@ -7,4 +7,4 @@ # attributes can be added in future. example_node: - interfaces: [Ethernet1/1, Ethernet1/10, Ethernet1/20] \ No newline at end of file + interfaces: [Ethernet1/1, Ethernet1/10, Ethernet1/20] diff --git a/tests/test_aaa_authentication_login.rb b/tests/test_aaa_authentication_login.rb new file mode 100644 index 00000000..e90be6ed --- /dev/null +++ b/tests/test_aaa_authentication_login.rb @@ -0,0 +1,342 @@ +# Copyright (c) 2013-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.expand_path("../ciscotest", __FILE__) +require File.expand_path("../../lib/cisco_node_utils/aaa_authentication_login", __FILE__) + +class TestAaaAuthenticationLogin < CiscoTestCase + DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH = false + DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE= false + DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE = false + DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE= false + DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAPV2_ENABLE = false + + def aaaauthenticationlogin_detach(authlogin) + # Reset the device to a clean test state. Note that AAA will raise an error + # when disabling an authentication method while a different type is present. + s = @device.cmd("show run | i 'aaa authentication login'") + if s[/aaa authentication login (\S+) enable/] + @device.cmd("conf t ; no aaa authentication login #{Regexp.last_match(1)} enable ; end") + node.cache_flush + end + authlogin.ascii_authentication = DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH + authlogin.error_display = DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE + end + + def get_match_line(name) + s = @device.cmd("show run aaa all | no-more") + prefix = "aaa authentication login" + line = /#{prefix} #{name}/.match(s) + line + end + + def test_aaaauthenticationlogin_get_ascii_authentication + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login ascii-authentication") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + refute(aaaauthlogin.ascii_authentication, + "Error: AAA authentication login ascii get\n" + + "See CSCuu12667 (4/29/15)") + + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login ascii-authentication") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert(aaaauthlogin.ascii_authentication, + "Error: AAA authentication login ascii get with preconfig") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_default_ascii_authentication + aaaauthlogin = AaaAuthenticationLogin + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login ascii-authentication") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH, + aaaauthlogin.default_ascii_authentication, + "Error: AAA authentication login, default ascii incorrect") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_set_ascii_authentication + state = true + + aaaauthlogin = AaaAuthenticationLogin + + aaaauthlogin.ascii_authentication = state + line = get_match_line("ascii-authentication") + refute_nil(line, "Error: AAA authentication login ascii not configured #{state}") + assert(aaaauthlogin.ascii_authentication, + "Error: AAA authentication login asci not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + # Now bring it back to default + state = DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH + aaaauthlogin.ascii_authentication = state + line = get_match_line("ascii-authentication") + refute_nil(line, "Error: AAA authentication login, default ascii not configured") + refute(aaaauthlogin.ascii_authentication, + "Error: AAA authentication login asci not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_chap + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login chap enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + refute(aaaauthlogin.chap, + "Error: AAA authentication login chap get\n" + + "See CSCuu12667 (4/29/15)") + + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login chap enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert(aaaauthlogin.chap, + "Error: AAA authentication login chap get with preconfig\n" + + "See CSCuu12667 (4/29/15)") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_default_chap + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login chap enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE, + aaaauthlogin.default_chap, + "Error: AAA authentication login, default chap incorrect") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_set_chap + state = true + + aaaauthlogin = AaaAuthenticationLogin + + aaaauthlogin.chap = state + line = get_match_line("chap enable") + refute_nil(line, "Error: AAA authentication login chap not configured #{state}") + assert(aaaauthlogin.chap, + "Error: AAA authentication login chap not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + # Now bring it back to default + state = DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE + aaaauthlogin.chap = state + line = get_match_line("chap enable") + refute_nil(line, "Error: AAA authentication login, default chap not configured") + refute(aaaauthlogin.chap, + "Error: AAA authentication login chap not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_error_display + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login error-enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + refute(aaaauthlogin.error_display, + "Error: AAA authentication login error display get") + + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login error-enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert(aaaauthlogin.error_display, + "Error: AAA authentication login error display get with preconfig") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_default_error_display + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login error-enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE, + aaaauthlogin.default_error_display, + "Error: AAA authentication login, default error display incorrect") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_set_error_display + state = true + + aaaauthlogin = AaaAuthenticationLogin + + aaaauthlogin.error_display = state + line = get_match_line("error-enable") + refute_nil(line, "Error: AAA authentication login error display not configured #{state}") + assert(aaaauthlogin.error_display, + "Error: AAA authentication login error display not set #{state}") + + # Now bring it back to default + state = DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE + aaaauthlogin.error_display = state + line = get_match_line("error-enable") + refute_nil(line, "Error: AAA authentication login, default error display not configured") + refute(aaaauthlogin.error_display, + "Error: AAA authentication login error display not set #{state}") + + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_mschap + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login mschap enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + refute(aaaauthlogin.mschap, + "Error: AAA authentication login mschap get\n" + + "See CSCuu12667 (4/29/15)") + + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login mschap enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert(aaaauthlogin.mschap, + "Error: AAA authentication login mschap get with preconfig\n" + + "See CSCuu12667 (4/29/15)") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_default_mschap + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login mschap enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE, + aaaauthlogin.default_mschap, + "Error: AAA authentication login, default mschap incorrect") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_set_mschap + state = true + + aaaauthlogin = AaaAuthenticationLogin + + aaaauthlogin.mschap = state + line = get_match_line("mschap enable") + refute_nil(line, "Error: AAA authentication login mschap not configured #{state}") + assert(aaaauthlogin.mschap, + "Error: AAA authentication login mschap not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + # Now bring it back to default + state = DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE + aaaauthlogin.mschap = state + line = get_match_line("mschap enable") + refute_nil(line, "Error: AAA authentication login, default mschap not configured") + refute(aaaauthlogin.mschap, + "Error: AAA authentication login mschap not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_mschapv2 + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login mschapv2 enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + refute(aaaauthlogin.mschapv2, + "Error: AAA authentication login mschapv2 get\n" + + "See CSCuu12667 (4/29/15)") + + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login mschapv2 enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert(aaaauthlogin.mschapv2, + "Error: AAA authentication login mschapv2 get with preconfig\n" + + "See CSCuu12667 (4/29/15)") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_get_default_mschapv2 + aaaauthlogin = AaaAuthenticationLogin + + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa authentication login mschapv2 enable") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAPV2_ENABLE, + aaaauthlogin.default_mschapv2, + "Error: AAA authentication login, default mschapv2 incorrect") + aaaauthenticationlogin_detach(aaaauthlogin) + end + + def test_aaaauthenticationlogin_set_mschapv2 + state = true + + aaaauthlogin = AaaAuthenticationLogin + + aaaauthlogin.mschapv2 = state + line = get_match_line("mschapv2 enable") + refute_nil(line, "Error: AAA authentication login mschapv2 not configured #{state}") + assert(aaaauthlogin.mschapv2, + "Error: AAA authentication login mschapv2 not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + # Now bring it back to default + state = DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAPV2_ENABLE + aaaauthlogin.mschapv2 = state + line = get_match_line("mschapv2 enable") + refute_nil(line, "Error: AAA authentication login, default mschapv2 not configured") + refute(aaaauthlogin.mschapv2, + "Error: AAA authentication login mschapv2 not set #{state}\n" + + "See CSCuu12667 (4/29/15)") + + aaaauthenticationlogin_detach(aaaauthlogin) + end +end diff --git a/tests/test_aaa_authentication_login_service.rb b/tests/test_aaa_authentication_login_service.rb new file mode 100644 index 00000000..955cb448 --- /dev/null +++ b/tests/test_aaa_authentication_login_service.rb @@ -0,0 +1,855 @@ +# Copyright (c) 2014-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.expand_path("../ciscotest", __FILE__) +require File.expand_path( + "../../lib/cisco_node_utils/aaa_authentication_login_service", __FILE__) + +AAA_AUTH_LOGIN_SERVICE_METHOD_NONE = :none +AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL = :local +AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED = :unselected + +class TestAaaAuthenticationLoginService < CiscoTestCase + def unconfig_tacacs + # unconfig + s = @device.cmd("configure terminal") + s = @device.cmd("no feature tacacs+") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def unconfig_aaa + # configure defaults = unconfigure + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login default local") + s = @device.cmd("aaa authentication login console local") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def config_tacacs_servers(servers) + s = @device.cmd("configure terminal") + s = @device.cmd("feature tacacs+") + servers.each do | server | + s = @device.cmd("aaa group server tacacs+ #{server}") + end + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def aaaauthloginservices_default + # change it to default + s = @device.cmd("show run aaa all | no-more") + prefix = "aaa authentication login" + + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login default local") + s = @device.cmd("aaa authentication login console local") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def aaaauthloginservice_detach(authloginservice, revert = true) + aaaauthloginservices_default if revert != false + begin + authloginservice.destroy + rescue Exception => e + raise e.message + "\n(see CSCuu86609)" + end + end + + def get_match_line(name) + s = @device.cmd("show run aaa all | no-more") + prefix = "aaa authentication login" + line = /#{prefix} #{name}/.match(s) + line + end + + def test_aaaauthloginservice_create_empty_service + assert_raises(ArgumentError) do + aaaauthloginservice = AaaAuthenticationLoginService.new("") + end + end + + def test_aaaauthloginservice_create_invalid_service + assert_raises(TypeError) do + aaaauthloginservice = AaaAuthenticationLoginService.new(:test) + end + end + + def test_aaaauthloginservice_create_service_default + aaaauthloginservice = AaaAuthenticationLoginService.new("default") + refute_nil(aaaauthloginservice, + "Error: AAA authentication login service default create") + aaaauthloginservice_detach(aaaauthloginservice) unless aaaauthloginservice.nil? + end + + def test_aaaauthloginservice_create_service_console + aaaauthloginservice = AaaAuthenticationLoginService.new("console") + refute_nil(aaaauthloginservice, + "Error: AAA authentication login service console create") + aaaauthloginservice_detach(aaaauthloginservice) unless aaaauthloginservice.nil? + end + + def test_aaaauthloginservice_collection_with_service_default + unconfig_aaa + aaaauthloginservice_list = AaaAuthenticationLoginService.services + refute_empty(aaaauthloginservice_list, + "Error: AAA Authentication Login service collection is not filled") + assert_equal(1, aaaauthloginservice_list.size, + "Error: AAA Authentication Login collection not reporting correct " + + " size (see CSCuu29429)") + assert(aaaauthloginservice_list.key?("default"), + "Error: AAA Authentication Login collection does contain default") + aaaauthloginservice_list.each do |name, aaaauthloginservice| + assert_equal(name, aaaauthloginservice.name, + "Error: Invalid AaaAuthenticationLoginService #{name} in collection") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, + "Error: Invalid AaaAuthenticationLoginService method for defaultin collection") + assert_empty(aaaauthloginservice.groups, + "Error: Invalid AaaAuthenticationLoginService groups for default in collection") + aaaauthloginservice_detach(aaaauthloginservice, false) + end + aaaauthloginservices_default + end + + def test_aaaauthloginservice_collection_with_service_default_and_console + unconfig_aaa + # preconfig console + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login console none") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + + aaaauthloginservice_list = AaaAuthenticationLoginService.services + refute_empty(aaaauthloginservice_list, + "Error: AAA Authentication Login service collection is not filled") + assert_equal(2, aaaauthloginservice_list.size, + "Error: AAA Authentication Login collection not reporting correct size") + assert(aaaauthloginservice_list.key?("default"), + "Error: AAA Authentication Login collection does contain default") + assert(aaaauthloginservice_list.key?("console"), + "Error: AAA Authentication Login collection does contain console") + aaaauthloginservice_list.each do |name, aaaauthloginservice| + assert_equal(name, aaaauthloginservice.name, + "Error: Invalid AaaAuthenticationLoginService #{name} in collection") + if name == "default" + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice.method, + "Error: Invalid AaaAuthLoginService method for default in " + + "collection (see CSCuu29429)") + end + + if name == "console" + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, + "Error: Invalid AaaAuthLoginService method for console in collection") + end + + assert_equal([], aaaauthloginservice.groups, + "Error: Invalid AaaAuthLoginService groups for default in collection") + aaaauthloginservice_detach(aaaauthloginservice, false) + end + aaaauthloginservices_default + end + + def test_aaaauthloginservice_collection_with_service_default_and_console_with_group + # preconfig servers + servers = %w(group1 group2) + config_tacacs_servers(servers) + + # preconfig console + s = @device.cmd("configure terminal") + # we need in some specific order + s = @device.cmd("aaa authentication login default group group2 group1 none") + s = @device.cmd("aaa authentication login console group group1") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + + aaaauthloginservice_list = AaaAuthenticationLoginService.services + refute_empty(aaaauthloginservice_list, + "Error: AAA Authentication Login service collection is not filled") + assert_equal(2, aaaauthloginservice_list.size, + "Error: AAA Authentication Login collection not reporting correct size") + assert(aaaauthloginservice_list.key?("default"), + "Error: AAA Authentication Login collection does contain default") + assert(aaaauthloginservice_list.key?("console"), + "Error: AAA Authentication Login collection does contain console") + aaaauthloginservice_list.each do |name, aaaauthloginservice| + assert_equal(name, aaaauthloginservice.name, + "Error: Invalid AaaAuthenticationLoginService #{name} in collection") + + if name == "default" + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, + "Error: Invalid method for default in collection") + groups = %w(group2 group1) + assert_equal(groups, aaaauthloginservice.groups, + "Error: Invalid groups for default in collection") + end + + if name == "console" + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice.method, + "Error: Invalid AaaAuthenticationLoginService method for console " + + "in collection (see CSCuu29429)") + groups = ["group1"] + assert_equal(groups, aaaauthloginservice.groups, + "Error: Invalid AaaAuthenticationLoginService groups for default in collection") + end + aaaauthloginservice_detach(aaaauthloginservice, false) + end + aaaauthloginservices_default + unconfig_tacacs + end + + def test_aaaauthloginservice_service_default_get_method + aaaauthloginservice = + AaaAuthenticationLoginService.new("default") + + # default case + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, + "Error: AAA authentication login service default get method for local") + + # preconfig default + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login default none") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, + "Error: AAA authentication login service default get method for none") + + # preconfig servers + servers = %w(bxb100 bxb200) + config_tacacs_servers(servers) + + # preconfig default + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login default group bxb100 bxb200") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice.method, + "Error: AAA authentication login service default get method for group unselected") + + # preconfig default + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login default group bxb200 none") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, + "Error: AAA authentication login service default get method for group and none") + + # cleanup + aaaauthloginservice_detach(aaaauthloginservice) + unconfig_tacacs + end + + def test_aaaauthloginservice_service_console_get_method + aaaauthloginservice = AaaAuthenticationLoginService.new("console") + + # default case + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, + "Error: AAA authentication login service console get method for local") + + # preconfig console + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login console none") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, + "Error: AAA authentication login service console get method for none") + + # preconfig servers + servers = %w(bxb100 bxb200) + config_tacacs_servers(servers) + + # preconfig console + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login console group bxb100 bxb200") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice.method, + "Error: AAA authentication login service console get method for " + + "group unselected (see CSCuu29429)") + + # preconfig console + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login console group bxb200 none") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, + "Error: AAA authentication login service console get method for group and none") + + # cleanup + aaaauthloginservice_detach(aaaauthloginservice) + unconfig_tacacs + end + + def test_aaaauthloginservice_get_default_method + # service default + aaaauthloginservice = + AaaAuthenticationLoginService.new("default") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice.default_method, + "Error: AAA authentication login service default, default method") + aaaauthloginservice_detach(aaaauthloginservice) + + # service console + aaaauthloginservice = + AaaAuthenticationLoginService.new("console") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice.default_method, + "Error: AAA authentication login service console, default method") + aaaauthloginservice_detach(aaaauthloginservice, false) + end + + def test_aaaauthloginservice_service_default_get_groups + aaaauthloginservice = + AaaAuthenticationLoginService.new("default") + + # default case + assert_equal(aaaauthloginservice.default_groups, aaaauthloginservice.groups, + "Error: AAA authentication login service default get groups for default") + + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # preconfig default + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login default group bxb100 sjc200") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + groups = %w(bxb100 sjc200) + assert_equal(groups, aaaauthloginservice.groups, + "Error: AAA authentication login service default get groups") + + # preconfig default + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login default group sjc200 bxb100 rtp10 none") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + groups = %w(sjc200 bxb100 rtp10) + assert_equal(groups, aaaauthloginservice.groups, + "Error: AAA authentication login service default get groups") + + # cleanup + aaaauthloginservice_detach(aaaauthloginservice) + unconfig_tacacs + end + + def test_aaaauthloginservice_service_console_get_groups + aaaauthloginservice = + AaaAuthenticationLoginService.new("console") + + # default case + assert_equal(aaaauthloginservice.default_groups, aaaauthloginservice.groups, + "Error: AAA authentication login service console get groups for default") + + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # preconfig console + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login console group bxb100 sjc200") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + groups = %w(bxb100 sjc200) + assert_equal(groups, aaaauthloginservice.groups, + "Error: AAA authentication login service console get groups #{groups}" + + " (see CSCuu29429)") + + # preconfig console + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login console group rtp10 bxb100 none") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + groups = %w(rtp10 bxb100) + assert_equal(groups, aaaauthloginservice.groups, + "Error: AAA authentication login service console get groups #{groups}") + + # preconfig console + s = @device.cmd("configure terminal") + s = @device.cmd("aaa authentication login console group sjc200 bxb100 rtp10") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + groups = %w(sjc200 bxb100 rtp10) + assert_equal(groups, aaaauthloginservice.groups, + "Error: AAA authentication login service console get groups #{groups}") + + # cleanup + aaaauthloginservice_detach(aaaauthloginservice) + unconfig_tacacs + end + + def test_aaaauthloginservice_service_default_and_console_mix + aaaauthloginservice_default = + AaaAuthenticationLoginService.new("default") + aaaauthloginservice_console = + AaaAuthenticationLoginService.new("console") + + # default cases + assert_equal(aaaauthloginservice_default.default_groups, + aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups default") + assert_equal(aaaauthloginservice_console.default_groups, + aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups default") + assert_equal(aaaauthloginservice_default.default_method, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method default") + assert_equal(aaaauthloginservice_console.default_method, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method default") + + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + groups = %w(bxb100 sjc200) + aaaauthloginservice_default.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED) + + assert_equal(groups, aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups #{groups}") + assert_empty(aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups non empty") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method") + + # set groups + aaaauthloginservice_default.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + aaaauthloginservice_console.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + + # get + assert(aaaauthloginservice_default.groups.empty?, + "Error: AAA authentication login default ,get groups non empty") + assert_empty(aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups empty") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method none") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method none") + + # set groups + aaaauthloginservice_default.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + aaaauthloginservice_console.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + + # get + assert_empty(aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups non-empty") + assert_empty(aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups non-empty") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method local") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method local") + + # set groups + aaaauthloginservice_default.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + aaaauthloginservice_console.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + + # get + assert_empty(aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups non-empty") + assert_empty(aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups non-empty") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method none") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method local") + + # set groups + aaaauthloginservice_default.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + aaaauthloginservice_console.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + + # get + assert_empty(aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups non-empty") + assert_empty(aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups non-empty") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method local") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method none") + + # set groups + groups_default = ["bxb100"] + groups_console = %w(bxb100 sjc200) + # CSCuu29429 + begin + aaaauthloginservice_default.groups_method_set( + groups_default, AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED) + aaaauthloginservice_console.groups_method_set( + groups_console, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + rescue Exception => e + raise e.message + " (see CSCuu29429)" + end + + # get + assert_equal(groups_default, + aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups #{groups}") + assert_equal(groups_console, + aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups #{groups}") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method local") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method none") + + # set same groups and method + groups = ["bxb100"] + aaaauthloginservice_default.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + aaaauthloginservice_console.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + # get + assert_equal(groups, + aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups #{groups}") + assert_equal(groups, + aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups #{groups}") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method none") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method none") + + # set group for console and empty for default + groups = %w(bxb100 rtp10) + aaaauthloginservice_default.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + aaaauthloginservice_console.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + + # get + assert_empty(aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups non empty") + assert_equal(groups, + aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups #{groups}") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method local") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method none") + + # set groups for default and empty for console + groups = %w(bxb100 rtp10) + aaaauthloginservice_default.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + aaaauthloginservice_console.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + + # get + assert_equal(groups, + aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups #{groups}") + assert_empty(aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups non-empty") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method none") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method local") + + # set group for default and empty for console, same methos none + groups = %w(bxb100 rtp10) + aaaauthloginservice_default.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + aaaauthloginservice_console.groups_method_set( + [], AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + + # get + assert_equal(groups, + aaaauthloginservice_default.groups, + "Error: AAA authentication login default, get groups #{groups}") + assert_empty(aaaauthloginservice_console.groups, + "Error: AAA authentication login console, get groups non-empty") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_default.method, + "Error: AAA authentication login default, get method none") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice_console.method, + "Error: AAA authentication login console, get method none") + + # cleanup + aaaauthloginservice_detach(aaaauthloginservice_default) + aaaauthloginservice_detach(aaaauthloginservice_console) + unconfig_tacacs + end + + def test_aaaauthloginservice_get_default_groups + # service default + aaaauthloginservice = + AaaAuthenticationLoginService.new("default") + assert_empty(aaaauthloginservice.default_groups, + "Error: AAA authentication login default, default groups") + aaaauthloginservice_detach(aaaauthloginservice) + + # service console + aaaauthloginservice = + AaaAuthenticationLoginService.new("console") + assert_empty(aaaauthloginservice.default_groups, + "Error: AAA authentication login console, default groups") + aaaauthloginservice_detach(aaaauthloginservice) + end + + def test_aaaauthloginservice_service_default_set_groups + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # service default + service = "default" + aaaauthloginservice = + AaaAuthenticationLoginService.new(service) + + # one group and method is unselected + method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED + groups = ["bxb100"] + aaaauthloginservice.groups_method_set(groups, method) + match = "#{service} group bxb100" + line = get_match_line(match) + refute_nil(line, + "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + + # multiple group and method is unselected + method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED + groups = %w(bxb100 sjc200) + aaaauthloginservice.groups_method_set(groups, method) + match = "#{service} group bxb100 sjc200" + line = get_match_line(match) + refute_nil(line, + "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + + # multi group and method is none + method = AAA_AUTH_LOGIN_SERVICE_METHOD_NONE + groups = %w(rtp10 bxb100 sjc200) + aaaauthloginservice.groups_method_set(groups, method) + match = "#{service} group rtp10 bxb100 sjc200 none" + line = get_match_line(match) + refute_nil(line, + "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + + # default group and method + method = aaaauthloginservice.default_method + groups = aaaauthloginservice.default_groups + aaaauthloginservice.groups_method_set(groups, method) + match = "#{service} local" + line = get_match_line(match) + refute_nil(line, + "Error: AAA authentication login #{service}, set default groups and method") + + aaaauthloginservice_detach(aaaauthloginservice) + unconfig_tacacs + end + + def test_aaaauthloginservice_service_console_set_groups + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # service console + service = "console" + aaaauthloginservice = + AaaAuthenticationLoginService.new(service) + + # one group and method is unselected + method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED + groups = ["bxb100"] + # CSCuu29429 + begin + aaaauthloginservice.groups_method_set(groups, method) + rescue Exception => e + raise e.message + " (see CSCuu29429)" + end + match = "#{service} group bxb100" + line = get_match_line(match) + refute_nil(line, + "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + + # multi group and method is unselected + method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED + groups = %w(bxb100 sjc200) + aaaauthloginservice.groups_method_set(groups, method) + match = "#{service} group bxb100 sjc200" + line = get_match_line(match) + refute_nil(line, + "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + + # multi group and method is none + method = AAA_AUTH_LOGIN_SERVICE_METHOD_NONE + groups = %w(rtp10 bxb100 sjc200) + aaaauthloginservice.groups_method_set(groups, method) + match = "#{service} group rtp10 bxb100 sjc200 none" + line = get_match_line(match) + refute_nil(line, + "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + + # default group and method + method = aaaauthloginservice.default_method + groups = aaaauthloginservice.default_groups + aaaauthloginservice.groups_method_set(groups, method) + match = "#{service} local" + line = get_match_line(match) + assert_nil(line, + "Error: AAA authentication login #{service}, set default groups and method") + + aaaauthloginservice_detach(aaaauthloginservice) + unconfig_tacacs + end + + def test_aaaauthloginservice_service_set_groups_invalid_groups + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # service default + service = "default" + aaaauthloginservice = + AaaAuthenticationLoginService.new(service) + + # one invalid group + groups = ["test1"] + assert_raises(RuntimeError) do + aaaauthloginservice.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + end + + # multiple groups with invalid group + groups = %w(rtp10 test2 bxb100) + assert_raises(RuntimeError, "(see CSCuu63677)") do + aaaauthloginservice.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + end + + # multiple groups with invalid group + groups = %w(test4 test2 bxb100) + assert_raises(RuntimeError) do + aaaauthloginservice.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + end + + # invalid array + groups = ["bxb100", 100, "bxb100"] + assert_raises(TypeError) do + aaaauthloginservice.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + end + aaaauthloginservice_detach(aaaauthloginservice) + + # repeat the test for service 'console' + service = "console" + aaaauthloginservice = + AaaAuthenticationLoginService.new(service) + + # one invalid group + groups = ["test1"] + assert_raises(RuntimeError) do + aaaauthloginservice.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED) + end + + # multiple group with invalid group + groups = %w(rtp1 test1 bxb100) + assert_raises(RuntimeError) do + aaaauthloginservice.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) + end + + # multiple group with invalid group + groups = %w(rtp10 test1 bxb100) + assert_raises(RuntimeError) do + aaaauthloginservice.groups_method_set( + groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) + end + aaaauthloginservice_detach(aaaauthloginservice) + unconfig_tacacs + end + + def test_aaaauthloginservice_service_set_groups_invalid_method + # service default + service = "default" + aaaauthloginservice = + AaaAuthenticationLoginService.new(service) + + assert_raises(TypeError) do + aaaauthloginservice.groups_method_set([], "bxb100") + end + + assert_raises(ArgumentError) do + aaaauthloginservice.groups_method_set([], :invalid) + end + + aaaauthloginservice_detach(aaaauthloginservice) + + # service console + service = "console" + aaaauthloginservice = + AaaAuthenticationLoginService.new(service) + + assert_raises(TypeError) do + aaaauthloginservice.groups_method_set([], "test") + end + + assert_raises(TypeError) do + aaaauthloginservice.groups_method_set([], 15) + end + + aaaauthloginservice_detach(aaaauthloginservice) + end +end diff --git a/tests/test_aaa_server_group.rb b/tests/test_aaa_server_group.rb new file mode 100644 index 00000000..486811c6 --- /dev/null +++ b/tests/test_aaa_server_group.rb @@ -0,0 +1,628 @@ +# Copyright (c) 2014-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.expand_path("../ciscotest", __FILE__) +require File.expand_path("../../lib/cisco_node_utils/aaa_server_group", __FILE__) +require File.expand_path("../../lib/cisco_node_utils/tacacs_server_host", __FILE__) + +AAA_SERVER_GROUP_TACACS_SERVER = :tacacs +AAA_SERVER_GROUP_RADIUS_SERVER = :radius +DEFAULT_AAA_SERVER_GROUP_VRF = "default" +DEFAULT_AAA_SERVER_GROUP_DEADTIME = 0 +DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE = "" + +class TestAaaServerGroup < CiscoTestCase + def clean_tacacs_config + @device.cmd("configure terminal") + @device.cmd("no feature tacacs") + @device.cmd("feature tacacs") + @device.cmd("end") + end + + def create_tacacsserverhost(name="defaulttest") + tacacs_server_host = TacacsServerHost.new(name) + end + + def detach_tacacsserverhost(host) + host.destroy + end + + def detach_aaaservergroup(aaa_server_group) + aaa_server_group.destroy + end + + def create_aaa_group(group_name, server) + s = @device.cmd("configure terminal") + s = @device.cmd("aaa group server #{server} #{group_name}") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def destroy_aaa_group(group_name, server) + s = @device.cmd("configure terminal") + s = @device.cmd("no aaa group server #{server} #{group_name}") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def create_vrf(group_name, server, vrf_name) + s = @device.cmd("configure terminal") + s = @device.cmd("aaa group server #{server} #{group_name}") + s = @device.cmd("use-vrf #{vrf_name}") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def create_deadtime(group_name, server, deadtime) + s = @device.cmd("configure terminal") + s = @device.cmd("aaa group server #{server} #{group_name}") + s = @device.cmd("deadtime #{deadtime}") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def create_source_interface(group_name, server, interface) + s = @device.cmd("configure terminal") + s = @device.cmd("aaa group server #{server} #{group_name}") + s = @device.cmd("source-interface #{interface}") + s = @device.cmd("end") + # Flush the cache since we've modified the device + node.cache_flush + end + + def get_match_line(name) + s = @device.cmd("show run tacacs+ all | no-more") + line = /#{name}/.match(s) + end + + def get_match_line_group_tacacs(name) + s = @device.cmd("show run tacacs+ all | no-more") + prefix = "aaa group server tacacs+ #{name}" + puts prefix + line = /#{prefix}/.match(s) + puts line + end + + def test_aaaservergroup_create_invalid_type + assert_raises(TypeError) do + aaa_group = AaaServerGroup.new(node, "Group1") + end + end + + def test_aaaservergroup_create_invalid_name_tacacs + assert_raises(TypeError) do + aaa_group = AaaServerGroup.new(nil, nil) + end + end + + def test_aaaservergroup_create_invalid_name_radius + # TBD + end + + def test_aaaservergroup_create_valid_tacacs + group_name = "Group1" + aaa_group = AaaServerGroup.new(group_name, :tacacs) + + # Verify groups is created + line = get_match_line("#{group_name}") + sh_run_group = line.to_s.split(" ").last + refute_nil(line, "Error: Group not configured") + assert_equal(sh_run_group, sh_run_group, + "Error: #{group_name} not configured") + + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_create_valid_radius + # TBD + end + + def test_aaaservergroup_create_valid_multiple_tacacs + group_name1 = "Group1" + group_name2 = "Group2" + aaa_group1 = AaaServerGroup.new(group_name1, :tacacs) + aaa_group2 = AaaServerGroup.new(group_name2, :tacacs) + + line = get_match_line("#{group_name1}") + sh_run_group = line.to_s.split(" ").last + refute_nil(line, "Error: Group not configured") + assert_equal(sh_run_group, group_name1, + "Error: #{group_name1} not configured") + line = get_match_line("#{group_name2}") + sh_run_group = line.to_s.split(" ").last + assert_equal(sh_run_group, group_name2, + "Error: #{group_name2} not configured") + + detach_aaaservergroup(aaa_group1) + detach_aaaservergroup(aaa_group2) + end + + def test_aaaservergroup_create_valid_multiple_radius + # TBD + end + + def test_aaaservergroup_get_parent_radius + # TBD + end + + def test_aaaservergroup_collection_empty_tacacs + clean_tacacs_config + aaa_group_list = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) + assert_empty(aaa_group_list, + "Error: AaaServerGroup collection is not empty") + end + + def test_aaaservergroup_collection_empty_radius + # TBD + end + + def test_aaaservergroup_collection_invalid_nil_radius + # TBD + end + + def test_aaaservergroup_collection_invalid_tacacs + assert_raises(TypeError) do + aaa_group_list = AaaServerGroup.groups("TEST") + end + end + + def test_aaaservergroup_collection_invalid_radius + # TBD + end + + def test_aaaservergroup_collection_single_tacacs + clean_tacacs_config + group_name1 = "Group1" + group_name2 = "Group2" + group_name3 = "Group3" + aaa_group1 = AaaServerGroup.new(group_name1, :tacacs) + + groups = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) + refute_empty(groups, "Error: AaaServerGroup collection is not filled") + assert_equal(1, groups.size, + "Error: AaaServerGroup collection not reporting correct size") + assert(groups.key?(group_name1), + "Error: AaaServerGroup collection does contain #{group_name1}") + detach_aaaservergroup(aaa_group1) + + create_aaa_group(group_name2, "tacacs+") + create_aaa_group(group_name3, "tacacs+") + groups = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) + refute_empty(groups, "Error: AaaServerGroup collection is not filled") + assert_equal(2, groups.size, + "Error: AaaServerGroup collection not reporting correct size") + assert(groups.key?(group_name2), + "Error: AaaServerGroup collection does contain #{group_name2}") + assert(groups.key?(group_name3), + "Error: AaaServerGroup collection does contain #{group_name3}") + + destroy_aaa_group(group_name2, "tacacs+") + destroy_aaa_group(group_name3, "tacacs+") + end + + def test_aaaservergroup_collection_single_radius + # TBD + end + + def test_aaaservergroup_collection_multi_tacacs + clean_tacacs_config + group_name1 = "Group1" + group_name2 = "Group2" + group_name3 = "Group3" + aaa_group1 = AaaServerGroup.new(group_name1, :tacacs) + + aaa_group2 = AaaServerGroup.new(group_name2, :tacacs) + + aaa_group3 = AaaServerGroup.new(group_name3, :tacacs) + + groups = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) + refute_empty(groups, "Error: AaaServerGroup collection is not filled") + assert_equal(3, groups.size, + "Error: AaaServerGroup collection not reporting correct size") + assert(groups.key?(group_name1), + "Error: AaaServerGroup collection does contain #{group_name1}") + assert(groups.key?(group_name2), + "Error: AaaServerGroup collection does contain #{group_name2}") + assert(groups.key?(group_name3), + "Error: AaaServerGroup collection does contain #{group_name3}") + + detach_aaaservergroup(aaa_group1) + detach_aaaservergroup(aaa_group2) + detach_aaaservergroup(aaa_group3) + end + + def test_aaaservergroup_collection_multi_radius + # TBD + end + + def test_aaaservergroup_servers_tacacs + clean_tacacs_config + server_name1 = "server1" + server_name2 = "server2" + server1 = create_tacacsserverhost(server_name1) + server2 = create_tacacsserverhost(server_name2) + + aaa_group = AaaServerGroup.new("Group1", :tacacs) + + # pre check that default servers are empty + default_server = AaaServerGroup.default_servers + assert_empty(default_server, "Error: Default Servers are not empty") + + aaa_group.servers = [server_name1, server_name2] + + # Check collection size + servers = aaa_group.servers.keys + assert_equal(2, servers.size(), + "Error: Collection is not two servers") + assert(servers.include?('server1'), + "Error: Collection does not contain #{server_name1}") + assert(servers.include?('server2'), + "Error: Collection does not contain #{server_name2}") + + detach_aaaservergroup(aaa_group) + detach_tacacsserverhost(server1) + detach_tacacsserverhost(server2) + end + + def test_aaaservergroup_servers_radius + # TBD + end + + def test_aaaservergroup_add_server_tacacs + server_name1 = "server1" + server_name2 = "server2" + server1 = create_tacacsserverhost(server_name1) + server2 = create_tacacsserverhost(server_name2) + + aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group.servers = [server_name1, server_name2] + + line = get_match_line("server #{server_name1}") + sh_run_server = line.to_s.split(" ").last + refute_nil(line, "Error: Server not configured") + assert_equal(sh_run_server, server_name1, + "Error: #{server_name1} not configured") + line = get_match_line("server #{server_name2}") + sh_run_server = line.to_s.split(" ").last + assert_equal(sh_run_server, server_name2, + "Error: #{server_name2} not configured") + + detach_aaaservergroup(aaa_group) + detach_tacacsserverhost(server1) + detach_tacacsserverhost(server2) + end + + def test_aaaservergroup_add_server_radius + # TBD + end + + def test_aaaservergroup_add_server_twice_tacacs + clean_tacacs_config + server_name1 = "server1" + server_name2 = "server2" + server1 = create_tacacsserverhost(server_name1) + server2 = create_tacacsserverhost(server_name2) + + aaa_group = AaaServerGroup.new("Group1", :tacacs) + # aaa_group.servers = [server_name1, server_name2, server_name2] + # this behavior is different on n9k vs n3k, so comment out for now + # n3k throws a CLIError and n9k silently ignores + aaa_group.servers = [server_name1, server_name2] + + servers = aaa_group.servers + assert_equal(2, servers.size(), + "Error: Collection is not two servers") + + line = get_match_line("server #{server_name1}") + sh_run_server = line.to_s.split(" ").last + assert_equal(false, line.nil?, + "Error: Server not configured") + assert_equal(sh_run_server, server_name1, + "Error: #{server_name1} not configured") + line = get_match_line("server #{server_name2}") + sh_run_server = line.to_s.split(" ").last + assert_equal(sh_run_server, server_name2, + "Error: #{server_name2} not configured") + + detach_aaaservergroup(aaa_group) + detach_tacacsserverhost(server1) + detach_tacacsserverhost(server2) + end + + def test_aaaservergroup_add_server_twice_radius + # TBD + end + + def test_aaaservergroup_remove_server_tacacs + clean_tacacs_config + server_name1 = "server1" + server_name2 = "server2" + server1 = create_tacacsserverhost(server_name1) + server2 = create_tacacsserverhost(server_name2) + + aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group.servers = [server_name1, server_name2] + + # Check collection size + servers = aaa_group.servers + assert_equal(2, servers.size(), + "Error: Collection is not two servers") + + # Now remove them and then check again + aaa_group.servers = [server_name2] + line = get_match_line("server #{server_name1}") + sh_run_server = line.to_s.split(" ").last + assert_nil(line, "Error: Server not unconfigured") + + aaa_group.servers = [] + line = get_match_line("server #{server_name2}") + sh_run_server = line.to_s.split(" ").last + assert_nil(line, "Error: Server not unconfigured") + + detach_aaaservergroup(aaa_group) + detach_tacacsserverhost(server1) + detach_tacacsserverhost(server2) + end + + def test_aaaservergroup_remove_server_radius + # TBD + end + + def test_aaaservergroup_remove_server_twice_tacacs + clean_tacacs_config + server_name1 = "server1" + server_name2 = "server2" + server1 = create_tacacsserverhost(server_name1) + server2 = create_tacacsserverhost(server_name2) + + aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group.servers = [server_name1, server_name2] + + # Check collection size + servers = aaa_group.servers + assert_equal(2, servers.size(), + "Error: Collection is not two servers") + + # Now remove them and then check again + aaa_group.servers = [server_name2] + line = get_match_line("server #{server_name1}") + sh_run_server = line.to_s.split(" ").last + assert_nil(line, "Error: Server not unconfigured") + + # Now remove server 1 again + aaa_group.servers = [] + line = get_match_line("server #{server_name2}") + sh_run_server = line.to_s.split(" ").last + assert_nil(line, "Error: Server not unconfigured") + + # Check collection size + servers = aaa_group.servers + assert_empty(servers, "Error: Collection not empty") + + detach_aaaservergroup(aaa_group) + detach_tacacsserverhost(server1) + detach_tacacsserverhost(server2) + end + + def test_aaaservergroup_remove_server_twice_radius + # TBD + end + + def test_aaaservergroup_get_vrf_tacacs + group_name1 = "Group1" + aaa_group = AaaServerGroup.new(group_name1, :tacacs) + + vrf = DEFAULT_AAA_SERVER_GROUP_VRF + assert_equal(vrf, aaa_group.vrf, + "Error: AaaServerGroup, vrf not default") + + vrf = "TESTME" + create_vrf(group_name1, "tacacs+", vrf) + assert_equal(vrf, aaa_group.vrf, + "Error: AaaServerGroup, vrf not configured") + + vrf = DEFAULT_AAA_SERVER_GROUP_VRF + aaa_group.vrf = vrf + assert_equal(vrf, aaa_group.vrf, + "Error: AaaServerGroup, vrf not restored to default") + + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_get_vrf_radius + # TBD + end + + def test_aaaservergroup_get_default_vrf_tacacs + aaa_group = AaaServerGroup.new("Group1", :tacacs) + assert_equal(DEFAULT_AAA_SERVER_GROUP_VRF, + AaaServerGroup.default_vrf, + "Error: AaaServerGroup, default vrf incorrect") + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_get_default_vrf_radius + # TBD + end + + def test_aaaservergroup_set_vrf_tacacs + vrf = "management-123" + aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group.vrf = vrf + line = get_match_line("use-vrf #{vrf}") + # Extract deadtime + sh_run_vrf = line.to_s.split(" ").last + # puts sh_run_vrf + refute_nil(line, "Error: AaaServerGroup, vrf not configured") + assert_equal(sh_run_vrf, aaa_group.vrf, + "Error: AaaServerGroup, vrf incorrect") + # Invalid case + vrf = 2450 + assert_raises(TypeError) do + aaa_group.vrf = vrf + end + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_set_vrf_radius + # TBD + end + + def test_aaaservergroup_get_deadtime_tacacs + group_name = "Group1" + aaa_group = AaaServerGroup.new(group_name, :tacacs) + + deadtime = DEFAULT_AAA_SERVER_GROUP_DEADTIME + assert_equal(deadtime, aaa_group.deadtime, + "Error: AaaServerGroup, deadtime not default") + + deadtime = 850 + create_deadtime(group_name, "tacacs+", deadtime) + assert_equal(deadtime, aaa_group.deadtime, + "Error: AaaServerGroup, deadtime not configured") + + deadtime = DEFAULT_AAA_SERVER_GROUP_DEADTIME + aaa_group.deadtime = deadtime + assert_equal(deadtime, aaa_group.deadtime, + "Error: AaaServerGroup, deadtime not restored to default") + + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_get_deadtime_radius + # TBD + end + + def test_aaaservergroup_get_default_deadtime_tacacs + aaa_group = AaaServerGroup.new("Group1", :tacacs) + assert_equal(DEFAULT_AAA_SERVER_GROUP_DEADTIME, + AaaServerGroup.default_deadtime, + "Error: AaaServerGroup, default deadtime incorrect") + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_get_default_deadtime_radius + # TBD + end + + def test_aaaservergroup_set_deadtime_tacacs + deadtime = 1250 + aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group.deadtime = deadtime + line = get_match_line("deadtime #{deadtime}") + # Extract deadtime + sh_run_deadtime = line.to_s.split(" ").last.to_i + refute_nil(line, "Error: AaaServerGroup, deadtime not configured") + assert_equal(sh_run_deadtime, aaa_group.deadtime, + "Error: AaaServerGroup, deadtime incorrect") + # Invalid case + deadtime = 2450 + assert_raises(CliError) do + aaa_group.deadtime = deadtime + end + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_set_deadtime_radius + # TBD + end + + def test_aaaservergroup_get_source_interface_tacacs + group_name = "Group1" + aaa_group = AaaServerGroup.new(group_name, :tacacs) + intf = DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE + assert_equal(intf, aaa_group.source_interface, + "Error: AaaServerGroup, source-interface set") + + intf = "Ethernet1/1" + create_source_interface(group_name, "tacacs+", intf) + assert_equal(intf, aaa_group.source_interface, + "Error: AaaServerGroup, source-interface not correct") + + intf = "Ethernet1/32" + create_source_interface(group_name, "tacacs+", intf) + assert_equal(intf, aaa_group.source_interface, + "Error: AaaServerGroup, source-interface not correct") + + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_get_source_interface_radius + # TBD + end + + def test_aaaservergroup_get_default_source_interface_tacacs + aaa_group = AaaServerGroup.new("Group1", :tacacs) + assert_equal(DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE, + AaaServerGroup.default_source_interface, + "Error: Aaa_Group Server, default source-interface incorrect") + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_get_default_source_interface_radius + # TBD + end + + def test_aaaservergroup_set_source_interface_tacacs + intf = DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE + aaa_group = AaaServerGroup.new("Group1", :tacacs) + assert_equal(intf, aaa_group.source_interface, + "Error: Aaa_Group Server, source-interface not default") + + intf = "Ethernet1/1" + aaa_group.source_interface = intf + line = get_match_line("source-interface #{intf}") + # Extract source-interface + sh_run_source_interface = line.to_s.split(" ").last + refute_nil(line, "Error: AaaServerGroup, source-interface not configured") + assert_equal(sh_run_source_interface, aaa_group.source_interface, + "Error: AaaServerGroup, source-interface not correct") + + # Now bring it back to default + intf = DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE + aaa_group.source_interface = intf + line = get_match_line("no source-interface") + refute_nil(line, "Error: AaaServerGroup, source-interface not default") + + # Invalid case + state = true + assert_raises(TypeError) do + aaa_group.source_interface = state + end + + detach_aaaservergroup(aaa_group) + end + + def test_aaaservergroup_set_source_interface_radius + # TBD + end + + def test_aaaservergroup_destroy_tacacs + group_name = "Group1" + aaa_group = AaaServerGroup.new(group_name, :tacacs) + + detach_aaaservergroup(aaa_group) + + line = get_match_line(group_name) + assert_nil(line, "Error: AaaServerGroup, not removed") + end + + def test_aaaservergroup_destroy_radius + # TBD + end +end diff --git a/tests/test_all_cisco.rb b/tests/test_all_cisco.rb index 7e1b27b6..1008d263 100644 --- a/tests/test_all_cisco.rb +++ b/tests/test_all_cisco.rb @@ -27,6 +27,9 @@ require File.expand_path("../test_node_ext", __FILE__) # Feature tests - please keep in alphabetical order +require File.expand_path("../test_aaa_authentication_login", __FILE__) +require File.expand_path("../test_aaa_authentication_login_service", __FILE__) +require File.expand_path("../test_aaa_server_group", __FILE__) require File.expand_path("../test_command_config", __FILE__) require File.expand_path("../test_interface", __FILE__) require File.expand_path("../test_interface_ospf", __FILE__) From c51e77e970b79fe029f15410bbaf389f0e9a53a4 Mon Sep 17 00:00:00 2001 From: ahunsber Date: Wed, 24 Jun 2015 16:47:00 -0400 Subject: [PATCH 002/386] don't try to remove aaa authentication service default local config --- lib/cisco_node_utils/aaa_authentication_login_service.rb | 8 ++++++-- tests/test_aaa_authentication_login_service.rb | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/cisco_node_utils/aaa_authentication_login_service.rb b/lib/cisco_node_utils/aaa_authentication_login_service.rb index 29865673..d3f0ad6c 100644 --- a/lib/cisco_node_utils/aaa_authentication_login_service.rb +++ b/lib/cisco_node_utils/aaa_authentication_login_service.rb @@ -58,8 +58,11 @@ def destroy g_str = groups.join(" ") if g_str.empty? - @@node.config_set("aaa_auth_login_service", "method", - "no", @name, m_str) + # cannot remove default local, so do nothing in this case + unless m == :local and @name == "default" + @@node.config_set("aaa_auth_login_service", "method", + "no", @name, m_str) + end else @@node.config_set("aaa_auth_login_service", "groups", "no", @name, g_str, m_str) @@ -109,6 +112,7 @@ def default_method # none | local | group [none] def groups_method_set(grps, m) raise TypeError unless grps.is_a? Array + raise TypeError unless grps.all? { |x| x.is_a? String } raise TypeError unless m.is_a? Symbol # only the following 3 are supported (unselected = blank) raise ArgumentError unless [:none, :local, :unselected].include? m diff --git a/tests/test_aaa_authentication_login_service.rb b/tests/test_aaa_authentication_login_service.rb index 955cb448..a38a7750 100644 --- a/tests/test_aaa_authentication_login_service.rb +++ b/tests/test_aaa_authentication_login_service.rb @@ -772,14 +772,14 @@ def test_aaaauthloginservice_service_set_groups_invalid_groups # multiple groups with invalid group groups = %w(rtp10 test2 bxb100) - assert_raises(RuntimeError, "(see CSCuu63677)") do + assert_raises(CliError) do aaaauthloginservice.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) end # multiple groups with invalid group groups = %w(test4 test2 bxb100) - assert_raises(RuntimeError) do + assert_raises(CliError) do aaaauthloginservice.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) end @@ -799,7 +799,7 @@ def test_aaaauthloginservice_service_set_groups_invalid_groups # one invalid group groups = ["test1"] - assert_raises(RuntimeError) do + assert_raises(CliError) do aaaauthloginservice.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED) end @@ -813,7 +813,7 @@ def test_aaaauthloginservice_service_set_groups_invalid_groups # multiple group with invalid group groups = %w(rtp10 test1 bxb100) - assert_raises(RuntimeError) do + assert_raises(CliError) do aaaauthloginservice.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) end From cb3569d4ddf446047e21306a824c08f380a552ae Mon Sep 17 00:00:00 2001 From: Chris Van Heuveln Date: Wed, 14 Oct 2015 15:17:27 -0400 Subject: [PATCH 003/386] Initial vxlan code drop from deepak rubocop 99% clean --- lib/cisco_node_utils.rb | 9 +- .../command_reference_common.yaml | 121 ++++++---- lib/cisco_node_utils/features.rb | 131 +++++++++++ lib/cisco_node_utils/interface.rb | 40 +++- lib/cisco_node_utils/pim.rb | 158 +++++++++++++ lib/cisco_node_utils/vlan.rb | 32 +++ lib/cisco_node_utils/vni.rb | 197 ++++++++++++++++ lib/cisco_node_utils/vxlan_vtep.rb | 217 ++++++++++++++++++ 8 files changed, 848 insertions(+), 57 deletions(-) create mode 100644 lib/cisco_node_utils/features.rb create mode 100644 lib/cisco_node_utils/pim.rb create mode 100644 lib/cisco_node_utils/vni.rb create mode 100644 lib/cisco_node_utils/vxlan_vtep.rb diff --git a/lib/cisco_node_utils.rb b/lib/cisco_node_utils.rb index 46f377e3..e68933de 100644 --- a/lib/cisco_node_utils.rb +++ b/lib/cisco_node_utils.rb @@ -15,13 +15,12 @@ require 'cisco_node_utils/cisco_cmn_utils' require 'cisco_node_utils/command_reference' require 'cisco_node_utils/configparser_lib' +require 'cisco_node_utils/features' require 'cisco_node_utils/interface' require 'cisco_node_utils/interface_ospf' -require 'cisco_node_utils/name_server' require 'cisco_node_utils/node' require 'cisco_node_utils/node_util' -require 'cisco_node_utils/ntp_config' -require 'cisco_node_utils/ntp_server' +require 'cisco_node_utils/pim' require 'cisco_node_utils/platform' require 'cisco_node_utils/router_ospf' require 'cisco_node_utils/router_ospf_vrf' @@ -29,11 +28,11 @@ require 'cisco_node_utils/snmpgroup' require 'cisco_node_utils/snmpserver' require 'cisco_node_utils/snmpuser' -require 'cisco_node_utils/syslog_server' -require 'cisco_node_utils/syslog_settings' require 'cisco_node_utils/tacacs_server' require 'cisco_node_utils/tacacs_server_host' require 'cisco_node_utils/version' require 'cisco_node_utils/vlan' +require 'cisco_node_utils/vni' require 'cisco_node_utils/vtp' +require 'cisco_node_utils/vxlan_vtep' require 'cisco_node_utils/yum' diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index c339f8bf..b4fce625 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -98,13 +98,6 @@ aaa_server_group: vrf: default_value: "default" -dnsclient: - name_server: - config_get: "show running-config all | include 'ip name-server' | exclude 'use-vrf'" - config_get_token: '/^ip name-server ([\s\d\.:]+)$/' - config_set: ' ip name-server ' - default_value: '' - domain_name: domain_name: # NOTE: This does not account for vrf ip domain-name @@ -240,7 +233,7 @@ interface: '/^negotiate auto$/' ] config_set: ["interface %s", "%s negotiate auto"] - default_value: true + default_value: false test_config_get_regex: [ !ruby/regexp '/^\s+no negotiate auto/', !ruby/regexp '/^\s+negotiate auto/' @@ -252,6 +245,12 @@ interface: false: RuntimeError true: RuntimeError + pim_sparse_mode: + config_get: "show running interface all" + config_get_token: ['/^interface %s$/i', '/^ip pim sparse\-mode$/'] + config_set: ["interface %s", "%s ip pim sparse-mode", "end"] + default_value: false + shutdown: config_get: "show running interface all" config_get_token: ['/^interface %s$/i', '/^shutdown$/'] @@ -459,25 +458,6 @@ inventory: config_get: "show inventory" config_get_token: ["TABLE_inv", "ROW_inv", 0, "vendorid"] -ntp_config: - source_interface: - config_get: "show running-config ntp" - config_get_token: '/^ntp source-interface\s+(.*)$/' - config_set: ' ntp source-interface ' - default_value: '' - -ntp_server: - server: - config_get: "show running-config all | include 'ntp server'" - config_get_token: '/ntp server ((?:[0-9]{1,3}\.){3}[0-9]{1,3})/' - config_set: ' ntp server ' - default_value: '' - - prefer: - config_get: "show running-config all | include 'ntp server(.*)(prefer)'" - config_get_token: '/ntp server ((?:[0-9]{1,3}\.){3}[0-9]{1,3})/' - default_value: '' - memory: total: config_get: 'show system resources' @@ -561,6 +541,40 @@ ospf: config_get_token: ['/^router ospf $/i', '/^vrf\s+(\S+)$/'] config_set: ["router ospf ", " vrf ", "end"] +pim: + all_pim: + config_get: "show running pim all" + config_get_token: '/^ip pim .*/' + + all_pim_vrf: + config_get: "show running pim all" + config_get_token: '/^vrf\s+context\s+(.+)$/i' + + feature: + config_get: 'show feature' + config_get_token: '/^pim\s+\d+\s+(\S+)/' + config_set: "%s feature pim" + + ssm_range: + config_get: "show running pim all" + config_get_token: '/^ip\s+pim\s+ssm\s+range\s+([0-9\.\/]+)$/' + config_set: ["%s ip pim ssm range %s", "end"] + + ssm_range_vrf: + config_get: "show running pim all" + config_get_token: ['/^vrf context %s/i', '/^ip pim ssm\s+range\s+([0-9\.\/]+)$/'] + config_set: ["vrf context %s", "%s ip pim ssm range %s", "end"] + + rp_list: + config_get: "show running pim all" + config_get_token: '/^ip pim rp-address ([0-9\.]*)\s+group-list\s+([0-9\.\/]*(?:bidir)*)$/' + config_set: ["%s ip pim rp-address %s group-list %s", "end"] + + rp_list_vrf: + config_get: "show running pim all" + config_get_token: ['/^vrf context %s/i', '/^ip pim rp-address ([0-9\.]*)\s+group-list\s+([0-9\.\/]*(?:bidir)*)$/'] + config_set: ["vrf context %s", "%s ip pim rp-address %s group-list %s", "end"] + show_system: uptime: config_get: 'show system uptime' @@ -752,30 +766,6 @@ snmp_user: config_get_token: ["TABLE_snmp_users", "ROW_snmp_users"] config_set: "%s snmp-server user %s %s %s %s %s %s" -syslog_settings: - timestamp: - config_get: "show running-config all | include '^logging timestamp'" - config_get_token: '/^logging timestamp (.*)$/' - config_set: ' logging timestamp ' - default_value: 'seconds' - -syslog_server: - server: - config_get: "show running-config all | include '^logging server'" - config_get_token: '/^logging server ((?:[0-9]{1,3}\.){3}[0-9]{1,3}).*/' - config_set: ' logging server ' - default_value: '' - - level: - config_get: "show running-config all | include '^logging server'" - config_get_token: '/^logging server %s (\d).*/' - default_value: '' - - vrf: - config_get: "show running-config all | include '^logging server(.*)(use-vrf)'" - config_get_token: '/^logging server %s.* use-vrf (.*)$/' - default_value: '' - system: resources: config_get: "show system resources" @@ -924,6 +914,35 @@ vtp: test_config_result: 3: "Cisco::CliError" +vxlan: + feature: + config_get: 'show feature' + config_get_token: '/^nve\s+\d+\s+(\S+)/' + config_set: "%s feature nv overlay" + +vxlan_vtep: + all_interfaces: + config_get: 'show running-config interface all' + config_get_token: '/^interface\s+(nve.*)$/' + + mac_distribution: + config_get: 'show running-config interface all' + config_get_token: ['/^interface $/', '/^host-reachability protocol (\S+)/'] + config_set: ['interface ', ' host-reachability protocol ', 'end'] + + member_vni_mgrp: + config_get: 'show running-config interface all' + config_get_token: ['/^interface $/', '/^member vni (\S+)/', '/^mcast-group (\S+)$/'] + config_set: ['interface ', ' member vni ', 'mcast-group ','end'] + + member_vni_arp: + config_set: ['interface ', ' member vni ', 'suppress-arp'] + + source_intf: + config_get: 'show running-config interface' + config_get_token: ['/^interface $/','/^source\-interface (\S+)$/'] + config_set: ['interface ', ' source-interface ', 'end'] + yum: install: config_set: "install add %s %s activate" diff --git a/lib/cisco_node_utils/features.rb b/lib/cisco_node_utils/features.rb new file mode 100644 index 00000000..5c5f2390 --- /dev/null +++ b/lib/cisco_node_utils/features.rb @@ -0,0 +1,131 @@ +# +# NXAPI implementation of Interface class +# +# November 2015, Deepak Cherian +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node_utils') + +# TBD +module Features + def self.included(base) + base.extend(ClassMethods) + end + + # TBD + module ClassMethods + # @@node = Cisco::Node.instance + # debug "@@@@@ Loaded Features node is #{@@node}" + + def fabricpath_feature + debug "In Features node is #{@@node}" + fabricpath = config_get('fabricpath', 'feature') + fail 'fabricpath_feature not found' if fabricpath.nil? + return :disabled if fabricpath.nil? + fabricpath.shift.to_sym + end + + def fabricpath_feature_set(fabricpath_set) + curr = fabricpath_feature + return if curr == fabricpath_set + + case fabricpath_set + when :enabled + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + config_set('fabricpath', 'feature', '') + when :disabled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + return + when :installed + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + when :uninstalled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + config_set('fabricpath', 'feature_install', 'no') + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def vni_feature + debug "In Features node is #{@@node}" + vni = config_get('vni', 'feature') + fail 'vni feature not found' if vni.nil? + return :disabled if vni.nil? + vni.first.to_sym + end + + def vni_feature_set(vni_set) + curr = vni_feature + return if curr == vni_set + + case vni_set + when :enabled + config_set('vni', 'feature', '') + when :disabled + config_set('vni', 'feature', 'no') if curr == :enabled + return + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def vxlan_feature + debug "In Features node is #{@@node}" + vxlan = config_get('vxlan', 'feature') + fail 'vxlan/nv_overlay feature not found' if vxlan.nil? + return :disabled if vxlan.nil? + vxlan.first.to_sym + end + + def vxlan_feature_set(vxlan_set) + curr = vxlan_feature + return if curr == vxlan_set + + case vxlan_set + when :enabled + config_set('vxlan', 'feature', '') + when :disabled + config_set('vxlan', 'feature', 'no') if curr == :enabled + return + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def pim_feature + debug "In Features node is #{@@node}" + pim = config_get('pim', 'feature') + fail 'pim feature not found' if pim.nil? + return :disabled if pim.nil? + pim.first.to_sym + end + + def pim_feature_set(pim_set) + curr = pim_feature + return if curr == pim_set + + case pim_set + when :enabled + config_set('pim', 'feature', '') + when :disabled + config_set('pim', 'feature', 'no') if curr == :enabled + return + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + end # end of module ClassMethods +end # end of module Features diff --git a/lib/cisco_node_utils/interface.rb b/lib/cisco_node_utils/interface.rb index cf22836c..58598593 100644 --- a/lib/cisco_node_utils/interface.rb +++ b/lib/cisco_node_utils/interface.rb @@ -15,6 +15,7 @@ # limitations under the License. require File.join(File.dirname(__FILE__), 'node_util') +require File.join(File.dirname(__FILE__), 'features') # Add some interface-specific constants to the Cisco namespace module Cisco @@ -24,11 +25,13 @@ module Cisco trunk: 'trunk', fex_fabric: 'fex-fabric', tunnel: 'dot1q-tunnel', + fabricpath: 'fabricpath', } # Interface - node utility class for general interface config management class Interface < NodeUtil attr_reader :name + include Features def initialize(name, instantiate=true) fail TypeError unless name.is_a?(String) @@ -100,6 +103,22 @@ def default_description config_get_default('interface', 'description') end + def enable_pim_sparse_mode + state = config_get('interface', 'pim_sparse_mode', @name) + state ? true : false + end + + def enable_pim_sparse_mode=(state) + no_cmd = (state ? '' : 'no') + config_set('interface', 'pim_sparse_mode', @name, no_cmd) + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def default_enable_pim_sparse_mode + config_get_default('interface', pim_sparse_mode) + end + def encapsulation_dot1q val = config_get('interface', 'encapsulation_dot1q', @name) return default_encapsulation_dot1q if val.nil? @@ -120,6 +139,23 @@ def default_encapsulation_dot1q config_get_default('interface', 'encapsulation_dot1q') end + def encapsulation_profile_vni + val = config_get('interface', 'encapsulation_vni', @name) + debug "val from get is #{val}" + return '' if val.nil? + val.first.strip + end + + def encapsulation_profile_vni=(val) + if val.nil? + config_set('interface', 'encapsulation_vni_del', @name, val) + else + config_set('interface', 'encapsulation_vni_add', @name, val) + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + def fex_feature fex = config_get('fex', 'feature') fail 'fex_feature not found' if fex.nil? @@ -401,7 +437,9 @@ def switchport_mode def switchport_enable_and_mode(mode_set) switchport_enable unless switchport - if (:fex_fabric == mode_set) + if (:fabricpath == mode_set) + fabricpath_feature_set(:enabled) unless (:enabled == fabricpath_feature) + elsif (:fex_fabric == mode_set) fex_feature_set(:enabled) unless (:enabled == fex_feature) end config_set('interface', switchport_mode_lookup_string, @name, '', diff --git a/lib/cisco_node_utils/pim.rb b/lib/cisco_node_utils/pim.rb new file mode 100644 index 00000000..35a43bd3 --- /dev/null +++ b/lib/cisco_node_utils/pim.rb @@ -0,0 +1,158 @@ +# +# NXAPI implementation of PIM class +# +# November 2015, Deepak Cherian +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node_util') +require File.join(File.dirname(__FILE__), 'features') + +module Cisco + # node_utils class for Pim + class Pim < NodeUtil + attr_reader :name + + include Features + + def initialize(name, instantiate=true) + fail TypeError unless name.is_a?(String) + fail ArgumentError unless name.length > 0 + @name = name.downcase + + create if instantiate + end + + def self.pims + hash = {} + feature = config_get('pim', 'feature') + return hash if (:enabled != feature.first.to_sym) + pim_list = config_get('pim', 'all_pim') + if !pim_list.nil? + pim_list = ['default'] + else + pim_list = [] + end + # vrf_pim_list = config_get("pim", "all_pim_vrf") + show = show("sh run pim all | inc '^vrf'") + vrf_pim_list = [] + if !show.nil? && show != {} + vrf_pim_list = show.split(/\n/).map do |elem| + match_arr = /\s+context\s+(\S+)/.match(elem) + match_arr[1] + end + end + pim_list.push(*vrf_pim_list) + return hash if pim_list.nil? + + pim_list.each do |id| + id = id.downcase + hash[id] = Pim.new(id, false) + end + hash + end + + def create + pim_feature_set(:enabled) unless (:enabled == pim_feature) + end + + def destroy + pim_feature_set(:disabled) + end + + ######################################################## + # PROPERTIES # + ######################################################## + + def rp_list + final_hash = {} + if @name == 'default' + rp_list_array = config_get('pim', 'rp_list') + else + rp_list_array = config_get('pim', 'rp_list_vrf', @name) + end + final_hash = rp_list_array.to_h unless rp_list_array.nil? + final_hash + end + + def rp_list=(val, prev_val=nil) + debug "val is of class #{val.class} and is #{val} prev is #{prev_val}" + # When prev_val is nil, HashDiff doesn't do a `+' on each element, so this + if prev_val.nil? + val.each do |fresh_rp, fresh_mgrp| + if @name == 'default' + splat_args = ['pim', 'rp_list', '', fresh_rp, fresh_mgrp] + else + splat_args = ['pim', 'rp_list_vrf', @name, '', fresh_rp, fresh_mgrp] + end + config_set(*splat_args) + end + return + end + require 'hashdiff' + hash_diff = HashDiff.diff(prev_val, val) + debug "hsh diff ; #{hash_diff}" + return if hash_diff == [] + if @name == 'default' + splat_args = %w(pim rp_list) + else + splat_args = ['pim', 'rp_list_vrf', @name] + end + hash_diff.each do |diff| + case diff[0] + when /\+/ + splat_args.push '', diff[1], diff[2] + when /\-/ + splat_args.push 'no', diff[1], diff[2] + when /~/ + new_splat_args = splat_args + ['no', diff[1], diff[2]] + config_set(*new_splat_args) + splat_args.push '', diff[1], diff[3] + end + config_set(*splat_args) + end + rescue CliError => e + raise "[vxlan_vtep #{@name}] '#{e.command}' : #{e.clierror}" + end + + def ssm_range + if @name == 'default' + ssm_range_arr = config_get('pim', 'ssm_range') + else + ssm_range_arr = config_get('pim', 'ssm_range_vrf', @name) + end + debug "ssm_range is #{ssm_range_arr}" + return '' if ssm_range_arr.nil? + ssm_range_arr.first.strip + end + + def ssm_range=(val) + fail TypeError unless val.is_a?(String) + if @name == 'default' + splat_args = %w(pim ssm_range) + else + splat_args = ['pim', 'ssm_range_vrf', @name] + end + if val.empty? + splat_args.push('no', val) + else + splat_args.push('', val) + end + config_set(*splat_args) + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + end # Class +end # Module diff --git a/lib/cisco_node_utils/vlan.rb b/lib/cisco_node_utils/vlan.rb index 5e0b9a9e..72ed883d 100644 --- a/lib/cisco_node_utils/vlan.rb +++ b/lib/cisco_node_utils/vlan.rb @@ -24,6 +24,7 @@ module Cisco # Vlan - node utility class for VLAN configuration management class Vlan < NodeUtil attr_reader :name, :vlan_id + include Features def initialize(vlan_id, instantiate=true) @vlan_id = vlan_id.to_s @@ -60,6 +61,37 @@ def cli_error_check(result) fail result[2]['body'] unless result[2]['body'].empty? end + def mode + result = config_get('vlan', 'mode', @vlan_id) + return default_mode if result.nil? + case result.first + when /fabricpath/i + return 'fabricpath' + when /ce/i + return 'ce' + end + end + + def mode=(str) + str = str.to_s + if str.empty? + result = config_set('vlan', 'mode', @vlan_id, 'no', '') + else + if ('fabricpath' == str) + fabricpath_feature_set(:enabled) unless + (:enabled == fabricpath_feature) + end + result = config_set('vlan', 'mode', @vlan_id, '', str) + end + cli_error_check(result) + rescue CliError => e + raise "[vlan #{@vlan_id}] '#{e.command}' : #{e.clierror}" + end + + def default_mode + config_get_default('vlan', 'mode') + end + def vlan_name result = config_get('vlan', 'name', @vlan_id) return default_vlan_name if result.nil? diff --git a/lib/cisco_node_utils/vni.rb b/lib/cisco_node_utils/vni.rb new file mode 100644 index 00000000..c6227501 --- /dev/null +++ b/lib/cisco_node_utils/vni.rb @@ -0,0 +1,197 @@ +# VNI provider class +# +# Deepak Cherian, September 2015 +# +# Copyright (c) 2014-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node_util') +require File.join(File.dirname(__FILE__), 'features') + +module Cisco + # node_utils class for Vni + class Vni < NodeUtil + attr_reader :name, :vni_id + + include Features + + def initialize(vni_id, instantiate=true) + @vni_id = vni_id.to_s + fail ArgumentError, + 'Invalid value(non-numeric VNI id)' unless @vni_id[/^\d+$/] + + create if instantiate + end + + def self.vnis + hash = {} + vni_feature = config_get('vni', 'feature') + return hash if (:enabled != vni_feature.first.to_sym) + vni_list = config_get('vni', 'all_vnis') + return hash if vni_list.nil? || vni_list == {} + + vni_list.each do |id| + hash[id] = Vni.new(id, false) + end + hash + end + + def create + vni_feature_set(:enabled) unless (:enabled == vni_feature) + config_set('vni', 'create', @vni_id) + end + + def destroy + config_set('vni', 'destroy', @vni_id) + end + + def cli_error_check(result) + # The NXOS vni cli does not raise an exception in some conditions and + # instead just displays a STDOUT error message; thus NXAPI does not detect + # the failure and we must catch it by inspecting the "body" hash entry + # returned by NXAPI. This cli behavior is unlikely to change. + fail result[2]['body'] unless result[2]['body'].empty? + end + + def encap_dot1q + final_hash = {} + show = show("sh encapsulation profile | inc 'vni [0-9,]*' p 1") + debug("show class is #{show.class} and show op is #{show}") + return final_hash if show == {} + match_pat = /vni (\S+).*dot1q\s+([ 0-9,\-]+)vni ([ 0-9,\-]+)/m + split_pat = /encapsulation profile / + pair_arr = show.split(split_pat) + pair_arr.each do |pair| + match_arr = match_pat.match(pair) + next if match_arr.nil? + debug "match arr 1 : #{match_arr[1]} 2: #{match_arr[2]} " \ + "3: #{match_arr[3]}" + key_arr = (match_arr[3].split(/,/)).map do |x| + x.strip! + if /-/.match(x) + x.gsub!('-', '..') + else + x + end + end + val_arr = (match_arr[2].split(/,/)).map do |x| + x.strip! + if /-/.match(x) + x.gsub!('-', '..') + else + x + end + end + + debug "key_arr = #{key_arr} val_arr = #{val_arr}" + + index = 0 + value = nil + key_arr.each do |key| + # puts "checking |#{key}| against |#{@vni_id}|" + # puts "checking #{key.class} against #{my_vni.class}" + if /\.\./.match(key) + range = eval(key) ###################### *MUSTFIX* REMOVE eval + if range.include?(@vni_id.to_i) + val_range = eval(val_arr[index]) ##### *MUSTFIX* REMOVE eval + position = @vni_id.to_i - range.begin + value = val_range.begin + position + value = value.to_s + debug "matched #{@vni_id} value is #{value}" + break + end + elsif key == @vni_id + value = val_arr[index] + debug "matched #{key} value is #{value}" + end + index += 1 + end + unless value.nil? + # final_hash[match_arr[1]] = value.to_i + final_hash[match_arr[1]] = value + end + end # pair.each + final_hash + end # end of encap_dot1q + + def encap_dot1q=(val, prev_val=nil) + debug "val is of class #{val.class} and is #{val} prev is #{prev_val}" + # When prev_val is nil, HashDiff doesn't do a `+' on each element, so this + if prev_val.nil? + val.each do |fresh_profile, fresh_dot1q| + config_set('vni', 'encap_dot1q', fresh_profile, '', + fresh_dot1q, @vni_id) + end + return + end + require 'hashdiff' + hash_diff = HashDiff.diff(prev_val, val) + debug "hsh diff ; #{hash_diff}" + return if hash_diff == [] + hash_diff.each do |diff| + result = + case diff[0] + when /\+/ + config_set('vni', 'encap_dot1q', diff[1], '', diff[2], @vni_id) + when /\-/ + config_set('vni', 'encap_dot1q', diff[1], 'no', diff[2], @vni_id) + when /~/ + config_set('vni', 'encap_dot1q', diff[1], 'no', diff[2], @vni_id) + config_set('vni', 'encap_dot1q', diff[1], '', diff[3], @vni_id) + end + cli_error_check(result) + end + rescue CliError => e + raise "[vni #{@vni_id}] '#{e.command}' : #{e.clierror}" + end + + def default_encap_dot1q + config_get_default('vni', 'encap_dot1q') + end + + def bridge_domain + bd_arr = config_get('vni', 'bridge_domain', @vni_id) + bd_arr.first.to_i + end + + def bridge_domain=(val) + no_cmd = (val) ? '' : 'no' + config_set('vni', 'bridge_domain_activate', no_cmd, val) + config_set('vni', 'bridge_domain', val, no_cmd, @vni_id) + end + + def default_bridge_domain + config_get_default('vni', 'bridge_domain') + end + + def shutdown + result = config_get('vni', 'shutdown', @vni_id) + return default_shutdown if result.nil? + # valid result is either: "active"(aka no shutdown) or "shutdown" + result.first[/shut/] ? true : false + end + + def shutdown=(val) + no_cmd = (val) ? '' : 'no' + result = config_set('vni', 'shutdown', @vni_id, no_cmd) + cli_error_check(result) + rescue CliError => e + raise "[vni #{@vni_id}] '#{e.command}' : #{e.clierror}" + end + + def default_shutdown + config_get_default('vni', 'shutdown') + end + end # class +end # module diff --git a/lib/cisco_node_utils/vxlan_vtep.rb b/lib/cisco_node_utils/vxlan_vtep.rb new file mode 100644 index 00000000..c6b851f9 --- /dev/null +++ b/lib/cisco_node_utils/vxlan_vtep.rb @@ -0,0 +1,217 @@ +# +# NXAPI implementation of VXLAN_VTEP class +# +# November 2015, Deepak Cherian +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node_util') +require File.join(File.dirname(__FILE__), 'features') + +module Cisco + # node_utils class for vxlan_vtep + class Vxlan_vtep < NodeUtil ############# *MUSTFIX* CLASS NAME (camelcase) + attr_reader :name + + include Features + + def initialize(name, instantiate=true) + fail TypeError unless name.is_a?(String) + fail ArgumentError unless name.length > 0 + @name = name.downcase + + create if instantiate + end + + def self.vteps + hash = {} + vxlan_feature = config_get('vxlan', 'feature') + return hash if (:enabled != vxlan_feature.first.to_sym) + vtep_list = config_get('vxlan_vtep', 'all_interfaces') + return hash if vtep_list.nil? + + vtep_list.each do |id| + id = id.downcase + hash[id] = Vxlan_vtep.new(id, false) + end + hash + end + + def create + unless (:enabled == vxlan_feature) + vdc_name = config_get('limit_resource', 'vdc') + @apply_to = vdc_name.first + debug("###### VDC is #{@apply_to}") + config_set('limit_resource', 'vxlan', @apply_to) + vxlan_feature_set(:enabled) + end + # re-use the "interface command ref hooks" + config_set('interface', 'create', @name) + end + + def destroy + # re-use the "interface command ref hooks" + config_set('interface', 'destroy', @name) + end + + ######################################################## + # PROPERTIES # + ######################################################## + + def description + desc = config_get('interface', 'description', @name) + return '' if desc.nil? + desc.shift.strip + end + + def description=(desc) + fail TypeError unless desc.is_a?(String) + if desc.empty? + config_set('interface', 'description', @name, 'no', '') + else + config_set('interface', 'description', @name, '', desc) + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def default_description + config_get_default('interface', 'description') + end + + def vni_mcast_grp_map + final_hash = {} + show = show("show running-config interface #{@name}") + debug("show class is #{show.class} and show op is #{show}") + return final_hash if show == {} + match_pat1 = /vni\s+(\S+).*mcast\-group\s+(\S+)/m + match_pat2 = /vni\s+(\S+).*(associate\-vrf)/m + split_pat = /member\s+/ + pair_arr = show.split(split_pat) + pair_arr.each do |pair| + match_arr = match_pat1.match(pair) + match_arr ||= match_pat2.match(pair) + unless match_arr.nil? + debug "match arr 1 : #{match_arr[1]} 2: #{match_arr[2]}" + final_hash[match_arr[1]] = "#{match_arr[2]}" + end + end + final_hash + end + + def vni_mcast_grp_map=(val, prev_val=nil) + debug "val is of class #{val.class} and is #{val} prev is #{prev_val}" + # When prev_val is nil, HashDiff doesn't do a `+' on each element, so this + debug "value of mac_dist = #{@mac_dist_proto}" + param_hash = {} + # supress_arp = (@mac_dist_proto == :evpn) ? "supress-arp" : "" + if prev_val.nil? + val.each do |fresh_vni, fresh_mgrp| + param_hash = { name: @name, no_cmd: '', vni: fresh_vni, + mcast_grp: fresh_mgrp } + config_set('vxlan_vtep', 'member_vni_mgrp', param_hash) + end + return + end + require 'hashdiff' + hash_diff = HashDiff.diff(prev_val, val) + debug "hsh diff ; #{hash_diff}" + return if hash_diff == [] + hash_diff.each do |diff| + case diff[0] + when /\+/ + param_hash = { name: @name, no_cmd: '', vni: diff[1], + mcast_grp: diff[2] } + when /\-/ + param_hash = { name: @name, no_cmd: 'no', vni: diff[1], + mcast_grp: diff[2] } + when /~/ + param_hash = { name: @name, no_cmd: 'no', vni: diff[1], + mcast_grp: diff[2] } + config_set('vxlan_vtep', 'member_vni_mgrp', param_hash) + param_hash = { name: @name, no_cmd: '', vni: diff[1], + mcast_grp: diff[3] } + end + config_set('vxlan_vtep', 'member_vni_mgrp', param_hash) + end + rescue CliError => e + raise "[vxlan_vtep #{@name}] '#{e.command}' : #{e.clierror}" + end + + def mac_distribution + mac_dist = config_get('vxlan_vtep', 'mac_distribution', name: @name) + debug "mac_dist is #{mac_dist}" + if mac_dist.nil? + @mac_dist_proto = :flood + else + @mac_dist_proto = (mac_dist.first.strip == 'bgp') ? :evpn : :flood + end + @mac_dist_proto.to_s + end + + def mac_distribution=(val) + debug "mac_distrib val is #{val} and class is #{val.class}" + if val == :flood + if @mac_dist_proto == :evpn + config_set('vxlan_vtep', 'mac_distribution', + name: @name, no_cmd: 'no', proto: 'bgp') + end + @mac_dist_proto = :flood + elsif val == :evpn + config_set('vxlan_vtep', 'mac_distribution', + name: @name, no_cmd: '', proto: 'bgp') + @mac_dist_proto = :evpn + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def source_interface + src_intf = config_get('vxlan_vtep', 'source_intf', name: @name) + debug "src_intf is #{src_intf}" + return '' if src_intf.nil? + src_intf.first.strip + end + + def source_interface=(val) + fail TypeError unless val.is_a?(String) + if val.empty? + config_set('vxlan_vtep', 'source_intf', + name: @name, no_cmd: 'no', lpbk_intf: val) + else + config_set('vxlan_vtep', 'source_intf', + name: @name, no_cmd: '', lpbk_intf: val) + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def shutdown + state = config_get('interface', 'shutdown', @name) + state ? true : false + end + + def shutdown=(state) + no_cmd = (state ? '' : 'no') + config_set('interface', 'shutdown', @name, no_cmd) + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def default_shutdown + false + end + end # Class +end # Module From 7eacd99e43d27cb7d9ea01b3be633293c7a6d802 Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Thu, 15 Oct 2015 13:19:43 -0700 Subject: [PATCH 004/386] 1. remove methods from Features module and add to each class 2. add "show" method to node_util --- lib/cisco_node_utils.rb | 1 - .../command_reference_common.yaml | 2 +- .../command_reference_n7k.yaml | 97 ++++++++++++++++++- lib/cisco_node_utils/features.rb | 97 ------------------- lib/cisco_node_utils/interface.rb | 30 +++++- lib/cisco_node_utils/node_util.rb | 5 + lib/cisco_node_utils/pim.rb | 25 ++++- lib/cisco_node_utils/vlan.rb | 29 +++++- lib/cisco_node_utils/vni.rb | 25 ++++- lib/cisco_node_utils/vxlan_vtep.rb | 33 +++++-- 10 files changed, 228 insertions(+), 116 deletions(-) diff --git a/lib/cisco_node_utils.rb b/lib/cisco_node_utils.rb index e68933de..79e4cca4 100644 --- a/lib/cisco_node_utils.rb +++ b/lib/cisco_node_utils.rb @@ -15,7 +15,6 @@ require 'cisco_node_utils/cisco_cmn_utils' require 'cisco_node_utils/command_reference' require 'cisco_node_utils/configparser_lib' -require 'cisco_node_utils/features' require 'cisco_node_utils/interface' require 'cisco_node_utils/interface_ospf' require 'cisco_node_utils/node' diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index b4fce625..a3e4d1e8 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -211,7 +211,7 @@ interface: config_get: "show running interface all" config_get_token: ['/^interface %s$/i', '/^mtu (.*)$/'] config_set: ["interface %s", "%s mtu %s"] - default_value: 1500 + default_value: "" negotiate_auto_ethernet: config_get: "show running interface all" diff --git a/lib/cisco_node_utils/command_reference_n7k.yaml b/lib/cisco_node_utils/command_reference_n7k.yaml index d3e8d092..1c93ecf9 100755 --- a/lib/cisco_node_utils/command_reference_n7k.yaml +++ b/lib/cisco_node_utils/command_reference_n7k.yaml @@ -5,10 +5,58 @@ # - command_reference_common.yaml # --- +fabricpath: + feature: + config_get: "show feature-set" + config_get_token: '/^fabricpath[\s]+[\d]+[\s]+(\S+)/' + config_set: "%s feature-set fabricpath" + + feature_install: + config_set: "%s install feature-set fabricpath" + +fp_topology: + all_topos: + config_get: "show fabricpath topology" + config_get_token: '/^\S+[\s]+(\d+)[\s]+/' + + create: + config_set: ["fabricpath topology %s" , "end"] + + description: + config_get: "show fabricpath topology" + config_get_token: '/^(\S+)[\s]+%d+[\s]+\S+/' + config_set: ["fabricpath topology %d" , "%s description %s", "end"] + default_value: "" + + destroy: + config_set: "no fabricpath topology %s" + + member_vlans: + config_get: "show fabricpath topology vlan" + config_get_token: '/^\S+[\s]+%d+[\s]+(\S+)/' + config_set: ["fabricpath topology %d" , "%s member vlan %s", "end"] + default_value: "--" + + state: + config_get: "show fabricpath topology" + config_get_token: '/^\S+[\s]+%d+[\s]+(\S+)/' + default_value: "up" + interface: admin_state_ethernet_noswitchport_shutdown: default_value: "shutdown" + encapsulation_vni: + config_get: "show running interface all" + config_get_token: ['/^interface\s+%s$/i', '/^service.*$/i', '/^encapsulation\s+profile\s+(\S+).*$/i'] + + encapsulation_vni_add: + config_set: ['interface %s', 'service instance 1 vni', 'no shutdown', 'encapsulation profile %s default', 'end'] + + encapsulation_vni_del: + config_set: ['interface %s', 'no service instance 1 vni', 'end'] + + ipv4_redirects_loopback: default_value: false config_set: ~ @@ -30,16 +78,63 @@ interface: config_get_token: default_value: false - inventory: inventory: test_config_get_regex: [!ruby/regexp '/.*\nNAME: "(.+)",\s+DESCR: "(.+)"\s+\nPID: (\S+)\s+,\s+VID: (.+) ,\s+SN: (.+)\s+\n/', !ruby/regexp '/.*NAME: "(.+)",\s+DESCR: "(.+)"\s+PID: (\S+)\s+,\s+VID: (.+) ,\s+SN: (.+)\s+\n/'] +limit_resource: + vdc: + config_get: "show vdc current-vdc" + config_get_token: '/^Current vdc is.*\-\s+(\S+)/' + + vxlan: + config_set: ["terminal dont-ask", "vdc %s", "limit-resource module-type f3", "end"] show_version: description: test_config_get_regex: !ruby/regexp '/.*Hardware\n cisco (\w+ \w+ \(\w+ \w+\) \w+).*/' +vlan: + mode: + config_get: "show vlan" + config_get_token: '/^%d+\s+enet\s+(\S+)\s/' + config_set: ["vlan %d" , "%s mode %s", "end"] + default_value: "ce" + +vni: + all_vnis: + config_get: "show vni" + config_get_token: '/^(\d+)\s/' + + bridge_domain_activate: + config_set: ["%s system bridge-domain add %d", "end"] + + bridge_domain: + config_get: "show vni" + config_get_token: [ '/^%d\s+\S+\s+(\d+)/' ] + config_set: ["bridge-domain %d", "%s member vni %d", "end"] + default_value: ~ + + create: + config_set: ["vni %s" , "end"] + + destroy: + config_set: "no vni %s" + + encap_dot1q: + config_set: ["encapsulation profile vni %s", "%s dot1q %s vni %s", "end"] + default_value: ~ + + feature: + config_get: "show feature" + config_get_token: '/^vni\s+\d+\s+(\S+)/' + config_set: "%s feature vni" + + shutdown: + config_get: "show vni" + config_get_token: '/^%d\s+(\S+)/' + config_set: ["vni %d", "%s shutdown", "end"] + default_value: false vtp: version: diff --git a/lib/cisco_node_utils/features.rb b/lib/cisco_node_utils/features.rb index 5c5f2390..0b2f5e3a 100644 --- a/lib/cisco_node_utils/features.rb +++ b/lib/cisco_node_utils/features.rb @@ -30,102 +30,5 @@ module ClassMethods # @@node = Cisco::Node.instance # debug "@@@@@ Loaded Features node is #{@@node}" - def fabricpath_feature - debug "In Features node is #{@@node}" - fabricpath = config_get('fabricpath', 'feature') - fail 'fabricpath_feature not found' if fabricpath.nil? - return :disabled if fabricpath.nil? - fabricpath.shift.to_sym - end - - def fabricpath_feature_set(fabricpath_set) - curr = fabricpath_feature - return if curr == fabricpath_set - - case fabricpath_set - when :enabled - config_set('fabricpath', 'feature_install', '') if curr == :uninstalled - config_set('fabricpath', 'feature', '') - when :disabled - config_set('fabricpath', 'feature', 'no') if curr == :enabled - return - when :installed - config_set('fabricpath', 'feature_install', '') if curr == :uninstalled - when :uninstalled - config_set('fabricpath', 'feature', 'no') if curr == :enabled - config_set('fabricpath', 'feature_install', 'no') - end - rescue Cisco::CliError => e - raise "[#{@name}] '#{e.command}' : #{e.clierror}" - end - - def vni_feature - debug "In Features node is #{@@node}" - vni = config_get('vni', 'feature') - fail 'vni feature not found' if vni.nil? - return :disabled if vni.nil? - vni.first.to_sym - end - - def vni_feature_set(vni_set) - curr = vni_feature - return if curr == vni_set - - case vni_set - when :enabled - config_set('vni', 'feature', '') - when :disabled - config_set('vni', 'feature', 'no') if curr == :enabled - return - end - rescue Cisco::CliError => e - raise "[#{@name}] '#{e.command}' : #{e.clierror}" - end - - def vxlan_feature - debug "In Features node is #{@@node}" - vxlan = config_get('vxlan', 'feature') - fail 'vxlan/nv_overlay feature not found' if vxlan.nil? - return :disabled if vxlan.nil? - vxlan.first.to_sym - end - - def vxlan_feature_set(vxlan_set) - curr = vxlan_feature - return if curr == vxlan_set - - case vxlan_set - when :enabled - config_set('vxlan', 'feature', '') - when :disabled - config_set('vxlan', 'feature', 'no') if curr == :enabled - return - end - rescue Cisco::CliError => e - raise "[#{@name}] '#{e.command}' : #{e.clierror}" - end - - def pim_feature - debug "In Features node is #{@@node}" - pim = config_get('pim', 'feature') - fail 'pim feature not found' if pim.nil? - return :disabled if pim.nil? - pim.first.to_sym - end - - def pim_feature_set(pim_set) - curr = pim_feature - return if curr == pim_set - - case pim_set - when :enabled - config_set('pim', 'feature', '') - when :disabled - config_set('pim', 'feature', 'no') if curr == :enabled - return - end - rescue Cisco::CliError => e - raise "[#{@name}] '#{e.command}' : #{e.clierror}" - end end # end of module ClassMethods end # end of module Features diff --git a/lib/cisco_node_utils/interface.rb b/lib/cisco_node_utils/interface.rb index 58598593..e63e37e0 100644 --- a/lib/cisco_node_utils/interface.rb +++ b/lib/cisco_node_utils/interface.rb @@ -15,7 +15,6 @@ # limitations under the License. require File.join(File.dirname(__FILE__), 'node_util') -require File.join(File.dirname(__FILE__), 'features') # Add some interface-specific constants to the Cisco namespace module Cisco @@ -31,7 +30,6 @@ module Cisco # Interface - node utility class for general interface config management class Interface < NodeUtil attr_reader :name - include Features def initialize(name, instantiate=true) fail TypeError unless name.is_a?(String) @@ -156,6 +154,34 @@ def encapsulation_profile_vni=(val) raise "[#{@name}] '#{e.command}' : #{e.clierror}" end + def fabricpath_feature + fabricpath = config_get('fabricpath', 'feature') + fail 'fabricpath_feature not found' if fabricpath.nil? + return :disabled if fabricpath.nil? + fabricpath.shift.to_sym + end + + def fabricpath_feature_set(fabricpath_set) + curr = fabricpath_feature + return if curr == fabricpath_set + + case fabricpath_set + when :enabled + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + config_set('fabricpath', 'feature', '') + when :disabled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + return + when :installed + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + when :uninstalled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + config_set('fabricpath', 'feature_install', 'no') + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + def fex_feature fex = config_get('fex', 'feature') fail 'fex_feature not found' if fex.nil? diff --git a/lib/cisco_node_utils/node_util.rb b/lib/cisco_node_utils/node_util.rb index efc6cbd8..a3bfcbed 100644 --- a/lib/cisco_node_utils/node_util.rb +++ b/lib/cisco_node_utils/node_util.rb @@ -57,5 +57,10 @@ def self.config_set(*args) def config_set(*args) node.config_set(*args) end + + def show(*args) + node.show(*args) + end + end end diff --git a/lib/cisco_node_utils/pim.rb b/lib/cisco_node_utils/pim.rb index 35a43bd3..8801c5d8 100644 --- a/lib/cisco_node_utils/pim.rb +++ b/lib/cisco_node_utils/pim.rb @@ -18,15 +18,12 @@ # limitations under the License. require File.join(File.dirname(__FILE__), 'node_util') -require File.join(File.dirname(__FILE__), 'features') module Cisco # node_utils class for Pim class Pim < NodeUtil attr_reader :name - include Features - def initialize(name, instantiate=true) fail TypeError unless name.is_a?(String) fail ArgumentError unless name.length > 0 @@ -64,6 +61,28 @@ def self.pims hash end + def pim_feature + pim = config_get('pim', 'feature') + fail 'pim feature not found' if pim.nil? + return :disabled if pim.nil? + pim.first.to_sym + end + + def pim_feature_set(pim_set) + curr = pim_feature + return if curr == pim_set + + case pim_set + when :enabled + config_set('pim', 'feature', '') + when :disabled + config_set('pim', 'feature', 'no') if curr == :enabled + return + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + def create pim_feature_set(:enabled) unless (:enabled == pim_feature) end diff --git a/lib/cisco_node_utils/vlan.rb b/lib/cisco_node_utils/vlan.rb index 72ed883d..4106bd38 100644 --- a/lib/cisco_node_utils/vlan.rb +++ b/lib/cisco_node_utils/vlan.rb @@ -24,7 +24,6 @@ module Cisco # Vlan - node utility class for VLAN configuration management class Vlan < NodeUtil attr_reader :name, :vlan_id - include Features def initialize(vlan_id, instantiate=true) @vlan_id = vlan_id.to_s @@ -61,6 +60,34 @@ def cli_error_check(result) fail result[2]['body'] unless result[2]['body'].empty? end + def fabricpath_feature + fabricpath = config_get('fabricpath', 'feature') + fail 'fabricpath_feature not found' if fabricpath.nil? + return :disabled if fabricpath.nil? + fabricpath.shift.to_sym + end + + def fabricpath_feature_set(fabricpath_set) + curr = fabricpath_feature + return if curr == fabricpath_set + + case fabricpath_set + when :enabled + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + config_set('fabricpath', 'feature', '') + when :disabled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + return + when :installed + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + when :uninstalled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + config_set('fabricpath', 'feature_install', 'no') + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + def mode result = config_get('vlan', 'mode', @vlan_id) return default_mode if result.nil? diff --git a/lib/cisco_node_utils/vni.rb b/lib/cisco_node_utils/vni.rb index c6227501..dfc40ddb 100644 --- a/lib/cisco_node_utils/vni.rb +++ b/lib/cisco_node_utils/vni.rb @@ -17,15 +17,12 @@ # limitations under the License. require File.join(File.dirname(__FILE__), 'node_util') -require File.join(File.dirname(__FILE__), 'features') module Cisco # node_utils class for Vni class Vni < NodeUtil attr_reader :name, :vni_id - include Features - def initialize(vni_id, instantiate=true) @vni_id = vni_id.to_s fail ArgumentError, @@ -47,6 +44,28 @@ def self.vnis hash end + def vni_feature + vni = config_get('vni', 'feature') + fail 'vni feature not found' if vni.nil? + return :disabled if vni.nil? + vni.first.to_sym + end + + def vni_feature_set(vni_set) + curr = vni_feature + return if curr == vni_set + + case vni_set + when :enabled + config_set('vni', 'feature', '') + when :disabled + config_set('vni', 'feature', 'no') if curr == :enabled + return + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + def create vni_feature_set(:enabled) unless (:enabled == vni_feature) config_set('vni', 'create', @vni_id) diff --git a/lib/cisco_node_utils/vxlan_vtep.rb b/lib/cisco_node_utils/vxlan_vtep.rb index c6b851f9..f013e0df 100644 --- a/lib/cisco_node_utils/vxlan_vtep.rb +++ b/lib/cisco_node_utils/vxlan_vtep.rb @@ -18,15 +18,12 @@ # limitations under the License. require File.join(File.dirname(__FILE__), 'node_util') -require File.join(File.dirname(__FILE__), 'features') module Cisco # node_utils class for vxlan_vtep - class Vxlan_vtep < NodeUtil ############# *MUSTFIX* CLASS NAME (camelcase) + class VxlanVtep < NodeUtil attr_reader :name - include Features - def initialize(name, instantiate=true) fail TypeError unless name.is_a?(String) fail ArgumentError unless name.length > 0 @@ -37,18 +34,40 @@ def initialize(name, instantiate=true) def self.vteps hash = {} - vxlan_feature = config_get('vxlan', 'feature') - return hash if (:enabled != vxlan_feature.first.to_sym) + is_vxlan_feature = config_get('vxlan', 'feature') + return hash if (:enabled != is_vxlan_feature.first.to_sym) vtep_list = config_get('vxlan_vtep', 'all_interfaces') return hash if vtep_list.nil? vtep_list.each do |id| id = id.downcase - hash[id] = Vxlan_vtep.new(id, false) + hash[id] = VxlanVtep.new(id, false) end hash end + def vxlan_feature + vxlan = config_get('vxlan', 'feature') + fail 'vxlan/nv_overlay feature not found' if vxlan.nil? + return :disabled if vxlan.nil? + vxlan.first.to_sym + end + + def vxlan_feature_set(vxlan_set) + curr = vxlan_feature + return if curr == vxlan_set + + case vxlan_set + when :enabled + config_set('vxlan', 'feature', '') + when :disabled + config_set('vxlan', 'feature', 'no') if curr == :enabled + return + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + def create unless (:enabled == vxlan_feature) vdc_name = config_get('limit_resource', 'vdc') From e6c412474c792af24e4622ff18101c776c5a1e8e Mon Sep 17 00:00:00 2001 From: Alex Hunsberger Date: Wed, 21 Oct 2015 11:39:10 -0400 Subject: [PATCH 005/386] aaa author service node utils --- .../aaa_authorization_service.rb | 150 ++ .../command_reference_common.yaml | 19 + tests/test_aaa_authorization_service.rb | 1230 +++++++++++++++++ 3 files changed, 1399 insertions(+) create mode 100644 lib/cisco_node_utils/aaa_authorization_service.rb create mode 100644 tests/test_aaa_authorization_service.rb diff --git a/lib/cisco_node_utils/aaa_authorization_service.rb b/lib/cisco_node_utils/aaa_authorization_service.rb new file mode 100644 index 00000000..e9a0510b --- /dev/null +++ b/lib/cisco_node_utils/aaa_authorization_service.rb @@ -0,0 +1,150 @@ +# NXAPI implementation of AaaAuthorizationService class +# +# May 2015, Alex Hunsberger +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'node_util' + +module Cisco + # AaaAuthorizationService - node util class for aaa authorization management + class AaaAuthorizationService < NodeUtil + attr_reader :name, :type + + def initialize(type, name, create=true) + fail TypeError unless name.is_a? String + fail TypeError unless type.is_a? Symbol + # only console and default are supported currently + fail ArgumentError unless %w(console default).include? name + fail ArgumentError unless + %i(commands config_commands ssh_certificate ssh_publickey).include? type + @name = name + @type = type + type_str = AaaAuthorizationService.auth_type_sym_to_str(type) + + return unless create + + config_set('aaa_authorization_service', 'method', '', type_str, name) + end + + def self.services + servs = {} + servs_arr = config_get('aaa_authorization_service', 'services') + unless servs_arr.nil? + servs_arr.each do |type, name| + type = auth_type_str_to_sym(type) + servs[type] ||= {} + servs[type][name] = AaaAuthorizationService.new(type, name, false) + end + end + servs + end + + def destroy + # must specify exact current config string to unconfigure + m = method + m_str = m == :unselected ? '' : m.to_s + g_str = groups.join(' ') + t_str = AaaAuthorizationService.auth_type_sym_to_str(@type) + + if g_str.empty? + # cannot remove no groups + local, so do nothing in this case + unless m == :local + config_set('aaa_authorization_service', 'method', + 'no', t_str, @name) + end + else + config_set('aaa_authorization_service', 'groups', + 'no', t_str, @name, g_str, m_str) + end + end + + # groups aren't retrieved via the usual CLI regex memory type because + # there can be an arbitrary number of groups and specifying a repeating + # memory regex only captures the last match + # ex: aaa authorization console group group1 group2 group3 local + def groups + # config_get returns the following format: + # [{"appl_subtype": "console", + # "cmd_type": "config-commands", + # "methods": "group foo bar local "}], ... + hsh_arr = config_get('aaa_authorization_service', 'groups') + fail 'unable to retrieve aaa groups information' if hsh_arr.nil? + type_s = AaaAuthorizationService.auth_type_sym_to_str(@type) + hsh = hsh_arr.find do |x| + x['appl_subtype'] == @name && x['cmd_type'] == type_s + end + fail "no aaa info for #{@type},#{@name}" if hsh.nil? + fail "no aaa info for #{@type},#{@name}. api/feature change?" unless + hsh.key? 'methods' + # ex: ["group", "group1", "local"] + grps = hsh['methods'].strip.split + # return [] if grps.size == 1 + # remove local, group keywords + grps -= %w(local group) + grps + end + + # default is [] + def default_groups + config_get_default('aaa_authorization_service', 'groups') + end + + def method + t_str = AaaAuthorizationService.auth_type_sym_to_str(@type) + m = config_get('aaa_authorization_service', 'method', @name, t_str) + m.nil? ? :unselected : m.first.to_sym + end + + # default is :local + def default_method + config_get_default('aaa_authorization_service', 'method') + end + + # groups and method must be set in the same CLI string + # aaa authorization login / + # local | group [local] + def groups_method_set(grps, m) + fail TypeError unless grps.is_a? Array + fail TypeError unless grps.all? { |x| x.is_a? String } + fail TypeError unless m.is_a? Symbol + # only the following are supported (unselected = blank) + fail ArgumentError unless [:local, :unselected].include? m + + # raise "type 'local' not allowed when groups are configured" if + # m == :local and not grps.empty? + m_str = m == :unselected ? '' : m.to_s + g_str = grps.join(' ') + t_str = AaaAuthorizationService.auth_type_sym_to_str(@type) + + # different config_set depending on whether we're setting groups or not + if g_str.empty? + config_set('aaa_authorization_service', 'method', + '', t_str, @name) + else + config_set('aaa_authorization_service', 'groups', + '', t_str, @name, g_str, m_str) + end + end + + def self.auth_type_sym_to_str(sym) + sym.to_s.sub('_', '-') + end + + def self.auth_type_str_to_sym(str) + str.sub('-', '_').to_sym + end + end +end diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index 7f511ea1..db1ea745 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -35,6 +35,25 @@ aaa_authentication_login: config_set: "%s aaa authentication login mschapv2 enable" default_value: false +aaa_authorization_service: + groups: + config_get: "show aaa authorization all" + config_get_token: ["TABLE_cmd_methods", "ROW_cmd_methods"] + # this set is only used when there are groups to configure + config_set: "%s aaa authorization %s %s group %s %s" + default_value: [] + + method: + config_get: "show aaa authorization all" + config_get_token: '/^\s+%s authorization for %s:.*(local) ?$/' + # this set is only used when there are no groups to configure + config_set: "%s aaa authorization %s %s local" + default_value: :local + + services: + config_get: "show run aaa all" + config_get_token: '/^aaa authorization (\S+) (\S+) .*(?:local)? ?$/' + aaa_auth_login_service: groups: config_get: "show aaa authentication" diff --git a/tests/test_aaa_authorization_service.rb b/tests/test_aaa_authorization_service.rb new file mode 100644 index 00000000..2e74d8da --- /dev/null +++ b/tests/test_aaa_authorization_service.rb @@ -0,0 +1,1230 @@ +# Copyright (c) 2013-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'ciscotest' +require_relative '../lib/cisco_node_utils/aaa_authorization_service' + +# TestAaaAuthorizationService - Minitest for AaaAuthorizationService util +# rubocop:disable ClassLength +class TestAaaAuthorizationService < CiscoTestCase + # Method to pre-configure a valid tacacs server and aaa group. This + # group can be included in the testing such access to the device + # never is compromised. + def preconfig_tacacs_server_access(group_name, keep=true) + @device.cmd('configure terminal') + if keep + @device.cmd('tacacs-server key testing123') + @device.cmd('tacacs-server host 10.122.197.197 key testing123') + @device.cmd("aaa group server tacacs+ #{group_name}") + @device.cmd('server 10.122.197.197') + @device.cmd('use-vrf management') + @device.cmd('source-interface mgmt0') + @device.cmd('aaa authentication login ascii-authentication') + else + @device.cmd("no aaa group server tacacs+ #{group_name}") + end + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + end + + def feature_tacacs(feature=true) + @device.cmd('configure terminal') + if feature + @device.cmd('feature tacacs') + else + @device.cmd('no feature tacacs') + @device.cmd('no aaa authentication login ascii-authentication') + end + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + end + + def config_tacacs_servers(servers) + @device.cmd('configure terminal') + @device.cmd('feature tacacs+') + servers.each do |server| + @device.cmd("aaa group server tacacs+ #{server}") + end + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + end + + def get_match_line(name) + s = @device.cmd('show run aaa all | no-more') + prefix = 'aaa authorization' + line = /#{prefix} #{name}/.match(s) + line + end + + def test_aaaauthorizationservice_create_unsupported_type + assert_raises(ArgumentError) do + AaaAuthorizationService.new(:none, 'default') + end + end + + def test_aaaauthorizationservice_create_nil_type + assert_raises(TypeError) do + AaaAuthorizationService.new(nil, 'default') + end + end + + def test_aaaauthorizationservice_create_invalid_type + assert_raises(TypeError) do + AaaAuthorizationService.new('test', 'default') + end + end + + def test_aaaauthorizationservice_create_invalid_range_type + assert_raises(TypeError) do + AaaAuthorizationService.new(34, 'default') + end + end + + def test_aaaauthorizationservice_create_invalid_service + assert_raises(ArgumentError) do + AaaAuthorizationService.new(:commands, 'test') + end + end + + def test_aaaauthorizationservice_create_empty_service + assert_raises(ArgumentError) do + AaaAuthorizationService.new(:commands, '') + end + end + + def test_aaaauthorizationservice_create_commands_default + feature_tacacs + aaa_a_service = AaaAuthorizationService.new(:commands, 'default') + + refute_nil(aaa_a_service, + 'Error: AaaAuthorizationService creating commands default') + aaa_a_service.destroy unless aaa_a_service.nil? + feature_tacacs(false) + end + + def test_aaaauthorizationservice_create_commands_console + feature_tacacs + aaa_a_service = AaaAuthorizationService.new(:commands, 'console') + + refute_nil(aaa_a_service, + 'Error: AaaAuthorizationService creating commands default') + aaa_a_service.destroy unless aaa_a_service.nil? + feature_tacacs(false) + end + + def test_aaaauthorizationservice_create_config_commands_default + feature_tacacs + aaa_a_service = AaaAuthorizationService.new(:config_commands, 'default') + + refute_nil(aaa_a_service, + 'Error: AaaAuthorizationService creating ' \ + 'config-commands default') + aaa_a_service.destroy unless aaa_a_service.nil? + feature_tacacs(false) + end + + def test_aaaauthorizationservice_create_config_commands_console + feature_tacacs + aaa_a_service = AaaAuthorizationService.new(:config_commands, 'console') + + refute_nil(aaa_a_service, + 'Error: AaaAuthorizationService creating commands default') + aaa_a_service.destroy unless aaa_a_service.nil? + feature_tacacs(false) + end + + def test_aaaauthorizationservice_get_type + feature_tacacs + type = :config_commands + aaa_a_service = AaaAuthorizationService.new(type, 'default') + assert_equal(type, aaa_a_service.type, 'Error : Invalid type') + aaa_a_service.destroy + feature_tacacs(false) + end + + def test_aaaauthorizationservice_get_name + feature_tacacs + service = 'default' + aaa_a_service = AaaAuthorizationService.new(:config_commands, service) + assert_equal(service, aaa_a_service.name, 'Error : Invalid service name') + aaa_a_service.destroy + feature_tacacs(false) + end + + def test_aaaauthorizationservice_collection_invalid + assert_nil(AaaAuthorizationService.services['TEST']) + end + + def test_aaaauthorizationservice_collection_services_type_commands + # Need feature tacacs for this test + feature_tacacs + type = :commands + collection = AaaAuthorizationService.services[type] + + # Collection will not be empty since tacacs feature is enabled. + refute_empty(collection, + 'Error: AaaAuthorizationService collection is not filled') + assert_equal(2, collection.size, + 'Error: AaaAuthorizationService collection not correct size') + assert(collection.key?('default'), + 'Error: AaaAuthorizationService collection does contain default') + assert(collection.key?('console'), + 'Error: AaaAuthorizationService collection does contain console') + + collection.each do |service, aaa_a_service| + assert_equal(service, aaa_a_service.name, + 'Error: Invalid AaaAuthorizationService ' \ + "#{service} in collection") + + method = :local + assert_equal(method, aaa_a_service.method, + 'Error: Invalid AaaAuthorizationService method for ' \ + "#{service} in collection") + + groups = [] + assert_equal(groups, aaa_a_service.groups, + 'Error: Invalid AaaAuthorizationService groups for ' \ + "#{service} in collection") + aaa_a_service.destroy + end + feature_tacacs(false) + end + + def test_aaaauthorizationservice_collection_services_type_config_commands + feature_tacacs + type = :config_commands + collection = AaaAuthorizationService.services[type] + + # Collection will not be empty since tacacs feature is enabled. + refute_empty(collection, + 'Error: AaaAuthorizationService collection is not filled') + assert_equal(2, collection.size, + 'Error: AaaAuthorizationService collection not correct size') + assert(collection.key?('default'), + 'Error: AaaAuthorizationService collection does contain default') + assert(collection.key?('console'), + 'Error: AaaAuthorizationService collection does contain console') + + collection.each do |service, aaa_a_service| + assert_equal(service, aaa_a_service.name, + "Error: Invalid AaaAuthorizationService #{service} " \ + 'in collection') + assert_equal(:local, aaa_a_service.method, + 'Error: Invalid AaaAuthorizationService method for ' \ + "#{service} in collection") + + # Due to preconfig groups will indeed be populated + groups = [] + assert_equal(groups, aaa_a_service.groups, + 'Error: Invalid AaaAuthorizationService groups for ' \ + "#{service} in collection") + aaa_a_service.destroy + end + feature_tacacs(false) + end + + def test_aaaauthorizationservice_type_commands_default_console_group + feature_tacacs + + # Preconfig AAA Authorization + cmd1 = 'aaa authorization commands default group group2 group1 local' + cmd2 = 'aaa authorization commands console group group1 local' + @device.cmd('configure terminal') + @device.cmd('aaa group server tacacs+ group1') + @device.cmd('aaa group server tacacs+ group2') + @device.cmd(cmd1) + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + type = :commands + collection = AaaAuthorizationService.services[type] + refute_empty(collection, + 'Error: AaaAuthorizationService collection is not filled') + assert_equal(2, collection.size, + 'Error: AaaAuthorizationService collection not ' \ + 'reporting correct size') + assert(collection.key?('default'), + 'Error: AaaAuthorizationService collection does contain default') + assert(collection.key?('console'), + 'Error: AaaAuthorizationService collection does contain console') + + service = 'default' + aaa_a_service = collection[service] + + assert_equal(service, aaa_a_service.name, + "Error: Invalid AaaAuthorizationService #{service} " \ + 'in collection') + + assert_equal(:local, aaa_a_service.method, + 'Error: Invalid AaaAuthorizationService method for ' \ + 'default in collection') + groups = %w(group2 group1) + assert_equal(groups, aaa_a_service.groups, + 'Error: Invalid AaaAuthorizationService groups for ' \ + 'default in collection') + + # only one of default or console can be configured at a time without + # locking the CLI + @device.cmd('configure terminal') + @device.cmd("no #{cmd1}") + @device.cmd(cmd2) + @device.cmd('end') + node.cache_flush + + service = 'console' + aaa_a_service = collection[service] + + assert_equal(:local, aaa_a_service.method, + 'Error: Invalid AaaAuthorizationService method for ' \ + 'console in collection') + groups = ['group1'] + assert_equal(groups, aaa_a_service.groups, + 'Error: Invalid AaaAuthorizationService groups for ' \ + 'console in collection') + + @device.cmd('configure terminal') + @device.cmd("no #{cmd2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + feature_tacacs(false) + end + + def test_aaaauthorizationservice_type_config_commands_default_console_group + feature_tacacs + # Preconfig AAA Authorization + cmd1 = 'aaa authorization config-commands default group group2 group1 local' + cmd2 = 'aaa authorization config-commands console group group1 local' + @device.cmd('configure terminal') + @device.cmd('aaa group server tacacs+ group1') + @device.cmd('aaa group server tacacs+ group2') + @device.cmd(cmd1) + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + type = :config_commands + collection = AaaAuthorizationService.services[type] + refute_empty(collection, + 'Error: AaaAuthorizationService collection is not filled') + assert_equal(2, collection.size, + 'Error: AaaAuthorizationService collection not ' \ + 'reporting correct size') + assert(collection.key?('default'), + 'Error: AaaAuthorizationService collection does contain default') + assert(collection.key?('console'), + 'Error: AaaAuthorizationService collection does contain console') + + service = 'default' + aaa_a_service = collection[service] + + assert_equal(service, aaa_a_service.name, + "Error: Invalid AaaAuthorizationService #{service} " \ + 'in collection') + + assert_equal(:local, aaa_a_service.method, + 'Error: Invalid AaaAuthorizationService method ' \ + 'for default in collection') + groups = %w(group2 group1) + assert_equal(groups, aaa_a_service.groups, + 'Error: Invalid AaaAuthorizationService groups ' \ + 'for default in collection') + + @device.cmd('configure terminal') + @device.cmd("no #{cmd1}") + @device.cmd(cmd2) + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + service = 'console' + aaa_a_service = collection[service] + + assert_equal(:local, aaa_a_service.method, + 'Error: Invalid AaaAuthorizationService method ' \ + 'for console in collection') + groups = ['group1'] + assert_equal(groups, aaa_a_service.groups, + 'Error: Invalid AaaAuthorizationService groups ' \ + 'for console in collection') + + @device.cmd('configure terminal') + @device.cmd("no #{cmd2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + feature_tacacs(false) + end + + def test_aaaauthorizationservice_get_default_method + feature_tacacs + type = :commands + aaa_a_service = AaaAuthorizationService.new(type, 'default') + assert_equal(:local, aaa_a_service.default_method, + 'Error: AaaAuthorizationService command default, ' \ + 'default method') + aaa_a_service.destroy + + aaa_a_service = AaaAuthorizationService.new(type, 'console') + assert_equal(:local, aaa_a_service.default_method, + 'Error: AaaAuthorizationService command console, ' \ + 'default method') + aaa_a_service.destroy + + type = :config_commands + aaa_a_service = AaaAuthorizationService.new(type, 'default') + assert_equal(:local, aaa_a_service.default_method, + 'Error: AaaAuthorizationService config-command ' \ + 'default, default method') + aaa_a_service.destroy + + aaa_a_service = AaaAuthorizationService.new(type, 'console') + assert_equal(:local, aaa_a_service.default_method, + 'Error: AaaAuthorizationService config-command ' \ + 'console, default method') + aaa_a_service.destroy + feature_tacacs(false) + end + + def test_aaaauthorizationservice_collection_groups_commands_default + feature_tacacs + + type = :commands + aaa_a_service = AaaAuthorizationService.new(type, 'default') + + # Default case + assert_equal(aaa_a_service.default_groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService commands, ' \ + 'get groups for default') + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + @device.cmd('configure terminal') + @device.cmd('aaa authorization commands default group ' \ + "#{group0} #{group1} #{group2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group1, group2] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService default get groups, 0/1/2') + assert_equal(:unselected, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/1/2') + + # Change the config to have different groups and method + @device.cmd('configure terminal') + @device.cmd('aaa authorization commands default group ' \ + "#{group0} #{group3} #{group1} local") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group3, group1] + # puts aaa_a_service.groups + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService default get groups, 0/3/1') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/3/1') + + # Mix default and console, but since our instance is for 'default' + # service we should only get 'default' groups and not 'console' + # groups. + aaa_cmd1 = 'aaa authorization commands default group ' \ + "#{group0} #{group2} #{group1} #{group3} local" + aaa_cmd2 = 'aaa authorization commands console group ' \ + "#{group0} #{group2} #{group3} local" + @device.cmd('configure terminal') + @device.cmd(aaa_cmd1) + @device.cmd(aaa_cmd2) + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group2, group1, group3] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService default get groups, 0/2/1/3') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/3/1') + + # Cleanup + aaa_a_service.destroy + @device.cmd('configure terminal') + @device.cmd("no #{aaa_cmd1}") + @device.cmd("no #{aaa_cmd2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_collection_groups_commands_console + feature_tacacs + + type = :commands + aaa_a_service = AaaAuthorizationService.new(type, 'console') + + # Default case + assert_equal(aaa_a_service.default_groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService commands, ' \ + 'get groups for console') + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + @device.cmd('configure terminal') + @device.cmd('aaa authorization commands console group ' \ + "#{group0} #{group1} #{group2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group1, group2] + # puts aaa_a_service.groups + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService console get groups, 0/1/2') + assert_equal(:unselected, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/1/2') + + # Change the config to have different groups and method + @device.cmd('configure terminal') + @device.cmd('aaa authorization commands console group ' \ + "#{group0} #{group3} #{group1} local") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group3, group1] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService console get groups, 0/3/1') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/3/1') + + # Mix default and console, but since our instance is for 'console' + # service we should only get 'console' groups and not 'default' + # groups. + aaa_cmd1 = 'aaa authorization commands console group ' \ + "#{group0} #{group2} #{group1} #{group3} local" + aaa_cmd2 = 'aaa authorization commands default group ' \ + "#{group0} #{group2} #{group3} local" + @device.cmd('configure terminal') + @device.cmd(aaa_cmd1) + @device.cmd(aaa_cmd2) + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group2, group1, group3] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService console get groups, 0/2/1/3') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/2/1/3') + + # Cleanup + aaa_a_service.destroy + @device.cmd('configure terminal') + @device.cmd("no #{aaa_cmd1}") + @device.cmd("no #{aaa_cmd2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_collection_groups_config_commands_default + feature_tacacs + + type = :config_commands + aaa_a_service = AaaAuthorizationService.new(type, 'default') + + # Default case + assert_equal(aaa_a_service.default_groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService config-commands, ' \ + 'get groups for default') + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + @device.cmd('configure terminal') + @device.cmd('aaa authorization config-commands default group ' \ + "#{group0} #{group1} #{group2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group1, group2] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService default get groups, 0/1/2') + assert_equal(:unselected, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/1/2') + + # Change the config to have different groups and method + @device.cmd('configure terminal') + @device.cmd('aaa authorization config-commands default group ' \ + "#{group0} #{group3} #{group1} local") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group3, group1] + # puts aaa_a_service.groups + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService default get groups, 0/3/1') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/3/1') + + # Mix default and console, but since our instance is for 'default' + # service we should only get 'default' groups and not 'console' + # groups. + aaa_cmd1 = 'aaa authorization config-commands default group ' \ + "#{group0} #{group2} #{group1} #{group3} local" + aaa_cmd2 = 'aaa authorization config-commands console group ' \ + "#{group0} #{group2} #{group3} local" + @device.cmd('configure terminal') + @device.cmd(aaa_cmd1) + @device.cmd(aaa_cmd2) + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group2, group1, group3] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService default get groups, 0/2/1/3') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/2/1/3') + + # Cleanup + aaa_a_service.destroy + @device.cmd('configure terminal') + @device.cmd("no #{aaa_cmd1}") + @device.cmd("no #{aaa_cmd2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_collection_groups_config_commands_console + feature_tacacs + + type = :config_commands + aaa_a_service = AaaAuthorizationService.new(type, 'console') + + # Default case + assert_equal(aaa_a_service.default_groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService config-commands, ' \ + 'get groups for console') + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + @device.cmd('configure terminal') + @device.cmd('aaa authorization config-commands console group ' \ + "#{group0} #{group1} #{group2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group1, group2] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService console get groups, 0/1/2') + assert_equal(:unselected, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/1/2') + + # Change the config to have different groups and method + @device.cmd('configure terminal') + @device.cmd('aaa authorization config-commands console group ' \ + "#{group0} #{group3} #{group1} local") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group3, group1] + # puts aaa_a_service.groups + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService console get groups, 0/3/1') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/3/1') + + # Mix default and console, but since our instance is for 'console' + # service we should only get 'console' groups and not 'default' + # groups. + aaa_cmd1 = 'aaa authorization config-commands console group ' \ + "#{group0} #{group2} #{group1} #{group3} local" + aaa_cmd2 = 'aaa authorization config-commands default group ' \ + "#{group0} #{group2} #{group3} local" + @device.cmd('configure terminal') + @device.cmd(aaa_cmd1) + @device.cmd(aaa_cmd2) + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + + groups = [group0, group2, group1, group3] + assert_equal(groups, aaa_a_service.groups, + 'Error: AaaAuthorizationService console get groups, 0/2/1/3') + assert_equal(:local, aaa_a_service.method, + 'Error: AaaAuthorizationService default get method, 0/2/1/3') + + # Cleanup + aaa_a_service.destroy + @device.cmd('configure terminal') + @device.cmd("no #{aaa_cmd1}") + @device.cmd("no #{aaa_cmd2}") + @device.cmd('end') + # Flush the cache since we've modified the device outside of RLB + node.cache_flush + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_get_default_groups + feature_tacacs + groups = [] + + type = :commands + aaa_a_service = AaaAuthorizationService.new(type, 'default') + + assert_equal(groups, aaa_a_service.default_groups, + 'Error: AaaAuthorizationService commands default, ' \ + 'default groups') + aaa_a_service.destroy + + aaa_a_service = AaaAuthorizationService.new(type, 'console') + + assert_equal(groups, aaa_a_service.default_groups, + 'Error: AaaAuthorizationService commands console, ' \ + 'default groups') + aaa_a_service.destroy + + type = :config_commands + aaa_a_service = AaaAuthorizationService.new(type, 'default') + + assert_equal(groups, aaa_a_service.default_groups, + 'Error: AaaAuthorizationService config-commands ' \ + 'default, default groups') + aaa_a_service.destroy + + aaa_a_service = AaaAuthorizationService.new(type, 'console') + + assert_equal(groups, aaa_a_service.default_groups, + 'Error: AaaAuthorizationService config-commands ' \ + 'console, default groups') + aaa_a_service.destroy + + feature_tacacs(false) + end + + def test_aaaauthorizationservice_commands_default_set_groups + feature_tacacs + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + # Commands, service default + type_str = 'commands' + type = :commands + service = 'default' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # Single group, with method 'unselected' + method = :unselected + groups = [group0] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0}" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0} #{method}") + + # Multi group, with method 'unselected' + method = :unselected + groups = [group0, group1, group2] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group2} #{method}") + + # Multi group, with method 'local' + method = :local + groups = [group0, group1, group3] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group3} #{method}") + + # Default group and method + method = aaa_a_service.default_method + groups = aaa_a_service.default_groups + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + 'set default groups and method') + + # Cleanup + aaa_a_service.destroy + + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_commands_console_set_groups + feature_tacacs + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + # Commands, service console + type_str = 'commands' + type = :commands + service = 'console' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # Single group, with method 'unselected' + method = :unselected + groups = [group0] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0}" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0} #{method}") + + # Multi group, with method 'unselected' + method = :unselected + groups = [group0, group1, group2] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group2} #{method}") + + # Multi group, with method 'local' + method = :local + groups = [group0, group1, group3] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group3} #{method}") + + # Default group and method + method = aaa_a_service.default_method + groups = aaa_a_service.default_groups + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationservice #{type_str} #{service}, " \ + 'set default groups and method') + + # Cleanup + aaa_a_service.destroy + + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_config_commands_default_set_groups + feature_tacacs + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + # Commands, service default + type_str = 'config-commands' + type = :config_commands + service = 'default' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # Single group, with method 'unselected' + method = :unselected + groups = [group0] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0}" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0} #{method}") + + # Multi group, with method 'unselected' + method = :unselected + groups = [group0, group1, group2] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group2} #{method}") + + # Multi group, with method 'local' + method = :local + groups = [group0, group1, group3] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group3} #{method}") + + # Default group and method + method = aaa_a_service.default_method + groups = aaa_a_service.default_groups + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + 'set default groups and method') + + # Cleanup + aaa_a_service.destroy + + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_config_commands_console_set_groups + feature_tacacs + + # Preconfigure tacacs, tacacs server and AAA valid group + group0 = 'tac_group' + preconfig_tacacs_server_access(group0) + + # Preconfig for test + group1 = 'bxb100' + group2 = 'sjc200' + group3 = 'rtp10' + servers = [group1, group2, group3] + config_tacacs_servers(servers) + + # Commands, service console + type_str = 'config-commands' + type = :config_commands + service = 'console' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # Single group, with method 'unselected' + method = :unselected + groups = [group0] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0}" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0} #{method}") + + # Multi group, with method 'unselected' + method = :unselected + groups = [group0, group1, group2] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" + line = get_match_line(match) + refute_nil(line, "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group2} #{method}") + + # Multi group, with method 'local' + method = :local + groups = [group0, group1, group3] + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationService #{type_str} #{service}, " \ + "set groups #{group0}/#{group1}/#{group3} #{method}") + + # Default group and method + method = aaa_a_service.default_method + groups = aaa_a_service.default_groups + aaa_a_service.groups_method_set(groups, method) + match = "#{type_str} #{service} local" + line = get_match_line(match) + refute_nil(line, + "Error: AaaAuthorizationservice #{type_str} #{service}, " \ + 'set default groups and method') + + # Cleanup + aaa_a_service.destroy + + # Unconfigure tacacs, tacacs server and AAA valid group + preconfig_tacacs_server_access(group0, false) + feature_tacacs(false) + end + + def test_aaaauthorizationservice_commands_invalid_groups_method_set_groups + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # Commands, with service default + type = :commands + service = 'default' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # Single invalid group + groups = ['test1'] + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :unselected) + end + + # Multi groups with invalid group + groups = %w(rtp10 test2 bxb100) + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :local) + end + aaa_a_service.destroy + + # Repeat the test for service 'console' + service = 'console' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # Single invalid group + groups = ['test1'] + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :unselected) + end + + # Multi group with invalid group + groups = %w(rtp10 test1 bxb100) + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :local) + end + + # Multiple group with group and invalid method + groups = %w(rtp10 bxb100) + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 45) + end + + aaa_a_service.destroy + feature_tacacs(false) + end + + def test_aaaauthorizationservice_config_commands_invalid_set_groups + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # Commands, with service default + type = :config_commands + service = 'default' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # Single invalid group + groups = ['test1'] + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :unselected) + end + + # Multi groups with invalid group + groups = %w(rtp10 test2 bxb100) + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :local) + end + aaa_a_service.destroy + + # Repeat the test for service 'console' + service = 'console' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # one invalid group + groups = ['test1'] + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :unselected) + end + + # multiple group with invalid group + groups = %w(rtp10 test1 bxb100) + assert_raises(RuntimeError) do + aaa_a_service.groups_method_set(groups, :local) + end + + # Multiple group with group and invalid method + groups = %w(rtp10 bxb100) + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 45) + end + + aaa_a_service.destroy + feature_tacacs(false) + end + + def test_aaaauthorizationservice_commands_invalid_method + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # Commands, with service default + type = :commands + service = 'default' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # No group and invalid method + groups = [] + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 'test') + end + + # Multiple group with group and invalid method + groups = %w(rtp10 bxb100) + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 45) + end + aaa_a_service.destroy + + # Repeat the test for service 'console' + service = 'console' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # No group and invalid method + groups = [] + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 'test') + end + + # Multiple group with group and invalid method + groups = %w(rtp10 bxb100) + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 45) + end + + aaa_a_service.destroy + feature_tacacs(false) + end + + def test_aaaauthorizationservice_config_commands_invalid_method + # preconfig servers + servers = %w(bxb100 sjc200 rtp10) + config_tacacs_servers(servers) + + # Commands, with service default + type = :config_commands + service = 'default' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # No group and invalid method + groups = [] + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 'test') + end + + # Multiple group with group and invalid method + groups = %w(rtp10 bxb100) + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 45) + end + aaa_a_service.destroy + + # Repeat the test for service 'console' + service = 'console' + aaa_a_service = AaaAuthorizationService.new(type, service) + + # No group and invalid method + groups = [] + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 'test') + end + + # Multiple group with group and invalid method + groups = %w(rtp10 bxb100) + assert_raises(TypeError) do + aaa_a_service.groups_method_set(groups, 45) + end + + aaa_a_service.destroy + feature_tacacs(false) + end +end From 238350a785b9e4e45ff50884f9a9dc7202071682 Mon Sep 17 00:00:00 2001 From: Alex Hunsberger Date: Thu, 22 Oct 2015 11:06:37 -0400 Subject: [PATCH 006/386] aaa author service address code review comments --- tests/test_aaa_authorization_service.rb | 421 +++++++----------------- 1 file changed, 116 insertions(+), 305 deletions(-) diff --git a/tests/test_aaa_authorization_service.rb b/tests/test_aaa_authorization_service.rb index 2e74d8da..4c8fe972 100644 --- a/tests/test_aaa_authorization_service.rb +++ b/tests/test_aaa_authorization_service.rb @@ -16,58 +16,56 @@ require_relative '../lib/cisco_node_utils/aaa_authorization_service' # TestAaaAuthorizationService - Minitest for AaaAuthorizationService util -# rubocop:disable ClassLength class TestAaaAuthorizationService < CiscoTestCase + def setup + super + feature_tacacs + end + + def teardown + feature_tacacs(false) + super + end + # Method to pre-configure a valid tacacs server and aaa group. This # group can be included in the testing such access to the device # never is compromised. def preconfig_tacacs_server_access(group_name, keep=true) - @device.cmd('configure terminal') if keep - @device.cmd('tacacs-server key testing123') - @device.cmd('tacacs-server host 10.122.197.197 key testing123') - @device.cmd("aaa group server tacacs+ #{group_name}") - @device.cmd('server 10.122.197.197') - @device.cmd('use-vrf management') - @device.cmd('source-interface mgmt0') - @device.cmd('aaa authentication login ascii-authentication') + config('tacacs-server key testing123', + 'tacacs-server host 10.122.197.197 key testing123', + "aaa group server tacacs+ #{group_name}", + 'server 10.122.197.197', + 'use-vrf management', + 'source-interface mgmt0', + 'aaa authentication login ascii-authentication') else - @device.cmd("no aaa group server tacacs+ #{group_name}") + config("no aaa group server tacacs+ #{group_name}") end - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush end def feature_tacacs(feature=true) - @device.cmd('configure terminal') if feature - @device.cmd('feature tacacs') + config('feature tacacs') else - @device.cmd('no feature tacacs') - @device.cmd('no aaa authentication login ascii-authentication') + config('no feature tacacs', + 'no aaa authentication login ascii-authentication') end - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush end def config_tacacs_servers(servers) - @device.cmd('configure terminal') - @device.cmd('feature tacacs+') + config('feature tacacs+') servers.each do |server| - @device.cmd("aaa group server tacacs+ #{server}") + config("aaa group server tacacs+ #{server}") end - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush end - def get_match_line(name) - s = @device.cmd('show run aaa all | no-more') - prefix = 'aaa authorization' - line = /#{prefix} #{name}/.match(s) - line + def show_cmd + 'show run aaa all | no-more' + end + + def prefix + 'aaa authorization' end def test_aaaauthorizationservice_create_unsupported_type @@ -107,62 +105,46 @@ def test_aaaauthorizationservice_create_empty_service end def test_aaaauthorizationservice_create_commands_default - feature_tacacs aaa_a_service = AaaAuthorizationService.new(:commands, 'default') - refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating commands default') aaa_a_service.destroy unless aaa_a_service.nil? - feature_tacacs(false) end def test_aaaauthorizationservice_create_commands_console - feature_tacacs aaa_a_service = AaaAuthorizationService.new(:commands, 'console') - refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating commands default') aaa_a_service.destroy unless aaa_a_service.nil? - feature_tacacs(false) end def test_aaaauthorizationservice_create_config_commands_default - feature_tacacs aaa_a_service = AaaAuthorizationService.new(:config_commands, 'default') - refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating ' \ 'config-commands default') aaa_a_service.destroy unless aaa_a_service.nil? - feature_tacacs(false) end def test_aaaauthorizationservice_create_config_commands_console - feature_tacacs aaa_a_service = AaaAuthorizationService.new(:config_commands, 'console') - refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating commands default') aaa_a_service.destroy unless aaa_a_service.nil? - feature_tacacs(false) end def test_aaaauthorizationservice_get_type - feature_tacacs type = :config_commands aaa_a_service = AaaAuthorizationService.new(type, 'default') assert_equal(type, aaa_a_service.type, 'Error : Invalid type') aaa_a_service.destroy - feature_tacacs(false) end def test_aaaauthorizationservice_get_name - feature_tacacs service = 'default' aaa_a_service = AaaAuthorizationService.new(:config_commands, service) assert_equal(service, aaa_a_service.name, 'Error : Invalid service name') aaa_a_service.destroy - feature_tacacs(false) end def test_aaaauthorizationservice_collection_invalid @@ -170,8 +152,6 @@ def test_aaaauthorizationservice_collection_invalid end def test_aaaauthorizationservice_collection_services_type_commands - # Need feature tacacs for this test - feature_tacacs type = :commands collection = AaaAuthorizationService.services[type] @@ -201,11 +181,9 @@ def test_aaaauthorizationservice_collection_services_type_commands "#{service} in collection") aaa_a_service.destroy end - feature_tacacs(false) end def test_aaaauthorizationservice_collection_services_type_config_commands - feature_tacacs type = :config_commands collection = AaaAuthorizationService.services[type] @@ -234,22 +212,15 @@ def test_aaaauthorizationservice_collection_services_type_config_commands "#{service} in collection") aaa_a_service.destroy end - feature_tacacs(false) end def test_aaaauthorizationservice_type_commands_default_console_group - feature_tacacs - # Preconfig AAA Authorization cmd1 = 'aaa authorization commands default group group2 group1 local' cmd2 = 'aaa authorization commands console group group1 local' - @device.cmd('configure terminal') - @device.cmd('aaa group server tacacs+ group1') - @device.cmd('aaa group server tacacs+ group2') - @device.cmd(cmd1) - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa group server tacacs+ group1', + 'aaa group server tacacs+ group2', + cmd1) type = :commands collection = AaaAuthorizationService.services[type] @@ -280,11 +251,7 @@ def test_aaaauthorizationservice_type_commands_default_console_group # only one of default or console can be configured at a time without # locking the CLI - @device.cmd('configure terminal') - @device.cmd("no #{cmd1}") - @device.cmd(cmd2) - @device.cmd('end') - node.cache_flush + config("no #{cmd1}", cmd2) service = 'console' aaa_a_service = collection[service] @@ -297,26 +264,16 @@ def test_aaaauthorizationservice_type_commands_default_console_group 'Error: Invalid AaaAuthorizationService groups for ' \ 'console in collection') - @device.cmd('configure terminal') - @device.cmd("no #{cmd2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush - feature_tacacs(false) + config("no #{cmd2}") end def test_aaaauthorizationservice_type_config_commands_default_console_group - feature_tacacs # Preconfig AAA Authorization cmd1 = 'aaa authorization config-commands default group group2 group1 local' cmd2 = 'aaa authorization config-commands console group group1 local' - @device.cmd('configure terminal') - @device.cmd('aaa group server tacacs+ group1') - @device.cmd('aaa group server tacacs+ group2') - @device.cmd(cmd1) - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa group server tacacs+ group1', + 'aaa group server tacacs+ group2', + cmd1) type = :config_commands collection = AaaAuthorizationService.services[type] @@ -345,12 +302,7 @@ def test_aaaauthorizationservice_type_config_commands_default_console_group 'Error: Invalid AaaAuthorizationService groups ' \ 'for default in collection') - @device.cmd('configure terminal') - @device.cmd("no #{cmd1}") - @device.cmd(cmd2) - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config("no #{cmd1}", cmd2) service = 'console' aaa_a_service = collection[service] @@ -363,16 +315,10 @@ def test_aaaauthorizationservice_type_config_commands_default_console_group 'Error: Invalid AaaAuthorizationService groups ' \ 'for console in collection') - @device.cmd('configure terminal') - @device.cmd("no #{cmd2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush - feature_tacacs(false) + config("no #{cmd2}") end def test_aaaauthorizationservice_get_default_method - feature_tacacs type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'default') assert_equal(:local, aaa_a_service.default_method, @@ -398,12 +344,9 @@ def test_aaaauthorizationservice_get_default_method 'Error: AaaAuthorizationService config-command ' \ 'console, default method') aaa_a_service.destroy - feature_tacacs(false) end def test_aaaauthorizationservice_collection_groups_commands_default - feature_tacacs - type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'default') @@ -423,12 +366,8 @@ def test_aaaauthorizationservice_collection_groups_commands_default servers = [group1, group2, group3] config_tacacs_servers(servers) - @device.cmd('configure terminal') - @device.cmd('aaa authorization commands default group ' \ - "#{group0} #{group1} #{group2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization commands default group ' \ + "#{group0} #{group1} #{group2}") groups = [group0, group1, group2] assert_equal(groups, aaa_a_service.groups, @@ -437,15 +376,10 @@ def test_aaaauthorizationservice_collection_groups_commands_default 'Error: AaaAuthorizationService default get method, 0/1/2') # Change the config to have different groups and method - @device.cmd('configure terminal') - @device.cmd('aaa authorization commands default group ' \ - "#{group0} #{group3} #{group1} local") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization commands default group ' \ + "#{group0} #{group3} #{group1} local") groups = [group0, group3, group1] - # puts aaa_a_service.groups assert_equal(groups, aaa_a_service.groups, 'Error: AaaAuthorizationService default get groups, 0/3/1') assert_equal(:local, aaa_a_service.method, @@ -458,12 +392,7 @@ def test_aaaauthorizationservice_collection_groups_commands_default "#{group0} #{group2} #{group1} #{group3} local" aaa_cmd2 = 'aaa authorization commands console group ' \ "#{group0} #{group2} #{group3} local" - @device.cmd('configure terminal') - @device.cmd(aaa_cmd1) - @device.cmd(aaa_cmd2) - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config(aaa_cmd1, aaa_cmd2) groups = [group0, group2, group1, group3] assert_equal(groups, aaa_a_service.groups, @@ -473,21 +402,13 @@ def test_aaaauthorizationservice_collection_groups_commands_default # Cleanup aaa_a_service.destroy - @device.cmd('configure terminal') - @device.cmd("no #{aaa_cmd1}") - @device.cmd("no #{aaa_cmd2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config("no #{aaa_cmd1}", "no #{aaa_cmd2}") # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_collection_groups_commands_console - feature_tacacs - type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'console') @@ -507,12 +428,8 @@ def test_aaaauthorizationservice_collection_groups_commands_console servers = [group1, group2, group3] config_tacacs_servers(servers) - @device.cmd('configure terminal') - @device.cmd('aaa authorization commands console group ' \ - "#{group0} #{group1} #{group2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization commands console group ' \ + "#{group0} #{group1} #{group2}") groups = [group0, group1, group2] # puts aaa_a_service.groups @@ -522,12 +439,8 @@ def test_aaaauthorizationservice_collection_groups_commands_console 'Error: AaaAuthorizationService default get method, 0/1/2') # Change the config to have different groups and method - @device.cmd('configure terminal') - @device.cmd('aaa authorization commands console group ' \ - "#{group0} #{group3} #{group1} local") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization commands console group ' \ + "#{group0} #{group3} #{group1} local") groups = [group0, group3, group1] assert_equal(groups, aaa_a_service.groups, @@ -542,12 +455,7 @@ def test_aaaauthorizationservice_collection_groups_commands_console "#{group0} #{group2} #{group1} #{group3} local" aaa_cmd2 = 'aaa authorization commands default group ' \ "#{group0} #{group2} #{group3} local" - @device.cmd('configure terminal') - @device.cmd(aaa_cmd1) - @device.cmd(aaa_cmd2) - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config(aaa_cmd1, aaa_cmd2) groups = [group0, group2, group1, group3] assert_equal(groups, aaa_a_service.groups, @@ -557,21 +465,13 @@ def test_aaaauthorizationservice_collection_groups_commands_console # Cleanup aaa_a_service.destroy - @device.cmd('configure terminal') - @device.cmd("no #{aaa_cmd1}") - @device.cmd("no #{aaa_cmd2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config("no #{aaa_cmd1}", "no #{aaa_cmd2}") # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_collection_groups_config_commands_default - feature_tacacs - type = :config_commands aaa_a_service = AaaAuthorizationService.new(type, 'default') @@ -591,12 +491,8 @@ def test_aaaauthorizationservice_collection_groups_config_commands_default servers = [group1, group2, group3] config_tacacs_servers(servers) - @device.cmd('configure terminal') - @device.cmd('aaa authorization config-commands default group ' \ - "#{group0} #{group1} #{group2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization config-commands default group ' \ + "#{group0} #{group1} #{group2}") groups = [group0, group1, group2] assert_equal(groups, aaa_a_service.groups, @@ -605,12 +501,8 @@ def test_aaaauthorizationservice_collection_groups_config_commands_default 'Error: AaaAuthorizationService default get method, 0/1/2') # Change the config to have different groups and method - @device.cmd('configure terminal') - @device.cmd('aaa authorization config-commands default group ' \ - "#{group0} #{group3} #{group1} local") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization config-commands default group ' \ + "#{group0} #{group3} #{group1} local") groups = [group0, group3, group1] # puts aaa_a_service.groups @@ -626,12 +518,7 @@ def test_aaaauthorizationservice_collection_groups_config_commands_default "#{group0} #{group2} #{group1} #{group3} local" aaa_cmd2 = 'aaa authorization config-commands console group ' \ "#{group0} #{group2} #{group3} local" - @device.cmd('configure terminal') - @device.cmd(aaa_cmd1) - @device.cmd(aaa_cmd2) - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config(aaa_cmd1, aaa_cmd2) groups = [group0, group2, group1, group3] assert_equal(groups, aaa_a_service.groups, @@ -641,21 +528,13 @@ def test_aaaauthorizationservice_collection_groups_config_commands_default # Cleanup aaa_a_service.destroy - @device.cmd('configure terminal') - @device.cmd("no #{aaa_cmd1}") - @device.cmd("no #{aaa_cmd2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config("no #{aaa_cmd1}", "no #{aaa_cmd2}") # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_collection_groups_config_commands_console - feature_tacacs - type = :config_commands aaa_a_service = AaaAuthorizationService.new(type, 'console') @@ -675,12 +554,8 @@ def test_aaaauthorizationservice_collection_groups_config_commands_console servers = [group1, group2, group3] config_tacacs_servers(servers) - @device.cmd('configure terminal') - @device.cmd('aaa authorization config-commands console group ' \ - "#{group0} #{group1} #{group2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization config-commands console group ' \ + "#{group0} #{group1} #{group2}") groups = [group0, group1, group2] assert_equal(groups, aaa_a_service.groups, @@ -689,12 +564,8 @@ def test_aaaauthorizationservice_collection_groups_config_commands_console 'Error: AaaAuthorizationService default get method, 0/1/2') # Change the config to have different groups and method - @device.cmd('configure terminal') - @device.cmd('aaa authorization config-commands console group ' \ - "#{group0} #{group3} #{group1} local") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config('aaa authorization config-commands console group ' \ + "#{group0} #{group3} #{group1} local") groups = [group0, group3, group1] # puts aaa_a_service.groups @@ -710,12 +581,7 @@ def test_aaaauthorizationservice_collection_groups_config_commands_console "#{group0} #{group2} #{group1} #{group3} local" aaa_cmd2 = 'aaa authorization config-commands default group ' \ "#{group0} #{group2} #{group3} local" - @device.cmd('configure terminal') - @device.cmd(aaa_cmd1) - @device.cmd(aaa_cmd2) - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config(aaa_cmd1, aaa_cmd2) groups = [group0, group2, group1, group3] assert_equal(groups, aaa_a_service.groups, @@ -725,21 +591,14 @@ def test_aaaauthorizationservice_collection_groups_config_commands_console # Cleanup aaa_a_service.destroy - @device.cmd('configure terminal') - @device.cmd("no #{aaa_cmd1}") - @device.cmd("no #{aaa_cmd2}") - @device.cmd('end') - # Flush the cache since we've modified the device outside of RLB - node.cache_flush + config("no #{aaa_cmd1}", "no #{aaa_cmd2}") + # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_get_default_groups - feature_tacacs groups = [] - type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'default') @@ -769,13 +628,9 @@ def test_aaaauthorizationservice_get_default_groups 'Error: AaaAuthorizationService config-commands ' \ 'console, default groups') aaa_a_service.destroy - - feature_tacacs(false) end def test_aaaauthorizationservice_commands_default_set_groups - feature_tacacs - # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -797,53 +652,43 @@ def test_aaaauthorizationservice_commands_default_set_groups method = :unselected groups = [group0] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0}" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'unselected' method = :unselected groups = [group0, group1, group2] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group2} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0} #{group1} #{group2}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'local' method = :local groups = [group0, group1, group3] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group3} #{method}") + + group_str = "group #{group0} #{group1} #{group3}" + p = /#{prefix} #{type_str} #{service} #{group_str} local/ + assert_show_match(command: show_cmd, pattern: p) # Default group and method method = aaa_a_service.default_method groups = aaa_a_service.default_groups aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - 'set default groups and method') + + p = /#{prefix} #{type_str} #{service} local/ + assert_show_match(command: show_cmd, pattern: p) # Cleanup aaa_a_service.destroy # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_commands_console_set_groups - feature_tacacs - # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -865,53 +710,42 @@ def test_aaaauthorizationservice_commands_console_set_groups method = :unselected groups = [group0] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0}" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'unselected' method = :unselected groups = [group0, group1, group2] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group2} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0} #{group1} #{group2}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'local' method = :local groups = [group0, group1, group3] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group3} #{method}") + + group_str = "group #{group0} #{group1} #{group3}" + p = /#{prefix} #{type_str} #{service} #{group_str} local/ + assert_show_match(command: show_cmd, pattern: p) # Default group and method method = aaa_a_service.default_method groups = aaa_a_service.default_groups aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationservice #{type_str} #{service}, " \ - 'set default groups and method') - # Cleanup + p = /#{prefix} #{type_str} #{service} local/ + assert_show_match(command: show_cmd, pattern: p) + aaa_a_service.destroy # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_config_commands_default_set_groups - feature_tacacs - # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -933,53 +767,42 @@ def test_aaaauthorizationservice_config_commands_default_set_groups method = :unselected groups = [group0] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0}" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'unselected' method = :unselected groups = [group0, group1, group2] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group2} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0} #{group1} #{group2}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'local' method = :local groups = [group0, group1, group3] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group3} #{method}") + + group_str = "group #{group0} #{group1} #{group3}" + p = /#{prefix} #{type_str} #{service} #{group_str} local/ + assert_show_match(command: show_cmd, pattern: p) # Default group and method method = aaa_a_service.default_method groups = aaa_a_service.default_groups aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - 'set default groups and method') - # Cleanup + p = /#{prefix} #{type_str} #{service} local/ + assert_show_match(command: show_cmd, pattern: p) + aaa_a_service.destroy # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_config_commands_console_set_groups - feature_tacacs - # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -1001,47 +824,39 @@ def test_aaaauthorizationservice_config_commands_console_set_groups method = :unselected groups = [group0] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0}" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'unselected' method = :unselected groups = [group0, group1, group2] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group2}" - line = get_match_line(match) - refute_nil(line, "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group2} #{method}") + + p = /#{prefix} #{type_str} #{service} group #{group0} #{group1} #{group2}/ + assert_show_match(command: show_cmd, pattern: p) # Multi group, with method 'local' method = :local groups = [group0, group1, group3] aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} group #{group0} #{group1} #{group3} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationService #{type_str} #{service}, " \ - "set groups #{group0}/#{group1}/#{group3} #{method}") + + group_str = "group #{group0} #{group1} #{group3}" + p = /#{prefix} #{type_str} #{service} #{group_str} local/ + assert_show_match(command: show_cmd, pattern: p) # Default group and method method = aaa_a_service.default_method groups = aaa_a_service.default_groups aaa_a_service.groups_method_set(groups, method) - match = "#{type_str} #{service} local" - line = get_match_line(match) - refute_nil(line, - "Error: AaaAuthorizationservice #{type_str} #{service}, " \ - 'set default groups and method') - # Cleanup + p = /#{prefix} #{type_str} #{service} local/ + assert_show_match(command: show_cmd, pattern: p) + aaa_a_service.destroy # Unconfigure tacacs, tacacs server and AAA valid group preconfig_tacacs_server_access(group0, false) - feature_tacacs(false) end def test_aaaauthorizationservice_commands_invalid_groups_method_set_groups @@ -1090,7 +905,6 @@ def test_aaaauthorizationservice_commands_invalid_groups_method_set_groups end aaa_a_service.destroy - feature_tacacs(false) end def test_aaaauthorizationservice_config_commands_invalid_set_groups @@ -1139,7 +953,6 @@ def test_aaaauthorizationservice_config_commands_invalid_set_groups end aaa_a_service.destroy - feature_tacacs(false) end def test_aaaauthorizationservice_commands_invalid_method @@ -1182,7 +995,6 @@ def test_aaaauthorizationservice_commands_invalid_method end aaa_a_service.destroy - feature_tacacs(false) end def test_aaaauthorizationservice_config_commands_invalid_method @@ -1225,6 +1037,5 @@ def test_aaaauthorizationservice_config_commands_invalid_method end aaa_a_service.destroy - feature_tacacs(false) end end From 351e7876f56a7543f675ce6893bd361084cedf40 Mon Sep 17 00:00:00 2001 From: Chris Van Heuveln Date: Fri, 23 Oct 2015 17:37:20 -0400 Subject: [PATCH 007/386] rubocop fixes for AAA providers rubocop is clean, AAA minitests are 100% --- .../aaa_authentication_login.rb | 150 ++--- .../aaa_authentication_login_service.rb | 186 +++--- .../aaa_authorization_service.rb | 32 +- lib/cisco_node_utils/aaa_server_group.rb | 232 ++++---- tests/test_aaa_authentication_login.rb | 307 +++------- .../test_aaa_authentication_login_service.rb | 545 ++++++++---------- tests/test_aaa_authorization_service.rb | 78 +-- tests/test_aaa_server_group.rb | 455 ++++++--------- 8 files changed, 862 insertions(+), 1123 deletions(-) diff --git a/lib/cisco_node_utils/aaa_authentication_login.rb b/lib/cisco_node_utils/aaa_authentication_login.rb index 8d095649..4e3916a0 100644 --- a/lib/cisco_node_utils/aaa_authentication_login.rb +++ b/lib/cisco_node_utils/aaa_authentication_login.rb @@ -18,81 +18,83 @@ # limitations under the License. # -require File.join(File.dirname(__FILE__), 'node') +require_relative 'node_util' module Cisco -class AaaAuthenticationLogin - @@node = Cisco::Node.instance - - # There is no "feature aaa" or "aaa new-model" on nxos, and only one - # instance which is always available - - # TODO: onep didn't implement mschap, mschapv2, chap, default fallback, console - # fallback. Should I? - - def AaaAuthenticationLogin.ascii_authentication - not @@node.config_get("aaa_authentication_login", "ascii_authentication").nil? - end - - def AaaAuthenticationLogin.ascii_authentication=(val) - no_cmd = val ? "" : "no" - @@node.config_set("aaa_authentication_login", "ascii_authentication", no_cmd) - end - - def AaaAuthenticationLogin.default_ascii_authentication - @@node.config_get_default("aaa_authentication_login", "ascii_authentication") - end - - def AaaAuthenticationLogin.chap - not @@node.config_get("aaa_authentication_login", "chap").nil? - end - - def AaaAuthenticationLogin.chap=(val) - no_cmd = val ? "" : "no" - @@node.config_set("aaa_authentication_login", "chap", no_cmd) - end - - def AaaAuthenticationLogin.default_chap - @@node.config_get_default("aaa_authentication_login", "chap") - end - - def AaaAuthenticationLogin.error_display - not @@node.config_get("aaa_authentication_login", "error_display").nil? - end - - def AaaAuthenticationLogin.error_display=(val) - no_cmd = val ? "" : "no" - @@node.config_set("aaa_authentication_login", "error_display", no_cmd) - end - - def AaaAuthenticationLogin.default_error_display - @@node.config_get_default("aaa_authentication_login", "error_display") - end - - def AaaAuthenticationLogin.mschap - not @@node.config_get("aaa_authentication_login", "mschap").nil? - end - - def AaaAuthenticationLogin.mschap=(val) - no_cmd = val ? "" : "no" - @@node.config_set("aaa_authentication_login", "mschap", no_cmd) - end - - def AaaAuthenticationLogin.default_mschap - @@node.config_get_default("aaa_authentication_login", "mschap") - end - - def AaaAuthenticationLogin.mschapv2 - not @@node.config_get("aaa_authentication_login", "mschapv2").nil? - end - - def AaaAuthenticationLogin.mschapv2=(val) - no_cmd = val ? "" : "no" - @@node.config_set("aaa_authentication_login", "mschapv2", no_cmd) - end - - def AaaAuthenticationLogin.default_mschapv2 - @@node.config_get_default("aaa_authentication_login", "mschapv2") + # NXAPI implementation of AAA Authentication Login class + class AaaAuthenticationLogin < NodeUtil + # There is no "feature aaa" or "aaa new-model" on nxos, and only one + # instance which is always available + + # TODO: Missing properties: mschap, mschapv2, chap, default fallback, + # console fallback. + + def self.ascii_authentication + !node.config_get('aaa_authentication_login', + 'ascii_authentication').nil? + end + + def self.ascii_authentication=(val) + no_cmd = val ? '' : 'no' + node.config_set('aaa_authentication_login', + 'ascii_authentication', no_cmd) + end + + def self.default_ascii_authentication + node.config_get_default('aaa_authentication_login', + 'ascii_authentication') + end + + def self.chap + !node.config_get('aaa_authentication_login', 'chap').nil? + end + + def self.chap=(val) + no_cmd = val ? '' : 'no' + node.config_set('aaa_authentication_login', 'chap', no_cmd) + end + + def self.default_chap + node.config_get_default('aaa_authentication_login', 'chap') + end + + def self.error_display + !node.config_get('aaa_authentication_login', 'error_display').nil? + end + + def self.error_display=(val) + no_cmd = val ? '' : 'no' + node.config_set('aaa_authentication_login', 'error_display', no_cmd) + end + + def self.default_error_display + node.config_get_default('aaa_authentication_login', 'error_display') + end + + def self.mschap + !node.config_get('aaa_authentication_login', 'mschap').nil? + end + + def self.mschap=(val) + no_cmd = val ? '' : 'no' + node.config_set('aaa_authentication_login', 'mschap', no_cmd) + end + + def self.default_mschap + node.config_get_default('aaa_authentication_login', 'mschap') + end + + def self.mschapv2 + !node.config_get('aaa_authentication_login', 'mschapv2').nil? + end + + def self.mschapv2=(val) + no_cmd = val ? '' : 'no' + node.config_set('aaa_authentication_login', 'mschapv2', no_cmd) + end + + def self.default_mschapv2 + node.config_get_default('aaa_authentication_login', 'mschapv2') + end end end -end diff --git a/lib/cisco_node_utils/aaa_authentication_login_service.rb b/lib/cisco_node_utils/aaa_authentication_login_service.rb index d3f0ad6c..e6984a31 100644 --- a/lib/cisco_node_utils/aaa_authentication_login_service.rb +++ b/lib/cisco_node_utils/aaa_authentication_login_service.rb @@ -17,119 +17,117 @@ # See the License for the specific language governing permissions and # limitations under the License. -require File.join(File.dirname(__FILE__), 'node') +require_relative 'node_util' module Cisco -class AaaAuthenticationLoginService - @@node = Cisco::Node.instance + # NXAPI implementation of AAA Authentication Login Service class + class AaaAuthenticationLoginService < NodeUtil + attr_reader :name - attr_reader :name + def initialize(name, create=true) + fail TypeError unless name.is_a? String + # only console and default are supported currently + fail ArgumentError unless %w(console default).include? name + @name = name - def initialize(name, create=true) - raise TypeError unless name.is_a? String - # only console and default are supported currently - raise ArgumentError unless %w(console default).include? name - @name = name - - # console needs to be explicitly created before it appears in - # "show run aaa all" but oddly not before it shows up in - # "show aaa authentication" - if create + # console needs to be explicitly created before it appears in + # "show run aaa all" but oddly not before it shows up in + # "show aaa authentication" + return unless create m = default_method.to_s - @@node.config_set("aaa_auth_login_service", "method", "", name, m) + node.config_set('aaa_auth_login_service', 'method', '', name, m) end - end - def AaaAuthenticationLoginService.services - servs = {} - servs_arr = @@node.config_get("aaa_auth_login_service", "services") - unless servs_arr.nil? - servs_arr.each { |s| - servs[s] = AaaAuthenticationLoginService.new(s, false) - } + def self.services + servs = {} + servs_arr = node.config_get('aaa_auth_login_service', 'services') + unless servs_arr.nil? + servs_arr.each do |s| + servs[s] = AaaAuthenticationLoginService.new(s, false) + end + end + servs end - servs - end - def destroy - # must specify exact current config string to unconfigure - m = method - m_str = m == :unselected ? "" : m.to_s - g_str = groups.join(" ") + def destroy + # must specify exact current config string to unconfigure + m = method + m_str = m == :unselected ? '' : m.to_s + g_str = groups.join(' ') - if g_str.empty? - # cannot remove default local, so do nothing in this case - unless m == :local and @name == "default" - @@node.config_set("aaa_auth_login_service", "method", - "no", @name, m_str) + if g_str.empty? + # cannot remove default local, so do nothing in this case + unless m == :local && @name == 'default' + node.config_set('aaa_auth_login_service', 'method', + 'no', @name, m_str) + end + else + node.config_set('aaa_auth_login_service', 'groups', + 'no', @name, g_str, m_str) end - else - @@node.config_set("aaa_auth_login_service", "groups", - "no", @name, g_str, m_str) end - end - # groups aren't retrieved via the usual CLI regex memory method because - # there can be an arbitrary number of groups and specifying a repeating - # memory regex only captures the last match - # ex: aaa authentication login default group group1 group2 group3 none - def groups - # config_get returns the following format: - # [{service:"default",method:"group group1 none "}, - # {service:"console",method:"local "}] - hsh_arr = @@node.config_get("aaa_auth_login_service", "groups", @name) - raise "unable to retrieve aaa groups information" if hsh_arr.nil? - hsh = hsh_arr.find { |x| x["service"] == @name } - # this should never happen unless @name is invalid - raise "no aaa info found for service #{@name}" if hsh.nil? - raise "no method found for #{@name} - api or feature change?" unless - hsh.key? "method" - # ex: ["group", "group1", "local"] or maybe ["none"] - grps = hsh["method"].strip.split - return [] if grps.size == 1 - # remove local, none, group keywords - grps -= %w(none local group) - grps - end + # groups aren't retrieved via the usual CLI regex memory method because + # there can be an arbitrary number of groups and specifying a repeating + # memory regex only captures the last match + # ex: aaa authentication login default group group1 group2 group3 none + def groups + # node.config_get returns the following format: + # [{service:"default",method:"group group1 none "}, + # {service:"console",method:"local "}] + hsh_arr = node.config_get('aaa_auth_login_service', 'groups', @name) + fail 'unable to retrieve aaa groups information' if hsh_arr.nil? + hsh = hsh_arr.find { |x| x['service'] == @name } + # this should never happen unless @name is invalid + fail "no aaa info found for service #{@name}" if hsh.nil? + fail "no method found for #{@name} - api or feature change?" unless + hsh.key? 'method' + # ex: ["group", "group1", "local"] or maybe ["none"] + grps = hsh['method'].strip.split + return [] if grps.size == 1 + # remove local, none, group keywords + grps -= %w(none local group) + grps + end - # default is [] - def default_groups - @@node.config_get_default("aaa_auth_login_service", "groups") - end + # default is [] + def default_groups + node.config_get_default('aaa_auth_login_service', 'groups') + end - def method - m = @@node.config_get("aaa_auth_login_service", "method", @name) - m.nil? ? :unselected : m.first.to_sym - end + def method + m = node.config_get('aaa_auth_login_service', 'method', @name) + m.nil? ? :unselected : m.first.to_sym + end - # default is :local - def default_method - @@node.config_get_default("aaa_auth_login_service", "method") - end + # default is :local + def default_method + node.config_get_default('aaa_auth_login_service', 'method') + end - # groups and method must be set in the same CLI string - # aaa authentication login { console | default } / - # none | local | group [none] - def groups_method_set(grps, m) - raise TypeError unless grps.is_a? Array - raise TypeError unless grps.all? { |x| x.is_a? String } - raise TypeError unless m.is_a? Symbol - # only the following 3 are supported (unselected = blank) - raise ArgumentError unless [:none, :local, :unselected].include? m + # groups and method must be set in the same CLI string + # aaa authentication login { console | default } / + # none | local | group [none] + def groups_method_set(grps, m) + fail TypeError unless grps.is_a? Array + fail TypeError unless grps.all? { |x| x.is_a? String } + fail TypeError unless m.is_a? Symbol + # only the following 3 are supported (unselected = blank) + fail ArgumentError unless [:none, :local, :unselected].include? m - raise "method 'local' not allowed when groups are configured" if - m == :local and not grps.empty? - m_str = m == :unselected ? "" : m.to_s - g_str = grps.join(" ") + fail "method 'local' not allowed when groups are configured" if + m == :local && !grps.empty? + m_str = m == :unselected ? '' : m.to_s + g_str = grps.join(' ') - # different config_set depending on whether we're setting groups or not - if g_str.empty? - @@node.config_set("aaa_auth_login_service", "method", - "", @name, m_str) - else - @@node.config_set("aaa_auth_login_service", "groups", - "", @name, g_str, m_str) + # config_set depends on whether we're setting groups or not + if g_str.empty? + node.config_set('aaa_auth_login_service', 'method', + '', @name, m_str) + else + node.config_set('aaa_auth_login_service', 'groups', + '', @name, g_str, m_str) + end end end end -end diff --git a/lib/cisco_node_utils/aaa_authorization_service.rb b/lib/cisco_node_utils/aaa_authorization_service.rb index e9a0510b..6436134f 100644 --- a/lib/cisco_node_utils/aaa_authorization_service.rb +++ b/lib/cisco_node_utils/aaa_authorization_service.rb @@ -36,12 +36,12 @@ def initialize(type, name, create=true) return unless create - config_set('aaa_authorization_service', 'method', '', type_str, name) + node.config_set('aaa_authorization_service', 'method', '', type_str, name) end def self.services servs = {} - servs_arr = config_get('aaa_authorization_service', 'services') + servs_arr = node.config_get('aaa_authorization_service', 'services') unless servs_arr.nil? servs_arr.each do |type, name| type = auth_type_str_to_sym(type) @@ -62,12 +62,12 @@ def destroy if g_str.empty? # cannot remove no groups + local, so do nothing in this case unless m == :local - config_set('aaa_authorization_service', 'method', - 'no', t_str, @name) + node.config_set('aaa_authorization_service', 'method', + 'no', t_str, @name) end else - config_set('aaa_authorization_service', 'groups', - 'no', t_str, @name, g_str, m_str) + node.config_set('aaa_authorization_service', 'groups', + 'no', t_str, @name, g_str, m_str) end end @@ -76,11 +76,11 @@ def destroy # memory regex only captures the last match # ex: aaa authorization console group group1 group2 group3 local def groups - # config_get returns the following format: + # node.config_get returns the following format: # [{"appl_subtype": "console", # "cmd_type": "config-commands", # "methods": "group foo bar local "}], ... - hsh_arr = config_get('aaa_authorization_service', 'groups') + hsh_arr = node.config_get('aaa_authorization_service', 'groups') fail 'unable to retrieve aaa groups information' if hsh_arr.nil? type_s = AaaAuthorizationService.auth_type_sym_to_str(@type) hsh = hsh_arr.find do |x| @@ -99,18 +99,18 @@ def groups # default is [] def default_groups - config_get_default('aaa_authorization_service', 'groups') + node.config_get_default('aaa_authorization_service', 'groups') end def method t_str = AaaAuthorizationService.auth_type_sym_to_str(@type) - m = config_get('aaa_authorization_service', 'method', @name, t_str) + m = node.config_get('aaa_authorization_service', 'method', @name, t_str) m.nil? ? :unselected : m.first.to_sym end # default is :local def default_method - config_get_default('aaa_authorization_service', 'method') + node.config_get_default('aaa_authorization_service', 'method') end # groups and method must be set in the same CLI string @@ -129,13 +129,13 @@ def groups_method_set(grps, m) g_str = grps.join(' ') t_str = AaaAuthorizationService.auth_type_sym_to_str(@type) - # different config_set depending on whether we're setting groups or not + # config_set depends on whether we're setting groups or not if g_str.empty? - config_set('aaa_authorization_service', 'method', - '', t_str, @name) + node.config_set('aaa_authorization_service', 'method', + '', t_str, @name) else - config_set('aaa_authorization_service', 'groups', - '', t_str, @name, g_str, m_str) + node.config_set('aaa_authorization_service', 'groups', + '', t_str, @name, g_str, m_str) end end diff --git a/lib/cisco_node_utils/aaa_server_group.rb b/lib/cisco_node_utils/aaa_server_group.rb index 91e4a7b1..62ba32ed 100644 --- a/lib/cisco_node_utils/aaa_server_group.rb +++ b/lib/cisco_node_utils/aaa_server_group.rb @@ -17,162 +17,160 @@ # See the License for the specific language governing permissions and # limitations under the License. -require File.join(File.dirname(__FILE__), 'node') -require File.join(File.dirname(__FILE__), 'tacacs_server') +require_relative 'node_util' +require_relative 'tacacs_server' module Cisco -class AaaServerGroup - @@node = Cisco::Node.instance - - attr_reader :name, :type - - def initialize(name, type=:tacacs, create=true) - raise TypeError unless type.is_a? Symbol - raise TypeError unless name.is_a? String - @name = name - @type = type - if create + # NXAPI implementation of AAA Server Group class + class AaaServerGroup < NodeUtil + attr_reader :name, :type + + def initialize(name, type=:tacacs, create=true) + fail TypeError unless type.is_a? Symbol + fail TypeError unless name.is_a? String + @name = name + @type = type + return unless create if type == :tacacs TacacsServer.new.enable unless TacacsServer.enabled - @@node.config_set("aaa_server_group", "tacacs_group", "", name) + node.config_set('aaa_server_group', 'tacacs_group', '', name) # elsif type == :radius ... else - raise ArgumentError, "unsupported type #{type}" + fail ArgumentError, "unsupported type #{type}" end end - end - def destroy - if @type == :tacacs - @@node.config_set("aaa_server_group", "tacacs_group", "no", @name) - else - raise ArgumentError, "unsupported type #{@type}" + def destroy + if @type == :tacacs + node.config_set('aaa_server_group', 'tacacs_group', 'no', @name) + else + fail ArgumentError, "unsupported type #{@type}" + end end - end - def servers - servs = {} - if @type == :tacacs - tacservers = @@node.config_get("aaa_server_group", "tacacs_servers", @name) - unless tacservers.nil? - tacservers.each { |s| servs[s] = TacacsServerHost.new(s, false) } + def servers + servs = {} + if @type == :tacacs + tacservers = node.config_get('aaa_server_group', + 'tacacs_servers', @name) + unless tacservers.nil? + tacservers.each { |s| servs[s] = TacacsServerHost.new(s, false) } + end + else + fail ArgumentError, "unsupported type #{@type}" end - else - raise ArgumentError, "unsupported type #{@type}" + servs end - servs - end - def servers=(new_servs) - raise TypeError unless new_servs.is_a? Array - # just need the names of the current servers for comparison - current_servs = servers.keys - new_servs.each { |s| - # add any servers not yet configured - unless current_servs.include? s + def servers=(new_servs) + fail TypeError unless new_servs.is_a? Array + # just need the names of the current servers for comparison + current_servs = servers.keys + new_servs.each do |s| + # add any servers not yet configured + next if current_servs.include? s if @type == :tacacs - @@node.config_set("aaa_server_group", "tacacs_server", @name, "", s) + node.config_set('aaa_server_group', 'tacacs_server', @name, '', s) else - raise ArgumentError, "unsupported type #{@type}" + fail ArgumentError, "unsupported type #{@type}" end end - } - current_servs.each { |s| - # remove any undesired existing servers - unless new_servs.include? s + current_servs.each do |s| + # remove any undesired existing servers + next if new_servs.include? s if @type == :tacacs - @@node.config_set("aaa_server_group", "tacacs_server", @name, "no", s) + node.config_set('aaa_server_group', 'tacacs_server', @name, 'no', s) else - raise ArgumentError, "unsupported type #{@type}" + fail ArgumentError, "unsupported type #{@type}" end end - } - end + end - def AaaServerGroup.default_servers - @@node.config_get_default("aaa_server_group", "servers") - end + def self.default_servers + node.config_get_default('aaa_server_group', 'servers') + end - # allow optionally filtering on server type - def AaaServerGroup.groups(type=nil) - raise TypeError unless type.nil? or type.is_a? Symbol - grps = {} - tacgroups = @@node.config_get("aaa_server_group", "tacacs_groups") if - [nil, :tacacs].include? type and TacacsServer.enabled - unless tacgroups.nil? - tacgroups.each { |s| grps[s] = AaaServerGroup.new(s, :tacacs, false) } + # allow optionally filtering on server type + def self.groups(type=nil) + fail TypeError unless type.nil? || type.is_a?(Symbol) + grps = {} + tacgroups = node.config_get('aaa_server_group', 'tacacs_groups') if + [nil, :tacacs].include?(type) && TacacsServer.enabled + unless tacgroups.nil? + tacgroups.each { |s| grps[s] = AaaServerGroup.new(s, :tacacs, false) } + end + grps end - grps - end - def vrf - if @type == :tacacs - # vrf is always present in running config - v = @@node.config_get("aaa_server_group", "tacacs_vrf", @name) - return v.nil? ? AaaServerGroup.default_vrf : v.first - else - raise ArgumentError, "unsupported type #{@type}" + def vrf + if @type == :tacacs + # vrf is always present in running config + v = node.config_get('aaa_server_group', 'tacacs_vrf', @name) + return v.nil? ? AaaServerGroup.default_vrf : v.first + else + fail ArgumentError, "unsupported type #{@type}" + end end - end - def vrf=(v) - raise TypeError unless v.is_a? String - # vrf = "default" is equivalent to unconfiguring vrf - if @type == :tacacs - @@node.config_set("aaa_server_group", "tacacs_vrf", @name, "", v) - else - raise ArgumentError, "unsupported type #{@type}" + def vrf=(v) + fail TypeError unless v.is_a? String + # vrf = "default" is equivalent to unconfiguring vrf + if @type == :tacacs + node.config_set('aaa_server_group', 'tacacs_vrf', @name, '', v) + else + fail ArgumentError, "unsupported type #{@type}" + end end - end - def AaaServerGroup.default_vrf - @@node.config_get_default("aaa_server_group", "vrf") - end + def self.default_vrf + node.config_get_default('aaa_server_group', 'vrf') + end - def deadtime - if @type == :tacacs - d = @@node.config_get("aaa_server_group", "tacacs_deadtime", @name) - return d.nil? ? AaaServerGroup.default_deadtime : d.first.to_i - else - raise ArgumentError, "unsupported type #{@type}" + def deadtime + if @type == :tacacs + d = node.config_get('aaa_server_group', 'tacacs_deadtime', @name) + return d.nil? ? AaaServerGroup.default_deadtime : d.first.to_i + else + fail ArgumentError, "unsupported type #{@type}" + end end - end - def deadtime=(t) - no_cmd = t == AaaServerGroup.default_deadtime ? "no" : "" - if @type == :tacacs - @@node.config_set("aaa_server_group", "tacacs_deadtime", @name, no_cmd, t) - else - raise ArgumentError, "unsupported type #{@type}" + def deadtime=(t) + no_cmd = t == AaaServerGroup.default_deadtime ? 'no' : '' + if @type == :tacacs + node.config_set('aaa_server_group', 'tacacs_deadtime', @name, no_cmd, t) + else + fail ArgumentError, "unsupported type #{@type}" + end end - end - def AaaServerGroup.default_deadtime - @@node.config_get_default("aaa_server_group", "deadtime") - end + def self.default_deadtime + node.config_get_default('aaa_server_group', 'deadtime') + end - def source_interface - if @type == :tacacs - i = @@node.config_get("aaa_server_group", "tacacs_source_interface", @name) - return i.nil? ? AaaServerGroup.default_source_interface : i.first - else - raise ArgumentError, "unsupported type #{@type}" + def source_interface + if @type == :tacacs + i = node.config_get('aaa_server_group', + 'tacacs_source_interface', @name) + return i.nil? ? AaaServerGroup.default_source_interface : i.first + else + fail ArgumentError, "unsupported type #{@type}" + end end - end - def source_interface=(s) - raise TypeError unless s.is_a? String - no_cmd = s == AaaServerGroup.default_source_interface ? "no" : "" - if @type == :tacacs - @@node.config_set("aaa_server_group", "tacacs_source_interface", - @name, no_cmd, s) - else - raise ArgumentError, "unsupported type #{@type}" + def source_interface=(s) + fail TypeError unless s.is_a? String + no_cmd = s == AaaServerGroup.default_source_interface ? 'no' : '' + if @type == :tacacs + node.config_set('aaa_server_group', 'tacacs_source_interface', + @name, no_cmd, s) + else + fail ArgumentError, "unsupported type #{@type}" + end end - end - def AaaServerGroup.default_source_interface - @@node.config_get_default("aaa_server_group", "source_interface") + def self.default_source_interface + node.config_get_default('aaa_server_group', 'source_interface') + end end end -end diff --git a/tests/test_aaa_authentication_login.rb b/tests/test_aaa_authentication_login.rb index e90be6ed..5223c87a 100644 --- a/tests/test_aaa_authentication_login.rb +++ b/tests/test_aaa_authentication_login.rb @@ -12,14 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -require File.expand_path("../ciscotest", __FILE__) -require File.expand_path("../../lib/cisco_node_utils/aaa_authentication_login", __FILE__) +require_relative 'ciscotest' +require_relative '../lib/cisco_node_utils/aaa_authentication_login' +# Test class for AAA Authentication Login class TestAaaAuthenticationLogin < CiscoTestCase DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH = false - DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE= false + DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE = false DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE = false - DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE= false + DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE = false DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAPV2_ENABLE = false def aaaauthenticationlogin_detach(authlogin) @@ -27,315 +28,199 @@ def aaaauthenticationlogin_detach(authlogin) # when disabling an authentication method while a different type is present. s = @device.cmd("show run | i 'aaa authentication login'") if s[/aaa authentication login (\S+) enable/] - @device.cmd("conf t ; no aaa authentication login #{Regexp.last_match(1)} enable ; end") - node.cache_flush + config("no aaa authentication login #{Regexp.last_match(1)} enable") end authlogin.ascii_authentication = DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH authlogin.error_display = DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE end - def get_match_line(name) - s = @device.cmd("show run aaa all | no-more") - prefix = "aaa authentication login" - line = /#{prefix} #{name}/.match(s) - line - end - - def test_aaaauthenticationlogin_get_ascii_authentication + def test_get_ascii_authentication aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login ascii-authentication") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login ascii-authentication') refute(aaaauthlogin.ascii_authentication, - "Error: AAA authentication login ascii get\n" + - "See CSCuu12667 (4/29/15)") - - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login ascii-authentication") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + "Error: AAA authentication login ascii get\n" \ + 'See CSCuu12667 (4/29/15)') + + config('aaa authentication login ascii-authentication') assert(aaaauthlogin.ascii_authentication, - "Error: AAA authentication login ascii get with preconfig") + 'Error: AAA authentication login ascii get with preconfig') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_default_ascii_authentication + def test_get_default_ascii_authentication aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login ascii-authentication") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login ascii-authentication') assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH, aaaauthlogin.default_ascii_authentication, - "Error: AAA authentication login, default ascii incorrect") + 'Error: AAA authentication login, default ascii incorrect') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_set_ascii_authentication - state = true - + def test_set_ascii_authentication aaaauthlogin = AaaAuthenticationLogin - aaaauthlogin.ascii_authentication = state - line = get_match_line("ascii-authentication") - refute_nil(line, "Error: AAA authentication login ascii not configured #{state}") - assert(aaaauthlogin.ascii_authentication, - "Error: AAA authentication login asci not set #{state}\n" + - "See CSCuu12667 (4/29/15)") - - # Now bring it back to default - state = DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH - aaaauthlogin.ascii_authentication = state - line = get_match_line("ascii-authentication") - refute_nil(line, "Error: AAA authentication login, default ascii not configured") - refute(aaaauthlogin.ascii_authentication, - "Error: AAA authentication login asci not set #{state}\n" + - "See CSCuu12667 (4/29/15)") + aaaauthlogin.ascii_authentication = true + assert_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login ascii-authentication/) + + aaaauthlogin.ascii_authentication = + DEFAULT_AAA_AUTHENTICATION_LOGIN_ASCII_AUTH + refute_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login ascii-authentication/) aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_chap + def test_get_chap aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login chap enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login chap enable') refute(aaaauthlogin.chap, - "Error: AAA authentication login chap get\n" + - "See CSCuu12667 (4/29/15)") - - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login chap enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + "Error: AAA authentication login chap get\n" \ + 'See CSCuu12667 (4/29/15)') + + config('aaa authentication login chap enable') assert(aaaauthlogin.chap, - "Error: AAA authentication login chap get with preconfig\n" + - "See CSCuu12667 (4/29/15)") + "Error: AAA authentication login chap get with preconfig\n" \ + 'See CSCuu12667 (4/29/15)') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_default_chap + def test_get_default_chap aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login chap enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login chap enable') assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE, aaaauthlogin.default_chap, - "Error: AAA authentication login, default chap incorrect") + 'Error: AAA authentication login, default chap incorrect') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_set_chap - state = true - + def test_set_chap aaaauthlogin = AaaAuthenticationLogin - aaaauthlogin.chap = state - line = get_match_line("chap enable") - refute_nil(line, "Error: AAA authentication login chap not configured #{state}") - assert(aaaauthlogin.chap, - "Error: AAA authentication login chap not set #{state}\n" + - "See CSCuu12667 (4/29/15)") - - # Now bring it back to default - state = DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE - aaaauthlogin.chap = state - line = get_match_line("chap enable") - refute_nil(line, "Error: AAA authentication login, default chap not configured") - refute(aaaauthlogin.chap, - "Error: AAA authentication login chap not set #{state}\n" + - "See CSCuu12667 (4/29/15)") + aaaauthlogin.chap = true + assert_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login chap enable/) + aaaauthlogin.chap = DEFAULT_AAA_AUTHENTICATION_LOGIN_CHAP_ENABLE + refute_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login chap enable/) aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_error_display + def test_get_error_display aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login error-enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login error-enable') refute(aaaauthlogin.error_display, - "Error: AAA authentication login error display get") + 'Error: AAA authentication login error display get') - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login error-enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('aaa authentication login error-enable') assert(aaaauthlogin.error_display, - "Error: AAA authentication login error display get with preconfig") + 'Error: AAA authentication login error display get with preconfig') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_default_error_display + def test_get_default_error_display aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login error-enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login error-enable') assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE, aaaauthlogin.default_error_display, - "Error: AAA authentication login, default error display incorrect") + 'Error: default error display incorrect') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_set_error_display - state = true - + def test_set_error_display aaaauthlogin = AaaAuthenticationLogin - aaaauthlogin.error_display = state - line = get_match_line("error-enable") - refute_nil(line, "Error: AAA authentication login error display not configured #{state}") - assert(aaaauthlogin.error_display, - "Error: AAA authentication login error display not set #{state}") + aaaauthlogin.error_display = true + assert_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login error-enable/) - # Now bring it back to default - state = DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE - aaaauthlogin.error_display = state - line = get_match_line("error-enable") - refute_nil(line, "Error: AAA authentication login, default error display not configured") - refute(aaaauthlogin.error_display, - "Error: AAA authentication login error display not set #{state}") + aaaauthlogin.error_display = DEFAULT_AAA_AUTHENTICATION_LOGIN_ERROR_ENABLE + refute_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login error-enable/) aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_mschap + def test_get_mschap aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login mschap enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login mschap enable') refute(aaaauthlogin.mschap, - "Error: AAA authentication login mschap get\n" + - "See CSCuu12667 (4/29/15)") - - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login mschap enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + "Error: AAA authentication login mschap get\n" \ + 'See CSCuu12667 (4/29/15)') + + config('aaa authentication login mschap enable') assert(aaaauthlogin.mschap, - "Error: AAA authentication login mschap get with preconfig\n" + - "See CSCuu12667 (4/29/15)") + "Error: AAA authentication login mschap get with preconfig\n" \ + 'See CSCuu12667 (4/29/15)') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_default_mschap + def test_get_default_mschap aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login mschap enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login mschap enable') assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE, aaaauthlogin.default_mschap, - "Error: AAA authentication login, default mschap incorrect") + 'Error: AAA authentication login, default mschap incorrect') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_set_mschap - state = true - + def test_set_mschap aaaauthlogin = AaaAuthenticationLogin - aaaauthlogin.mschap = state - line = get_match_line("mschap enable") - refute_nil(line, "Error: AAA authentication login mschap not configured #{state}") - assert(aaaauthlogin.mschap, - "Error: AAA authentication login mschap not set #{state}\n" + - "See CSCuu12667 (4/29/15)") - - # Now bring it back to default - state = DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE - aaaauthlogin.mschap = state - line = get_match_line("mschap enable") - refute_nil(line, "Error: AAA authentication login, default mschap not configured") - refute(aaaauthlogin.mschap, - "Error: AAA authentication login mschap not set #{state}\n" + - "See CSCuu12667 (4/29/15)") + aaaauthlogin.mschap = true + assert_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login mschap enable/) + + aaaauthlogin.mschap = DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAP_ENABLE + refute_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login mschap enable/) aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_mschapv2 + def test_get_mschapv2 aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login mschapv2 enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login mschapv2 enable') refute(aaaauthlogin.mschapv2, - "Error: AAA authentication login mschapv2 get\n" + - "See CSCuu12667 (4/29/15)") - - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login mschapv2 enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + "Error: AAA authentication login mschapv2 get\n" \ + 'See CSCuu12667 (4/29/15)') + + config('aaa authentication login mschapv2 enable') assert(aaaauthlogin.mschapv2, - "Error: AAA authentication login mschapv2 get with preconfig\n" + - "See CSCuu12667 (4/29/15)") + "Error: AAA authentication login mschapv2 get with preconfig\n" \ + 'See CSCuu12667 (4/29/15)') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_get_default_mschapv2 + def test_get_default_mschapv2 aaaauthlogin = AaaAuthenticationLogin - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa authentication login mschapv2 enable") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no aaa authentication login mschapv2 enable') assert_equal(DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAPV2_ENABLE, aaaauthlogin.default_mschapv2, - "Error: AAA authentication login, default mschapv2 incorrect") + 'Error: AAA authentication login, default mschapv2 incorrect') aaaauthenticationlogin_detach(aaaauthlogin) end - def test_aaaauthenticationlogin_set_mschapv2 - state = true - + def test_set_mschapv2 aaaauthlogin = AaaAuthenticationLogin - aaaauthlogin.mschapv2 = state - line = get_match_line("mschapv2 enable") - refute_nil(line, "Error: AAA authentication login mschapv2 not configured #{state}") - assert(aaaauthlogin.mschapv2, - "Error: AAA authentication login mschapv2 not set #{state}\n" + - "See CSCuu12667 (4/29/15)") - - # Now bring it back to default - state = DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAPV2_ENABLE - aaaauthlogin.mschapv2 = state - line = get_match_line("mschapv2 enable") - refute_nil(line, "Error: AAA authentication login, default mschapv2 not configured") - refute(aaaauthlogin.mschapv2, - "Error: AAA authentication login mschapv2 not set #{state}\n" + - "See CSCuu12667 (4/29/15)") + aaaauthlogin.mschapv2 = true + assert_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login mschapv2 enable/) + + aaaauthlogin.mschapv2 = DEFAULT_AAA_AUTHENTICATION_LOGIN_MSCHAPV2_ENABLE + refute_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login mschapv2 enable/) aaaauthenticationlogin_detach(aaaauthlogin) end diff --git a/tests/test_aaa_authentication_login_service.rb b/tests/test_aaa_authentication_login_service.rb index a38a7750..b018248c 100644 --- a/tests/test_aaa_authentication_login_service.rb +++ b/tests/test_aaa_authentication_login_service.rb @@ -12,204 +12,177 @@ # See the License for the specific language governing permissions and # limitations under the License. -require File.expand_path("../ciscotest", __FILE__) -require File.expand_path( - "../../lib/cisco_node_utils/aaa_authentication_login_service", __FILE__) +require_relative 'ciscotest' +require_relative '../lib/cisco_node_utils/aaa_authentication_login_service' AAA_AUTH_LOGIN_SERVICE_METHOD_NONE = :none AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL = :local AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED = :unselected +# Test class for AAA Authentication Login Service class TestAaaAuthenticationLoginService < CiscoTestCase def unconfig_tacacs - # unconfig - s = @device.cmd("configure terminal") - s = @device.cmd("no feature tacacs+") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('no feature tacacs+') end def unconfig_aaa # configure defaults = unconfigure - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login default local") - s = @device.cmd("aaa authentication login console local") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('aaa authentication login default local') + config('aaa authentication login console local') end def config_tacacs_servers(servers) - s = @device.cmd("configure terminal") - s = @device.cmd("feature tacacs+") - servers.each do | server | - s = @device.cmd("aaa group server tacacs+ #{server}") + config('feature tacacs+') + servers.each do |server| + config("aaa group server tacacs+ #{server}") end - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush end def aaaauthloginservices_default - # change it to default - s = @device.cmd("show run aaa all | no-more") - prefix = "aaa authentication login" - - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login default local") - s = @device.cmd("aaa authentication login console local") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('aaa authentication login default local') + config('aaa authentication login console local') end - def aaaauthloginservice_detach(authloginservice, revert = true) + def aaaauthloginservice_detach(authloginservice, revert=true) aaaauthloginservices_default if revert != false - begin - authloginservice.destroy - rescue Exception => e - raise e.message + "\n(see CSCuu86609)" - end - end - - def get_match_line(name) - s = @device.cmd("show run aaa all | no-more") - prefix = "aaa authentication login" - line = /#{prefix} #{name}/.match(s) - line + authloginservice.destroy end - def test_aaaauthloginservice_create_empty_service + def test_create_empty_service assert_raises(ArgumentError) do - aaaauthloginservice = AaaAuthenticationLoginService.new("") + AaaAuthenticationLoginService.new('') end end - def test_aaaauthloginservice_create_invalid_service + def test_create_invalid_service assert_raises(TypeError) do - aaaauthloginservice = AaaAuthenticationLoginService.new(:test) + AaaAuthenticationLoginService.new(:test) end end - def test_aaaauthloginservice_create_service_default - aaaauthloginservice = AaaAuthenticationLoginService.new("default") + def test_create_service_default + aaaauthloginservice = AaaAuthenticationLoginService.new('default') refute_nil(aaaauthloginservice, - "Error: AAA authentication login service default create") - aaaauthloginservice_detach(aaaauthloginservice) unless aaaauthloginservice.nil? + 'Error: login service default create') + aaaauthloginservice_detach(aaaauthloginservice) unless + aaaauthloginservice.nil? end - def test_aaaauthloginservice_create_service_console - aaaauthloginservice = AaaAuthenticationLoginService.new("console") + def test_create_service_console + aaaauthloginservice = AaaAuthenticationLoginService.new('console') refute_nil(aaaauthloginservice, - "Error: AAA authentication login service console create") - aaaauthloginservice_detach(aaaauthloginservice) unless aaaauthloginservice.nil? + 'Error: login service console create') + aaaauthloginservice_detach(aaaauthloginservice) unless + aaaauthloginservice.nil? end - def test_aaaauthloginservice_collection_with_service_default + def test_collection_with_service_default unconfig_aaa aaaauthloginservice_list = AaaAuthenticationLoginService.services refute_empty(aaaauthloginservice_list, - "Error: AAA Authentication Login service collection is not filled") + 'Error: service collection is not filled') assert_equal(1, aaaauthloginservice_list.size, - "Error: AAA Authentication Login collection not reporting correct " + - " size (see CSCuu29429)") - assert(aaaauthloginservice_list.key?("default"), - "Error: AAA Authentication Login collection does contain default") + 'Error: collection not reporting correct ' \ + ' size (see CSCuu29429)') + assert(aaaauthloginservice_list.key?('default'), + 'Error: collection does contain default') aaaauthloginservice_list.each do |name, aaaauthloginservice| assert_equal(name, aaaauthloginservice.name, - "Error: Invalid AaaAuthenticationLoginService #{name} in collection") - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, - "Error: Invalid AaaAuthenticationLoginService method for defaultin collection") + "Error: Invalid name #{name} in collection") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice.method, + 'Error: Invalid method for defaultin collection') assert_empty(aaaauthloginservice.groups, - "Error: Invalid AaaAuthenticationLoginService groups for default in collection") + 'Error: Invalid groups for default in collection') aaaauthloginservice_detach(aaaauthloginservice, false) end aaaauthloginservices_default end - def test_aaaauthloginservice_collection_with_service_default_and_console + def test_collection_with_service_default_and_console unconfig_aaa # preconfig console - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login console none") - s = @device.cmd("end") + config('configure terminal') + config('aaa authentication login console none') + config('end') # Flush the cache since we've modified the device node.cache_flush aaaauthloginservice_list = AaaAuthenticationLoginService.services refute_empty(aaaauthloginservice_list, - "Error: AAA Authentication Login service collection is not filled") + 'Error: service collection is not filled') assert_equal(2, aaaauthloginservice_list.size, - "Error: AAA Authentication Login collection not reporting correct size") - assert(aaaauthloginservice_list.key?("default"), - "Error: AAA Authentication Login collection does contain default") - assert(aaaauthloginservice_list.key?("console"), - "Error: AAA Authentication Login collection does contain console") + 'Error: collection not reporting correct size') + assert(aaaauthloginservice_list.key?('default'), + 'Error: collection does contain default') + assert(aaaauthloginservice_list.key?('console'), + 'Error: collection does contain console') aaaauthloginservice_list.each do |name, aaaauthloginservice| assert_equal(name, aaaauthloginservice.name, - "Error: Invalid AaaAuthenticationLoginService #{name} in collection") - if name == "default" + "Error: Invalid name #{name} in collection") + if name == 'default' assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, - "Error: Invalid AaaAuthLoginService method for default in " + - "collection (see CSCuu29429)") + 'Error: Invalid method for default in ' \ + 'collection (see CSCuu29429)') end - if name == "console" - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, - "Error: Invalid AaaAuthLoginService method for console in collection") + if name == 'console' + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice.method, + 'Error: Invalid method for console in collection') end assert_equal([], aaaauthloginservice.groups, - "Error: Invalid AaaAuthLoginService groups for default in collection") + 'Error: Invalid groups for default in collection') aaaauthloginservice_detach(aaaauthloginservice, false) end aaaauthloginservices_default end - def test_aaaauthloginservice_collection_with_service_default_and_console_with_group + def test_collection_with_service_default_and_console_with_group # preconfig servers servers = %w(group1 group2) config_tacacs_servers(servers) # preconfig console - s = @device.cmd("configure terminal") + config('configure terminal') # we need in some specific order - s = @device.cmd("aaa authentication login default group group2 group1 none") - s = @device.cmd("aaa authentication login console group group1") - s = @device.cmd("end") + config('aaa authentication login default group group2 group1 none') + config('aaa authentication login console group group1') + config('end') # Flush the cache since we've modified the device node.cache_flush aaaauthloginservice_list = AaaAuthenticationLoginService.services refute_empty(aaaauthloginservice_list, - "Error: AAA Authentication Login service collection is not filled") + 'Error: service collection is not filled') assert_equal(2, aaaauthloginservice_list.size, - "Error: AAA Authentication Login collection not reporting correct size") - assert(aaaauthloginservice_list.key?("default"), - "Error: AAA Authentication Login collection does contain default") - assert(aaaauthloginservice_list.key?("console"), - "Error: AAA Authentication Login collection does contain console") + 'Error: Login collection not reporting correct size') + assert(aaaauthloginservice_list.key?('default'), + 'Error: collection does contain default') + assert(aaaauthloginservice_list.key?('console'), + 'Error: collection does contain console') aaaauthloginservice_list.each do |name, aaaauthloginservice| assert_equal(name, aaaauthloginservice.name, - "Error: Invalid AaaAuthenticationLoginService #{name} in collection") + "Error: Invalid name #{name} in collection") - if name == "default" - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, - "Error: Invalid method for default in collection") + if name == 'default' + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice.method, + 'Error: Invalid method for default in collection') groups = %w(group2 group1) assert_equal(groups, aaaauthloginservice.groups, - "Error: Invalid groups for default in collection") + 'Error: Invalid groups for default in collection') end - if name == "console" - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice.method, - "Error: Invalid AaaAuthenticationLoginService method for console " + - "in collection (see CSCuu29429)") - groups = ["group1"] + if name == 'console' + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, + aaaauthloginservice.method, + 'Error: Invalid method for console in collection') + groups = ['group1'] assert_equal(groups, aaaauthloginservice.groups, - "Error: Invalid AaaAuthenticationLoginService groups for default in collection") + 'Error: Invalid groups for default in collection') end aaaauthloginservice_detach(aaaauthloginservice, false) end @@ -217,216 +190,197 @@ def test_aaaauthloginservice_collection_with_service_default_and_console_with_gr unconfig_tacacs end - def test_aaaauthloginservice_service_default_get_method + def test_service_default_get_method aaaauthloginservice = - AaaAuthenticationLoginService.new("default") + AaaAuthenticationLoginService.new('default') # default case - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, - "Error: AAA authentication login service default get method for local") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice.method, + 'Error: login service default get method for local') # preconfig default - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login default none") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, - "Error: AAA authentication login service default get method for none") + config('aaa authentication login default none') + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice.method, + 'Error: login service default get method for none') # preconfig servers servers = %w(bxb100 bxb200) config_tacacs_servers(servers) # preconfig default - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login default group bxb100 bxb200") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice.method, - "Error: AAA authentication login service default get method for group unselected") + config('aaa authentication login default group bxb100 bxb200') + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, + aaaauthloginservice.method, + 'Error: login service group or method incorrect') # preconfig default - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login default group bxb200 none") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, - "Error: AAA authentication login service default get method for group and none") + config('aaa authentication login default group bxb200 none') + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice.method, + "Error: login service group incorrect or method not 'none'") # cleanup aaaauthloginservice_detach(aaaauthloginservice) unconfig_tacacs end - def test_aaaauthloginservice_service_console_get_method - aaaauthloginservice = AaaAuthenticationLoginService.new("console") + def test_service_console_get_method + aaaauthloginservice = AaaAuthenticationLoginService.new('console') # default case - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, - "Error: AAA authentication login service console get method for local") + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, + aaaauthloginservice.method, + "Error: login service method not 'local'") # preconfig console - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login console none") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, - "Error: AAA authentication login service console get method for none") + config('aaa authentication login console none') + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice.method, + "Error: login service method not 'none'") # preconfig servers servers = %w(bxb100 bxb200) config_tacacs_servers(servers) # preconfig console - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login console group bxb100 bxb200") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice.method, - "Error: AAA authentication login service console get method for " + - "group unselected (see CSCuu29429)") + config('aaa authentication login console group bxb100 bxb200') + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, + aaaauthloginservice.method, + "Error: login service method not 'unselected'") # preconfig console - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login console group bxb200 none") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush - assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice.method, - "Error: AAA authentication login service console get method for group and none") + config('aaa authentication login console group bxb200 none') + assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, + aaaauthloginservice.method, + "Error: login service group incorrect or method not 'none'") # cleanup aaaauthloginservice_detach(aaaauthloginservice) unconfig_tacacs end - def test_aaaauthloginservice_get_default_method + def test_get_default_method # service default aaaauthloginservice = - AaaAuthenticationLoginService.new("default") + AaaAuthenticationLoginService.new('default') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.default_method, - "Error: AAA authentication login service default, default method") + 'Error: login service default, default method') aaaauthloginservice_detach(aaaauthloginservice) # service console aaaauthloginservice = - AaaAuthenticationLoginService.new("console") + AaaAuthenticationLoginService.new('console') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.default_method, - "Error: AAA authentication login service console, default method") + 'Error: login service console, default method') aaaauthloginservice_detach(aaaauthloginservice, false) end - def test_aaaauthloginservice_service_default_get_groups + def test_service_default_get_groups aaaauthloginservice = - AaaAuthenticationLoginService.new("default") + AaaAuthenticationLoginService.new('default') # default case assert_equal(aaaauthloginservice.default_groups, aaaauthloginservice.groups, - "Error: AAA authentication login service default get groups for default") + 'Error: login service default get groups for default') # preconfig servers servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) # preconfig default - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login default group bxb100 sjc200") - s = @device.cmd("end") + config('configure terminal') + config('aaa authentication login default group bxb100 sjc200') + config('end') # Flush the cache since we've modified the device node.cache_flush groups = %w(bxb100 sjc200) assert_equal(groups, aaaauthloginservice.groups, - "Error: AAA authentication login service default get groups") + 'Error: login service default get groups') # preconfig default - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login default group sjc200 bxb100 rtp10 none") - s = @device.cmd("end") + config('configure terminal') + config('aaa authentication login default group sjc200 bxb100 rtp10 none') + config('end') # Flush the cache since we've modified the device node.cache_flush groups = %w(sjc200 bxb100 rtp10) assert_equal(groups, aaaauthloginservice.groups, - "Error: AAA authentication login service default get groups") + 'Error: login service default get groups') # cleanup aaaauthloginservice_detach(aaaauthloginservice) unconfig_tacacs end - def test_aaaauthloginservice_service_console_get_groups + def test_service_console_get_groups aaaauthloginservice = - AaaAuthenticationLoginService.new("console") + AaaAuthenticationLoginService.new('console') # default case assert_equal(aaaauthloginservice.default_groups, aaaauthloginservice.groups, - "Error: AAA authentication login service console get groups for default") + 'Error: login service console get groups for default') # preconfig servers servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) # preconfig console - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login console group bxb100 sjc200") - s = @device.cmd("end") + config('configure terminal') + config('aaa authentication login console group bxb100 sjc200') + config('end') # Flush the cache since we've modified the device node.cache_flush groups = %w(bxb100 sjc200) assert_equal(groups, aaaauthloginservice.groups, - "Error: AAA authentication login service console get groups #{groups}" + - " (see CSCuu29429)") + "Error: login service console get groups #{groups}" \ + ' (see CSCuu29429)') # preconfig console - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login console group rtp10 bxb100 none") - s = @device.cmd("end") + config('configure terminal') + config('aaa authentication login console group rtp10 bxb100 none') + config('end') # Flush the cache since we've modified the device node.cache_flush groups = %w(rtp10 bxb100) assert_equal(groups, aaaauthloginservice.groups, - "Error: AAA authentication login service console get groups #{groups}") + "Error: login service console get groups #{groups}") # preconfig console - s = @device.cmd("configure terminal") - s = @device.cmd("aaa authentication login console group sjc200 bxb100 rtp10") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config('aaa authentication login console group sjc200 bxb100 rtp10') groups = %w(sjc200 bxb100 rtp10) assert_equal(groups, aaaauthloginservice.groups, - "Error: AAA authentication login service console get groups #{groups}") + "Error: login service console get groups #{groups}") # cleanup aaaauthloginservice_detach(aaaauthloginservice) unconfig_tacacs end - def test_aaaauthloginservice_service_default_and_console_mix + # rubocop:disable Metrics/MethodLength,Metrics/AbcSize + # TODO: Consider refactoring this method + def test_service_default_and_console_mix aaaauthloginservice_default = - AaaAuthenticationLoginService.new("default") + AaaAuthenticationLoginService.new('default') aaaauthloginservice_console = - AaaAuthenticationLoginService.new("console") + AaaAuthenticationLoginService.new('console') # default cases assert_equal(aaaauthloginservice_default.default_groups, aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups default") + 'Error: login default, get groups default') assert_equal(aaaauthloginservice_console.default_groups, aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups default") - assert_equal(aaaauthloginservice_default.default_method, - aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method default") + 'Error: login console, get groups default') + assert_equal(aaaauthloginservice_default.default_method, + aaaauthloginservice_default.method, + 'Error: login default, get method default') assert_equal(aaaauthloginservice_console.default_method, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method default") + 'Error: login console, get method default') # preconfig servers servers = %w(bxb100 sjc200 rtp10) @@ -437,15 +391,15 @@ def test_aaaauthloginservice_service_default_and_console_mix groups, AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED) assert_equal(groups, aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups #{groups}") + "Error: login default, get groups #{groups}") assert_empty(aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups non empty") + 'Error: login console, get groups non empty') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method") + 'Error: login default, get method') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method") + 'Error: login console, get method') # set groups aaaauthloginservice_default.groups_method_set( @@ -455,15 +409,15 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert(aaaauthloginservice_default.groups.empty?, - "Error: AAA authentication login default ,get groups non empty") + 'Error: login default ,get groups non empty') assert_empty(aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups empty") + 'Error: login console, get groups empty') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method none") + 'Error: login default, get method none') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method none") + 'Error: login console, get method none') # set groups aaaauthloginservice_default.groups_method_set( @@ -473,15 +427,15 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert_empty(aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups non-empty") + 'Error: login default, get groups non-empty') assert_empty(aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups non-empty") + 'Error: login console, get groups non-empty') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method local") + 'Error: login default, get method local') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method local") + 'Error: login console, get method local') # set groups aaaauthloginservice_default.groups_method_set( @@ -491,15 +445,15 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert_empty(aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups non-empty") + 'Error: login default, get groups non-empty') assert_empty(aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups non-empty") + 'Error: login console, get groups non-empty') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method none") + 'Error: login default, get method none') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method local") + 'Error: login console, get method local') # set groups aaaauthloginservice_default.groups_method_set( @@ -509,45 +463,40 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert_empty(aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups non-empty") + 'Error: login default, get groups non-empty') assert_empty(aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups non-empty") + 'Error: login console, get groups non-empty') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method local") + 'Error: login default, get method local') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method none") + 'Error: login console, get method none') # set groups - groups_default = ["bxb100"] + groups_default = ['bxb100'] groups_console = %w(bxb100 sjc200) - # CSCuu29429 - begin aaaauthloginservice_default.groups_method_set( groups_default, AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED) aaaauthloginservice_console.groups_method_set( groups_console, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) - rescue Exception => e - raise e.message + " (see CSCuu29429)" - end # get assert_equal(groups_default, aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups #{groups}") + "Error: login default, get groups #{groups}") assert_equal(groups_console, aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups #{groups}") + "Error: login console, get groups #{groups}") assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method local") + 'Error: login default, get method local') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method none") + 'Error: login console, get method none') # set same groups and method - groups = ["bxb100"] + groups = ['bxb100'] aaaauthloginservice_default.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) aaaauthloginservice_console.groups_method_set( @@ -555,16 +504,16 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert_equal(groups, aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups #{groups}") + "Error: login default, get groups #{groups}") assert_equal(groups, aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups #{groups}") + "Error: login console, get groups #{groups}") assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method none") + 'Error: login default, get method none') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method none") + 'Error: login console, get method none') # set group for console and empty for default groups = %w(bxb100 rtp10) @@ -575,16 +524,16 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert_empty(aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups non empty") + 'Error: login default, get groups non empty') assert_equal(groups, aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups #{groups}") + "Error: login console, get groups #{groups}") assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method local") + 'Error: login default, get method local') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method none") + 'Error: login console, get method none') # set groups for default and empty for console groups = %w(bxb100 rtp10) @@ -596,15 +545,15 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert_equal(groups, aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups #{groups}") + "Error: login default, get groups #{groups}") assert_empty(aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups non-empty") + 'Error: login console, get groups non-empty') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method none") + 'Error: login default, get method none') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method local") + 'Error: login console, get method local') # set group for default and empty for console, same methos none groups = %w(bxb100 rtp10) @@ -616,155 +565,137 @@ def test_aaaauthloginservice_service_default_and_console_mix # get assert_equal(groups, aaaauthloginservice_default.groups, - "Error: AAA authentication login default, get groups #{groups}") + "Error: login default, get groups #{groups}") assert_empty(aaaauthloginservice_console.groups, - "Error: AAA authentication login console, get groups non-empty") + 'Error: login console, get groups non-empty') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_default.method, - "Error: AAA authentication login default, get method none") + 'Error: login default, get method none') assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_NONE, aaaauthloginservice_console.method, - "Error: AAA authentication login console, get method none") + 'Error: login console, get method none') # cleanup aaaauthloginservice_detach(aaaauthloginservice_default) aaaauthloginservice_detach(aaaauthloginservice_console) unconfig_tacacs end + # rubocop:enable Metrics/MethodLength,Metrics/AbcSize - def test_aaaauthloginservice_get_default_groups + def test_get_default_groups # service default aaaauthloginservice = - AaaAuthenticationLoginService.new("default") + AaaAuthenticationLoginService.new('default') assert_empty(aaaauthloginservice.default_groups, - "Error: AAA authentication login default, default groups") + 'Error: login default, default groups') aaaauthloginservice_detach(aaaauthloginservice) # service console aaaauthloginservice = - AaaAuthenticationLoginService.new("console") + AaaAuthenticationLoginService.new('console') assert_empty(aaaauthloginservice.default_groups, - "Error: AAA authentication login console, default groups") + 'Error: login console, default groups') aaaauthloginservice_detach(aaaauthloginservice) end - def test_aaaauthloginservice_service_default_set_groups + def test_service_default_set_groups # preconfig servers + prefix = '^aaa authentication login default group ' servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) # service default - service = "default" + service = 'default' aaaauthloginservice = AaaAuthenticationLoginService.new(service) # one group and method is unselected method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED - groups = ["bxb100"] + groups = ['bxb100'] aaaauthloginservice.groups_method_set(groups, method) - match = "#{service} group bxb100" - line = get_match_line(match) - refute_nil(line, - "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + assert_show_match(command: 'show run aaa all | no-more', + pattern: Regexp.new(prefix + groups.join(' '))) # multiple group and method is unselected method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED groups = %w(bxb100 sjc200) aaaauthloginservice.groups_method_set(groups, method) - match = "#{service} group bxb100 sjc200" - line = get_match_line(match) - refute_nil(line, - "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + assert_show_match(command: 'show run aaa all | no-more', + pattern: Regexp.new(prefix + groups.join(' '))) # multi group and method is none method = AAA_AUTH_LOGIN_SERVICE_METHOD_NONE groups = %w(rtp10 bxb100 sjc200) aaaauthloginservice.groups_method_set(groups, method) - match = "#{service} group rtp10 bxb100 sjc200 none" - line = get_match_line(match) - refute_nil(line, - "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + assert_show_match(command: 'show run aaa all | no-more', + pattern: Regexp.new(prefix + groups.join(' '))) # default group and method method = aaaauthloginservice.default_method groups = aaaauthloginservice.default_groups aaaauthloginservice.groups_method_set(groups, method) - match = "#{service} local" - line = get_match_line(match) - refute_nil(line, - "Error: AAA authentication login #{service}, set default groups and method") + assert_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login default local/) aaaauthloginservice_detach(aaaauthloginservice) unconfig_tacacs end - def test_aaaauthloginservice_service_console_set_groups + def test_service_console_set_groups # preconfig servers + prefix = '^aaa authentication login console group ' servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) # service console - service = "console" + service = 'console' aaaauthloginservice = AaaAuthenticationLoginService.new(service) # one group and method is unselected method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED - groups = ["bxb100"] - # CSCuu29429 - begin + groups = ['bxb100'] aaaauthloginservice.groups_method_set(groups, method) - rescue Exception => e - raise e.message + " (see CSCuu29429)" - end - match = "#{service} group bxb100" - line = get_match_line(match) - refute_nil(line, - "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + assert_show_match(command: 'show run aaa all | no-more', + pattern: Regexp.new(prefix + groups.join(' '))) # multi group and method is unselected method = AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED groups = %w(bxb100 sjc200) aaaauthloginservice.groups_method_set(groups, method) - match = "#{service} group bxb100 sjc200" - line = get_match_line(match) - refute_nil(line, - "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + assert_show_match(command: 'show run aaa all | no-more', + pattern: Regexp.new(prefix + groups.join(' '))) # multi group and method is none method = AAA_AUTH_LOGIN_SERVICE_METHOD_NONE groups = %w(rtp10 bxb100 sjc200) aaaauthloginservice.groups_method_set(groups, method) - match = "#{service} group rtp10 bxb100 sjc200 none" - line = get_match_line(match) - refute_nil(line, - "Error: AAA authentication login #{service}, set groups #{groups} #{method}") + assert_show_match(command: 'show run aaa all | no-more', + pattern: Regexp.new(prefix + groups.join(' '))) # default group and method method = aaaauthloginservice.default_method groups = aaaauthloginservice.default_groups aaaauthloginservice.groups_method_set(groups, method) - match = "#{service} local" - line = get_match_line(match) - assert_nil(line, - "Error: AAA authentication login #{service}, set default groups and method") + refute_show_match(command: 'show run aaa all | no-more', + pattern: /^aaa authentication login console local/) aaaauthloginservice_detach(aaaauthloginservice) unconfig_tacacs end - def test_aaaauthloginservice_service_set_groups_invalid_groups + def test_service_set_groups_invalid_groups # preconfig servers servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) # service default - service = "default" + service = 'default' aaaauthloginservice = AaaAuthenticationLoginService.new(service) # one invalid group - groups = ["test1"] + groups = ['test1'] assert_raises(RuntimeError) do aaaauthloginservice.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL) @@ -785,7 +716,7 @@ def test_aaaauthloginservice_service_set_groups_invalid_groups end # invalid array - groups = ["bxb100", 100, "bxb100"] + groups = ['bxb100', 100, 'bxb100'] assert_raises(TypeError) do aaaauthloginservice.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_NONE) @@ -793,12 +724,12 @@ def test_aaaauthloginservice_service_set_groups_invalid_groups aaaauthloginservice_detach(aaaauthloginservice) # repeat the test for service 'console' - service = "console" + service = 'console' aaaauthloginservice = AaaAuthenticationLoginService.new(service) # one invalid group - groups = ["test1"] + groups = ['test1'] assert_raises(CliError) do aaaauthloginservice.groups_method_set( groups, AAA_AUTH_LOGIN_SERVICE_METHOD_UNSELECTED) @@ -821,14 +752,14 @@ def test_aaaauthloginservice_service_set_groups_invalid_groups unconfig_tacacs end - def test_aaaauthloginservice_service_set_groups_invalid_method + def test_service_set_groups_invalid_method # service default - service = "default" + service = 'default' aaaauthloginservice = AaaAuthenticationLoginService.new(service) assert_raises(TypeError) do - aaaauthloginservice.groups_method_set([], "bxb100") + aaaauthloginservice.groups_method_set([], 'bxb100') end assert_raises(ArgumentError) do @@ -838,12 +769,12 @@ def test_aaaauthloginservice_service_set_groups_invalid_method aaaauthloginservice_detach(aaaauthloginservice) # service console - service = "console" + service = 'console' aaaauthloginservice = AaaAuthenticationLoginService.new(service) assert_raises(TypeError) do - aaaauthloginservice.groups_method_set([], "test") + aaaauthloginservice.groups_method_set([], 'test') end assert_raises(TypeError) do diff --git a/tests/test_aaa_authorization_service.rb b/tests/test_aaa_authorization_service.rb index 4c8fe972..e305b19a 100644 --- a/tests/test_aaa_authorization_service.rb +++ b/tests/test_aaa_authorization_service.rb @@ -68,57 +68,57 @@ def prefix 'aaa authorization' end - def test_aaaauthorizationservice_create_unsupported_type + def test_create_unsupported_type assert_raises(ArgumentError) do AaaAuthorizationService.new(:none, 'default') end end - def test_aaaauthorizationservice_create_nil_type + def test_create_nil_type assert_raises(TypeError) do AaaAuthorizationService.new(nil, 'default') end end - def test_aaaauthorizationservice_create_invalid_type + def test_create_invalid_type assert_raises(TypeError) do AaaAuthorizationService.new('test', 'default') end end - def test_aaaauthorizationservice_create_invalid_range_type + def test_create_invalid_range_type assert_raises(TypeError) do AaaAuthorizationService.new(34, 'default') end end - def test_aaaauthorizationservice_create_invalid_service + def test_create_invalid_service assert_raises(ArgumentError) do AaaAuthorizationService.new(:commands, 'test') end end - def test_aaaauthorizationservice_create_empty_service + def test_create_empty_service assert_raises(ArgumentError) do AaaAuthorizationService.new(:commands, '') end end - def test_aaaauthorizationservice_create_commands_default + def test_create_commands_default aaa_a_service = AaaAuthorizationService.new(:commands, 'default') refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating commands default') aaa_a_service.destroy unless aaa_a_service.nil? end - def test_aaaauthorizationservice_create_commands_console + def test_create_commands_console aaa_a_service = AaaAuthorizationService.new(:commands, 'console') refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating commands default') aaa_a_service.destroy unless aaa_a_service.nil? end - def test_aaaauthorizationservice_create_config_commands_default + def test_create_config_commands_default aaa_a_service = AaaAuthorizationService.new(:config_commands, 'default') refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating ' \ @@ -126,32 +126,32 @@ def test_aaaauthorizationservice_create_config_commands_default aaa_a_service.destroy unless aaa_a_service.nil? end - def test_aaaauthorizationservice_create_config_commands_console + def test_create_config_commands_console aaa_a_service = AaaAuthorizationService.new(:config_commands, 'console') refute_nil(aaa_a_service, 'Error: AaaAuthorizationService creating commands default') aaa_a_service.destroy unless aaa_a_service.nil? end - def test_aaaauthorizationservice_get_type + def test_get_type type = :config_commands aaa_a_service = AaaAuthorizationService.new(type, 'default') assert_equal(type, aaa_a_service.type, 'Error : Invalid type') aaa_a_service.destroy end - def test_aaaauthorizationservice_get_name + def test_get_name service = 'default' aaa_a_service = AaaAuthorizationService.new(:config_commands, service) assert_equal(service, aaa_a_service.name, 'Error : Invalid service name') aaa_a_service.destroy end - def test_aaaauthorizationservice_collection_invalid + def test_collection_invalid assert_nil(AaaAuthorizationService.services['TEST']) end - def test_aaaauthorizationservice_collection_services_type_commands + def test_collection_services_type_commands type = :commands collection = AaaAuthorizationService.services[type] @@ -183,7 +183,7 @@ def test_aaaauthorizationservice_collection_services_type_commands end end - def test_aaaauthorizationservice_collection_services_type_config_commands + def test_collection_services_type_config_commands type = :config_commands collection = AaaAuthorizationService.services[type] @@ -214,7 +214,7 @@ def test_aaaauthorizationservice_collection_services_type_config_commands end end - def test_aaaauthorizationservice_type_commands_default_console_group + def test_type_commands_default_console_group # Preconfig AAA Authorization cmd1 = 'aaa authorization commands default group group2 group1 local' cmd2 = 'aaa authorization commands console group group1 local' @@ -267,7 +267,7 @@ def test_aaaauthorizationservice_type_commands_default_console_group config("no #{cmd2}") end - def test_aaaauthorizationservice_type_config_commands_default_console_group + def test_type_config_commands_default_console_group # Preconfig AAA Authorization cmd1 = 'aaa authorization config-commands default group group2 group1 local' cmd2 = 'aaa authorization config-commands console group group1 local' @@ -318,7 +318,7 @@ def test_aaaauthorizationservice_type_config_commands_default_console_group config("no #{cmd2}") end - def test_aaaauthorizationservice_get_default_method + def test_get_default_method type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'default') assert_equal(:local, aaa_a_service.default_method, @@ -346,7 +346,7 @@ def test_aaaauthorizationservice_get_default_method aaa_a_service.destroy end - def test_aaaauthorizationservice_collection_groups_commands_default + def test_collection_groups_commands_default type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'default') @@ -408,7 +408,7 @@ def test_aaaauthorizationservice_collection_groups_commands_default preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_collection_groups_commands_console + def test_collection_groups_commands_console type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'console') @@ -471,7 +471,7 @@ def test_aaaauthorizationservice_collection_groups_commands_console preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_collection_groups_config_commands_default + def test_collection_groups_config_commands_default type = :config_commands aaa_a_service = AaaAuthorizationService.new(type, 'default') @@ -534,7 +534,7 @@ def test_aaaauthorizationservice_collection_groups_config_commands_default preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_collection_groups_config_commands_console + def test_collection_groups_config_commands_console type = :config_commands aaa_a_service = AaaAuthorizationService.new(type, 'console') @@ -597,7 +597,7 @@ def test_aaaauthorizationservice_collection_groups_config_commands_console preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_get_default_groups + def test_get_default_groups groups = [] type = :commands aaa_a_service = AaaAuthorizationService.new(type, 'default') @@ -630,7 +630,7 @@ def test_aaaauthorizationservice_get_default_groups aaa_a_service.destroy end - def test_aaaauthorizationservice_commands_default_set_groups + def test_commands_default_set_groups # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -688,7 +688,7 @@ def test_aaaauthorizationservice_commands_default_set_groups preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_commands_console_set_groups + def test_commands_console_set_groups # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -745,7 +745,7 @@ def test_aaaauthorizationservice_commands_console_set_groups preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_config_commands_default_set_groups + def test_config_commands_default_set_groups # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -802,7 +802,7 @@ def test_aaaauthorizationservice_config_commands_default_set_groups preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_config_commands_console_set_groups + def test_config_commands_console_set_groups # Preconfigure tacacs, tacacs server and AAA valid group group0 = 'tac_group' preconfig_tacacs_server_access(group0) @@ -859,7 +859,7 @@ def test_aaaauthorizationservice_config_commands_console_set_groups preconfig_tacacs_server_access(group0, false) end - def test_aaaauthorizationservice_commands_invalid_groups_method_set_groups + def test_commands_invalid_groups_method_set_groups # preconfig servers servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) @@ -871,13 +871,13 @@ def test_aaaauthorizationservice_commands_invalid_groups_method_set_groups # Single invalid group groups = ['test1'] - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :unselected) end # Multi groups with invalid group groups = %w(rtp10 test2 bxb100) - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :local) end aaa_a_service.destroy @@ -888,13 +888,13 @@ def test_aaaauthorizationservice_commands_invalid_groups_method_set_groups # Single invalid group groups = ['test1'] - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :unselected) end # Multi group with invalid group groups = %w(rtp10 test1 bxb100) - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :local) end @@ -907,7 +907,7 @@ def test_aaaauthorizationservice_commands_invalid_groups_method_set_groups aaa_a_service.destroy end - def test_aaaauthorizationservice_config_commands_invalid_set_groups + def test_config_commands_invalid_set_groups # preconfig servers servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) @@ -919,13 +919,13 @@ def test_aaaauthorizationservice_config_commands_invalid_set_groups # Single invalid group groups = ['test1'] - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :unselected) end # Multi groups with invalid group groups = %w(rtp10 test2 bxb100) - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :local) end aaa_a_service.destroy @@ -936,13 +936,13 @@ def test_aaaauthorizationservice_config_commands_invalid_set_groups # one invalid group groups = ['test1'] - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :unselected) end # multiple group with invalid group groups = %w(rtp10 test1 bxb100) - assert_raises(RuntimeError) do + assert_raises(Cisco::CliError) do aaa_a_service.groups_method_set(groups, :local) end @@ -955,7 +955,7 @@ def test_aaaauthorizationservice_config_commands_invalid_set_groups aaa_a_service.destroy end - def test_aaaauthorizationservice_commands_invalid_method + def test_commands_invalid_method # preconfig servers servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) @@ -997,7 +997,7 @@ def test_aaaauthorizationservice_commands_invalid_method aaa_a_service.destroy end - def test_aaaauthorizationservice_config_commands_invalid_method + def test_config_commands_invalid_method # preconfig servers servers = %w(bxb100 sjc200 rtp10) config_tacacs_servers(servers) diff --git a/tests/test_aaa_server_group.rb b/tests/test_aaa_server_group.rb index 486811c6..98210248 100644 --- a/tests/test_aaa_server_group.rb +++ b/tests/test_aaa_server_group.rb @@ -12,26 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -require File.expand_path("../ciscotest", __FILE__) -require File.expand_path("../../lib/cisco_node_utils/aaa_server_group", __FILE__) -require File.expand_path("../../lib/cisco_node_utils/tacacs_server_host", __FILE__) +require_relative 'ciscotest' +require_relative '../lib/cisco_node_utils/aaa_server_group' +require_relative '../lib/cisco_node_utils/tacacs_server_host' AAA_SERVER_GROUP_TACACS_SERVER = :tacacs AAA_SERVER_GROUP_RADIUS_SERVER = :radius -DEFAULT_AAA_SERVER_GROUP_VRF = "default" +DEFAULT_AAA_SERVER_GROUP_VRF = 'default' DEFAULT_AAA_SERVER_GROUP_DEADTIME = 0 -DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE = "" +DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE = '' +# Test class for AAA Server Group class TestAaaServerGroup < CiscoTestCase def clean_tacacs_config - @device.cmd("configure terminal") - @device.cmd("no feature tacacs") - @device.cmd("feature tacacs") - @device.cmd("end") + config('no feature tacacs', + 'feature tacacs') end - def create_tacacsserverhost(name="defaulttest") - tacacs_server_host = TacacsServerHost.new(name) + def create_tacacsserverhost(name='defaulttest') + TacacsServerHost.new(name) end def detach_tacacsserverhost(host) @@ -43,187 +42,142 @@ def detach_aaaservergroup(aaa_server_group) end def create_aaa_group(group_name, server) - s = @device.cmd("configure terminal") - s = @device.cmd("aaa group server #{server} #{group_name}") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config("aaa group server #{server} #{group_name}") end def destroy_aaa_group(group_name, server) - s = @device.cmd("configure terminal") - s = @device.cmd("no aaa group server #{server} #{group_name}") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config("no aaa group server #{server} #{group_name}") end def create_vrf(group_name, server, vrf_name) - s = @device.cmd("configure terminal") - s = @device.cmd("aaa group server #{server} #{group_name}") - s = @device.cmd("use-vrf #{vrf_name}") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config("aaa group server #{server} #{group_name} ; use-vrf #{vrf_name}") end def create_deadtime(group_name, server, deadtime) - s = @device.cmd("configure terminal") - s = @device.cmd("aaa group server #{server} #{group_name}") - s = @device.cmd("deadtime #{deadtime}") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config("aaa group server #{server} #{group_name} ; deadtime #{deadtime}") end def create_source_interface(group_name, server, interface) - s = @device.cmd("configure terminal") - s = @device.cmd("aaa group server #{server} #{group_name}") - s = @device.cmd("source-interface #{interface}") - s = @device.cmd("end") - # Flush the cache since we've modified the device - node.cache_flush + config("aaa group server #{server} #{group_name} ; " \ + "source-interface #{interface}") end - def get_match_line(name) - s = @device.cmd("show run tacacs+ all | no-more") - line = /#{name}/.match(s) - end - - def get_match_line_group_tacacs(name) - s = @device.cmd("show run tacacs+ all | no-more") - prefix = "aaa group server tacacs+ #{name}" - puts prefix - line = /#{prefix}/.match(s) - puts line - end - - def test_aaaservergroup_create_invalid_type + def test_create_invalid_type assert_raises(TypeError) do - aaa_group = AaaServerGroup.new(node, "Group1") + AaaServerGroup.new(node, 'Group1') end end - def test_aaaservergroup_create_invalid_name_tacacs + def test_create_invalid_name_tacacs assert_raises(TypeError) do - aaa_group = AaaServerGroup.new(nil, nil) + AaaServerGroup.new(nil, nil) end end - def test_aaaservergroup_create_invalid_name_radius + def test_create_invalid_name_radius # TBD end - def test_aaaservergroup_create_valid_tacacs - group_name = "Group1" + def test_create_valid_tacacs + group_name = 'Group1' aaa_group = AaaServerGroup.new(group_name, :tacacs) - - # Verify groups is created - line = get_match_line("#{group_name}") - sh_run_group = line.to_s.split(" ").last - refute_nil(line, "Error: Group not configured") - assert_equal(sh_run_group, sh_run_group, - "Error: #{group_name} not configured") + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /Group1/) detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_create_valid_radius + def test_create_valid_radius # TBD end - def test_aaaservergroup_create_valid_multiple_tacacs - group_name1 = "Group1" - group_name2 = "Group2" + def test_create_valid_multiple_tacacs + group_name1 = 'Group1' + group_name2 = 'Group2' aaa_group1 = AaaServerGroup.new(group_name1, :tacacs) aaa_group2 = AaaServerGroup.new(group_name2, :tacacs) - line = get_match_line("#{group_name1}") - sh_run_group = line.to_s.split(" ").last - refute_nil(line, "Error: Group not configured") - assert_equal(sh_run_group, group_name1, - "Error: #{group_name1} not configured") - line = get_match_line("#{group_name2}") - sh_run_group = line.to_s.split(" ").last - assert_equal(sh_run_group, group_name2, - "Error: #{group_name2} not configured") + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /Group1/) + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /Group2/) detach_aaaservergroup(aaa_group1) detach_aaaservergroup(aaa_group2) end - def test_aaaservergroup_create_valid_multiple_radius + def test_create_valid_multiple_radius # TBD end - def test_aaaservergroup_get_parent_radius + def test_get_parent_radius # TBD end - def test_aaaservergroup_collection_empty_tacacs + def test_collection_empty_tacacs clean_tacacs_config aaa_group_list = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) assert_empty(aaa_group_list, - "Error: AaaServerGroup collection is not empty") + 'Error: AaaServerGroup collection is not empty') end - def test_aaaservergroup_collection_empty_radius + def test_collection_empty_radius # TBD end - def test_aaaservergroup_collection_invalid_nil_radius + def test_collection_invalid_nil_radius # TBD end - def test_aaaservergroup_collection_invalid_tacacs + def test_collection_invalid_tacacs assert_raises(TypeError) do - aaa_group_list = AaaServerGroup.groups("TEST") + AaaServerGroup.groups('TEST') end end - def test_aaaservergroup_collection_invalid_radius + def test_collection_invalid_radius # TBD end - def test_aaaservergroup_collection_single_tacacs + def test_collection_single_tacacs clean_tacacs_config - group_name1 = "Group1" - group_name2 = "Group2" - group_name3 = "Group3" + group_name1 = 'Group1' + group_name2 = 'Group2' + group_name3 = 'Group3' aaa_group1 = AaaServerGroup.new(group_name1, :tacacs) groups = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) - refute_empty(groups, "Error: AaaServerGroup collection is not filled") + refute_empty(groups, 'Error: AaaServerGroup collection is not filled') assert_equal(1, groups.size, - "Error: AaaServerGroup collection not reporting correct size") + 'Error: AaaServerGroup collection not reporting correct size') assert(groups.key?(group_name1), - "Error: AaaServerGroup collection does contain #{group_name1}") + "Error: AaaServerGroup collection does contain #{group_name1}") detach_aaaservergroup(aaa_group1) - create_aaa_group(group_name2, "tacacs+") - create_aaa_group(group_name3, "tacacs+") + create_aaa_group(group_name2, 'tacacs+') + create_aaa_group(group_name3, 'tacacs+') groups = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) - refute_empty(groups, "Error: AaaServerGroup collection is not filled") + refute_empty(groups, 'Error: AaaServerGroup collection is not filled') assert_equal(2, groups.size, - "Error: AaaServerGroup collection not reporting correct size") + 'Error: AaaServerGroup collection not reporting correct size') assert(groups.key?(group_name2), - "Error: AaaServerGroup collection does contain #{group_name2}") + "Error: AaaServerGroup collection does contain #{group_name2}") assert(groups.key?(group_name3), - "Error: AaaServerGroup collection does contain #{group_name3}") + "Error: AaaServerGroup collection does contain #{group_name3}") - destroy_aaa_group(group_name2, "tacacs+") - destroy_aaa_group(group_name3, "tacacs+") + destroy_aaa_group(group_name2, 'tacacs+') + destroy_aaa_group(group_name3, 'tacacs+') end - def test_aaaservergroup_collection_single_radius + def test_collection_single_radius # TBD end - def test_aaaservergroup_collection_multi_tacacs + def test_collection_multi_tacacs clean_tacacs_config - group_name1 = "Group1" - group_name2 = "Group2" - group_name3 = "Group3" + group_name1 = 'Group1' + group_name2 = 'Group2' + group_name3 = 'Group3' aaa_group1 = AaaServerGroup.new(group_name1, :tacacs) aaa_group2 = AaaServerGroup.new(group_name2, :tacacs) @@ -231,246 +185,227 @@ def test_aaaservergroup_collection_multi_tacacs aaa_group3 = AaaServerGroup.new(group_name3, :tacacs) groups = AaaServerGroup.groups(AAA_SERVER_GROUP_TACACS_SERVER) - refute_empty(groups, "Error: AaaServerGroup collection is not filled") + refute_empty(groups, 'Error: AaaServerGroup collection is not filled') assert_equal(3, groups.size, - "Error: AaaServerGroup collection not reporting correct size") + 'Error: AaaServerGroup collection not reporting correct size') assert(groups.key?(group_name1), - "Error: AaaServerGroup collection does contain #{group_name1}") + "Error: AaaServerGroup collection does contain #{group_name1}") assert(groups.key?(group_name2), - "Error: AaaServerGroup collection does contain #{group_name2}") + "Error: AaaServerGroup collection does contain #{group_name2}") assert(groups.key?(group_name3), - "Error: AaaServerGroup collection does contain #{group_name3}") + "Error: AaaServerGroup collection does contain #{group_name3}") detach_aaaservergroup(aaa_group1) detach_aaaservergroup(aaa_group2) detach_aaaservergroup(aaa_group3) end - def test_aaaservergroup_collection_multi_radius + def test_collection_multi_radius # TBD end - def test_aaaservergroup_servers_tacacs + def test_servers_tacacs clean_tacacs_config - server_name1 = "server1" - server_name2 = "server2" + server_name1 = 'server1' + server_name2 = 'server2' server1 = create_tacacsserverhost(server_name1) server2 = create_tacacsserverhost(server_name2) - aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group = AaaServerGroup.new('Group1', :tacacs) # pre check that default servers are empty default_server = AaaServerGroup.default_servers - assert_empty(default_server, "Error: Default Servers are not empty") + assert_empty(default_server, 'Error: Default Servers are not empty') aaa_group.servers = [server_name1, server_name2] # Check collection size servers = aaa_group.servers.keys - assert_equal(2, servers.size(), - "Error: Collection is not two servers") + assert_equal(2, servers.size, + 'Error: Collection is not two servers') assert(servers.include?('server1'), - "Error: Collection does not contain #{server_name1}") + "Error: Collection does not contain #{server_name1}") assert(servers.include?('server2'), - "Error: Collection does not contain #{server_name2}") + "Error: Collection does not contain #{server_name2}") detach_aaaservergroup(aaa_group) detach_tacacsserverhost(server1) detach_tacacsserverhost(server2) end - def test_aaaservergroup_servers_radius + def test_servers_radius # TBD end - def test_aaaservergroup_add_server_tacacs - server_name1 = "server1" - server_name2 = "server2" + def test_add_server_tacacs + server_name1 = 'server1' + server_name2 = 'server2' server1 = create_tacacsserverhost(server_name1) server2 = create_tacacsserverhost(server_name2) - aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group = AaaServerGroup.new('Group1', :tacacs) aaa_group.servers = [server_name1, server_name2] - line = get_match_line("server #{server_name1}") - sh_run_server = line.to_s.split(" ").last - refute_nil(line, "Error: Server not configured") - assert_equal(sh_run_server, server_name1, - "Error: #{server_name1} not configured") - line = get_match_line("server #{server_name2}") - sh_run_server = line.to_s.split(" ").last - assert_equal(sh_run_server, server_name2, - "Error: #{server_name2} not configured") + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server1/) + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server2/) detach_aaaservergroup(aaa_group) detach_tacacsserverhost(server1) detach_tacacsserverhost(server2) end - def test_aaaservergroup_add_server_radius + def test_add_server_radius # TBD end - def test_aaaservergroup_add_server_twice_tacacs + def test_add_server_twice_tacacs clean_tacacs_config - server_name1 = "server1" - server_name2 = "server2" + server_name1 = 'server1' + server_name2 = 'server2' server1 = create_tacacsserverhost(server_name1) server2 = create_tacacsserverhost(server_name2) - aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group = AaaServerGroup.new('Group1', :tacacs) # aaa_group.servers = [server_name1, server_name2, server_name2] # this behavior is different on n9k vs n3k, so comment out for now # n3k throws a CLIError and n9k silently ignores aaa_group.servers = [server_name1, server_name2] servers = aaa_group.servers - assert_equal(2, servers.size(), - "Error: Collection is not two servers") - - line = get_match_line("server #{server_name1}") - sh_run_server = line.to_s.split(" ").last - assert_equal(false, line.nil?, - "Error: Server not configured") - assert_equal(sh_run_server, server_name1, - "Error: #{server_name1} not configured") - line = get_match_line("server #{server_name2}") - sh_run_server = line.to_s.split(" ").last - assert_equal(sh_run_server, server_name2, - "Error: #{server_name2} not configured") + assert_equal(2, servers.size, + 'Error: Collection is not two servers') + + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server server1/) + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server server2/) detach_aaaservergroup(aaa_group) detach_tacacsserverhost(server1) detach_tacacsserverhost(server2) end - def test_aaaservergroup_add_server_twice_radius + def test_add_server_twice_radius # TBD end - def test_aaaservergroup_remove_server_tacacs + def test_remove_server_tacacs clean_tacacs_config - server_name1 = "server1" - server_name2 = "server2" + server_name1 = 'server1' + server_name2 = 'server2' server1 = create_tacacsserverhost(server_name1) server2 = create_tacacsserverhost(server_name2) - aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group = AaaServerGroup.new('Group1', :tacacs) aaa_group.servers = [server_name1, server_name2] # Check collection size servers = aaa_group.servers - assert_equal(2, servers.size(), - "Error: Collection is not two servers") + assert_equal(2, servers.size, + 'Error: Collection is not two servers') # Now remove them and then check again aaa_group.servers = [server_name2] - line = get_match_line("server #{server_name1}") - sh_run_server = line.to_s.split(" ").last - assert_nil(line, "Error: Server not unconfigured") + refute_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server server1/) aaa_group.servers = [] - line = get_match_line("server #{server_name2}") - sh_run_server = line.to_s.split(" ").last - assert_nil(line, "Error: Server not unconfigured") + refute_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server server2/) detach_aaaservergroup(aaa_group) detach_tacacsserverhost(server1) detach_tacacsserverhost(server2) end - def test_aaaservergroup_remove_server_radius + def test_remove_server_radius # TBD end - def test_aaaservergroup_remove_server_twice_tacacs + def test_remove_server_twice_tacacs clean_tacacs_config - server_name1 = "server1" - server_name2 = "server2" + server_name1 = 'server1' + server_name2 = 'server2' server1 = create_tacacsserverhost(server_name1) server2 = create_tacacsserverhost(server_name2) - aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group = AaaServerGroup.new('Group1', :tacacs) aaa_group.servers = [server_name1, server_name2] # Check collection size servers = aaa_group.servers - assert_equal(2, servers.size(), - "Error: Collection is not two servers") + assert_equal(2, servers.size, + 'Error: Collection is not two servers') # Now remove them and then check again aaa_group.servers = [server_name2] - line = get_match_line("server #{server_name1}") - sh_run_server = line.to_s.split(" ").last - assert_nil(line, "Error: Server not unconfigured") + refute_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server server1/) # Now remove server 1 again aaa_group.servers = [] - line = get_match_line("server #{server_name2}") - sh_run_server = line.to_s.split(" ").last - assert_nil(line, "Error: Server not unconfigured") + refute_show_match(command: 'show run tacacs+ all | no-more', + pattern: /server server2/) # Check collection size servers = aaa_group.servers - assert_empty(servers, "Error: Collection not empty") + assert_empty(servers, 'Error: Collection not empty') detach_aaaservergroup(aaa_group) detach_tacacsserverhost(server1) detach_tacacsserverhost(server2) end - def test_aaaservergroup_remove_server_twice_radius + def test_remove_server_twice_radius # TBD end - def test_aaaservergroup_get_vrf_tacacs - group_name1 = "Group1" + def test_get_vrf_tacacs + group_name1 = 'Group1' aaa_group = AaaServerGroup.new(group_name1, :tacacs) vrf = DEFAULT_AAA_SERVER_GROUP_VRF assert_equal(vrf, aaa_group.vrf, - "Error: AaaServerGroup, vrf not default") + 'Error: AaaServerGroup, vrf not default') - vrf = "TESTME" - create_vrf(group_name1, "tacacs+", vrf) + vrf = 'TESTME' + create_vrf(group_name1, 'tacacs+', vrf) assert_equal(vrf, aaa_group.vrf, - "Error: AaaServerGroup, vrf not configured") + 'Error: AaaServerGroup, vrf not configured') vrf = DEFAULT_AAA_SERVER_GROUP_VRF aaa_group.vrf = vrf assert_equal(vrf, aaa_group.vrf, - "Error: AaaServerGroup, vrf not restored to default") + 'Error: AaaServerGroup, vrf not restored to default') detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_get_vrf_radius + def test_get_vrf_radius # TBD end - def test_aaaservergroup_get_default_vrf_tacacs - aaa_group = AaaServerGroup.new("Group1", :tacacs) + def test_get_default_vrf_tacacs + aaa_group = AaaServerGroup.new('Group1', :tacacs) assert_equal(DEFAULT_AAA_SERVER_GROUP_VRF, AaaServerGroup.default_vrf, - "Error: AaaServerGroup, default vrf incorrect") + 'Error: AaaServerGroup, default vrf incorrect') detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_get_default_vrf_radius + def test_get_default_vrf_radius # TBD end - def test_aaaservergroup_set_vrf_tacacs - vrf = "management-123" - aaa_group = AaaServerGroup.new("Group1", :tacacs) + def test_set_vrf_tacacs + vrf = 'management-123' + aaa_group = AaaServerGroup.new('Group1', :tacacs) aaa_group.vrf = vrf - line = get_match_line("use-vrf #{vrf}") - # Extract deadtime - sh_run_vrf = line.to_s.split(" ").last - # puts sh_run_vrf - refute_nil(line, "Error: AaaServerGroup, vrf not configured") - assert_equal(sh_run_vrf, aaa_group.vrf, - "Error: AaaServerGroup, vrf incorrect") + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /use-vrf management-123/) + # Invalid case vrf = 2450 assert_raises(TypeError) do @@ -479,57 +414,54 @@ def test_aaaservergroup_set_vrf_tacacs detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_set_vrf_radius + def test_set_vrf_radius # TBD end - def test_aaaservergroup_get_deadtime_tacacs - group_name = "Group1" + def test_get_deadtime_tacacs + group_name = 'Group1' aaa_group = AaaServerGroup.new(group_name, :tacacs) deadtime = DEFAULT_AAA_SERVER_GROUP_DEADTIME assert_equal(deadtime, aaa_group.deadtime, - "Error: AaaServerGroup, deadtime not default") + 'Error: AaaServerGroup, deadtime not default') deadtime = 850 - create_deadtime(group_name, "tacacs+", deadtime) + create_deadtime(group_name, 'tacacs+', deadtime) assert_equal(deadtime, aaa_group.deadtime, - "Error: AaaServerGroup, deadtime not configured") + 'Error: AaaServerGroup, deadtime not configured') deadtime = DEFAULT_AAA_SERVER_GROUP_DEADTIME aaa_group.deadtime = deadtime assert_equal(deadtime, aaa_group.deadtime, - "Error: AaaServerGroup, deadtime not restored to default") + 'Error: AaaServerGroup, deadtime not restored to default') detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_get_deadtime_radius + def test_get_deadtime_radius # TBD end - def test_aaaservergroup_get_default_deadtime_tacacs - aaa_group = AaaServerGroup.new("Group1", :tacacs) + def test_get_default_deadtime_tacacs + aaa_group = AaaServerGroup.new('Group1', :tacacs) assert_equal(DEFAULT_AAA_SERVER_GROUP_DEADTIME, AaaServerGroup.default_deadtime, - "Error: AaaServerGroup, default deadtime incorrect") + 'Error: AaaServerGroup, default deadtime incorrect') detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_get_default_deadtime_radius + def test_get_default_deadtime_radius # TBD end - def test_aaaservergroup_set_deadtime_tacacs + def test_set_deadtime_tacacs deadtime = 1250 - aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group = AaaServerGroup.new('Group1', :tacacs) aaa_group.deadtime = deadtime - line = get_match_line("deadtime #{deadtime}") - # Extract deadtime - sh_run_deadtime = line.to_s.split(" ").last.to_i - refute_nil(line, "Error: AaaServerGroup, deadtime not configured") - assert_equal(sh_run_deadtime, aaa_group.deadtime, - "Error: AaaServerGroup, deadtime incorrect") + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /deadtime 1250/, + msg: 'Error: deadtime not configured') # Invalid case deadtime = 2450 assert_raises(CliError) do @@ -538,66 +470,60 @@ def test_aaaservergroup_set_deadtime_tacacs detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_set_deadtime_radius + def test_set_deadtime_radius # TBD end - def test_aaaservergroup_get_source_interface_tacacs - group_name = "Group1" + def test_get_source_interface_tacacs + group_name = 'Group1' aaa_group = AaaServerGroup.new(group_name, :tacacs) intf = DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE assert_equal(intf, aaa_group.source_interface, - "Error: AaaServerGroup, source-interface set") + 'Error: AaaServerGroup, source-interface set') - intf = "Ethernet1/1" - create_source_interface(group_name, "tacacs+", intf) + intf = 'Ethernet1/1' + create_source_interface(group_name, 'tacacs+', intf) assert_equal(intf, aaa_group.source_interface, - "Error: AaaServerGroup, source-interface not correct") + 'Error: AaaServerGroup, source-interface not correct') - intf = "Ethernet1/32" - create_source_interface(group_name, "tacacs+", intf) + intf = 'Ethernet1/32' + create_source_interface(group_name, 'tacacs+', intf) assert_equal(intf, aaa_group.source_interface, - "Error: AaaServerGroup, source-interface not correct") + 'Error: AaaServerGroup, source-interface not correct') detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_get_source_interface_radius + def test_get_source_interface_radius # TBD end - def test_aaaservergroup_get_default_source_interface_tacacs - aaa_group = AaaServerGroup.new("Group1", :tacacs) + def test_get_default_source_interface_tacacs + aaa_group = AaaServerGroup.new('Group1', :tacacs) assert_equal(DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE, AaaServerGroup.default_source_interface, - "Error: Aaa_Group Server, default source-interface incorrect") + 'Error: Aaa_Group Server, default source-interface incorrect') detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_get_default_source_interface_radius + def test_get_default_source_interface_radius # TBD end - def test_aaaservergroup_set_source_interface_tacacs + def test_set_source_interface_tacacs intf = DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE - aaa_group = AaaServerGroup.new("Group1", :tacacs) + aaa_group = AaaServerGroup.new('Group1', :tacacs) assert_equal(intf, aaa_group.source_interface, - "Error: Aaa_Group Server, source-interface not default") - - intf = "Ethernet1/1" - aaa_group.source_interface = intf - line = get_match_line("source-interface #{intf}") - # Extract source-interface - sh_run_source_interface = line.to_s.split(" ").last - refute_nil(line, "Error: AaaServerGroup, source-interface not configured") - assert_equal(sh_run_source_interface, aaa_group.source_interface, - "Error: AaaServerGroup, source-interface not correct") - - # Now bring it back to default - intf = DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE - aaa_group.source_interface = intf - line = get_match_line("no source-interface") - refute_nil(line, "Error: AaaServerGroup, source-interface not default") + 'Error: Aaa_Group Server, source-interface not default') + + aaa_group.source_interface = 'loopback1' + assert_show_match(command: 'show run tacacs+ all | no-more', + pattern: /source-interface loopback1/, + msg: 'Error: source-interface not correct') + + aaa_group.source_interface = DEFAULT_AAA_SERVER_GROUP_SOURCE_INTERFACE + refute_show_match(command: 'show run tacacs+ all | no-more', + pattern: /source-interface loopback1/) # Invalid case state = true @@ -608,21 +534,20 @@ def test_aaaservergroup_set_source_interface_tacacs detach_aaaservergroup(aaa_group) end - def test_aaaservergroup_set_source_interface_radius + def test_set_source_interface_radius # TBD end - def test_aaaservergroup_destroy_tacacs - group_name = "Group1" + def test_destroy_tacacs + group_name = 'Group1' aaa_group = AaaServerGroup.new(group_name, :tacacs) detach_aaaservergroup(aaa_group) - - line = get_match_line(group_name) - assert_nil(line, "Error: AaaServerGroup, not removed") + refute_show_match(command: 'show run tacacs+ all | no-more', + pattern: /Group1/) end - def test_aaaservergroup_destroy_radius + def test_destroy_radius # TBD end end From 23a4a8a69bdda7c5ece40f5be963a25cd929e839 Mon Sep 17 00:00:00 2001 From: Chris Van Heuveln Date: Mon, 26 Oct 2015 10:34:01 -0400 Subject: [PATCH 008/386] Addressed code review comments --- .../aaa_authentication_login.rb | 36 +++++++------- .../aaa_authentication_login_service.rb | 30 ++++++------ .../aaa_authorization_service.rb | 30 ++++++------ lib/cisco_node_utils/aaa_server_group.rb | 47 +++++++++---------- tests/test_aaa_authentication_login.rb | 23 +++------ .../test_aaa_authentication_login_service.rb | 37 ++------------- 6 files changed, 82 insertions(+), 121 deletions(-) diff --git a/lib/cisco_node_utils/aaa_authentication_login.rb b/lib/cisco_node_utils/aaa_authentication_login.rb index 4e3916a0..29e4bdbf 100644 --- a/lib/cisco_node_utils/aaa_authentication_login.rb +++ b/lib/cisco_node_utils/aaa_authentication_login.rb @@ -30,71 +30,71 @@ class AaaAuthenticationLogin < NodeUtil # console fallback. def self.ascii_authentication - !node.config_get('aaa_authentication_login', - 'ascii_authentication').nil? + !config_get('aaa_authentication_login', + 'ascii_authentication').nil? end def self.ascii_authentication=(val) no_cmd = val ? '' : 'no' - node.config_set('aaa_authentication_login', - 'ascii_authentication', no_cmd) + config_set('aaa_authentication_login', + 'ascii_authentication', no_cmd) end def self.default_ascii_authentication - node.config_get_default('aaa_authentication_login', - 'ascii_authentication') + config_get_default('aaa_authentication_login', + 'ascii_authentication') end def self.chap - !node.config_get('aaa_authentication_login', 'chap').nil? + !config_get('aaa_authentication_login', 'chap').nil? end def self.chap=(val) no_cmd = val ? '' : 'no' - node.config_set('aaa_authentication_login', 'chap', no_cmd) + config_set('aaa_authentication_login', 'chap', no_cmd) end def self.default_chap - node.config_get_default('aaa_authentication_login', 'chap') + config_get_default('aaa_authentication_login', 'chap') end def self.error_display - !node.config_get('aaa_authentication_login', 'error_display').nil? + !config_get('aaa_authentication_login', 'error_display').nil? end def self.error_display=(val) no_cmd = val ? '' : 'no' - node.config_set('aaa_authentication_login', 'error_display', no_cmd) + config_set('aaa_authentication_login', 'error_display', no_cmd) end def self.default_error_display - node.config_get_default('aaa_authentication_login', 'error_display') + config_get_default('aaa_authentication_login', 'error_display') end def self.mschap - !node.config_get('aaa_authentication_login', 'mschap').nil? + !config_get('aaa_authentication_login', 'mschap').nil? end def self.mschap=(val) no_cmd = val ? '' : 'no' - node.config_set('aaa_authentication_login', 'mschap', no_cmd) + config_set('aaa_authentication_login', 'mschap', no_cmd) end def self.default_mschap - node.config_get_default('aaa_authentication_login', 'mschap') + config_get_default('aaa_authentication_login', 'mschap') end def self.mschapv2 - !node.config_get('aaa_authentication_login', 'mschapv2').nil? + !config_get('aaa_authentication_login', 'mschapv2').nil? end def self.mschapv2=(val) no_cmd = val ? '' : 'no' - node.config_set('aaa_authentication_login', 'mschapv2', no_cmd) + config_set('aaa_authentication_login', 'mschapv2', no_cmd) end def self.default_mschapv2 - node.config_get_default('aaa_authentication_login', 'mschapv2') + config_get_default('aaa_authentication_login', 'mschapv2') end end end diff --git a/lib/cisco_node_utils/aaa_authentication_login_service.rb b/lib/cisco_node_utils/aaa_authentication_login_service.rb index e6984a31..be1dbe5b 100644 --- a/lib/cisco_node_utils/aaa_authentication_login_service.rb +++ b/lib/cisco_node_utils/aaa_authentication_login_service.rb @@ -35,12 +35,12 @@ def initialize(name, create=true) # "show aaa authentication" return unless create m = default_method.to_s - node.config_set('aaa_auth_login_service', 'method', '', name, m) + config_set('aaa_auth_login_service', 'method', '', name, m) end def self.services servs = {} - servs_arr = node.config_get('aaa_auth_login_service', 'services') + servs_arr = config_get('aaa_auth_login_service', 'services') unless servs_arr.nil? servs_arr.each do |s| servs[s] = AaaAuthenticationLoginService.new(s, false) @@ -58,12 +58,12 @@ def destroy if g_str.empty? # cannot remove default local, so do nothing in this case unless m == :local && @name == 'default' - node.config_set('aaa_auth_login_service', 'method', - 'no', @name, m_str) + config_set('aaa_auth_login_service', 'method', + 'no', @name, m_str) end else - node.config_set('aaa_auth_login_service', 'groups', - 'no', @name, g_str, m_str) + config_set('aaa_auth_login_service', 'groups', + 'no', @name, g_str, m_str) end end @@ -72,10 +72,10 @@ def destroy # memory regex only captures the last match # ex: aaa authentication login default group group1 group2 group3 none def groups - # node.config_get returns the following format: + # config_get returns the following format: # [{service:"default",method:"group group1 none "}, # {service:"console",method:"local "}] - hsh_arr = node.config_get('aaa_auth_login_service', 'groups', @name) + hsh_arr = config_get('aaa_auth_login_service', 'groups', @name) fail 'unable to retrieve aaa groups information' if hsh_arr.nil? hsh = hsh_arr.find { |x| x['service'] == @name } # this should never happen unless @name is invalid @@ -92,17 +92,17 @@ def groups # default is [] def default_groups - node.config_get_default('aaa_auth_login_service', 'groups') + config_get_default('aaa_auth_login_service', 'groups') end def method - m = node.config_get('aaa_auth_login_service', 'method', @name) + m = config_get('aaa_auth_login_service', 'method', @name) m.nil? ? :unselected : m.first.to_sym end # default is :local def default_method - node.config_get_default('aaa_auth_login_service', 'method') + config_get_default('aaa_auth_login_service', 'method') end # groups and method must be set in the same CLI string @@ -122,11 +122,11 @@ def groups_method_set(grps, m) # config_set depends on whether we're setting groups or not if g_str.empty? - node.config_set('aaa_auth_login_service', 'method', - '', @name, m_str) + config_set('aaa_auth_login_service', 'method', + '', @name, m_str) else - node.config_set('aaa_auth_login_service', 'groups', - '', @name, g_str, m_str) + config_set('aaa_auth_login_service', 'groups', + '', @name, g_str, m_str) end end end diff --git a/lib/cisco_node_utils/aaa_authorization_service.rb b/lib/cisco_node_utils/aaa_authorization_service.rb index 6436134f..7c6189ce 100644 --- a/lib/cisco_node_utils/aaa_authorization_service.rb +++ b/lib/cisco_node_utils/aaa_authorization_service.rb @@ -36,12 +36,12 @@ def initialize(type, name, create=true) return unless create - node.config_set('aaa_authorization_service', 'method', '', type_str, name) + config_set('aaa_authorization_service', 'method', '', type_str, name) end def self.services servs = {} - servs_arr = node.config_get('aaa_authorization_service', 'services') + servs_arr = config_get('aaa_authorization_service', 'services') unless servs_arr.nil? servs_arr.each do |type, name| type = auth_type_str_to_sym(type) @@ -62,12 +62,12 @@ def destroy if g_str.empty? # cannot remove no groups + local, so do nothing in this case unless m == :local - node.config_set('aaa_authorization_service', 'method', - 'no', t_str, @name) + config_set('aaa_authorization_service', 'method', + 'no', t_str, @name) end else - node.config_set('aaa_authorization_service', 'groups', - 'no', t_str, @name, g_str, m_str) + config_set('aaa_authorization_service', 'groups', + 'no', t_str, @name, g_str, m_str) end end @@ -76,11 +76,11 @@ def destroy # memory regex only captures the last match # ex: aaa authorization console group group1 group2 group3 local def groups - # node.config_get returns the following format: + # config_get returns the following format: # [{"appl_subtype": "console", # "cmd_type": "config-commands", # "methods": "group foo bar local "}], ... - hsh_arr = node.config_get('aaa_authorization_service', 'groups') + hsh_arr = config_get('aaa_authorization_service', 'groups') fail 'unable to retrieve aaa groups information' if hsh_arr.nil? type_s = AaaAuthorizationService.auth_type_sym_to_str(@type) hsh = hsh_arr.find do |x| @@ -99,18 +99,18 @@ def groups # default is [] def default_groups - node.config_get_default('aaa_authorization_service', 'groups') + config_get_default('aaa_authorization_service', 'groups') end def method t_str = AaaAuthorizationService.auth_type_sym_to_str(@type) - m = node.config_get('aaa_authorization_service', 'method', @name, t_str) + m = config_get('aaa_authorization_service', 'method', @name, t_str) m.nil? ? :unselected : m.first.to_sym end # default is :local def default_method - node.config_get_default('aaa_authorization_service', 'method') + config_get_default('aaa_authorization_service', 'method') end # groups and method must be set in the same CLI string @@ -131,11 +131,11 @@ def groups_method_set(grps, m) # config_set depends on whether we're setting groups or not if g_str.empty? - node.config_set('aaa_authorization_service', 'method', - '', t_str, @name) + config_set('aaa_authorization_service', 'method', + '', t_str, @name) else - node.config_set('aaa_authorization_service', 'groups', - '', t_str, @name, g_str, m_str) + config_set('aaa_authorization_service', 'groups', + '', t_str, @name, g_str, m_str) end end diff --git a/lib/cisco_node_utils/aaa_server_group.rb b/lib/cisco_node_utils/aaa_server_group.rb index 62ba32ed..8600fed4 100644 --- a/lib/cisco_node_utils/aaa_server_group.rb +++ b/lib/cisco_node_utils/aaa_server_group.rb @@ -33,7 +33,7 @@ def initialize(name, type=:tacacs, create=true) return unless create if type == :tacacs TacacsServer.new.enable unless TacacsServer.enabled - node.config_set('aaa_server_group', 'tacacs_group', '', name) + config_set('aaa_server_group', 'tacacs_group', '', name) # elsif type == :radius ... else fail ArgumentError, "unsupported type #{type}" @@ -42,22 +42,19 @@ def initialize(name, type=:tacacs, create=true) def destroy if @type == :tacacs - node.config_set('aaa_server_group', 'tacacs_group', 'no', @name) + config_set('aaa_server_group', 'tacacs_group', 'no', @name) else fail ArgumentError, "unsupported type #{@type}" end end def servers + fail ArgumentError, "unsupported type #{@type}" unless @type == :tacacs + tacservers = config_get('aaa_server_group', + 'tacacs_servers', @name) servs = {} - if @type == :tacacs - tacservers = node.config_get('aaa_server_group', - 'tacacs_servers', @name) - unless tacservers.nil? - tacservers.each { |s| servs[s] = TacacsServerHost.new(s, false) } - end - else - fail ArgumentError, "unsupported type #{@type}" + unless tacservers.nil? + tacservers.each { |s| servs[s] = TacacsServerHost.new(s, false) } end servs end @@ -70,7 +67,7 @@ def servers=(new_servs) # add any servers not yet configured next if current_servs.include? s if @type == :tacacs - node.config_set('aaa_server_group', 'tacacs_server', @name, '', s) + config_set('aaa_server_group', 'tacacs_server', @name, '', s) else fail ArgumentError, "unsupported type #{@type}" end @@ -79,7 +76,7 @@ def servers=(new_servs) # remove any undesired existing servers next if new_servs.include? s if @type == :tacacs - node.config_set('aaa_server_group', 'tacacs_server', @name, 'no', s) + config_set('aaa_server_group', 'tacacs_server', @name, 'no', s) else fail ArgumentError, "unsupported type #{@type}" end @@ -87,14 +84,14 @@ def servers=(new_servs) end def self.default_servers - node.config_get_default('aaa_server_group', 'servers') + config_get_default('aaa_server_group', 'servers') end # allow optionally filtering on server type def self.groups(type=nil) fail TypeError unless type.nil? || type.is_a?(Symbol) grps = {} - tacgroups = node.config_get('aaa_server_group', 'tacacs_groups') if + tacgroups = config_get('aaa_server_group', 'tacacs_groups') if [nil, :tacacs].include?(type) && TacacsServer.enabled unless tacgroups.nil? tacgroups.each { |s| grps[s] = AaaServerGroup.new(s, :tacacs, false) } @@ -105,7 +102,7 @@ def self.groups(type=nil) def vrf if @type == :tacacs # vrf is always present in running config - v = node.config_get('aaa_server_group', 'tacacs_vrf', @name) + v = config_get('aaa_server_group', 'tacacs_vrf', @name) return v.nil? ? AaaServerGroup.default_vrf : v.first else fail ArgumentError, "unsupported type #{@type}" @@ -116,19 +113,19 @@ def vrf=(v) fail TypeError unless v.is_a? String # vrf = "default" is equivalent to unconfiguring vrf if @type == :tacacs - node.config_set('aaa_server_group', 'tacacs_vrf', @name, '', v) + config_set('aaa_server_group', 'tacacs_vrf', @name, '', v) else fail ArgumentError, "unsupported type #{@type}" end end def self.default_vrf - node.config_get_default('aaa_server_group', 'vrf') + config_get_default('aaa_server_group', 'vrf') end def deadtime if @type == :tacacs - d = node.config_get('aaa_server_group', 'tacacs_deadtime', @name) + d = config_get('aaa_server_group', 'tacacs_deadtime', @name) return d.nil? ? AaaServerGroup.default_deadtime : d.first.to_i else fail ArgumentError, "unsupported type #{@type}" @@ -138,20 +135,20 @@ def deadtime def deadtime=(t) no_cmd = t == AaaServerGroup.default_deadtime ? 'no' : '' if @type == :tacacs - node.config_set('aaa_server_group', 'tacacs_deadtime', @name, no_cmd, t) + config_set('aaa_server_group', 'tacacs_deadtime', @name, no_cmd, t) else fail ArgumentError, "unsupported type #{@type}" end end def self.default_deadtime - node.config_get_default('aaa_server_group', 'deadtime') + config_get_default('aaa_server_group', 'deadtime') end def source_interface if @type == :tacacs - i = node.config_get('aaa_server_group', - 'tacacs_source_interface', @name) + i = config_get('aaa_server_group', + 'tacacs_source_interface', @name) return i.nil? ? AaaServerGroup.default_source_interface : i.first else fail ArgumentError, "unsupported type #{@type}" @@ -162,15 +159,15 @@ def source_interface=(s) fail TypeError unless s.is_a? String no_cmd = s == AaaServerGroup.default_source_interface ? 'no' : '' if @type == :tacacs - node.config_set('aaa_server_group', 'tacacs_source_interface', - @name, no_cmd, s) + config_set('aaa_server_group', 'tacacs_source_interface', + @name, no_cmd, s) else fail ArgumentError, "unsupported type #{@type}" end end def self.default_source_interface - node.config_get_default('aaa_server_group', 'source_interface') + config_get_default('aaa_server_group', 'source_interface') end end end diff --git a/tests/test_aaa_authentication_login.rb b/tests/test_aaa_authentication_login.rb index 5223c87a..6724339f 100644 --- a/tests/test_aaa_authentication_login.rb +++ b/tests/test_aaa_authentication_login.rb @@ -38,9 +38,7 @@ def test_get_ascii_authentication aaaauthlogin = AaaAuthenticationLogin config('no aaa authentication login ascii-authentication') - refute(aaaauthlogin.ascii_authentication, - "Error: AAA authentication login ascii get\n" \ - 'See CSCuu12667 (4/29/15)') + refute(aaaauthlogin.ascii_authentication) config('aaa authentication login ascii-authentication') assert(aaaauthlogin.ascii_authentication, @@ -76,14 +74,11 @@ def test_get_chap aaaauthlogin = AaaAuthenticationLogin config('no aaa authentication login chap enable') - refute(aaaauthlogin.chap, - "Error: AAA authentication login chap get\n" \ - 'See CSCuu12667 (4/29/15)') + refute(aaaauthlogin.chap) config('aaa authentication login chap enable') assert(aaaauthlogin.chap, - "Error: AAA authentication login chap get with preconfig\n" \ - 'See CSCuu12667 (4/29/15)') + "Error: AAA authentication login chap get with preconfig\n") aaaauthenticationlogin_detach(aaaauthlogin) end @@ -152,13 +147,11 @@ def test_get_mschap config('no aaa authentication login mschap enable') refute(aaaauthlogin.mschap, - "Error: AAA authentication login mschap get\n" \ - 'See CSCuu12667 (4/29/15)') + "Error: AAA authentication login mschap get\n") config('aaa authentication login mschap enable') assert(aaaauthlogin.mschap, - "Error: AAA authentication login mschap get with preconfig\n" \ - 'See CSCuu12667 (4/29/15)') + "Error: AAA authentication login mschap get with preconfig\n") aaaauthenticationlogin_detach(aaaauthlogin) end @@ -191,13 +184,11 @@ def test_get_mschapv2 config('no aaa authentication login mschapv2 enable') refute(aaaauthlogin.mschapv2, - "Error: AAA authentication login mschapv2 get\n" \ - 'See CSCuu12667 (4/29/15)') + "Error: AAA authentication login mschapv2 get\n") config('aaa authentication login mschapv2 enable') assert(aaaauthlogin.mschapv2, - "Error: AAA authentication login mschapv2 get with preconfig\n" \ - 'See CSCuu12667 (4/29/15)') + "Error: AAA authentication login mschapv2 get with preconfig\n") aaaauthenticationlogin_detach(aaaauthlogin) end diff --git a/tests/test_aaa_authentication_login_service.rb b/tests/test_aaa_authentication_login_service.rb index b018248c..a53f872b 100644 --- a/tests/test_aaa_authentication_login_service.rb +++ b/tests/test_aaa_authentication_login_service.rb @@ -82,8 +82,7 @@ def test_collection_with_service_default refute_empty(aaaauthloginservice_list, 'Error: service collection is not filled') assert_equal(1, aaaauthloginservice_list.size, - 'Error: collection not reporting correct ' \ - ' size (see CSCuu29429)') + 'Error: collection not reporting correct ') assert(aaaauthloginservice_list.key?('default'), 'Error: collection does contain default') aaaauthloginservice_list.each do |name, aaaauthloginservice| @@ -102,11 +101,7 @@ def test_collection_with_service_default def test_collection_with_service_default_and_console unconfig_aaa # preconfig console - config('configure terminal') config('aaa authentication login console none') - config('end') - # Flush the cache since we've modified the device - node.cache_flush aaaauthloginservice_list = AaaAuthenticationLoginService.services refute_empty(aaaauthloginservice_list, @@ -123,8 +118,7 @@ def test_collection_with_service_default_and_console if name == 'default' assert_equal(AAA_AUTH_LOGIN_SERVICE_METHOD_LOCAL, aaaauthloginservice.method, - 'Error: Invalid method for default in ' \ - 'collection (see CSCuu29429)') + 'Error: Invalid method for default in collection') end if name == 'console' @@ -146,13 +140,9 @@ def test_collection_with_service_default_and_console_with_group config_tacacs_servers(servers) # preconfig console - config('configure terminal') # we need in some specific order - config('aaa authentication login default group group2 group1 none') - config('aaa authentication login console group group1') - config('end') - # Flush the cache since we've modified the device - node.cache_flush + config('aaa authentication login default group group2 group1 none', + 'aaa authentication login console group group1') aaaauthloginservice_list = AaaAuthenticationLoginService.services refute_empty(aaaauthloginservice_list, @@ -292,21 +282,13 @@ def test_service_default_get_groups config_tacacs_servers(servers) # preconfig default - config('configure terminal') config('aaa authentication login default group bxb100 sjc200') - config('end') - # Flush the cache since we've modified the device - node.cache_flush groups = %w(bxb100 sjc200) assert_equal(groups, aaaauthloginservice.groups, 'Error: login service default get groups') # preconfig default - config('configure terminal') config('aaa authentication login default group sjc200 bxb100 rtp10 none') - config('end') - # Flush the cache since we've modified the device - node.cache_flush groups = %w(sjc200 bxb100 rtp10) assert_equal(groups, aaaauthloginservice.groups, 'Error: login service default get groups') @@ -329,22 +311,13 @@ def test_service_console_get_groups config_tacacs_servers(servers) # preconfig console - config('configure terminal') config('aaa authentication login console group bxb100 sjc200') - config('end') - # Flush the cache since we've modified the device - node.cache_flush groups = %w(bxb100 sjc200) assert_equal(groups, aaaauthloginservice.groups, - "Error: login service console get groups #{groups}" \ - ' (see CSCuu29429)') + "Error: login service console get groups #{groups}") # preconfig console - config('configure terminal') config('aaa authentication login console group rtp10 bxb100 none') - config('end') - # Flush the cache since we've modified the device - node.cache_flush groups = %w(rtp10 bxb100) assert_equal(groups, aaaauthloginservice.groups, "Error: login service console get groups #{groups}") From 814cd74545ffaf1244156a5e5423850ad499dd21 Mon Sep 17 00:00:00 2001 From: mikewiebe Date: Thu, 29 Oct 2015 12:52:59 -0400 Subject: [PATCH 009/386] rubocop fixes --- lib/cisco_node_utils/features.rb | 1 - lib/cisco_node_utils/node_util.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/cisco_node_utils/features.rb b/lib/cisco_node_utils/features.rb index 0b2f5e3a..d7ab081a 100644 --- a/lib/cisco_node_utils/features.rb +++ b/lib/cisco_node_utils/features.rb @@ -29,6 +29,5 @@ def self.included(base) module ClassMethods # @@node = Cisco::Node.instance # debug "@@@@@ Loaded Features node is #{@@node}" - end # end of module ClassMethods end # end of module Features diff --git a/lib/cisco_node_utils/node_util.rb b/lib/cisco_node_utils/node_util.rb index 55f8dbcd..8714599d 100644 --- a/lib/cisco_node_utils/node_util.rb +++ b/lib/cisco_node_utils/node_util.rb @@ -61,6 +61,5 @@ def config_set(*args) def show(*args) node.show(*args) end - end end From 5666d3e1dc94911ff60f379fe9351cb7e97839b3 Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Thu, 29 Oct 2015 11:15:42 -0700 Subject: [PATCH 010/386] Initial drop of fabricpath node_utils --- lib/cisco_node_utils/command_reference.rb | 5 +- .../command_reference_common.yaml | 4 +- .../command_reference_n5k.yaml | 211 +++++++++ .../command_reference_n7k.yaml | 170 ++++++- lib/cisco_node_utils/fabricpath_global.rb | 431 ++++++++++++++++++ lib/cisco_node_utils/fabricpath_topology.rb | 125 +++++ lib/cisco_node_utils/interface.rb | 66 ++- lib/cisco_node_utils/node.rb | 9 + lib/cisco_node_utils/vlan.rb | 59 +++ tests/test_fabricpath_global.rb | 220 +++++++++ 10 files changed, 1294 insertions(+), 6 deletions(-) create mode 100755 lib/cisco_node_utils/command_reference_n5k.yaml create mode 100644 lib/cisco_node_utils/fabricpath_global.rb create mode 100644 lib/cisco_node_utils/fabricpath_topology.rb create mode 100644 tests/test_fabricpath_global.rb diff --git a/lib/cisco_node_utils/command_reference.rb b/lib/cisco_node_utils/command_reference.rb index b5559f6c..17388202 100644 --- a/lib/cisco_node_utils/command_reference.rb +++ b/lib/cisco_node_utils/command_reference.rb @@ -174,9 +174,12 @@ def initialize(product_id, files=nil) CommandPlatformFile.new(/N9K/, File.join(File.dirname(__FILE__), 'command_reference_n9k.yaml')), - CommandPlatformFile.new(/N7K/, + CommandPlatformFile.new(/N7[K,7]/, File.join(File.dirname(__FILE__), 'command_reference_n7k.yaml')), + CommandPlatformFile.new(/N5K/, + File.join(File.dirname(__FILE__), + 'command_reference_n5k.yaml')), CommandPlatformFile.new(/C3064/, File.join(File.dirname(__FILE__), 'command_reference_n3064.yaml')), diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index b3ac925c..938dfe17 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -638,13 +638,13 @@ radius_global: config_get: "show running-config radius all" config_get_token: '/^radius-server timeout (\d+).*/' config_set: ' radius-server timeout ' - default: '5' + default_value: '5' retransmit: config_get: "show running-config radius all" config_get_token: '/^radius-server retransmit (\d+).*/' config_set: ' radius-server retransmit ' - default: '1' + default_value: '1' key_format: config_get: "show running-config radius all" diff --git a/lib/cisco_node_utils/command_reference_n5k.yaml b/lib/cisco_node_utils/command_reference_n5k.yaml new file mode 100755 index 00000000..64c9947f --- /dev/null +++ b/lib/cisco_node_utils/command_reference_n5k.yaml @@ -0,0 +1,211 @@ +# Command Reference N7K +# +# For documentation please see these files for fields and defaults: +# - README_YAML.md +# - command_reference_common.yaml +# +--- +fabricpath: + aggregate_multicast_routes: + config_get: 'unsupported' + config_get_token: 'unsupported' + config_set: '%s unsupported' + default_value: 'unsupported' + + allocate_delay: + config_get: "show fabricpath timers" + config_get_token: '/^Allocate Delay Timer\s+:\s+(\d+)/' + config_set: "%s fabricpath timers allocate-delay %s" + default_value: 10 + + auto_switch_id: + config_get: "show fabricpath switch-id" + config_get_token: '/^\*\s+(\d+).*No$/' + + feature: + config_get: "show feature-set" + config_get_token: '/^fabricpath[\s]+[\d]+[\s]+(\S+)/' + config_set: "%s feature-set fabricpath" + + feature_install: + config_set: "%s install feature-set fabricpath" + + graceful_merge: + config_get: "show run fabricpath" + config_get_token: '/^fabricpath graceful\-merge (\S+)/' + config_set: "%s fabricpath graceful-merge disable" + default_value: true + + linkup_delay: + config_get: "show fabricpath timers" + config_get_token: '/^Link\-up Delay Timer\s+:\s+(\d+)/' + config_set: "%s fabricpath timers linkup-delay %s" + default_value: 10 + + linkup_delay_always: + config_get: 'unsupported' + config_get_token: 'unsupported' + config_set: '%s unsupported' + default_value: 'unsupported' + + linkup_delay_enable: + config_get: 'unsupported' + config_get_token: 'unsupported' + config_set: '%s unsupported' + default_value: 'unsupported' + + loadbalance_algorithm: + config_get: "show fabricpath load-balance" + config_get_token: '/^Hash Control: (\S+)/' + config_set: "%s fabricpath load-balance %s" + default_value: "source-destination" + + loadbalance_multicast_rotate: + config_get: 'unsupported' + config_get_token: 'unsupported' + default_value: 'unsupported' + + loadbalance_multicast_has_vlan: + config_get: 'unsupported' + config_get_token: 'unsupported' + default_value: 'unsupported' + + loadbalance_multicast_reset: + config_set: 'unsupported' + + loadbalance_multicast_set: + config_set: 'unsupported ' + + loadbalance_unicast_layer: + config_get: "show fabricpath load-balance" + config_get_token: '/^L3\/L4 Preference: (\S+)/' + config_set: "%s fabricpath load-balance unicast %s" + default_value: "mixed" + + loadbalance_unicast_rotate: + config_get: 'unsupported' + config_get_token: 'unsupported' + config_set: '%s unsupported %s' + default_value: 'unsupported' + + loadbalance_unicast_has_vlan: + config_get: "show fabricpath load-balance" + config_get_token: '/^Use VLAN: (\S+)/' + config_set: "%s fabricpath load-balance unicast include-vlan" + default_value: true + + mode: + config_get: "show run fabricpath" + config_get_token: '/^fabricpath mode (\S+)/' + config_set: "%s fabricpath mode transit" + default_value: "normal" + + switch_id: + config_get: "show run fabricpath" + config_get_token: '/^fabricpath switch-id (\d+)/' + config_set: "fabricpath switch-id %s" + + transition_delay: + config_get: "show fabricpath timers" + config_get_token: '/^Transition Delay Timer\s+:\s+(\d+)/' + config_set: "%s fabricpath timers transition-delay %s" + default_value: 10 + +fp_topology: + all_topos: + config_get: "show fabricpath topology" + config_get_token: '/^\S+[\s]+(\d+)[\s]+/' + + create: + config_set: ["fabricpath topology %s" , "end"] + + description: + config_get: "show fabricpath topology" + config_get_token: '/^(\S+)[\s]+%d+[\s]+\S+/' + config_set: ["fabricpath topology %d" , "%s description %s", "end"] + default_value: "" + + destroy: + config_set: "no fabricpath topology %s" + + member_vlans: + config_get: "show fabricpath topology vlan" + config_get_token: '/^\S+[\s]+%d+[\s]+(\S+)/' + config_set: ["fabricpath topology %d" , "%s member vlan %s", "end"] + default_value: "--" + + state: + config_get: "show fabricpath topology" + config_get_token: '/^\S+[\s]+%d+[\s]+(\S+)/' + default_value: "up" + +interface: + admin_state_ethernet_noswitchport_shutdown: + default_value: "shutdown" + + ipv4_redirects_loopback: + default_value: false + config_set: ~ + config_get: ~ + config_get_token: ~ + test_config_result: + false: RuntimeError + true: RuntimeError + + negotiate_auto_ethernet: + config_set: ~ + config_get: ~ + config_get_token: ~ + default_value: false + + negotiate_auto_portchannel: + config_set: ~ + config_get: ~ + config_get_token: + default_value: false + +inventory: + inventory: + test_config_get_regex: [!ruby/regexp '/.*\nNAME: "(.+)",\s+DESCR: "(.+)"\s+\nPID: (\S+)\s+,\s+VID: (.+) ,\s+SN: (.+)\s+\n/', !ruby/regexp '/.*NAME: "(.+)",\s+DESCR: "(.+)"\s+PID: (\S+)\s+,\s+VID: (.+) ,\s+SN: (.+)\s+\n/'] + +show_version: + description: + test_config_get_regex: !ruby/regexp '/.*Hardware\n cisco (\w+ \w+ \(\w+ \w+\) \w+).*/' + +supported: + aggregate_multicast_routes: + default_value: false + + linkup_delay_always: + default_value: false + + linkup_delay_enable: + default_value: false + + loadbalance_algorithm: + default_value: 'source-destination' + + loadbalance_multicast: + default_value: 'combined' + + loadbalance_multicast_rotate: + default_value: false + + loadbalance_unicast: + default_value: 'split' + + loadbalance_unicast_rotate: + default_value: false + +vlan: + mode: + config_get: "show vlan" + config_get_token: '/^%d+\s+enet\s+(\S+)\s/' + config_set: ["vlan %d" , "%s mode %s", "end"] + default_value: "ce" + +vtp: + version: + test_config_result: + 3: 3 + diff --git a/lib/cisco_node_utils/command_reference_n7k.yaml b/lib/cisco_node_utils/command_reference_n7k.yaml index d3e8d092..1594eaa8 100755 --- a/lib/cisco_node_utils/command_reference_n7k.yaml +++ b/lib/cisco_node_utils/command_reference_n7k.yaml @@ -5,6 +5,143 @@ # - command_reference_common.yaml # --- +fabricpath: + aggregate_multicast_routes: + config_get: "show run fabricpath" + config_get_token: '/^fabricpath multicast (aggregate\-routes)/' + config_set: "%s fabricpath multicast aggregate-routes" + default_value: false + + allocate_delay: + config_get: "show fabricpath timers" + config_get_token: '/^Allocate Delay Timer\s+:\s+(\d+)/' + config_set: "%s fabricpath timers allocate-delay %s" + default_value: 10 + + auto_switch_id: + config_get: "show fabricpath switch-id" + config_get_token: '/^\*\s+(\d+).*No$/' + + feature: + config_get: "show feature-set" + config_get_token: '/^fabricpath[\s]+[\d]+[\s]+(\S+)/' + config_set: "%s feature-set fabricpath" + + feature_install: + config_set: "%s install feature-set fabricpath" + + graceful_merge: + config_get: "show run fabricpath" + config_get_token: '/^fabricpath graceful\-merge (\S+)/' + config_set: "%s fabricpath graceful-merge disable" + default_value: true + + linkup_delay: + config_get: "show fabricpath timers" + config_get_token: '/^Link\-up Delay Timer\s+:\s+(\d+)/' + config_set: "%s fabricpath timers linkup-delay %s" + default_value: 10 + + linkup_delay_always: + config_get: "show fabricpath timers" + config_get_token: '/^Link\-up Delay Timer\s+:\s+\d+\s+\((always)\)$/' + config_set: "%s fabricpath timers linkup-delay always" + default_value: false + + linkup_delay_enable: + config_get: "show fabricpath timers" + config_get_token: '/^Link\-up Delay\s+:\s+(\S+)/' + config_set: "%s fabricpath linkup-delay" + default_value: true + + loadbalance_algorithm: + config_get: "show fabricpath load-balance" + config_get_token: '/^Hash Control: (\S+)/' + config_set: "%s fabricpath load-balance %s" + default_value: "symmetric" + + loadbalance_multicast_rotate: + config_get: "show fabricpath load-balance | begin Ftag" + config_get_token: '/^Rotate amount: (\d+)/' + default_value: 5 + + loadbalance_multicast_has_vlan: + config_get: "show fabricpath load-balance | begin Ftag" + config_get_token: '/^Use VLAN: (\S+)/' + default_value: false + + loadbalance_multicast_reset: + config_set: "no fabricpath load-balance multicast" + + loadbalance_multicast_set: + config_set: 'fabricpath load-balance multicast ' + + loadbalance_unicast_layer: + config_get: "show fabricpath load-balance" + config_get_token: '/^L3\/L4 Preference: (\S+)/' + default_value: "mixed" + + loadbalance_unicast_rotate: + config_get: "show fabricpath load-balance" + config_get_token: '/^Rotate amount: (\d+)/' + default_value: 5 + + loadbalance_unicast_has_vlan: + config_get: "show fabricpath load-balance" + config_get_token: '/^Use VLAN: (\S+)/' + default_value: false + + loadbalance_unicast_reset: + config_set: "no fabricpath load-balance unicast" + + loadbalance_unicast_set: + config_set: 'fabricpath load-balance unicast ' + + mode: + config_get: "show run fabricpath" + config_get_token: '/^fabricpath mode (\S+)/' + config_set: "%s fabricpath mode transit" + default_value: "normal" + + switch_id: + config_get: "show run fabricpath" + config_get_token: '/^fabricpath switch-id (\d+)/' + config_set: "fabricpath switch-id %s" + + transition_delay: + config_get: "show fabricpath timers" + config_get_token: '/^Transition Delay Timer\s+:\s+(\d+)/' + config_set: "%s fabricpath timers transition-delay %s" + default_value: 10 + +fp_topology: + all_topos: + config_get: "show fabricpath topology" + config_get_token: '/^\S+[\s]+(\d+)[\s]+/' + + create: + config_set: ["fabricpath topology %s" , "end"] + + description: + config_get: "show fabricpath topology" + config_get_token: '/^(\S+)[\s]+%d+[\s]+\S+/' + config_set: ["fabricpath topology %d" , "%s description %s", "end"] + default_value: "" + + destroy: + config_set: "no fabricpath topology %s" + + member_vlans: + config_get: "show fabricpath topology vlan" + config_get_token: '/^\S+[\s]+%d+[\s]+(\S+)/' + config_set: ["fabricpath topology %d" , "%s member vlan %s", "end"] + default_value: "--" + + state: + config_get: "show fabricpath topology" + config_get_token: '/^\S+[\s]+%d+[\s]+(\S+)/' + default_value: "up" + interface: admin_state_ethernet_noswitchport_shutdown: default_value: "shutdown" @@ -30,16 +167,45 @@ interface: config_get_token: default_value: false - inventory: inventory: test_config_get_regex: [!ruby/regexp '/.*\nNAME: "(.+)",\s+DESCR: "(.+)"\s+\nPID: (\S+)\s+,\s+VID: (.+) ,\s+SN: (.+)\s+\n/', !ruby/regexp '/.*NAME: "(.+)",\s+DESCR: "(.+)"\s+PID: (\S+)\s+,\s+VID: (.+) ,\s+SN: (.+)\s+\n/'] - show_version: description: test_config_get_regex: !ruby/regexp '/.*Hardware\n cisco (\w+ \w+ \(\w+ \w+\) \w+).*/' +supported: + aggregate_multicast_routes: + default_value: true + + linkup_delay_always: + default_value: true + + linkup_delay_enable: + default_value: true + + loadbalance_algorithm: + default_value: 'symmetric' + + loadbalance_multicast: + default_value: 'combined' + + loadbalance_multicast_rotate: + default_value: true + + loadbalance_unicast: + default_value: 'combined' + + loadbalance_unicast_rotate: + default_value: true + +vlan: + mode: + config_get: "show vlan" + config_get_token: '/^%d+\s+enet\s+(\S+)\s/' + config_set: ["vlan %d" , "%s mode %s", "end"] + default_value: "ce" vtp: version: diff --git a/lib/cisco_node_utils/fabricpath_global.rb b/lib/cisco_node_utils/fabricpath_global.rb new file mode 100644 index 00000000..ec458f85 --- /dev/null +++ b/lib/cisco_node_utils/fabricpath_global.rb @@ -0,0 +1,431 @@ +# +# NXAPI implementation of Fabricpath Global class +# +# November 2015, Deepak Cherian +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node_util') + +module Cisco + # node_utils class for fabricpath_global + class FabricpathGlobal < NodeUtil + attr_reader :name + + def initialize(name, instantiate=true) + fail TypeError unless name.is_a?(String) + fail ArgumentError unless name == "default" + @name = name.downcase + + create if instantiate + end + + def self.globals + hash = {} + is_fabricpath_feature = config_get('fabricpath', 'feature') + return hash if (:enabled != is_fabricpath_feature.first.to_sym) + hash['default'] = FabricpathGlobal.new('default', false) + hash + end + + def fabricpath_feature + fabricpath = config_get('fabricpath', 'feature') + fail 'fabricpath_feature not found' if fabricpath.nil? + return :disabled if fabricpath.nil? + fabricpath.shift.to_sym + end + + def fabricpath_feature_set(fabricpath_set) + curr = fabricpath_feature + return if curr == fabricpath_set + + case fabricpath_set + when :enabled + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + config_set('fabricpath', 'feature', '') + when :disabled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + return + when :installed + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + when :uninstalled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + config_set('fabricpath', 'feature_install', 'no') + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def create + fabricpath_feature_set(:enabled) unless :enabled == fabricpath_feature + end + + def destroy + @name = nil + fabricpath_feature_set(:disabled) + end + + def my_munge(property, set_val) + val = config_get_default('supported', property) + case property + when /loadbalance_algorithm/ + if (val == 'source-destination') && (set_val == 'symmetric' || set_val == 'xor') + val + else + set_val + end + when /loadbalance_.*_rotate/ + if val == false || set_val == '' + '' + else + "rotate-amount 0x#{set_val.to_s(16)}" + end + else + set_val + end + end + + ######################################################## + # PROPERTIES # + ######################################################## + + def aggregate_multicast_routes + agg_routes = config_get('fabricpath', 'aggregate_multicast_routes') + return default_aggregate_multicast_routes if agg_routes.nil? + agg_routes.first == 'aggregate-routes' ? true : false + end + + def aggregate_multicast_routes=(val) + if (val == true) + config_set('fabricpath', 'aggregate_multicast_routes', '') + else + config_set('fabricpath', 'aggregate_multicast_routes', 'no') + end + rescue Cisco::CliError => e + raise "[Setting agg-routes #{val}] '#{e.command}' : #{e.clierror}" + end + + def default_aggregate_multicast_routes + config_get_default('fabricpath', 'aggregate_multicast_routes') + end + + def allocate_delay + delay = config_get('fabricpath', 'allocate_delay') + return default_allocate_routes if delay.nil? + delay.first.to_i + end + + def allocate_delay=(val) + if val == '' + config_set('fabricpath', 'allocate_delay', 'no', '') + else + config_set('fabricpath', 'allocate_delay', '', val) + end + rescue Cisco::CliError => e + raise "[Setting allocate-delay #{val}] '#{e.command}' : #{e.clierror}" + end + + def default_allocate_delay + config_get_default('fabricpath', 'allocate_delay') + end + + def graceful_merge + graceful_merge_conf = config_get('fabricpath', 'graceful_merge') + return default_graceful_merge if graceful_merge_conf.nil? + graceful_merge_conf.first == 'disable' ? false : true + end + + def auto_switch_id + val = config_get('fabricpath', 'auto_switch_id') + val.first.to_i + end + + def graceful_merge=(val) + if val == '' || val == true + config_set('fabricpath', 'graceful_merge', 'no') + else + config_set('fabricpath', 'graceful_merge', '') + end + rescue Cisco::CliError => e + raise "[Setting allocate-delay #{val}] '#{e.command}' : #{e.clierror}" + end + + def default_graceful_merge + config_get_default('fabricpath', 'graceful_merge') + end + + def linkup_delay + delay = config_get('fabricpath', 'linkup_delay') + return default_linkup_delay if delay.nil? + delay.first.to_i + end + + def linkup_delay=(val) + if val == '' + config_set('fabricpath', 'linkup_delay', 'no', '') + else + config_set('fabricpath', 'linkup_delay', '', val) + end + rescue Cisco::CliError => e + raise "[Setting linkup-delay #{val}] '#{e.command}' : #{e.clierror}" + end + + def default_linkup_delay + config_get_default('fabricpath', 'linkup_delay') + end + + def linkup_delay_always + enabled = config_get('fabricpath', 'linkup_delay_always') + return default_linkup_delay_always if enabled.nil? + enabled.first.strip == 'always' ? true : false + end + + def linkup_delay_always=(val) + if val == '' || val == true + config_set('fabricpath', 'linkup_delay_always', '') + else + config_set('fabricpath', 'linkup_delay_always', 'no') + end + rescue Cisco::CliError => e + raise "[Setting linkup-delay-always #{val}] '#{e.command}' + : #{e.clierror}" + end + + def default_linkup_delay_always + config_get_default('fabricpath', 'linkup_delay_always') + end + + def linkup_delay_enable + enabled = config_get('fabricpath', 'linkup_delay_enable') + return default_linkup_delay_enable if enabled.nil? + enabled.first.strip == 'Enabled' ? true : false + end + + def linkup_delay_enable=(val) + if val == '' || val == true + config_set('fabricpath', 'linkup_delay_enable', '') + else + config_set('fabricpath', 'linkup_delay_enable', 'no') + end + rescue Cisco::CliError => e + raise "[Setting linkup-delay-enable #{val}] '#{e.command}' + : #{e.clierror}" + end + + def default_linkup_delay_enable + config_get_default('fabricpath', 'linkup_delay_enable') + end + + def loadbalance_algorithm + algo = config_get('fabricpath', 'loadbalance_algorithm') + return default_loadbalance_algorithm if algo.nil? + algo.first.strip.downcase + end + + def loadbalance_algorithm=(val) + val = my_munge('loadbalance_algorithm', val) + if val == '' + config_set('fabricpath', 'loadbalance_algorithm', 'no', '') + else + config_set('fabricpath', 'loadbalance_algorithm', '', val) + end + rescue Cisco::CliError => e + raise "[Setting loadbalance-algo #{val}] '#{e.command}' : #{e.clierror}" + end + + def default_loadbalance_algorithm + config_get_default('fabricpath', 'loadbalance_algorithm') + end + + def loadbalance_multicast_rotate + multicast = config_get('fabricpath', 'loadbalance_multicast_rotate') + return default_loadbalance_multicast_rotate if multicast.nil? + multicast.first.to_i + end + + def loadbalance_multicast_has_vlan + multicast = config_get('fabricpath', 'loadbalance_multicast_has_vlan') + return default_loadbalance_multicast_has_vlan if multicast.nil? + multicast.first.strip == 'TRUE' ? true : false + end + + def loadbalance_multicast=(rotate, has_vlan) + if rotate == '' && (has_vlan == '' || has_vlan == false) + config_set('fabricpath', 'loadbalance_multicast_reset') + else + rotate = my_munge('loadbalance_multicast_rotate', rotate) + has_vlan = (has_vlan == true) ? "include-vlan" : '' + config_set('fabricpath', 'loadbalance_multicast_set', + rotate_amt: rotate, inc_vlan: has_vlan) + end + rescue Cisco::CliError => e + raise "[Setting loadbalance #{rotate} #{has_vlan}] '#{e.command}' + : #{e.clierror}" + end + + def default_loadbalance_multicast_rotate + config_get_default('fabricpath', 'loadbalance_multicast_rotate') + end + + def default_loadbalance_multicast_has_vlan + config_get_default('fabricpath', 'loadbalance_multicast_has_vlan') + end + + def loadbalance_unicast_layer + unicast = config_get('fabricpath', 'loadbalance_unicast_layer') + return default_loadbalance_unicast_layer if unicast.nil? + case unicast.first.strip + when /L4/ + "layer4" + when /L3/ + "layer3" + when /Mixed/ + "mixed" + end + end + + def loadbalance_unicast_rotate + unicast = config_get('fabricpath', 'loadbalance_unicast_rotate') + return default_loadbalance_unicast_rotate if unicast.nil? + unicast.first.to_i + end + + def loadbalance_unicast_has_vlan + unicast = config_get('fabricpath', 'loadbalance_unicast_has_vlan') + return default_loadbalance_unicast_has_vlan if unicast.nil? + unicast.first.strip == 'TRUE' ? true : false + end + + def split_loadbalance_unicast_layer=(val) + if val == '' + config_set('fabricpath', 'loadbalance_unicast_layer', 'no', val) + else + config_set('fabricpath', 'loadbalance_unicast_layer', '', val) + end + rescue Cisco::CliError => e + raise "[Setting loadbalance layer #{val} ] '#{e.command}' + : #{e.clierror}" + end + + def split_loadbalance_unicast_rotate=(val) + if val == '' + config_set('fabricpath', 'loadbalance_unicast_rotate', 'no', val) + else + config_set('fabricpath', 'loadbalance_unicast_rotate', '', val) + end + rescue Cisco::CliError => e + raise "[Setting loadbalance rotate #{val} ] '#{e.command}' + : #{e.clierror}" + end + + def split_loadbalance_unicast_has_vlan=(val) + if val == '' || val == false + config_set('fabricpath', 'loadbalance_unicast_has_vlan', 'no') + else + config_set('fabricpath', 'loadbalance_unicast_has_vlan', '') + end + rescue Cisco::CliError => e + raise "[Setting loadbalance has_vlan #{val} ] '#{e.command}' + : #{e.clierror}" + end + + def loadbalance_unicast=(layer, rotate, has_vlan) + support = config_get_default('supported', 'loadbalance_unicast') + if support == 'combined' + if layer == '' && rotate == '' && (has_vlan == '' || has_vlan == false) + config_set('fabricpath', 'loadbalance_unicast_reset') + else + rotate = my_munge('loadbalance_unicast_rotate', rotate) + has_vlan = (has_vlan == true) ? "include-vlan" : '' + config_set('fabricpath', 'loadbalance_unicast_set', + pref: layer, rotate_amt: rotate, inc_vlan: has_vlan) + end + else + split_loadbalance_unicast_layer = layer + split_loadbalance_unicast_rotate = rotate + split_loadbalance_unicast_has_vlan = has_vlan + end + rescue Cisco::CliError => e + raise "[Setting loadbalance #{layer} #{rotate} #{has_vlan}] '#{e.command}' + : #{e.clierror}" + end + + def default_loadbalance_unicast_layer + config_get_default('fabricpath', 'loadbalance_unicast_layer') + end + + def default_loadbalance_unicast_rotate + config_get_default('fabricpath', 'loadbalance_unicast_rotate') + end + + def default_loadbalance_unicast_has_vlan + config_get_default('fabricpath', 'loadbalance_unicast_has_vlan') + end + + def mode + mode_conf = config_get('fabricpath', 'mode') + return default_mode if mode_conf.nil? + mode_conf.first + end + + def mode=(val) + if val == '' || val == 'normal' + config_set('fabricpath', 'mode', 'no') + else + config_set('fabricpath', 'mode', '') + end + rescue Cisco::CliError => e + raise "[Setting mode #{val}] '#{e.command}' : #{e.clierror}" + end + + def default_mode + config_get_default('fabricpath', 'mode') + end + + def switch_id + switch_id_conf = config_get('fabricpath', 'switch_id') + return auto_switch_id if switch_id_conf.nil? + switch_id_conf.first.to_i + end + + def switch_id=(val) + # There is no no-form for this command + config_set('fabricpath', 'switch_id', val.to_s) + rescue Cisco::CliError => e + raise "[Setting switch-id #{val}] '#{e.command}' : #{e.clierror}" + end + + def transition_delay + delay = config_get('fabricpath', 'transition_delay') + return default_transition_delay if delay.nil? + delay.first.to_i + end + + def transition_delay=(val) + if val == '' + config_set('fabricpath', 'transition_delay', 'no', '') + else + config_set('fabricpath', 'transition_delay', '', val) + end + rescue Cisco::CliError => e + raise "[Setting linkup-delay #{val}] '#{e.command}' : #{e.clierror}" + end + + def default_transition_delay + config_get_default('fabricpath', 'transition_delay') + end + + end # class +end # module diff --git a/lib/cisco_node_utils/fabricpath_topology.rb b/lib/cisco_node_utils/fabricpath_topology.rb new file mode 100644 index 00000000..a86f599e --- /dev/null +++ b/lib/cisco_node_utils/fabricpath_topology.rb @@ -0,0 +1,125 @@ +# Topology provider class +# +# Deepak Cherian, November 2015 +# +# Copyright (c) 2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node_util') + +module Cisco + + class Topo < NodeUtil + attr_reader :topo_id + + def initialize(topo_id, instantiate=true) + @topo_id = topo_id.to_s + raise ArgumentError, + "Invalid value(non-numeric Topo id #{@topo_id})" unless @topo_id[/^\d+$/] + + create if instantiate + end + + def Topo.topos + hash = {} + fabricpath = config_get("fabricpath", "feature") + return hash if (:enabled != fabricpath.first.to_sym) + topo_list = config_get("fp_topology", "all_topos") + return hash if topo_list.nil? + + topo_list.each do |id| + hash[id] = Topo.new(id, false) + end + hash + end + + def create + fabricpath_feature_set(:enabled) unless (:enabled == fabricpath_feature) + config_set("fp_topology", "create", @topo_id) unless @topo_id == "0" + end + + def destroy + config_set("fp_topology", "destroy", @topo_id) + end + + def cli_error_check(result) + # The NXOS vlan cli does not raise an exception in some conditions and + # instead just displays a STDOUT error message; thus NXAPI does not detect + # the failure and we must catch it by inspecting the "body" hash entry + # returned by NXAPI. This vlan cli behavior is unlikely to change. + raise result[2]["body"] unless result[2]["body"].empty? + end + + def state + result = config_get("fp_topology", "state", @topo_id) + return default_state if result.nil? + case result.first + when /Up/ + return "up" + when /Down/ + return "default" + end + end + + def default_state + config_get_default("fp_topology", "state") + end + + def member_vlans + array = config_get("fp_topology", "member_vlans", @topo_id) + str = array.first + return [] if str == "--" + str.gsub!("-", "..") + if /,/.match(str) + str.split(/\s*,\s*/) + else + str.lines.to_a + end + end + + def member_vlans=(str) + debug "str is #{str} whose class is #{str.class}" + str = str.join(",") if !str.empty? + if str.empty? + result = config_set("fp_topology", "member_vlans", @topo_id, "no", "") + else + str.gsub!("..", "-") + result = config_set("fp_topology", "member_vlans", @topo_id, "", str) + end + cli_error_check(result) + rescue CliError => e + raise "[topo #{@topo_id}] '#{e.command}' : #{e.clierror}" + end + + def topo_name + desc = config_get("fp_topology", "description", @topo_id) + return "" if desc.nil? + desc.shift.strip + end + + def topo_name=(desc) + raise TypeError unless desc.is_a?(String) + desc.empty? ? + config_set("fp_topology", "description", @topo_id, "no", "") : + config_set("fp_topology", "description", @topo_id, "", desc) + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def default_topo_name + config_get_default("fp_topology", "description") + end + + end # class +end # module diff --git a/lib/cisco_node_utils/interface.rb b/lib/cisco_node_utils/interface.rb index 140933b1..7d5f2cb2 100644 --- a/lib/cisco_node_utils/interface.rb +++ b/lib/cisco_node_utils/interface.rb @@ -24,6 +24,7 @@ module Cisco trunk: 'trunk', fex_fabric: 'fex-fabric', tunnel: 'dot1q-tunnel', + fabricpath: 'fabricpath', } # Interface - node utility class for general interface config management @@ -100,6 +101,22 @@ def default_description config_get_default('interface', 'description') end + def enable_pim_sparse_mode + state = config_get('interface', 'pim_sparse_mode', @name) + state ? true : false + end + + def enable_pim_sparse_mode=(state) + no_cmd = (state ? '' : 'no') + config_set('interface', 'pim_sparse_mode', @name, no_cmd) + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def default_enable_pim_sparse_mode + config_get_default('interface', pim_sparse_mode) + end + def encapsulation_dot1q val = config_get('interface', 'encapsulation_dot1q', @name) return default_encapsulation_dot1q if val.nil? @@ -120,6 +137,51 @@ def default_encapsulation_dot1q config_get_default('interface', 'encapsulation_dot1q') end + def encapsulation_profile_vni + val = config_get('interface', 'encapsulation_vni', @name) + debug "val from get is #{val}" + return '' if val.nil? + val.first.strip + end + + def encapsulation_profile_vni=(val) + if val.nil? + config_set('interface', 'encapsulation_vni_del', @name, val) + else + config_set('interface', 'encapsulation_vni_add', @name, val) + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def fabricpath_feature + fabricpath = config_get('fabricpath', 'feature') + fail 'fabricpath_feature not found' if fabricpath.nil? + return :disabled if fabricpath.nil? + fabricpath.shift.to_sym + end + + def fabricpath_feature_set(fabricpath_set) + curr = fabricpath_feature + return if curr == fabricpath_set + + case fabricpath_set + when :enabled + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + config_set('fabricpath', 'feature', '') + when :disabled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + return + when :installed + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + when :uninstalled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + config_set('fabricpath', 'feature_install', 'no') + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + def fex_feature fex = config_get('fex', 'feature') fail 'fex_feature not found' if fex.nil? @@ -401,7 +463,9 @@ def switchport_mode def switchport_enable_and_mode(mode_set) switchport_enable unless switchport - if (:fex_fabric == mode_set) + if (:fabricpath == mode_set) + fabricpath_feature_set(:enabled) unless (:enabled == fabricpath_feature) + elsif (:fex_fabric == mode_set) fex_feature_set(:enabled) unless (:enabled == fex_feature) end config_set('interface', switchport_mode_lookup_string, @name, '', diff --git a/lib/cisco_node_utils/node.rb b/lib/cisco_node_utils/node.rb index 002652f8..7c8ac40a 100644 --- a/lib/cisco_node_utils/node.rb +++ b/lib/cisco_node_utils/node.rb @@ -88,6 +88,9 @@ def config_get(feature, name, *args) text = build_config_get(feature, ref, :ascii) return Cisco.find_ascii(text, token) else + if token == 'unsupported' + return nil + end hash = build_config_get(feature, ref, :structured) return hash[token] end @@ -159,10 +162,16 @@ def config_set(feature, name, *args) end end if config_set.is_a?(String) + if config_set =~ /[a-z0-9]*\s*unsupported[a-z0-9 ]*/ + return + end config(sprintf(config_set, *args)) elsif config_set.is_a?(Array) new_config_set = [] config_set.each do |line| + if line =~ /[a-z0-9]*\s*unsupported[a-z0-9 ]*/ + return + end param_count = line.scan(/%/).length new_config_set << sprintf(line, *args.first(param_count)) args = args[param_count..-1] diff --git a/lib/cisco_node_utils/vlan.rb b/lib/cisco_node_utils/vlan.rb index 358e3ecc..d41922a7 100644 --- a/lib/cisco_node_utils/vlan.rb +++ b/lib/cisco_node_utils/vlan.rb @@ -60,6 +60,65 @@ def cli_error_check(result) fail result[2]['body'] unless result[2]['body'].empty? end + def fabricpath_feature + fabricpath = config_get('fabricpath', 'feature') + fail 'fabricpath_feature not found' if fabricpath.nil? + return :disabled if fabricpath.nil? + fabricpath.shift.to_sym + end + + def fabricpath_feature_set(fabricpath_set) + curr = fabricpath_feature + return if curr == fabricpath_set + + case fabricpath_set + when :enabled + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + config_set('fabricpath', 'feature', '') + when :disabled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + return + when :installed + config_set('fabricpath', 'feature_install', '') if curr == :uninstalled + when :uninstalled + config_set('fabricpath', 'feature', 'no') if curr == :enabled + config_set('fabricpath', 'feature_install', 'no') + end + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def mode + result = config_get('vlan', 'mode', @vlan_id) + return default_mode if result.nil? + case result.first + when /fabricpath/i + return 'fabricpath' + when /ce/i + return 'ce' + end + end + + def mode=(str) + str = str.to_s + if str.empty? + result = config_set('vlan', 'mode', @vlan_id, 'no', '') + else + if ('fabricpath' == str) + fabricpath_feature_set(:enabled) unless + (:enabled == fabricpath_feature) + end + result = config_set('vlan', 'mode', @vlan_id, '', str) + end + cli_error_check(result) + rescue CliError => e + raise "[vlan #{@vlan_id}] '#{e.command}' : #{e.clierror}" + end + + def default_mode + config_get_default('vlan', 'mode') + end + def vlan_name result = config_get('vlan', 'name', @vlan_id) return default_vlan_name if result.nil? diff --git a/tests/test_fabricpath_global.rb b/tests/test_fabricpath_global.rb new file mode 100644 index 00000000..3c0a6eaa --- /dev/null +++ b/tests/test_fabricpath_global.rb @@ -0,0 +1,220 @@ +# Copyright (c) 2014-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'ciscotest' +require_relative '../lib/cisco_node_utils/cisco_cmn_utils' +require_relative '../lib/cisco_node_utils/fabricpath_global' + +include Cisco + +#TestFabricpathGlobal - Minitest for Fabricpath Global node utils +class TestFabricpathGlobal < CiscoTestCase + def setup + # setup runs at the beginning of each test + super + no_feature_fabricpath + end + + def teardown + # teardown runs at the end of each test + no_feature_fabricpath + super + end + + def no_feature_fabricpath + # Turn the feature off for a clean test. + config('no feature-set fabricpath') + config('no install feature-set fabricpath') + end + + def assert(val, str) + return if val == 'unsupported' + super + end + + def refute(val, str) + return if val == 'unsupported' + super + end + + def assert_equal(expected, actual, str) + return if actual == 'unsupported' + super + end + + def refute_equal(expected, actual, str) + return if actual == 'unsupported' + super + end + + # TESTS + + def test_global_collection_empty + globals = FabricpathGlobal.globals + assert_equal(true, globals.empty?, + 'Globals should be empty for this test') + end + + def test_global_create + @global = FabricpathGlobal.new('default') + assert_equal(true, @global.name == 'default', + "Global name not set correctly #{@global.name}") + assert_equal(:enabled, @global.fabricpath_feature, + "Fabricpath feature should have been enabled") + refute(FabricpathGlobal.globals.empty?, + 'Globals should not be empty after create'); + end + + def test_global_destroy + # create and test again + test_global_create + @global.destroy + # now it should be wiped out + test_global_collection_empty + end + + def test_aggregate_multicast_routes + @global = FabricpathGlobal.new('default') + @global.aggregate_multicast_routes = true + assert(@global.aggregate_multicast_routes, + 'Aggregate multicast routes not set') + @global.aggregate_multicast_routes = false + refute(@global.aggregate_multicast_routes, + 'Aggregate multicast routes not reset') + end + + def test_allocate_delay + @global = FabricpathGlobal.new('default') + #test default value + assert_equal(10, @global.allocate_delay, + 'Default allocate_delay not set to 10') + @global.allocate_delay = 20 + assert_equal(20, @global.allocate_delay, + 'allocate_delay not set to 20') + end + + def test_graceful_merge + @global = FabricpathGlobal.new('default') + #test default value + assert(@global.graceful_merge, + 'Default graceful_merge not set to true') + @global.graceful_merge = false + refute(@global.graceful_merge, 'graceful merge not set to false') + end + + def test_linkup_delay_all + @global = FabricpathGlobal.new('default') + #test default value + assert_equal(10, @global.linkup_delay, + 'Default linkup_delay not set to 10') + @global.linkup_delay = 25 + assert_equal(25, @global.linkup_delay, + 'linkup_delay not set to 25') + refute(@global.linkup_delay_always, + 'linkup_delay_always should not be set by default') + @global.linkup_delay_always = true + assert(@global.linkup_delay_always, + 'linkup_delay_always is not getting set') + @global.linkup_delay_enable = true + @global.linkup_delay_enable = false + refute(@global.linkup_delay_enable, + 'linkup_delay is not getting disabled') + end + + def test_loadbalance_algorithm + @global = FabricpathGlobal.new('default') + #test default value + check_val = @global.my_munge('loadbalance_algorithm', 'symmetric') + assert_equal(check_val, @global.loadbalance_algorithm, + "default algo should be #{check_val} but is + #{@global.loadbalance_algorithm}") + @global.loadbalance_algorithm = 'source-destination' + assert_equal('source-destination', @global.loadbalance_algorithm, + 'algo not getting set to source-destination') + end + + def test_loadbalance_multicast + @global = FabricpathGlobal.new('default') + #test default values first + assert_equal(6, @global.loadbalance_multicast_rotate, + "default mcast rotate should be 6 + but is #{@global.loadbalance_multicast_rotate}") + assert(@global.loadbalance_multicast_has_vlan, + "default mcast include-vlan should be true + but is #{@global.loadbalance_multicast_has_vlan}") + @global.send(:loadbalance_multicast=, 3, false) + assert_equal(3, @global.loadbalance_multicast_rotate, + "mcast rotate should now be 3 + but is #{@global.loadbalance_multicast_rotate}") + refute(@global.loadbalance_multicast_has_vlan, + "mcast include-vlan should now be false + but is #{@global.loadbalance_multicast_has_vlan}") + end + + def test_loadbalance_unicast + @global = FabricpathGlobal.new('default') + #test default values first + assert_equal("mixed", @global.loadbalance_unicast_layer, + "default unicast layer should be mixed + but is #{@global.loadbalance_unicast_layer}") + assert_equal(6, @global.loadbalance_unicast_rotate, + "default mcast rotate should be 6 + but is #{@global.loadbalance_unicast_rotate}") + assert(@global.loadbalance_unicast_has_vlan, + "default unicast include-vlan should be true + but is #{@global.loadbalance_unicast_has_vlan}") + @global.send(:loadbalance_unicast=, "layer4", 3, false) + assert_equal("layer4", @global.loadbalance_unicast_layer, + "unicast layer should be layer4 + but is #{@global.loadbalance_unicast_layer}") + assert_equal(3, @global.loadbalance_unicast_rotate, + "unicast rotate should now be 3 + but is #{@global.loadbalance_unicast_rotate}") + refute(@global.loadbalance_unicast_has_vlan, + "unicast include-vlan should now be false + but is #{@global.loadbalance_unicast_has_vlan}") + end + + def test_mode + @global = FabricpathGlobal.new('default') + #test default value + assert_equal('normal', @global.mode, + "default mode should be normal but is #{@global.mode}") + @global.mode = 'transit' + assert_equal('transit', @global.mode, + 'mode not getting set to transit') + @global.mode = 'normal' + assert_equal('normal', @global.mode, + 'mode not getting set to transit') + end + + def test_switch_id + @global = FabricpathGlobal.new('default') + #auto_id = @global.switch_id + @global.switch_id = 100 + assert_equal(100, @global.switch_id, + 'switchid not getting set to 100') + end + + def test_transition_delay + @global = FabricpathGlobal.new('default') + #test default value + assert_equal(10, @global.transition_delay, + 'Default allocate_delay not set to 10') + @global.transition_delay = 20 + assert_equal(20, @global.transition_delay, + 'transition_delay not set to 20') + end + +end From 15f18a57a9fcc4ae7c4c3bc09883496849fddcfc Mon Sep 17 00:00:00 2001 From: Andi Shen Date: Thu, 29 Oct 2015 17:21:45 -0400 Subject: [PATCH 011/386] add advertise l2vpn evpn to bgp af --- lib/cisco_node_utils/bgp_af.rb | 16 +++++++++ .../command_reference_common_bgp.yaml | 5 +++ tests/test_bgp_af.rb | 36 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/lib/cisco_node_utils/bgp_af.rb b/lib/cisco_node_utils/bgp_af.rb index da6f90a0..bccced82 100644 --- a/lib/cisco_node_utils/bgp_af.rb +++ b/lib/cisco_node_utils/bgp_af.rb @@ -216,6 +216,22 @@ def default_additional_paths_selection config_get_default('bgp_af', 'additional_paths_selection') end + # advertise_l2vpn_evpn + def advertise_l2vpn_evpn + state = config_get('bgp_af', 'advertise_l2vpn_evpn', @get_args) + state ? true : false + end + + def advertise_l2vpn_evpn=(state) + state = (state ? '' : 'no') + set_args_keys(state: state) + config_set('bgp_af', 'advertise_l2vpn_evpn', @set_args) + end + + def default_advertise_l2vpn_evpn + config_get_default('bgp_af', 'advertise_l2vpn_evpn') + end + # # dampen_igp_metric (Getter/Setter/Default) # diff --git a/lib/cisco_node_utils/command_reference_common_bgp.yaml b/lib/cisco_node_utils/command_reference_common_bgp.yaml index fb4be63a..7fc32c08 100644 --- a/lib/cisco_node_utils/command_reference_common_bgp.yaml +++ b/lib/cisco_node_utils/command_reference_common_bgp.yaml @@ -201,6 +201,11 @@ bgp_af: config_set_append: ' additional-paths selection route-map ' default_value: "" + advertise_l2vpn_evpn: + config_get_token_append: '/^advertise l2vpn evpn$/' + config_set_append: ' advertise l2vpn evpn' + default_value: false + client_to_client: config_get_token_append: '/^client-to-client reflection$/' config_set_append: ' client-to-client reflection' diff --git a/tests/test_bgp_af.rb b/tests/test_bgp_af.rb index 858a0ff3..7fe8e42d 100644 --- a/tests/test_bgp_af.rb +++ b/tests/test_bgp_af.rb @@ -71,10 +71,14 @@ def test_collection_empty ## BGP Address Family ## Configure router bgp, some VRF's and address-family statements ## - verify that the final instance objects are correctly populated + ## Enable VXLAN and the EVPN ## def test_collection_not_empty @device.cmd('configure terminal') @device.cmd('feature bgp') + @device.cmd('feature vn-segment') + @device.cmd('feature nv overlay') + @device.cmd('nv overlay evpn') @device.cmd('router bgp 55') @device.cmd('address-family ipv4 unicast') @device.cmd('vrf red') @@ -352,6 +356,38 @@ def test_additional_paths_selection 'configured and should not be') end + ## + ## advertise_l2vpn_evpn + ## + def advertise_l2vpn_evpn(asn, vrf, af) + bgp_af = RouterBgpAF.new(asn, vrf, af) + + # + # Set and verify + # + val = false + bgp_af.advertise_l2vpn_evpn = val + assert_equal(bgp_af.advertise_l2vpn_evpn, val, + 'Error: maximum paths value not match to set value') + + val = true + bgp_af.advertise_l2vpn_evpn = val + assert_equal(bgp_af.advertise_l2vpn_evpn, val, + 'Error: maximum paths value not match to set value') + + val = bgp_af.default_advertise_l2vpn_evpn + bgp_af.advertise_l2vpn_evpn = val + assert_equal(bgp_af.advertise_l2vpn_evpn, val, + 'Error: maximum paths value not match to default value') + end + + def test_advertise_l2vpn_evpn + afs = [%w(ipv4 unicast), %w(ipv6 unicast)] + afs.each do |af| + advertise_l2vpn_evpn(55, 'red', af) + end + end + ## ## get_dampen_igp_metric ## From 3a20adc1cda937ef62f53bdf684a07774bcfe545 Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Thu, 29 Oct 2015 15:33:16 -0700 Subject: [PATCH 012/386] 1.fixed rubocop errors and 2.fixed n5k test failure --- lib/cisco_node_utils/fabricpath_global.rb | 50 ++++++------- lib/cisco_node_utils/fabricpath_topology.rb | 65 ++++++++-------- tests/test_fabricpath_global.rb | 83 ++++++++++----------- 3 files changed, 99 insertions(+), 99 deletions(-) diff --git a/lib/cisco_node_utils/fabricpath_global.rb b/lib/cisco_node_utils/fabricpath_global.rb index ec458f85..e7988c7d 100644 --- a/lib/cisco_node_utils/fabricpath_global.rb +++ b/lib/cisco_node_utils/fabricpath_global.rb @@ -26,7 +26,7 @@ class FabricpathGlobal < NodeUtil def initialize(name, instantiate=true) fail TypeError unless name.is_a?(String) - fail ArgumentError unless name == "default" + fail ArgumentError unless name == 'default' @name = name.downcase create if instantiate @@ -81,7 +81,8 @@ def my_munge(property, set_val) val = config_get_default('supported', property) case property when /loadbalance_algorithm/ - if (val == 'source-destination') && (set_val == 'symmetric' || set_val == 'xor') + if (val == 'source-destination') && + (set_val == 'symmetric' || set_val == 'xor') val else set_val @@ -266,12 +267,12 @@ def loadbalance_multicast=(rotate, has_vlan) config_set('fabricpath', 'loadbalance_multicast_reset') else rotate = my_munge('loadbalance_multicast_rotate', rotate) - has_vlan = (has_vlan == true) ? "include-vlan" : '' - config_set('fabricpath', 'loadbalance_multicast_set', + has_vlan = (has_vlan == true) ? 'include-vlan' : '' + config_set('fabricpath', 'loadbalance_multicast_set', rotate_amt: rotate, inc_vlan: has_vlan) end rescue Cisco::CliError => e - raise "[Setting loadbalance #{rotate} #{has_vlan}] '#{e.command}' + raise "[Setting loadbalance #{rotate} #{has_vlan}] '#{e.command}' : #{e.clierror}" end @@ -288,11 +289,11 @@ def loadbalance_unicast_layer return default_loadbalance_unicast_layer if unicast.nil? case unicast.first.strip when /L4/ - "layer4" + 'layer4' when /L3/ - "layer3" + 'layer3' when /Mixed/ - "mixed" + 'mixed' end end @@ -314,9 +315,9 @@ def split_loadbalance_unicast_layer=(val) else config_set('fabricpath', 'loadbalance_unicast_layer', '', val) end - rescue Cisco::CliError => e - raise "[Setting loadbalance layer #{val} ] '#{e.command}' - : #{e.clierror}" + rescue Cisco::CliError => e + raise "[Setting loadbalance layer #{val} ] '#{e.command}' + : #{e.clierror}" end def split_loadbalance_unicast_rotate=(val) @@ -325,9 +326,9 @@ def split_loadbalance_unicast_rotate=(val) else config_set('fabricpath', 'loadbalance_unicast_rotate', '', val) end - rescue Cisco::CliError => e - raise "[Setting loadbalance rotate #{val} ] '#{e.command}' - : #{e.clierror}" + rescue Cisco::CliError => e + raise "[Setting loadbalance rotate #{val} ] '#{e.command}' + : #{e.clierror}" end def split_loadbalance_unicast_has_vlan=(val) @@ -336,9 +337,9 @@ def split_loadbalance_unicast_has_vlan=(val) else config_set('fabricpath', 'loadbalance_unicast_has_vlan', '') end - rescue Cisco::CliError => e - raise "[Setting loadbalance has_vlan #{val} ] '#{e.command}' - : #{e.clierror}" + rescue Cisco::CliError => e + raise "[Setting loadbalance has_vlan #{val} ] '#{e.command}' + : #{e.clierror}" end def loadbalance_unicast=(layer, rotate, has_vlan) @@ -348,15 +349,15 @@ def loadbalance_unicast=(layer, rotate, has_vlan) config_set('fabricpath', 'loadbalance_unicast_reset') else rotate = my_munge('loadbalance_unicast_rotate', rotate) - has_vlan = (has_vlan == true) ? "include-vlan" : '' - config_set('fabricpath', 'loadbalance_unicast_set', + has_vlan = (has_vlan == true) ? 'include-vlan' : '' + config_set('fabricpath', 'loadbalance_unicast_set', pref: layer, rotate_amt: rotate, inc_vlan: has_vlan) end - else - split_loadbalance_unicast_layer = layer - split_loadbalance_unicast_rotate = rotate - split_loadbalance_unicast_has_vlan = has_vlan - end + else + self.split_loadbalance_unicast_layer = layer + self.split_loadbalance_unicast_rotate = rotate + self.split_loadbalance_unicast_has_vlan = has_vlan + end rescue Cisco::CliError => e raise "[Setting loadbalance #{layer} #{rotate} #{has_vlan}] '#{e.command}' : #{e.clierror}" @@ -426,6 +427,5 @@ def transition_delay=(val) def default_transition_delay config_get_default('fabricpath', 'transition_delay') end - end # class end # module diff --git a/lib/cisco_node_utils/fabricpath_topology.rb b/lib/cisco_node_utils/fabricpath_topology.rb index a86f599e..3910138c 100644 --- a/lib/cisco_node_utils/fabricpath_topology.rb +++ b/lib/cisco_node_utils/fabricpath_topology.rb @@ -1,4 +1,4 @@ -# Topology provider class +# Fabricpath Topology provider class # # Deepak Cherian, November 2015 # @@ -19,38 +19,38 @@ require File.join(File.dirname(__FILE__), 'node_util') module Cisco - - class Topo < NodeUtil + # node_utils class for fabricpath_topology + class FabricpathTopo < NodeUtil attr_reader :topo_id def initialize(topo_id, instantiate=true) @topo_id = topo_id.to_s - raise ArgumentError, - "Invalid value(non-numeric Topo id #{@topo_id})" unless @topo_id[/^\d+$/] + fail ArgumentError, "Invalid value(non-numeric + Topo id #{@topo_id})" unless @topo_id[/^\d+$/] create if instantiate end - def Topo.topos + def self.topos hash = {} - fabricpath = config_get("fabricpath", "feature") - return hash if (:enabled != fabricpath.first.to_sym) - topo_list = config_get("fp_topology", "all_topos") + fabricpath = config_get('fabricpath', 'feature') + return hash if (:enabled != fabricpath.first.to_sym) + topo_list = config_get('fp_topology', 'all_topos') return hash if topo_list.nil? topo_list.each do |id| - hash[id] = Topo.new(id, false) + hash[id] = FabricpathTopo.new(id, false) end hash end def create fabricpath_feature_set(:enabled) unless (:enabled == fabricpath_feature) - config_set("fp_topology", "create", @topo_id) unless @topo_id == "0" + config_set('fp_topology', 'create', @topo_id) unless @topo_id == '0' end def destroy - config_set("fp_topology", "destroy", @topo_id) + config_set('fp_topology', 'destroy', @topo_id) end def cli_error_check(result) @@ -58,29 +58,29 @@ def cli_error_check(result) # instead just displays a STDOUT error message; thus NXAPI does not detect # the failure and we must catch it by inspecting the "body" hash entry # returned by NXAPI. This vlan cli behavior is unlikely to change. - raise result[2]["body"] unless result[2]["body"].empty? + fail result[2]['body'] unless result[2]['body'].empty? end def state - result = config_get("fp_topology", "state", @topo_id) + result = config_get('fp_topology', 'state', @topo_id) return default_state if result.nil? case result.first when /Up/ - return "up" + return 'up' when /Down/ - return "default" + return 'default' end end def default_state - config_get_default("fp_topology", "state") + config_get_default('fp_topology', 'state') end def member_vlans - array = config_get("fp_topology", "member_vlans", @topo_id) + array = config_get('fp_topology', 'member_vlans', @topo_id) str = array.first - return [] if str == "--" - str.gsub!("-", "..") + return [] if str == '--' + str.gsub!('-', '..') if /,/.match(str) str.split(/\s*,\s*/) else @@ -90,12 +90,12 @@ def member_vlans def member_vlans=(str) debug "str is #{str} whose class is #{str.class}" - str = str.join(",") if !str.empty? + str = str.join(',') unless str.empty? if str.empty? - result = config_set("fp_topology", "member_vlans", @topo_id, "no", "") + result = config_set('fp_topology', 'member_vlans', @topo_id, 'no', '') else - str.gsub!("..", "-") - result = config_set("fp_topology", "member_vlans", @topo_id, "", str) + str.gsub!('..', '-') + result = config_set('fp_topology', 'member_vlans', @topo_id, '', str) end cli_error_check(result) rescue CliError => e @@ -103,23 +103,24 @@ def member_vlans=(str) end def topo_name - desc = config_get("fp_topology", "description", @topo_id) - return "" if desc.nil? + desc = config_get('fp_topology', 'description', @topo_id) + return '' if desc.nil? desc.shift.strip end def topo_name=(desc) - raise TypeError unless desc.is_a?(String) - desc.empty? ? - config_set("fp_topology", "description", @topo_id, "no", "") : - config_set("fp_topology", "description", @topo_id, "", desc) + fail TypeError unless desc.is_a?(String) + if desc.empty? + config_set('fp_topology', 'description', @topo_id, 'no', '') + else + config_set('fp_topology', 'description', @topo_id, '', desc) + end rescue Cisco::CliError => e raise "[#{@name}] '#{e.command}' : #{e.clierror}" end def default_topo_name - config_get_default("fp_topology", "description") + config_get_default('fp_topology', 'description') end - end # class end # module diff --git a/tests/test_fabricpath_global.rb b/tests/test_fabricpath_global.rb index 3c0a6eaa..119441c8 100644 --- a/tests/test_fabricpath_global.rb +++ b/tests/test_fabricpath_global.rb @@ -18,7 +18,7 @@ include Cisco -#TestFabricpathGlobal - Minitest for Fabricpath Global node utils +# TestFabricpathGlobal - Minitest for Fabricpath Global node utils class TestFabricpathGlobal < CiscoTestCase def setup # setup runs at the beginning of each test @@ -39,22 +39,22 @@ def no_feature_fabricpath end def assert(val, str) - return if val == 'unsupported' + return if val == 'unsupported' super end def refute(val, str) - return if val == 'unsupported' + return if val == 'unsupported' super end - + def assert_equal(expected, actual, str) - return if actual == 'unsupported' + return if actual == 'unsupported' super end def refute_equal(expected, actual, str) - return if actual == 'unsupported' + return if actual == 'unsupported' super end @@ -62,7 +62,7 @@ def refute_equal(expected, actual, str) def test_global_collection_empty globals = FabricpathGlobal.globals - assert_equal(true, globals.empty?, + assert_equal(true, globals.empty?, 'Globals should be empty for this test') end @@ -71,9 +71,9 @@ def test_global_create assert_equal(true, @global.name == 'default', "Global name not set correctly #{@global.name}") assert_equal(:enabled, @global.fabricpath_feature, - "Fabricpath feature should have been enabled") - refute(FabricpathGlobal.globals.empty?, - 'Globals should not be empty after create'); + 'Fabricpath feature should have been enabled') + refute(FabricpathGlobal.globals.empty?, + 'Globals should not be empty after create') end def test_global_destroy @@ -89,15 +89,15 @@ def test_aggregate_multicast_routes @global.aggregate_multicast_routes = true assert(@global.aggregate_multicast_routes, 'Aggregate multicast routes not set') - @global.aggregate_multicast_routes = false + @global.aggregate_multicast_routes = false refute(@global.aggregate_multicast_routes, 'Aggregate multicast routes not reset') end def test_allocate_delay @global = FabricpathGlobal.new('default') - #test default value - assert_equal(10, @global.allocate_delay, + # test default value + assert_equal(10, @global.allocate_delay, 'Default allocate_delay not set to 10') @global.allocate_delay = 20 assert_equal(20, @global.allocate_delay, @@ -106,8 +106,8 @@ def test_allocate_delay def test_graceful_merge @global = FabricpathGlobal.new('default') - #test default value - assert(@global.graceful_merge, + # test default value + assert(@global.graceful_merge, 'Default graceful_merge not set to true') @global.graceful_merge = false refute(@global.graceful_merge, 'graceful merge not set to false') @@ -115,29 +115,29 @@ def test_graceful_merge def test_linkup_delay_all @global = FabricpathGlobal.new('default') - #test default value - assert_equal(10, @global.linkup_delay, + # test default value + assert_equal(10, @global.linkup_delay, 'Default linkup_delay not set to 10') @global.linkup_delay = 25 assert_equal(25, @global.linkup_delay, 'linkup_delay not set to 25') - refute(@global.linkup_delay_always, + refute(@global.linkup_delay_always, 'linkup_delay_always should not be set by default') @global.linkup_delay_always = true - assert(@global.linkup_delay_always, + assert(@global.linkup_delay_always, 'linkup_delay_always is not getting set') @global.linkup_delay_enable = true @global.linkup_delay_enable = false - refute(@global.linkup_delay_enable, + refute(@global.linkup_delay_enable, 'linkup_delay is not getting disabled') end def test_loadbalance_algorithm @global = FabricpathGlobal.new('default') - #test default value + # test default value check_val = @global.my_munge('loadbalance_algorithm', 'symmetric') assert_equal(check_val, @global.loadbalance_algorithm, - "default algo should be #{check_val} but is + "default algo should be #{check_val} but is #{@global.loadbalance_algorithm}") @global.loadbalance_algorithm = 'source-destination' assert_equal('source-destination', @global.loadbalance_algorithm, @@ -146,49 +146,49 @@ def test_loadbalance_algorithm def test_loadbalance_multicast @global = FabricpathGlobal.new('default') - #test default values first + # test default values first assert_equal(6, @global.loadbalance_multicast_rotate, - "default mcast rotate should be 6 + "default mcast rotate should be 6 but is #{@global.loadbalance_multicast_rotate}") assert(@global.loadbalance_multicast_has_vlan, - "default mcast include-vlan should be true + "default mcast include-vlan should be true but is #{@global.loadbalance_multicast_has_vlan}") @global.send(:loadbalance_multicast=, 3, false) assert_equal(3, @global.loadbalance_multicast_rotate, - "mcast rotate should now be 3 + "mcast rotate should now be 3 but is #{@global.loadbalance_multicast_rotate}") refute(@global.loadbalance_multicast_has_vlan, - "mcast include-vlan should now be false + "mcast include-vlan should now be false but is #{@global.loadbalance_multicast_has_vlan}") end def test_loadbalance_unicast @global = FabricpathGlobal.new('default') - #test default values first - assert_equal("mixed", @global.loadbalance_unicast_layer, - "default unicast layer should be mixed + # test default values first + assert_equal('mixed', @global.loadbalance_unicast_layer, + "default unicast layer should be mixed but is #{@global.loadbalance_unicast_layer}") assert_equal(6, @global.loadbalance_unicast_rotate, - "default mcast rotate should be 6 + "default mcast rotate should be 6 but is #{@global.loadbalance_unicast_rotate}") assert(@global.loadbalance_unicast_has_vlan, - "default unicast include-vlan should be true + "default unicast include-vlan should be true but is #{@global.loadbalance_unicast_has_vlan}") - @global.send(:loadbalance_unicast=, "layer4", 3, false) - assert_equal("layer4", @global.loadbalance_unicast_layer, - "unicast layer should be layer4 + @global.send(:loadbalance_unicast=, 'layer4', 3, false) + assert_equal('layer4', @global.loadbalance_unicast_layer, + "unicast layer should be layer4 but is #{@global.loadbalance_unicast_layer}") assert_equal(3, @global.loadbalance_unicast_rotate, - "unicast rotate should now be 3 + "unicast rotate should now be 3 but is #{@global.loadbalance_unicast_rotate}") refute(@global.loadbalance_unicast_has_vlan, - "unicast include-vlan should now be false + "unicast include-vlan should now be false but is #{@global.loadbalance_unicast_has_vlan}") end def test_mode @global = FabricpathGlobal.new('default') - #test default value + # test default value assert_equal('normal', @global.mode, "default mode should be normal but is #{@global.mode}") @global.mode = 'transit' @@ -201,7 +201,7 @@ def test_mode def test_switch_id @global = FabricpathGlobal.new('default') - #auto_id = @global.switch_id + # auto_id = @global.switch_id @global.switch_id = 100 assert_equal(100, @global.switch_id, 'switchid not getting set to 100') @@ -209,12 +209,11 @@ def test_switch_id def test_transition_delay @global = FabricpathGlobal.new('default') - #test default value - assert_equal(10, @global.transition_delay, + # test default value + assert_equal(10, @global.transition_delay, 'Default allocate_delay not set to 10') @global.transition_delay = 20 assert_equal(20, @global.transition_delay, 'transition_delay not set to 20') end - end From aa0140dde4c4351187cc3363d645b9d3f5963ed4 Mon Sep 17 00:00:00 2001 From: Jonathan Tripathy Date: Mon, 26 Oct 2015 13:44:34 +0000 Subject: [PATCH 013/386] Added radius_server_group --- CHANGELOG.md | 1 + .../command_reference_common.yaml | 13 ++ lib/cisco_node_utils/radius_server_group.rb | 107 ++++++++++++++++ tests/test_radius_server_group.rb | 119 ++++++++++++++++++ 4 files changed, 240 insertions(+) create mode 100644 lib/cisco_node_utils/radius_server_group.rb create mode 100644 tests/test_radius_server_group.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index ef9e0ab7..757bf1e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Changelog * Added `bin/check_metric_limits.rb` helper script in support of refactoring. * Added best practices development guide. * Added support for radius_global (@jonnytpuppet) +* Added support for radius_server_group (@jonnytpuppet) ### Fixed diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index 34af1ce0..974127ef 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -633,6 +633,19 @@ radius_server: config_set: ' radius-server host key ' default_value: null +radius_server_group: + group: + config_get: "show running-config radius all" + config_get_token: '/^aaa group server radius (\S+)/' + config_set: ' aaa group server radius ' + default_value: [] + + servers: + config_get: "show running-config radius all" + config_get_token: ['/^aaa group server radius %s $/i', '/server ((?:[0-9]{1,3}\.){3}[0-9]{1,3})/'] + config_set: ['aaa group server radius ', ' server '] + default_value: [] + radius_global: timeout: config_get: "show running-config radius all" diff --git a/lib/cisco_node_utils/radius_server_group.rb b/lib/cisco_node_utils/radius_server_group.rb new file mode 100644 index 00000000..bee78e55 --- /dev/null +++ b/lib/cisco_node_utils/radius_server_group.rb @@ -0,0 +1,107 @@ +# Radius Server Group provider class + +# Jonathan Tripathy et al., October 2015 + +# Copyright (c) 2014-2015 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. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'node_util' + +module Cisco + # RadiusServerGroup - node utility class for + # Raidus Server configuration management + class RadiusServerGroup < NodeUtil + attr_reader :name + + def initialize(name, instantiate=true) + unless name.is_a?(String) + fail ArgumentError, 'Invalid value (Name is not a String)' + end + + @name = name + + create if instantiate + end + + def self.radius_server_groups + hash = {} + group_list = config_get('radius_server_group', 'group') + return hash if group_list.nil? + + group_list.each do |id| + hash[id] = RadiusServerGroup.new(id, false) + end + + hash + end + + def create + config_set('radius_server_group', + 'group', + state: '', + name: @name) + end + + def destroy + config_set('radius_server_group', + 'group', + state: 'no', + name: @name) + end + + def ==(other) + name == other.name + end + + def default_servers + config_get_default('radius_server_group', 'servers') + end + + def servers + val = config_get('radius_server_group', 'servers', @name) + val = default_servers if val.nil? + val + end + + def servers=(val) + fail ArgumentError, 'Servers must be an array of valid IP addresses' \ + unless val.is_a?(Array) + + current = servers + + # Remove IPs that are no longer required + current.each do |old_ip| + next if val.include?(old_ip) + config_set('radius_server_group', + 'servers', + group: @name, + state: 'no', + ip: old_ip) + end + + # Add new IPs that aren't already on the device + val.each do |new_ip| + fail ArgumentError, 'Servers must be an array of valid IP addresses' \ + unless new_ip[/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/] + + next unless current.nil? || !current.include?(new_ip) + config_set('radius_server_group', + 'servers', + group: @name, + state: '', + ip: new_ip) + end + end + end # class +end # module diff --git a/tests/test_radius_server_group.rb b/tests/test_radius_server_group.rb new file mode 100644 index 00000000..155b6722 --- /dev/null +++ b/tests/test_radius_server_group.rb @@ -0,0 +1,119 @@ +# +# Minitest for RadiusServerGroup class +# +# Copyright (c) 2014-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.expand_path('../ciscotest', __FILE__) +require File.expand_path('../../lib/cisco_node_utils/radius_server_group', \ + __FILE__) + +# TestRadiusServerGroup - Minitest for RadiusServerGroup node utility. +class TestRadiusServerGroup < CiscoTestCase + def setup + # setup runs at the beginning of each test + super + config('radius-server host 8.8.8.8', + 'radius-server host 9.9.9.9', + 'radius-server host 10.10.10.10', + 'radius-server host 11.11.11.11', + 'radius-server host 12.12.12.12', + 'radius-server host 13.13.13.13') + no_radiusserver + end + + def teardown + # teardown runs at the end of each test + config('no radius-server host 8.8.8.8', + 'no radius-server host 9.9.9.9', + 'no radius-server host 10.10.10.10', + 'no radius-server host 11.11.11.11', + 'no radius-server host 12.12.12.12', + 'no radius-server host 13.13.13.13') + no_radiusserver + super + end + + def no_radiusserver + # Turn the feature off for a clean test. + config('no aaa group server radius red', + 'no aaa group server radius blue') + end + + # TESTS + + def test_create_destroy_single + id = 'red' + refute_includes(Cisco::RadiusServerGroup.radius_server_groups, id) + + group = Cisco::RadiusServerGroup.new(id, true) + assert_includes(Cisco::RadiusServerGroup.radius_server_groups, id) + assert_equal(Cisco::RadiusServerGroup.radius_server_groups[id], group) + + group.servers = ['8.8.8.8', '9.9.9.9'] + assert_equal(['8.8.8.8', '9.9.9.9'], + Cisco::RadiusServerGroup.radius_server_groups[id].servers) + + group.servers = ['8.8.8.8', '10.10.10.10'] + assert_equal(['8.8.8.8', '10.10.10.10'], + Cisco::RadiusServerGroup.radius_server_groups[id].servers) + + group.servers = [] + assert_equal([], + Cisco::RadiusServerGroup.radius_server_groups[id].servers) + + group.destroy + refute_includes(Cisco::RadiusServerGroup.radius_server_groups, id) + end + + def test_create_destroy_multiple + id = 'red' + id2 = 'blue' + refute_includes(Cisco::RadiusServerGroup.radius_server_groups, id) + refute_includes(Cisco::RadiusServerGroup.radius_server_groups, id2) + + group = Cisco::RadiusServerGroup.new(id, true) + group2 = Cisco::RadiusServerGroup.new(id2, true) + assert_includes(Cisco::RadiusServerGroup.radius_server_groups, id) + assert_equal(Cisco::RadiusServerGroup.radius_server_groups[id], group) + assert_includes(Cisco::RadiusServerGroup.radius_server_groups, id2) + assert_equal(Cisco::RadiusServerGroup.radius_server_groups[id2], group2) + + group.servers = ['8.8.8.8', '9.9.9.9'] + assert_equal(['8.8.8.8', '9.9.9.9'], + Cisco::RadiusServerGroup.radius_server_groups[id].servers) + group2.servers = ['11.11.11.11', '12.12.12.12'] + assert_equal(['11.11.11.11', '12.12.12.12'], + Cisco::RadiusServerGroup.radius_server_groups[id2].servers) + + group.servers = ['8.8.8.8', '10.10.10.10'] + assert_equal(['8.8.8.8', '10.10.10.10'], + Cisco::RadiusServerGroup.radius_server_groups[id].servers) + group2.servers = ['11.11.11.11', '13.13.13.13'] + assert_equal(['11.11.11.11', '13.13.13.13'], + Cisco::RadiusServerGroup.radius_server_groups[id2].servers) + + group.servers = [] + assert_equal([], + Cisco::RadiusServerGroup.radius_server_groups[id].servers) + group2.servers = [] + assert_equal([], + Cisco::RadiusServerGroup.radius_server_groups[id2].servers) + + group.destroy + group2.destroy + refute_includes(Cisco::RadiusServerGroup.radius_server_groups, id) + refute_includes(Cisco::RadiusServerGroup.radius_server_groups, id2) + end +end From cc387dd5fb7e16755edb66aa9cb107145a77be2e Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Fri, 30 Oct 2015 12:25:59 -0700 Subject: [PATCH 014/386] fixed rubocop errors on node.rb --- lib/cisco_node_utils/node.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/cisco_node_utils/node.rb b/lib/cisco_node_utils/node.rb index 7c8ac40a..4fe6eb93 100644 --- a/lib/cisco_node_utils/node.rb +++ b/lib/cisco_node_utils/node.rb @@ -70,6 +70,7 @@ class Node # @example config_get("show_version", "system_image") # @example config_get("ospf", "router_id", # {:name => "green", :vrf => "one"}) + # rubocop:disable Metrics/AbcSize def config_get(feature, name, *args) fail 'lazy_connect specified but did not request connect' unless @cmd_ref ref = @cmd_ref.lookup(feature, name) @@ -88,9 +89,7 @@ def config_get(feature, name, *args) text = build_config_get(feature, ref, :ascii) return Cisco.find_ascii(text, token) else - if token == 'unsupported' - return nil - end + return nil if token == 'unsupported' hash = build_config_get(feature, ref, :structured) return hash[token] end @@ -162,16 +161,12 @@ def config_set(feature, name, *args) end end if config_set.is_a?(String) - if config_set =~ /[a-z0-9]*\s*unsupported[a-z0-9 ]*/ - return - end + return if config_set =~ /[a-z0-9]*\s*unsupported[a-z0-9 ]*/ config(sprintf(config_set, *args)) elsif config_set.is_a?(Array) new_config_set = [] + return if config_set[0] =~ /[a-z0-9]*\s*unsupported[a-z0-9 ]*/ config_set.each do |line| - if line =~ /[a-z0-9]*\s*unsupported[a-z0-9 ]*/ - return - end param_count = line.scan(/%/).length new_config_set << sprintf(line, *args.first(param_count)) args = args[param_count..-1] From 29c26dfb7eeec010c53713ae070e7dcd19232baa Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Fri, 30 Oct 2015 12:37:37 -0700 Subject: [PATCH 015/386] changed lib/.rubocop.yml with AbcSize 48 and removed rubocop disable from node.rb --- lib/.rubocop.yml | 2 +- lib/cisco_node_utils/node.rb | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/.rubocop.yml b/lib/.rubocop.yml index 3db35fb8..b2b0ea8b 100644 --- a/lib/.rubocop.yml +++ b/lib/.rubocop.yml @@ -3,7 +3,7 @@ inherit_from: ../.rubocop.yml # Baseline code complexity metrics for the lib/ subdirectory: Metrics/AbcSize: - Max: 47 + Max: 48 Metrics/CyclomaticComplexity: Max: 17 diff --git a/lib/cisco_node_utils/node.rb b/lib/cisco_node_utils/node.rb index 4fe6eb93..e6c9d19c 100644 --- a/lib/cisco_node_utils/node.rb +++ b/lib/cisco_node_utils/node.rb @@ -70,7 +70,6 @@ class Node # @example config_get("show_version", "system_image") # @example config_get("ospf", "router_id", # {:name => "green", :vrf => "one"}) - # rubocop:disable Metrics/AbcSize def config_get(feature, name, *args) fail 'lazy_connect specified but did not request connect' unless @cmd_ref ref = @cmd_ref.lookup(feature, name) From 179ba3c54b2a1e521edcae5f4c036dbee3f5a9d8 Mon Sep 17 00:00:00 2001 From: Alok Aggarwal Date: Fri, 30 Oct 2015 16:20:32 -0700 Subject: [PATCH 016/386] Implementation of node-utils for vxlan_global type. Includes yaml file changes and minitest --- .../command_reference_common.yaml | 55 ++++++ lib/cisco_node_utils/vxlan_global.rb | 158 ++++++++++++++++++ tests/test_vxlan_global.rb | 104 ++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 lib/cisco_node_utils/vxlan_global.rb create mode 100755 tests/test_vxlan_global.rb diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index 84f9bc45..66055422 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -1054,3 +1054,58 @@ yum: remove: config_set: "install deactivate %s" +vxlan_global: + feature: + config_get: "show running | i ^feature" + config_get_token: '/^feature fabric forwarding$/' + config_set: " feature fabric forwarding" + + dup_host_ip_addr_detection: + config_get: 'show running fabric forwarding all' + config_get_token: '/^fabric forwarding dup-host-ip-addr-detection (\d+) (\d+)$/' + config_set: " fabric forwarding dup-host-ip-addr-detection " + + dup_host_ip_addr_detection_host_moves: + default_value: 5 + + dup_host_ip_addr_detection_timeout: + default_value: 180 + + anycast_gateway_mac: + config_get: 'show running fabric forwarding all' + config_get_token: '/^fabric forwarding anycast-gateway-mac (\S+)$/' + config_set: "%s fabric forwarding anycast-gateway-mac %s" + + dup_host_mac_detection: + config_get: 'show running | i l2rib' + config_get_token: '/^l2rib dup-host-mac-detection (\d+) (\d+)$/' + config_set: "l2rib dup-host-mac-detection " + + dup_host_mac_detection_default: + config_set: "l2rib dup-host-mac-detection default" + + dup_host_mac_detection_host_moves: + default_value: 5 + + dup_host_mac_detection_timeout: + default_value: 180 + + + + + + + + + + + + + + + + + + + + diff --git a/lib/cisco_node_utils/vxlan_global.rb b/lib/cisco_node_utils/vxlan_global.rb new file mode 100644 index 00000000..f75e32ae --- /dev/null +++ b/lib/cisco_node_utils/vxlan_global.rb @@ -0,0 +1,158 @@ +# VXLAN global provider class +# Provides configuration of anycast gateways and duplicate host IP and +# mac detection +# +# Alok Aggarwal, October 2015 +# +# Copyright (c) 2014-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.join(File.dirname(__FILE__), 'node_util') + +module Cisco + # node_utils class for vxlan_global + class VxlanGlobal < NodeUtil + def feature_enable + config_set('vxlan_global', 'feature', state: '') + end + + def feature_disable + config_set('vxlan_global', 'feature', state: 'no') + end + + # Check current state of the configuration + def self.feature_enabled + feat = config_get('vxlan_global', 'feature') + return !(feat.nil? || feat.empty?) + rescue Cisco::CliError => e + # This cmd will syntax reject if feature is not + # enabled. Just catch the reject and return false. + return false if e.clierror =~ /Syntax error/ + raise + end + + # ---------- + # PROPERTIES + # ---------- + + # dup-host-ip-addr-detection + def dup_host_ip_addr_detection + get_args = {} + match = config_get('vxlan_global', 'dup_host_ip_addr_detection', get_args) + if match.nil? || match.first.nil? + default_dup_host_ip_addr_detection + else + match.first.collect(&:to_i) + end + end + + def dup_host_ip_addr_detection_host_moves + host_moves, _timeout = dup_host_ip_addr_detection + return default_dup_host_ip_addr_detection_host_moves if host_moves.nil? + host_moves + end + + def dup_host_ip_addr_detection_timeout + _host_moves, timeout = dup_host_ip_addr_detection + return default_dup_host_ip_addr_detection_timeout if timeout.nil? + timeout + end + + def dup_host_ip_addr_detection_set(state, host_moves, timeout) + set_args = {} + set_args[:state] = state + set_args[:host_moves] = host_moves + set_args[:timeout] = timeout + + config_set('vxlan_global', 'dup_host_ip_addr_detection', set_args) + end + + def default_dup_host_ip_addr_detection + [default_dup_host_ip_addr_detection_host_moves, + default_dup_host_ip_addr_detection_timeout] + end + + def default_dup_host_ip_addr_detection_host_moves + config_get_default('vxlan_global', + 'dup_host_ip_addr_detection_host_moves') + end + + def default_dup_host_ip_addr_detection_timeout + config_get_default('vxlan_global', 'dup_host_ip_addr_detection_timeout') + end + + # dup-host-mac-detection + def dup_host_mac_detection + get_args = {} + match = config_get('vxlan_global', 'dup_host_mac_detection', get_args) + if match.nil? || match.first.nil? + default_dup_host_mac_detection + else + match.first.collect(&:to_i) + end + end + + def dup_host_mac_detection_host_moves + host_moves, _timeout = dup_host_mac_detection + return default_dup_host_mac_detection_host_moves if host_moves.nil? + host_moves + end + + def dup_host_mac_detection_timeout + _host_moves, timeout = dup_host_mac_detection + return default_dup_host_mac_detection_timeout if timeout.nil? + timeout + end + + def dup_host_mac_detection_set(host_moves, timeout) + set_args = {} + set_args[:host_moves] = host_moves + set_args[:timeout] = timeout + + config_set('vxlan_global', 'dup_host_mac_detection', set_args) + end + + def dup_host_mac_detection_default + config_set('vxlan_global', 'dup_host_mac_detection_default') + end + + def default_dup_host_mac_detection + [default_dup_host_mac_detection_host_moves, + default_dup_host_mac_detection_timeout] + end + + def default_dup_host_mac_detection_host_moves + config_get_default('vxlan_global', 'dup_host_mac_detection_host_moves') + end + + def default_dup_host_mac_detection_timeout + config_get_default('vxlan_global', 'dup_host_mac_detection_timeout') + end + + # anycast-gateway-mac + def anycast_gateway_mac + mac_addr = config_get('vxlan_global', 'anycast_gateway_mac') + mac_addr.nil? ? ' ' : mac_addr.first + end + + def anycast_gateway_mac_set(state, mac_addr) + fail TypeError unless mac_addr.is_a?(String) + if state == 'no' + config_set('vxlan_global', 'anycast_gateway_mac', 'no', ' ') + else + config_set('vxlan_global', 'anycast_gateway_mac', ' ', mac_addr) + end + end + end # class +end # module diff --git a/tests/test_vxlan_global.rb b/tests/test_vxlan_global.rb new file mode 100755 index 00000000..7d45441e --- /dev/null +++ b/tests/test_vxlan_global.rb @@ -0,0 +1,104 @@ +# Copyright (c) 2013-2015 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require File.expand_path('../ciscotest', __FILE__) +require File.expand_path('../../lib/cisco_node_utils/vxlan_global', __FILE__) + +include Cisco + +# TestVxlanGlobal - Minitest for VxlanGlobal node utility +class TestVxlanGlobal < CiscoTestCase + def setup + super + no_feature_vxlan_global + end + + def teardown + no_feature_vxlan_global + super + end + + def no_feature_vxlan_global + config('no feature fabric forwarding') + end + + def test_feature_on_off + feat = VxlanGlobal.new + feat.feature_enable + assert(VxlanGlobal.feature_enabled) + + feat.feature_disable + refute(VxlanGlobal.feature_enabled) + end + + def test_dup_host_ip_addr_detection_set + vxlan_global = VxlanGlobal.new + val = [200, 20] + vxlan_global.feature_enable + vxlan_global.dup_host_ip_addr_detection_set(' ', val[0], val[1]) + assert_equal(val, vxlan_global.dup_host_ip_addr_detection, + 'Error: fabric forwarding dup_host_ip_addr_detection ' \ + 'get values mismatch') + end + + def test_dup_host_ip_addr_detection_clear + vxlan_global = VxlanGlobal.new + val = [200, 20] + # After the config is cleared, the get method should return + # the default values + default = [5, 180] + vxlan_global.feature_enable + vxlan_global.dup_host_ip_addr_detection_set('no', val[0], val[1]) + assert_equal(default, vxlan_global.dup_host_ip_addr_detection, + 'Error: fabric forwarding dup_host_ip_addr_detection ' \ + 'get values mismatch') + end + + def test_dup_host_mac_detection_set + vxlan_global = VxlanGlobal.new + val = [200, 20] + vxlan_global.dup_host_mac_detection_set(val[0], val[1]) + assert_equal(val, vxlan_global.dup_host_mac_detection, + 'Error: l2rib dup_host_mac_detection ' \ + 'get values mismatch') + end + + def test_dup_host_mac_detection_default + vxlan_global = VxlanGlobal.new + # After the config is cleared, the get method should return + # the default values + default = [5, 180] + vxlan_global.dup_host_mac_detection_default + assert_equal(default, vxlan_global.dup_host_mac_detection, + 'Error: l2rib dup_host_mac_detection ' \ + 'get values mismatch') + end + + def test_anycast_gateway_mac_set + vxlan_global = VxlanGlobal.new + mac_addr = '1223.3445.5668' + vxlan_global.feature_enable + vxlan_global.anycast_gateway_mac_set(' ', mac_addr) + assert_equal(mac_addr, vxlan_global.anycast_gateway_mac, + 'Error: anycast-gateway-mac mismatch') + end + + def test_anycast_gateway_mac_clear + vxlan_global = VxlanGlobal.new + vxlan_global.feature_enable + vxlan_global.anycast_gateway_mac_set('no', '') + assert_equal(' ', vxlan_global.anycast_gateway_mac, + 'Error: anycast-gateway-mac mismatch') + end +end From 49091b0509b54cb8ee9eb82b88c23428c4aff449 Mon Sep 17 00:00:00 2001 From: Andi Shen Date: Mon, 2 Nov 2015 02:29:53 -0500 Subject: [PATCH 017/386] add minitest for l2vpn address family --- tests/test_bgp_neighbor_af.rb | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tests/test_bgp_neighbor_af.rb b/tests/test_bgp_neighbor_af.rb index 881037b4..892b9b09 100644 --- a/tests/test_bgp_neighbor_af.rb +++ b/tests/test_bgp_neighbor_af.rb @@ -31,10 +31,12 @@ def setup super if @@reset_feat config('no feature bgp', 'feature bgp') + config('no nv overlay evpn', 'nv overlay evpn') @@reset_feat = false # rubocop:disable Style/ClassVars else # Just ensure that feature is enabled config('feature bgp') + config('nv overlay evpn') end end @@ -66,9 +68,9 @@ def clean_af(af_args, ebgp=true) # 3 => [1, 'default', '10:1::1', %w(ipv6 multicast)], # 4 => [1, 'default', '10:1::1', %w(ipv6 unicast)], # 5 => [1, 'default', '1.1.1.1', %w(ipv4 multicast)], - 6 => [1, 'default', '1.1.1.1', %w(ipv4 unicast)], + 6 => [1, 'default', '1.1.1.1', %w(ipv4 unicast)], # 7 => [1, 'default', '1.1.1.1', %w(ipv6 multicast)], - 8 => [1, 'default', '1.1.1.1', %w(ipv6 unicast)], + 8 => [1, 'default', '1.1.1.1', %w(ipv6 unicast)], # 9 => [1, 'aa', '2.2.2.2', %w(ipv4 multicast)], # 10 => [1, 'aa', '2.2.2.2', %w(ipv4 unicast)], # 11 => [1, 'bb', '2.2.2.2', %w(ipv6 multicast)], @@ -77,6 +79,7 @@ def clean_af(af_args, ebgp=true) # 14 => [1, 'cc', '10:1::2', %w(ipv4 unicast)], # 15 => [1, 'cc', '10:1::2', %w(ipv6 multicast)], # 16 => [1, 'cc', '10:1::2', %w(ipv6 unicast)], + 17 => [1, 'default', '1.1.1.1', %w(l2vpn evpn)], } # --------------------------------- @@ -155,6 +158,8 @@ def props_bool(af, dbg) :suppress_inactive, ] + props = [:disable_peer_as_check] if dbg.include?('l2vpn/evpn') + # Call setter to false, then validate with getter props.each { |k| af.send("#{k}=", false) } props.each do |k| @@ -198,6 +203,8 @@ def props_string(af, dbg) unsuppress_map: 'unsupp-map-name', } + props.delete(:unsuppress_map) if dbg.include?('l2vpn/evpn') + props.each do |k, v| # Call setter. af.send("#{k}=", v) @@ -226,12 +233,14 @@ def test_tri_states @@matrix.values.each do |af_args| af, dbg = clean_af(af_args) - %w(additional_paths_receive additional_paths_send).each do |k| - [:enable, :disable, :inherit, 'enable', 'disable', 'inherit', - af.send("default_#{k}") - ].each do |val| - af.send("#{k}=", val) - assert_equal(val.to_sym, af.send(k), "#{dbg} Error: #{k}") + unless dbg.include?('l2vpn/evpn') + %w(additional_paths_receive additional_paths_send).each do |k| + [:enable, :disable, :inherit, 'enable', 'disable', 'inherit', + af.send("default_#{k}") + ].each do |val| + af.send("#{k}=", val) + assert_equal(val.to_sym, af.send(k), "#{dbg} Error: #{k}") + end end end @@ -250,6 +259,7 @@ def test_tri_states def test_advertise_map @@matrix.values.each do |af_args| af, dbg = clean_af(af_args) + next if dbg.include?('l2vpn/evpn') advertise_map(af, dbg) end end @@ -319,6 +329,7 @@ def allowas_in(af, dbg) def test_default_originate @@matrix.values.each do |af_args| af, dbg = clean_af(af_args) + next if dbg.include?('l2vpn/evpn') default_originate(af, dbg) end end From 7973217d3cf8dbb4dc41a01601803b9c36f1944c Mon Sep 17 00:00:00 2001 From: Helen Campbell Date: Thu, 29 Oct 2015 14:52:10 +0000 Subject: [PATCH 018/386] added speed and duplex to interface with test --- .../command_reference_common.yaml | 12 +++++ lib/cisco_node_utils/interface.rb | 38 +++++++++++++++ tests/test_interface.rb | 46 +++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index 938dfe17..a1dae697 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -238,6 +238,18 @@ interface: config_set: ["interface %s", "%s mtu %s"] default_value: 1500 + speed: + config_get: "show running interface all" + config_get_token: ['/^interface %s$/i', '/^speed (.*)$/'] + config_set: ["interface %s", "speed %s"] + default_value: "auto" + + duplex: + config_get: "show running interface all" + config_get_token: ['/^interface %s$/i', '/^duplex (.*)$/'] + config_set: ["interface %s", "duplex %s"] + default_value: "auto" + negotiate_auto_ethernet: config_get: "show running interface all" config_get_token: [ diff --git a/lib/cisco_node_utils/interface.rb b/lib/cisco_node_utils/interface.rb index 140933b1..455c2050 100644 --- a/lib/cisco_node_utils/interface.rb +++ b/lib/cisco_node_utils/interface.rb @@ -260,6 +260,44 @@ def default_mtu config_get_default('interface', 'mtu') end + def speed + speed = config_get('interface', 'speed', @name) + return default_speed if speed.nil? + speed.shift.strip + end + + def speed=(val) + if node.product_id =~ /C31\d\d/ + fail 'Changing interface speed is not permitted on this platform' + end + config_set('interface', 'speed', @name, val) + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def default_speed + config_get_default('interface', 'speed') + end + + def duplex + duplex = config_get('interface', 'duplex', @name) + return default_duplex if duplex.nil? + duplex.shift.strip + end + + def duplex=(val) + if node.product_id =~ /C31\d\d/ + fail 'Changing interface duplex is not permitted on this platform' + end + config_set('interface', 'duplex', @name, val) + rescue Cisco::CliError => e + raise "[#{@name}] '#{e.command}' : #{e.clierror}" + end + + def default_duplex + config_get_default('interface', 'duplex') + end + def negotiate_auto_lookup_string case @name when /Ethernet/i diff --git a/tests/test_interface.rb b/tests/test_interface.rb index ea5058b3..92852c6d 100755 --- a/tests/test_interface.rb +++ b/tests/test_interface.rb @@ -467,6 +467,52 @@ def test_interface_mtu_valid interface_ethernet_default(interfaces_id[0]) end + def test_interface_speed_change + interface = Interface.new(interfaces[0]) + interface.speed = 100 + assert_equal('100', interface.speed) + interface.speed = 1000 + assert_equal('1000', interface.speed) + interface_ethernet_default(interfaces_id[0]) + end + + def test_interface_speed_invalid + interface = Interface.new(interfaces[0]) + assert_raises(RuntimeError) { interface.speed = 'hello' } + end + + def test_interface_speed_valid + interface = Interface.new(interfaces[0]) + interface.speed = 1000 + assert_equal('1000', interface.speed) + interface_ethernet_default(interfaces_id[0]) + end + + def test_interface_duplex_change + interface = Interface.new(interfaces[0]) + interface.speed = 1000 + interface.duplex = 'full' + assert_equal('full', interface.duplex) + interface.duplex = 'auto' + assert_equal('auto', interface.duplex) + interface_ethernet_default(interfaces_id[0]) + end + + def test_interface_duplex_invalid + interface = Interface.new(interfaces[0]) + interface.speed = 1000 + assert_raises(RuntimeError) { interface.duplex = 'hello' } + interface_ethernet_default(interfaces_id[0]) + end + + def test_interface_duplex_valid + interface = Interface.new(interfaces[0]) + interface.speed = 1000 + interface.duplex = 'full' + assert_equal('full', interface.duplex) + interface_ethernet_default(interfaces_id[0]) + end + def test_interface_shutdown_valid interface = Interface.new(interfaces[0]) interface.shutdown = true From 3ca8b6c2c8a59f175dd6ba8ff7447417c4c2f29d Mon Sep 17 00:00:00 2001 From: Alok Aggarwal Date: Mon, 2 Nov 2015 18:19:28 -0800 Subject: [PATCH 019/386] reworked on Chris's comments --- .../command_reference_common.yaml | 23 +------ lib/cisco_node_utils/vxlan_global.rb | 60 ++++++------------- tests/test_vxlan_global.rb | 44 +++++++------- 3 files changed, 41 insertions(+), 86 deletions(-) diff --git a/lib/cisco_node_utils/command_reference_common.yaml b/lib/cisco_node_utils/command_reference_common.yaml index 66055422..990a3795 100755 --- a/lib/cisco_node_utils/command_reference_common.yaml +++ b/lib/cisco_node_utils/command_reference_common.yaml @@ -1074,7 +1074,7 @@ vxlan_global: anycast_gateway_mac: config_get: 'show running fabric forwarding all' config_get_token: '/^fabric forwarding anycast-gateway-mac (\S+)$/' - config_set: "%s fabric forwarding anycast-gateway-mac %s" + config_set: " fabric forwarding anycast-gateway-mac " dup_host_mac_detection: config_get: 'show running | i l2rib' @@ -1086,26 +1086,5 @@ vxlan_global: dup_host_mac_detection_host_moves: default_value: 5 - dup_host_mac_detection_timeout: default_value: 180 - - - - - - - - - - - - - - - - - - - - diff --git a/lib/cisco_node_utils/vxlan_global.rb b/lib/cisco_node_utils/vxlan_global.rb index f75e32ae..65487ced 100644 --- a/lib/cisco_node_utils/vxlan_global.rb +++ b/lib/cisco_node_utils/vxlan_global.rb @@ -18,21 +18,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -require File.join(File.dirname(__FILE__), 'node_util') +require_relative 'node_util' module Cisco # node_utils class for vxlan_global class VxlanGlobal < NodeUtil - def feature_enable + def enable config_set('vxlan_global', 'feature', state: '') end - def feature_disable + def disable config_set('vxlan_global', 'feature', state: 'no') end # Check current state of the configuration - def self.feature_enabled + def self.enabled feat = config_get('vxlan_global', 'feature') return !(feat.nil? || feat.empty?) rescue Cisco::CliError => e @@ -57,24 +57,13 @@ def dup_host_ip_addr_detection end end - def dup_host_ip_addr_detection_host_moves - host_moves, _timeout = dup_host_ip_addr_detection - return default_dup_host_ip_addr_detection_host_moves if host_moves.nil? - host_moves - end - - def dup_host_ip_addr_detection_timeout - _host_moves, timeout = dup_host_ip_addr_detection - return default_dup_host_ip_addr_detection_timeout if timeout.nil? - timeout - end - - def dup_host_ip_addr_detection_set(state, host_moves, timeout) - set_args = {} - set_args[:state] = state - set_args[:host_moves] = host_moves - set_args[:timeout] = timeout - + def dup_host_ip_addr_detection_set(configure, host_moves, timeout) + if configure == 'True' + state = '' + else + state = 'no' + end + set_args = {state: state, host_moves: host_moves, timeout: timeout} config_set('vxlan_global', 'dup_host_ip_addr_detection', set_args) end @@ -103,23 +92,8 @@ def dup_host_mac_detection end end - def dup_host_mac_detection_host_moves - host_moves, _timeout = dup_host_mac_detection - return default_dup_host_mac_detection_host_moves if host_moves.nil? - host_moves - end - - def dup_host_mac_detection_timeout - _host_moves, timeout = dup_host_mac_detection - return default_dup_host_mac_detection_timeout if timeout.nil? - timeout - end - def dup_host_mac_detection_set(host_moves, timeout) - set_args = {} - set_args[:host_moves] = host_moves - set_args[:timeout] = timeout - + set_args = {host_moves: host_moves, timeout: timeout} config_set('vxlan_global', 'dup_host_mac_detection', set_args) end @@ -143,15 +117,15 @@ def default_dup_host_mac_detection_timeout # anycast-gateway-mac def anycast_gateway_mac mac_addr = config_get('vxlan_global', 'anycast_gateway_mac') - mac_addr.nil? ? ' ' : mac_addr.first + mac_addr.nil? ? '' : mac_addr.first end - def anycast_gateway_mac_set(state, mac_addr) + def anycast_gateway_mac_set(configure, mac_addr) fail TypeError unless mac_addr.is_a?(String) - if state == 'no' - config_set('vxlan_global', 'anycast_gateway_mac', 'no', ' ') + if configure == 'True' + config_set('vxlan_global', 'anycast_gateway_mac', state: '', mac_addr: mac_addr) else - config_set('vxlan_global', 'anycast_gateway_mac', ' ', mac_addr) + config_set('vxlan_global', 'anycast_gateway_mac', state: 'no', mac_addr: '') end end end # class diff --git a/tests/test_vxlan_global.rb b/tests/test_vxlan_global.rb index 7d45441e..a45f9ec9 100755 --- a/tests/test_vxlan_global.rb +++ b/tests/test_vxlan_global.rb @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -require File.expand_path('../ciscotest', __FILE__) -require File.expand_path('../../lib/cisco_node_utils/vxlan_global', __FILE__) +require_relative 'ciscotest' +require_relative '../lib/cisco_node_utils/vxlan_global' include Cisco @@ -21,32 +21,32 @@ class TestVxlanGlobal < CiscoTestCase def setup super - no_feature_vxlan_global + no_vxlan_global end def teardown - no_feature_vxlan_global + no_vxlan_global super end - def no_feature_vxlan_global + def no_vxlan_global config('no feature fabric forwarding') end - def test_feature_on_off + def test_on_off feat = VxlanGlobal.new - feat.feature_enable - assert(VxlanGlobal.feature_enabled) + feat.enable + assert(VxlanGlobal.enabled) - feat.feature_disable - refute(VxlanGlobal.feature_enabled) + feat.disable + refute(VxlanGlobal.enabled) end def test_dup_host_ip_addr_detection_set vxlan_global = VxlanGlobal.new val = [200, 20] - vxlan_global.feature_enable - vxlan_global.dup_host_ip_addr_detection_set(' ', val[0], val[1]) + vxlan_global.enable + vxlan_global.dup_host_ip_addr_detection_set('True', val[0], val[1]) assert_equal(val, vxlan_global.dup_host_ip_addr_detection, 'Error: fabric forwarding dup_host_ip_addr_detection ' \ 'get values mismatch') @@ -57,9 +57,10 @@ def test_dup_host_ip_addr_detection_clear val = [200, 20] # After the config is cleared, the get method should return # the default values - default = [5, 180] - vxlan_global.feature_enable - vxlan_global.dup_host_ip_addr_detection_set('no', val[0], val[1]) + default = [vxlan_global.default_dup_host_ip_addr_detection_host_moves, + vxlan_global.default_dup_host_ip_addr_detection_timeout] + vxlan_global.enable + vxlan_global.dup_host_ip_addr_detection_set('False', val[0], val[1]) assert_equal(default, vxlan_global.dup_host_ip_addr_detection, 'Error: fabric forwarding dup_host_ip_addr_detection ' \ 'get values mismatch') @@ -78,7 +79,8 @@ def test_dup_host_mac_detection_default vxlan_global = VxlanGlobal.new # After the config is cleared, the get method should return # the default values - default = [5, 180] + default = [vxlan_global.default_dup_host_mac_detection_host_moves, + vxlan_global.default_dup_host_mac_detection_timeout] vxlan_global.dup_host_mac_detection_default assert_equal(default, vxlan_global.dup_host_mac_detection, 'Error: l2rib dup_host_mac_detection ' \ @@ -88,17 +90,17 @@ def test_dup_host_mac_detection_default def test_anycast_gateway_mac_set vxlan_global = VxlanGlobal.new mac_addr = '1223.3445.5668' - vxlan_global.feature_enable - vxlan_global.anycast_gateway_mac_set(' ', mac_addr) + vxlan_global.enable + vxlan_global.anycast_gateway_mac_set('True', mac_addr) assert_equal(mac_addr, vxlan_global.anycast_gateway_mac, 'Error: anycast-gateway-mac mismatch') end def test_anycast_gateway_mac_clear vxlan_global = VxlanGlobal.new - vxlan_global.feature_enable - vxlan_global.anycast_gateway_mac_set('no', '') - assert_equal(' ', vxlan_global.anycast_gateway_mac, + vxlan_global.enable + vxlan_global.anycast_gateway_mac_set('False', '') + assert_equal('', vxlan_global.anycast_gateway_mac, 'Error: anycast-gateway-mac mismatch') end end From cb5de4356b5928e6d3eab65a06db15dc450a1d46 Mon Sep 17 00:00:00 2001 From: Chris Van Heuveln Date: Tue, 3 Nov 2015 13:36:30 -0500 Subject: [PATCH 020/386] Add rescue for unsupported speed values in minitest % rubocop test_interface.rb Inspecting 1 file . 1 file inspected, no offenses detected Test with n3k/n9k/n9kv & n9k that discovered this problem: ruby-2.1.1 test_interface.rb -v -n test_interface_speed_change -- 1 runs, 2 assertions, 0 failures, 0 errors, 0 skips Coverage report generated for MiniTest to /nobackup/cvanheuv/git.nu.dev.cvh/cisco-network-node-utils/tests/coverage. 0.0 / 0.0 LOC (100.0%) covered. --- tests/test_interface.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/test_interface.rb b/tests/test_interface.rb index eedfa6fe..30db0856 100755 --- a/tests/test_interface.rb +++ b/tests/test_interface.rb @@ -469,11 +469,15 @@ def test_interface_mtu_valid def test_interface_speed_change interface = Interface.new(interfaces[0]) - interface.speed = 100 - assert_equal('100', interface.speed) - interface.speed = 1000 - assert_equal('1000', interface.speed) - interface_ethernet_default(interfaces_id[0]) + begin + interface.speed = 100 + assert_equal('100', interface.speed) + interface.speed = 1000 + assert_equal('1000', interface.speed) + interface_ethernet_default(interfaces_id[0]) + rescue RuntimeError => e + assert_match(/port doesn t support this speed/, e.message) + end end def test_interface_speed_invalid From 1103cbc1d1bf70dcd8dfa977df7cb6c4086a01c0 Mon Sep 17 00:00:00 2001 From: Andi Shen Date: Tue, 3 Nov 2015 15:00:28 -0500 Subject: [PATCH 021/386] fix comment --- tests/test_bgp_af.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_bgp_af.rb b/tests/test_bgp_af.rb index 09f30a04..a15eb3a9 100644 --- a/tests/test_bgp_af.rb +++ b/tests/test_bgp_af.rb @@ -364,17 +364,17 @@ def advertise_l2vpn_evpn(asn, vrf, af) val = false bgp_af.advertise_l2vpn_evpn = val assert_equal(bgp_af.advertise_l2vpn_evpn, val, - 'Error: maximum paths value not match to set value') + 'Error: advertise l2vpn evpn value not match to set value') val = true bgp_af.advertise_l2vpn_evpn = val assert_equal(bgp_af.advertise_l2vpn_evpn, val, - 'Error: maximum paths value not match to set value') + 'Error: advertise l2vpn evpn value not match to set value') val = bgp_af.default_advertise_l2vpn_evpn bgp_af.advertise_l2vpn_evpn = val assert_equal(bgp_af.advertise_l2vpn_evpn, val, - 'Error: maximum paths value not match to default value') + 'Error: advertise l2vpn evpn value not match to default value') end def test_advertise_l2vpn_evpn From 09d83b6f0e5fa625651008ddeb72dfd6956e7f03 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Thu, 22 Oct 2015 09:35:22 -0400 Subject: [PATCH 022/386] YAML refactoring from feature/grpc minus gRPC --- README.md | 4 +- docs/README-develop-best-practices.md | 232 ++-- docs/README-develop-node-utils-APIs.md | 66 +- lib/.rubocop.yml | 4 +- lib/cisco_node_utils/README_YAML.md | 325 ----- lib/cisco_node_utils/cmd_ref/README_YAML.md | 474 ++++++++ .../cmd_ref/aaa_auth_login_service.yaml | 21 + .../cmd_ref/aaa_authentication_login.yaml | 31 + .../cmd_ref/aaa_server_group.yaml | 42 + lib/cisco_node_utils/cmd_ref/bgp.yaml | 161 +++ lib/cisco_node_utils/cmd_ref/bgp_af.yaml | 102 ++ .../cmd_ref/bgp_neighbor.yaml | 112 ++ .../cmd_ref/bgp_neighbor_af.yaml | 154 +++ lib/cisco_node_utils/cmd_ref/dnsclient.yaml | 32 + lib/cisco_node_utils/cmd_ref/fex.yaml | 9 + lib/cisco_node_utils/cmd_ref/images.yaml | 6 + lib/cisco_node_utils/cmd_ref/interface.yaml | 260 ++++ .../cmd_ref/interface_ospf.yaml | 59 + lib/cisco_node_utils/cmd_ref/inventory.yaml | 44 + lib/cisco_node_utils/cmd_ref/memory.yaml | 13 + lib/cisco_node_utils/cmd_ref/ntp_config.yaml | 7 + lib/cisco_node_utils/cmd_ref/ntp_server.yaml | 12 + lib/cisco_node_utils/cmd_ref/ospf.yaml | 70 ++ .../cmd_ref/radius_global.yaml | 22 + .../cmd_ref/radius_server.yaml | 54 + .../cmd_ref/radius_server_group.yaml | 13 + lib/cisco_node_utils/cmd_ref/show_system.yaml | 5 + .../cmd_ref/show_version.yaml | 70 ++ .../cmd_ref/snmp_community.yaml | 22 + lib/cisco_node_utils/cmd_ref/snmp_group.yaml | 6 + lib/cisco_node_utils/cmd_ref/snmp_server.yaml | 44 + lib/cisco_node_utils/cmd_ref/snmp_user.yaml | 52 + .../cmd_ref/syslog_server.yaml | 17 + .../cmd_ref/syslog_settings.yaml | 7 + lib/cisco_node_utils/cmd_ref/system.yaml | 6 + .../cmd_ref/tacacs_server.yaml | 44 + .../cmd_ref/tacacs_server_host.yaml | 32 + .../cmd_ref/virtual_service.yaml | 5 + lib/cisco_node_utils/cmd_ref/vlan.yaml | 34 + lib/cisco_node_utils/cmd_ref/vrf.yaml | 21 + lib/cisco_node_utils/cmd_ref/vtp.yaml | 35 + lib/cisco_node_utils/cmd_ref/yum.yaml | 12 + lib/cisco_node_utils/command_reference.rb | 361 +++--- .../command_reference_common.yaml | 1076 ----------------- .../command_reference_common_bgp.yaml | 535 -------- .../command_reference_n3064.yaml | 13 - .../command_reference_n7k.yaml | 52 - .../command_reference_n9k.yaml | 26 - lib/cisco_node_utils/node.rb | 228 +--- tests/basetest.rb | 10 +- tests/ciscotest.rb | 13 +- tests/cmd_config.yaml | 4 +- tests/platform_info.rb | 3 +- tests/platform_info.yaml | 5 +- tests/test_command_config.rb | 4 +- tests/test_command_reference.rb | 218 ++-- tests/test_interface.rb | 31 +- tests/test_interface_svi.rb | 8 +- tests/test_interface_switchport.rb | 4 +- tests/test_node_ext.rb | 10 - tests/test_router_ospf.rb | 2 +- tests/test_vlan.rb | 2 +- 62 files changed, 2642 insertions(+), 2704 deletions(-) delete mode 100644 lib/cisco_node_utils/README_YAML.md create mode 100644 lib/cisco_node_utils/cmd_ref/README_YAML.md create mode 100644 lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/aaa_server_group.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/bgp.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/bgp_af.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/dnsclient.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/fex.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/images.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/interface.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/interface_ospf.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/inventory.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/memory.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/ntp_config.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/ntp_server.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/ospf.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/radius_global.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/radius_server.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/radius_server_group.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/show_system.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/show_version.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/snmp_community.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/snmp_group.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/snmp_server.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/snmp_user.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/syslog_server.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/syslog_settings.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/system.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/tacacs_server.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/virtual_service.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/vlan.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/vrf.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/vtp.yaml create mode 100644 lib/cisco_node_utils/cmd_ref/yum.yaml delete mode 100755 lib/cisco_node_utils/command_reference_common.yaml delete mode 100644 lib/cisco_node_utils/command_reference_common_bgp.yaml delete mode 100644 lib/cisco_node_utils/command_reference_n3064.yaml delete mode 100755 lib/cisco_node_utils/command_reference_n7k.yaml delete mode 100644 lib/cisco_node_utils/command_reference_n9k.yaml diff --git a/README.md b/README.md index 6c6ef36e..9f6a65c0 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ network node. It provides the base APIs `config_set`, `config_get`, and ### CommandReference -The `CommandReference` module provides for the abstraction of NX-OS CLI, +The `CommandReference` class provides for the abstraction of NX-OS CLI, especially to handle its variance between hardware platforms. A series of YAML files are used to describe the CLI corresponding to a given `(feature, attribute)` tuple for any given platform. When a `Node` is @@ -105,7 +105,7 @@ connected, the platform identification of the Node is used to construct a `CmdRef` object that corresponds to this platform. The `Node` APIs `config_set`, `config_get`, and `config_get_default` all rely on the `CmdRef`. -See also [README_YAML](lib/cisco_node_utils/README_YAML.md). +See also [README_YAML](lib/cisco_node_utils/cmd_ref/README_YAML.md). ### Feature Providers diff --git a/docs/README-develop-best-practices.md b/docs/README-develop-best-practices.md index 0853d6de..70978466 100644 --- a/docs/README-develop-best-practices.md +++ b/docs/README-develop-best-practices.md @@ -12,14 +12,15 @@ This document is intended to assist in developing cisco_node_utils API's that ar ## YAML Development Best Practices -* [Y1](#yaml1): All yaml feature entries should be kept in alphabetical order. -* [Y2](#yaml2): Use *regexp* anchors where needed for `config_get` and `config_get_token` entries. -* Y3: Avoid nested optional matches. -* [Y4](#yaml4): Use the `_template` feature when getting/setting the same property value at multiple levels. -* [Y5](#yaml5): When possible include a `default_value` that represents the system default value. -* [Y6](#yaml6): When possible, use the same `config_get` show command for all properties and document any anomalies. -* [Y7](#yaml7): Use Key-value wildcards instead of Printf-style wildcards. -* [Y8](#yaml8): Selection of `show` commands for `config_get`. +* [Y1](#yaml1): One feature per YAML file +* [Y2](#yaml2): All attribute entries must be kept in alphabetical order. +* [Y3](#yaml3): Use *regexp* anchors where needed for `config_get` and `config_get_token` entries. +* [Y4](#yaml4): Avoid nested optional matches. +* [Y5](#yaml5): Use the `_template` feature when getting/setting the same property value at multiple levels. +* [Y6](#yaml6): When possible include a `default_value` that represents the system default value. +* [Y7](#yaml7): When possible, use the same `config_get` show command for all properties and document any anomalies. +* [Y8](#yaml8): Use Key-value wildcards instead of Printf-style wildcards. +* [Y9](#yaml9): Selection of `show` commands for `config_get`. @@ -43,132 +44,145 @@ This document is intended to assist in developing cisco_node_utils API's that ar ## YAML Best Practices: -### Y1: All yaml feature entries should be kept in alphabetical order. +### Y1: One feature per YAML file -Please keep all feature names in alphabetical order, and all options under a feature in alphabetical order as well. As YAML permits duplicate entries (in which case the last entry overrides any earlier entries), keeping a consistent order helps to prevent accidentally introducing such duplication. +Each YAML file should define a single 'feature' (a closely related set of configuration properties). Don't create "one YAML file to rule them all". -Top level features in alpabetical order: +### Y2: All attribute entries must be kept in alphabetical order. -``` -aaa_authentication_login: -... -dnsclient: -... -interface: -``` - -Options under a feature: +All attribute entries in a given YAML file must be kept in alphabetical order. As YAML permits duplicate entries (in which case the last entry overrides any earlier entries), keeping a consistent order helps to prevent accidentally introducing such duplication. -``` -interface: - access_vlan: - ... - all_interfaces: - ... - create: - ... - description: - ... -``` +This rule is enforced by the `Cisco::CommandReference` class itself - it will raise an exception if it detects any out-of-order entries. -### Y2: Use *regexp* anchors where needed for `config_get` and `config_get_token` entries. +### Y3: Use *regexp* anchors where needed for `config_get` and `config_get_token` entries. Please use *regexp* anchors `^$` to ensure you match the correct feature information in the `show` output. +```yaml +# syslog_settings.yaml +timestamp: + config_get: "show running-config all | include '^logging timestamp'" + config_get_token: '/^logging timestamp (.*)$/' + config_set: ' logging timestamp ' + default_value: 'seconds' ``` -syslog_settings: - timestamp: - config_get: "show running-config all | include '^logging timestamp'" - config_get_token: '/^logging timestamp (.*)$/' - config_set: ' logging timestamp ' - default_value: 'seconds' + +### Y4: Avoid nested optional matches. + +Regexps containing optional match strings inside other match strings become +complex to work with and difficult to maintain. + +One case where this may crop up is in trying to match both affirmative and +negative variants of a config command: + +```yaml +config_get_token: ['/^interface $/i', '/^((no )?switchport)$/'] + +config_get_token: '/^(no)? ?ip tacacs source-interface ?(\S+)?$/' ``` -### Y3: Avoid nested optional matches. +Instead, match the affirmative form of a command and treat its absence as +confirmation of the negative form: -### Y4: Use the `_template` feature when getting/setting the same property value at multiple levels. +```yaml +config_get_token: ['/^interface $/i', '/^switchport$/'] + +config_get_token: '/^tacacs-server source-interface (\S+)$/' +``` + +### Y5: Use the `_template` feature when getting/setting the same property value at multiple levels. Using the template below, `auto_cost` and `default_metric` can be set under `router ospf foo` and `router ospf foo; vrf blue`. -``` -ospf: - _template: - config_get: "show running ospf all" - config_get_token: '/^router ospf $/' - config_get_token_append: - - '/^vrf $/' - config_set: "router ospf " - config_set_append: - - "vrf " - - auto_cost: - config_get_token_append: '/^auto-cost reference-bandwidth (\d+)\s*(\S+)?$/' - config_set_append: "auto-cost reference-bandwidth " - default_value: [40, "Gbps"] - - default_metric: - config_get_token_append: '/^default-metric (\d+)?$/' - config_set_append: " default-metric " - default_value: 0 +```yaml +# ospf.yaml +_template: + config_get: "show running ospf all" + config_get_token: '/^router ospf $/' + config_get_token_append: + - '/^vrf $/' + config_set: "router ospf " + config_set_append: + - "vrf " + +auto_cost: + config_get_token_append: '/^auto-cost reference-bandwidth (\d+)\s*(\S+)?$/' + config_set_append: "auto-cost reference-bandwidth " + default_value: [40, "Gbps"] + +default_metric: + config_get_token_append: '/^default-metric (\d+)?$/' + config_set_append: " default-metric " + default_value: 0 ``` -### Y5: When possible include a `default_value` that represents the system default value. +### Y6: When possible include a `default_value` that represents the system default value. Please make sure to specify a `default_value` and document properties that don't have a system default. System defaults may differ between cisco platforms making it important to define for lookup in the cisco_node_utils common object methods. Default value for `message_digest_alg_type` is `md5` -``` +```yaml message_digest_alg_type: - config_get: 'show running interface all' - config_get_token: ['/^interface %s$/i', '/^\s*ip ospf message-digest-key \d+ (\S+)/'] - default_value: 'md5' + config_get: 'show running interface all' + config_get_token: ['/^interface $/i', '/^\s*ip ospf message-digest-key \d+ (\S+)/'] + default_value: 'md5' ``` **NOTE1: Use strings rather then symbols when applicable**. -If the `default_value` differs between cisco platforms, the more specific `command_reference_[platform].yaml` file should be used. +If the `default_value` differs between cisco platforms, use per-API or per-platform keys in the YAML as needed. For example, if the default value on all platforms except the N9K is `md5` then you might do something like this: -For example, if the default value on all platforms except the n9k is `md5` then set the entry in `command_reference_common.yaml` to `md5` and set the entry in `command_reference_n9k.yaml` to it's default `sha2`. +```yaml +message_digest_alg_type: + config_get: 'show running interface all' + config_get_token: ['/^interface $/i', '/^\s*ip ospf message-digest-key \d+ (\S+)/'] + /N9K/: + default_value: 'sha2' + else: + default_value: 'md5' +``` + +See [README_YAML](../lib/cisco_node_utils/cmd_ref/README_YAML.md) for more details about this advanced feature. -### Y6: When possible, use the same `config_get` show command for all properties and document any anomalies. +### Y7: When possible, use the same `config_get` show command for all properties and document any anomalies. All properties below use the `show run tacacs all` command except `directed_request` which is documented. -``` -tacacs_server: - deadtime: - config_get: "show run tacacs all" - config_get_token: '/^tacacs-server deadtime\s+(\d+)/' - config_set: "%s tacacs-server deadtime %d" - default_value: 0 - - directed_request: - # oddly, directed request must be retrieved from aaa output - config_get: "show running aaa all" - config_get_token: '/(?:no)?\s*tacacs-server directed-request/' - config_set: "%s tacacs-server directed-request" - default_value: false - - encryption_type: - config_get: "show run tacacs all" - config_get_token: '/^tacacs-server key (\d+)\s+(\S+)/' - default_value: 0 - - encryption_password: - config_get: "show run tacacs all" - config_get_token: '/^tacacs-server key (\d+)\s+(\S+)/' - default_value: "" +```yaml +# tacacs_server.yaml +deadtime: + config_get: "show run tacacs all" + config_get_token: '/^tacacs-server deadtime\s+(\d+)/' + config_set: " tacacs-server deadtime Y7: Use Key-value wildcards instead of Printf-style wildcards. +### Y8: Use Key-value wildcards instead of Printf-style wildcards. -The following approach is moderately more complex to implement but is more readable in the ruby code and is flexible enough to handle significant platform differences in CLI. It is therefore the recommended approach for new development. +Key-value wildcards are moderately more complex to implement than Printf-style wildcards but they are more readable in the Ruby code and are flexible enough to handle significant platform differences in CLI. Key-value wildcards are therefore the recommended approach for new development. **Key-value wildcards** -``` +```yaml config_set_append: " log-adjacency-changes " ``` @@ -176,11 +190,11 @@ This following approach is quick to implement and concise, but less flexible - i **Printf-style wildcards** -``` +```yaml config_set_append: "%s log-adjacency-changes %s" ``` -### Y8: Selection of `show` commands for `config_get`. +### Y9: Selection of `show` commands for `config_get`. The following commands should be preferred over `show [feature]` commands since not all `show [feature]` commands behave in the same manner across cisco platforms. @@ -196,7 +210,7 @@ Many cisco features can be configured under the default or global vrf and also u The following `initialize` and `self.vrfs` methods account for configuration under `default` and `non-default vrfs`. -``` +```ruby def initialize(router, name, instantiate=true) fail TypeError if router.nil? fail TypeError if name.nil? @@ -237,9 +251,9 @@ The following `initialize` and `self.vrfs` methods account for configuration und Having this logic defined in the common object lets the minitest easily check the specific instances. -Without this equality operator `==` only passes if they are the same instance object. With this equality operator `==` passes if they are different objects referring to the same configuration on the node. +The built-in equality operator `==` returns true only if they are the same instance object. The `==` method below is used to override the built-in equality operator and return true even if they are different objects referring to the same configuration on the node. -``` +```ruby def ==(other) (name == other.name) && (vrf == other.vrf) end @@ -247,7 +261,7 @@ Without this equality operator `==` only passes if they are the same instance ob Example Usage: -``` +```ruby def test_dnsdomain_create_destroy_multiple id1 = 'aoeu.com' id2 = 'asdf.com' @@ -272,7 +286,7 @@ Example Usage: Our convention is to let `''` represent 'not configured at all' rather than `nil`. For example, `interface.rb`: -``` +```ruby def vrf vrf = config_get('interface', 'vrf', @name) return '' if vrf.nil? @@ -290,7 +304,7 @@ def vrf=(vrf) However, if a property has a default value (it is never truly 'removed'), then we should do this instead: -``` +```ruby def access_vlan vlan = config_get('interface', 'access_vlan', @name) return default_access_vlan if vlan.nil? @@ -307,7 +321,7 @@ In order to have a complete set of api's for each property it is important that This can be seen in the following `router_id` property. -``` +```ruby # Getter Method def router_id match = config_get('ospf', 'router_id', @get_args) @@ -362,7 +376,7 @@ The more specific assertions also produce more helpful failure messages if somet Rather then hardcode an interface name that may or may not exist, instead use the `interfaces[]` array. -``` +```ruby def create_interface(ifname=interfaces[0]) @default_show_command = show_cmd(ifname) Interface.new(ifname) @@ -375,11 +389,11 @@ If additional interfaces are needed array index `1` and `2` may be used. For conveninence the `config` helper method has been provided for device configuration within the minitests. -``` +```ruby config('no feature ospf') ``` -``` +```ruby config('feature ospf'; 'router ospf green') ``` @@ -387,7 +401,7 @@ config('feature ospf'; 'router ospf green') We have a very common pattern in minitest where we execute some show command over the telnet connection, match it against some regexp pattern, and succeed or fail based on the result. Helper methods `assert_show_match` and `refute_show_match` support this pattern. -``` +```ruby assert_show_match(command: 'show run all | no-more', pattern: /interface port-channel 1/, msg: 'port-channel is not present but it should be') @@ -395,7 +409,7 @@ assert_show_match(command: 'show run all | no-more', If your `command` and/or `pattern` are the same throughout a test case or throughout a test suite, you can set the test case instance variables `@default_show_command` and/or `@default_output_pattern` which serve as defaults for these parameters: -``` +```ruby @default_show_command = 'show run interface all | include "interface" | no-more' assert_output_match(pattern: /interface port-channel 10/) refute_output_match(pattern: /interface port-channel 11/) diff --git a/docs/README-develop-node-utils-APIs.md b/docs/README-develop-node-utils-APIs.md index 6392a58a..258f9980 100644 --- a/docs/README-develop-node-utils-APIs.md +++ b/docs/README-develop-node-utils-APIs.md @@ -102,11 +102,12 @@ Example: ### Step 1. YAML Definitions: router eigrp -The new API for `router eigrp` will need some basic YAML definitions. +The new API for `router eigrp` will need some basic YAML definitions. By convention we create a new YAML file to handle a new feature set, so we will create +the following file: -`command_reference_common.yaml` is used for settings that are common across all platforms while other files are used for settings that are unique to a given platform. Our `router eigrp` example uses the same cli syntax on all platforms, thus we only need to edit the common file: +`lib/cisco_node_utils/cmd_ref/eigrp.yaml` -`lib/cisco_node_utils/command_reference_common.yaml` +YAML files in the `/cmd_ref/` subdirectory are automatically discovered at runtime, so we don't need to do anything special once we have created this file Four basic command_reference parameters will be defined for each resource property: @@ -115,7 +116,7 @@ Four basic command_reference parameters will be defined for each resource proper 3. `config_set:` The NX-OS CLI configuration command(s) used to set the property configuration. May contain wildcards for variable parameters. 4. `default_value:` This is typically the "factory" default state of the property, expressed as an actual value (true, 12, "off", etc) -There are additional YAML command parameters available which are not covered by this document. Please see the [README_YAML.md](../lib/cisco_node_utils/README_YAML.md) document for more information on the structure and semantics of these files. +There are additional YAML command parameters available which are not covered by this document. Please see the [README_YAML.md](../lib/cisco_node_utils/cmd_ref/README_YAML.md) document for more information on the structure and semantics of these files. The properties in this example require additional context for their config_get_token values because they need to differentiate between different eigrp instances. Most properties will also have a default value. *Note: Eigrp also has vrf and address-family contexts. These contexts require additional coding and are beyond the scope of this document.* @@ -125,32 +126,32 @@ The properties in this example require additional context for their config_get_t *Note: The basic token definitions for multi-level commands can become long and complicated. A better solution for these commands is to use a command_reference _template: definition to simplify the configuration. The example below will use the basic syntax; see the ospf definitions in the YAML file for an example of _template: usage.* ```yaml -eigrp: - feature: - # feature eigrp must be enabled before configuring router eigrp - config_get: 'show running eigrp all' - config_get_token: '/^feature eigrp$/' - config_set: ' feature eigrp' - - router: - # There can be multiple eigrp instances - config_get: 'show running eigrp all' # all eigrp-related configs - config_get_token: '/^router eigrp (\S+)$/' # Match instance name - config_set: ' router eigrp ' # config to add or remove - - maximum_paths: - # This is an integer property - config_get: 'show running eigrp all' - config_get_token: ['/^router eigrp $/', '/^maximum-paths (\d+)/'] - config_set: ['router eigrp ', 'maximum-paths '] - default_value: 8 - - shutdown: - # This is a boolean property - config_get: 'show running eigrp all' - config_get_token: ['/^router eigrp $/', '/^shutdown$/'] - config_set: ['router eigrp ', ' shutdown'] - default_value: false +# eigrp.yaml +feature: + # feature eigrp must be enabled before configuring router eigrp + config_get: 'show running eigrp all' + config_get_token: '/^feature eigrp$/' + config_set: ' feature eigrp' + +router: + # There can be multiple eigrp instances + config_get: 'show running eigrp all' # all eigrp-related configs + config_get_token: '/^router eigrp (\S+)$/' # Match instance name + config_set: ' router eigrp ' # config to add or remove + +maximum_paths: + # This is an integer property + config_get: 'show running eigrp all' + config_get_token: ['/^router eigrp $/', '/^maximum-paths (\d+)/'] + config_set: ['router eigrp ', 'maximum-paths '] + default_value: 8 + +shutdown: + # This is a boolean property + config_get: 'show running eigrp all' + config_get_token: ['/^router eigrp $/', '/^shutdown$/'] + config_set: ['router eigrp ', ' shutdown'] + default_value: false ``` ### Step 2. cisco_node_utils API: router eigrp @@ -475,10 +476,11 @@ Inspecting 2 file The final step is to build and install the gem that contains the new APIs. -Please note: `gem build` will only include files that are part of the repository. This means that new file `router_eigrp.rb` will be ignored by the build until it is added to the repo with `git add`: +Please note: `gem build` will only include files that are part of the repository. This means that new files `router_eigrp.rb` and `eigrp.yaml` will be ignored by the build until they are added to the repo with `git add`: ```bash -git add lib/cisco_node_utils/router_eigrp.rb +git add lib/cisco_node_utils/router_eigrp.rb \ + lib/cisco_node_utils/cmd_ref/eigrp.yaml ``` From the root of the cisco-network-node-utils repository issue the following command. diff --git a/lib/.rubocop.yml b/lib/.rubocop.yml index 3db35fb8..cc7eaa97 100644 --- a/lib/.rubocop.yml +++ b/lib/.rubocop.yml @@ -3,13 +3,13 @@ inherit_from: ../.rubocop.yml # Baseline code complexity metrics for the lib/ subdirectory: Metrics/AbcSize: - Max: 47 + Max: 40 Metrics/CyclomaticComplexity: Max: 17 Metrics/MethodLength: - Max: 39 + Max: 37 Metrics/ParameterLists: Max: 9 diff --git a/lib/cisco_node_utils/README_YAML.md b/lib/cisco_node_utils/README_YAML.md deleted file mode 100644 index f88a404c..00000000 --- a/lib/cisco_node_utils/README_YAML.md +++ /dev/null @@ -1,325 +0,0 @@ -# Command Reference YAML - -The `command_reference_*.yaml` files in this directory are used with the -`CommandReference` module as a way to abstract away platform CLI differences. - -This document describes the structure and semantics of these files. - -## Structure - -```yaml -FEATURE_1: - _template: - # base parameters for all attributes of this feature go here - - ATTRIBUTE_1: - config_get: 'string' - config_get_token: 'string' - config_get_token_append: 'string' - config_set: 'string' - config_set_append: 'string' - default_value: string, boolean, integer, or constant - test_config_get: 'string' - test_config_get_regexp: '/regexp/' - test_config_result: - input_1: output_1 - input_2: output_2 - - ATTRIBUTE_2: - ... - - ATTRIBUTE_3: - ... - -FEATURE_2: - ... -``` - -All parameters are optional and may be omitted if not needed. - -### Wildcard substitution - -The `config_get_token` and `config_set` (and their associated `_append` -variants) all support two forms of wildcarding - printf-style and key-value. - -#### Printf-style wildcards - -```yaml -tacacs_server_host: - encryption: - config_set: '%s tacacs-server host %s key %s %s' -``` - -This permits parameter values to be passed as a simple sequence: - -```ruby -config_set('tacacs_server_host', 'encryption', 'no', 'user', 'md5', 'password') - -# this becomes 'no tacacs-server host user key md5 password' -# ^^ ^^^^ ^^^ ^^^^^^^^ -``` - -This approach is quick to implement and concise, but less flexible - in -particular it cannot handle a case where different platforms take parameters -in a different order - and less readable in the ruby code. - -#### Key-value wildcards - -```yaml -ospf: - auto_cost: - config_set: ['router ospf ', 'auto-cost reference-bandwidth '] -``` - -This requires parameter values to be passed as a hash: - -```ruby -config_set('ospf', 'auto_cost', {:name => 'red', - :cost => '40', - :type => 'Gbps'}) - -# this becomes the config sequence: -# router ospf red -# auto-cost reference-bandwidth 40 Gbps -``` - -This approach is moderately more complex to implement but is more readable in -the ruby code and is flexible enough to handle significant platform -differences in CLI. It is therefore the recommended approach for new -development. - -### `_template` - -The optional `_template` section can be used to define base parameters for all -attributes of a given feature. For example, all interface attributes might be -checked with the `show running-config interface all` command, and all -attributes might be set by first entering the interface configuration submode -with the `interface ` configuration command. Thus, you might have: - -```yaml -interface: - _template: - config_get: 'show running-config interface all' - config_get_token: '/^interface $/' - config_set: 'interface ' - - access_vlan: - config_get_token_append: '/^switchport access vlan (.*)$/' - config_set_append: 'switchport access vlan ' - - description: - config_get_token_append: '/^description (.*)$/' - config_set_append: 'description ' - - ... -``` - -instead of the more repetitive (but equally valid): - -```yaml -interface: - access_vlan: - config_get: 'show running interface all' - config_get_token: ['/^interface %s$/i', '/^switchport access vlan (.*)$/'] - config_set: ['interface %s', 'switchport access vlan %s'] - - description: - config_get: 'show running-config interface all' - config_get_token: ['/^interface $/i', '/^description (.*)$/'] - config_set: ['interface ', 'description '] - - ... -``` - -### `config_get` - -`config_get` must be a single string representing the CLI command (usually a -`show` command) to be used to display the information needed to get the -current value of this attribute. - -```yaml - config_get: 'show running-config interface all' -``` - -### `config_get_token` - -`config_get_token` can be a single string, a single regex, an array of strings, -or an array of regexs. - -If this value is a string or array of strings, then the `config_get` command -will be executed to produce _structured_ output and the string(s) will be -used as lookup keys. - -```yaml -show_version - cpu: - config_get: 'show version' - config_get_token: 'cpu_name' - # config_get('show_version', 'cpu') returns structured_output['cpu_name'] -``` - -```yaml -inventory: - productid: - config_get: 'show inventory' - config_get_token: ['TABLE_inv', 'ROW_inv', 0, 'productid'] - # config_get('inventory', 'productid') returns - # structured_output['TABLE_inv']['ROW_inv'][0]['productid'] -``` - -If this value is a regex or array or regexs, then the `config_get` command -will be executed to produce _plaintext_ output. - -For a single regex, it will be used to match against the plaintext. - -```yaml -memory: - total: - config_get: 'show system resources' - config_get_token: '/Memory.* (\S+) total/' - # config_get('memory', 'total') returns - # plaintext_output.scan(/Memory.* (\S+) total/) -``` - -For an array of regex, then the plaintext is assumed to be hierarchical in -nature (like `show running-config`) and the regexs are used to filter down -through the hierarchy. - -```yaml -interface: - description: - config_get: 'show running interface all' - config_get_token: ['/^interface %s$/i', '/^description (.*)/'] - # config_get('interface', 'description', 'Ethernet1/1') gets the plaintext - # output, finds the subsection under /^interface Ethernet1/1$/i, then finds - # the line matching /^description (.*)$/ in that subsection -``` - -### `config_get_token_append` - -When using a `_template` section, an attribute can use -`config_get_token_append` to extend the `config_get_token` value provided by -the template instead of replacing it: - -```yaml -interface: - _template: - config_get: 'show running-config interface all' - config_get_token: '/^interface $/' - - description: - config_get_token_append: '/^description (.*)$/' - # config_get_token value for 'description' is now: - # ['/^interface %s$/i', '/^description (.*)$/'] -``` - -This can also be used to specify conditional tokens which may or may not be -used depending on the set of parameters passed into `config_get()`: - -```yaml -bgp: - _template: - config_get: 'show running bgp all' - config_get_token: '/^router bgp $/' - config_get_token_append: - - '/^vrf $/' - - router_id: - config_get_token_append: '/^router-id (\S+)$/' -``` - -In this example, both `config_get('bgp', 'router_id', {:asnum => '1'})` and -`config_get('bgp', 'router_id', {:asnum => '1', :vrf => 'red'})` are valid - -the former will match 'router bgp 1' followed by 'router-id', while the latter -will match 'router bgp 1' followed by 'vrf red' followed by 'router-id'. - -### `config_set` - -The `config_set` parameter is a string or array of strings representing the -configuration CLI command(s) used to set the value of the attribute. - -```yaml -interface: - create: - config_set: 'interface ' - - description: - config_set: ['interface ', 'description '] -``` - -### `config_set_append` - -When using a `_template` section, an attribute can use `config_set_append` to -extend the `config_set` value provided by the template instead of replacing it: - -```yaml -interface: - _template: - config_set: 'interface ' - - access_vlan: - config_set_append: 'switchport access vlan ' - # config_set value for 'access_vlan' is now: - # ['interface ', 'switchport access vlan '] -``` - -Much like `config_get_token_append`, this can also be used to specify optional -commands that can be included or omitted as needed: - -```yaml -bgp: - _template: - config_set: 'router bgp ' - config_set_append: - - 'vrf ' -``` - -### `default_value` - -If there is a default value for this attribute when not otherwise specified by -the user, the `default_value` parameter describes it. This can be a string, -boolean, integer, or array. - -```yaml -interface: - description: - default_value: '' - -interface_ospf: - hello_interval: - default_value: 10 - -ospf: - auto_cost: - default_value: [40, 'Gbps'] -``` - -### `test_config_get` and `test_config_get_regex` - -Test-only equivalents to `config_get` and `config_get_token` - a show command -to be executed over telnet by the minitest unit test scripts, and a regex -(or array thereof) to match in the resulting plaintext output. -Should only be referenced by test scripts, never by a feature provider itself. - -```yaml -show_version: - boot_image: - test_config_get: 'show version | no-more' - test_config_get_regex: '/NXOS image file is: (.*)$/' -``` - -### `test_config_result` - -Test-only container for input-result pairs that might differ by platform. -Should only be referenced by test scripts, never by a feature provider itself. - -```yaml -vtp: - version: - test_config_result: - 3: 'Cisco::CliError' -``` - -## Style Guide - -Please see [YAML Best Practices](../../docs/README-develop-best-practices.md#ydbp). \ No newline at end of file diff --git a/lib/cisco_node_utils/cmd_ref/README_YAML.md b/lib/cisco_node_utils/cmd_ref/README_YAML.md new file mode 100644 index 00000000..ea34d499 --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/README_YAML.md @@ -0,0 +1,474 @@ +# Command Reference YAML + +The [YAML](http://yaml.org) files in this directory are used with the +`Cisco::CommandReference` module as a way to abstract away differences +between client APIs as well as differences between platforms sharing +the same client API. + +This document describes the structure and semantics of these files. + +* [Introduction](#introduction) +* [Basic attribute definition](#basic-attribute-definition) + * [Wildcard substitution](#wildcard-substitution) + * [Printf-style wildcards](#printf-style-wildcards) + * [Key-value wildcards](#key-value-wildcards) +* [Advanced attribute definition](#advanced-attribute-definition) + * [`_template`](#_template) + * [Platform and API variants](#platform-and-api-variants) + * [Product variants](#product-variants) + * [Combinations of these](#combinations-of-these) +* [Attribute properties](#attribute-properties) + * [`config_get`](#config_get) + * [`config_get_token`](#config_get_token) + * [`config_get_token_append`](#config_get_token_append) + * [`config_set`](#config_set) + * [`config_set_append`](#config_set_append) + * [`default_value`](#default_value) + * [`test_config_get` and `test_config_get_regex`](#test_config_get-and-test_config_get_regex) + * [`test_config_result`](#test_config_result) +* [Style Guide](#style-guide) + +## Introduction + +Each file describes a single 'feature' (a closely related set of +configurable attributes). The YAML within the file defines the set of +'attributes' belonging to this feature. When a `CommandReference` object +is instantiated, the user can look up any given attribute using the +`lookup('feature_name', 'attribute_name')` API. Usually, instead of calling +this API directly, node utility classes will call the various `Node` APIs, +for example: + +```ruby +config_set('feature_name', 'attribute_name', *args) +value = config_get('feature_name', 'attribute_name') +default = config_get_default('feature_name', 'attribute_name') +``` + +## Basic attribute definition + +The simplest definition of an attribute directly sets one or more properties +of this attribute. These properties' values can generally be set to any +basic Ruby type such as string, boolean, integer, array, or regexp. +An example: + +```yaml +# vtp.yaml +domain: + config_get: "show vtp status" + config_get_token: "domain_name" + config_set: "vtp domain " + +filename: + config_get: "show running vtp" + config_get_token: '/vtp file (\S+)/' + config_set: " vtp file " + default_value: "" +``` + +In the above example, two attributes are defined: ('vtp', 'domain') and ('vtp', +'filename'). + +Note that all attribute properties are optional and may be omitted if not +needed. In the above, example 'domain' does not have a value defined for +`default_value` but 'filename' does have a default. + +### Wildcard substitution + +The `config_get_token` and `config_set` properties (and their associated +`_append` variants) all support two forms of wildcarding - printf-style and +key-value. Key-value is generally preferred, as described below. + +#### Printf-style wildcards + +```yaml +# tacacs_server_host.yaml +encryption: + config_set: '%s tacacs-server host %s key %s %s' +``` + +This permits parameter values to be passed as a simple sequence to generate the resulting string or regexp: + +```ruby +irb(main):009:0> ref = cr.lookup('tacacs_server_host', 'encryption') +irb(main):010:0> ref.config_set('no', 'myhost', 'md5', 'mypassword') +=> ["no tacacs-server host myhost key md5 mypassword"] +``` + +Printf-style wildcards are quick to implement and concise, but less flexible - in particular they cannot handle a case where different platforms (or different +client APIs!) take parameters in a different order - and less readable in +the Ruby code. + +#### Key-value wildcards + +```yaml +# ospf.yaml +auto_cost: + config_set: ['router ospf ', 'auto-cost reference-bandwidth '] +``` + +This requires parameter values to be passed as a hash: + +```ruby +irb(main):015:0> ref = cr.lookup('ospf', 'auto_cost') +irb(main):016:0> ref.config_set(name: 'red', cost: '40', type: 'Gbps') +=> ["router ospf red", "auto-cost reference-bandwidth 40 Gbps"] +``` + +Key-value wildcards are moderately more complex to implement than Printf-style wildcards but they are more readable in the Ruby code and are flexible enough to handle significant platform differences in CLI. Key-value wildcards are therefore the recommended approach for new development. + +## Advanced attribute definition + +### `_template` + +The optional `_template` section can be used to define base parameters for all +attributes of a given feature. For example, all interface attributes might be +checked with the `show running-config interface all` command, and all +attributes might be set by first entering the interface configuration submode +with the `interface ` configuration command. Thus, you might have: + +```yaml +# interface.yaml +_template: + config_get: 'show running-config interface all' + config_get_token: '/^interface $/' + config_set: 'interface ' + +access_vlan: + config_get_token_append: '/^switchport access vlan (.*)$/' + config_set_append: 'switchport access vlan ' + +description: + config_get_token_append: '/^description (.*)$/' + config_set_append: 'description ' + +... +``` + +instead of the more repetitive (but equally valid): + +```yaml +# interface.yaml +access_vlan: + config_get: 'show running interface all' + config_get_token: ['/^interface $/i', '/^switchport access vlan (.*)$/'] + config_set: ['interface ', 'switchport access vlan '] + +description: + config_get: 'show running-config interface all' + config_get_token: ['/^interface $/i', '/^description (.*)$/'] + config_set: ['interface ', 'description '] + +... +``` + +### Platform and API variants + +Clients for different Cisco platforms may use different APIs. Currently the only supported API is NXAPI (CLI-based API used for Cisco Nexus platforms). Often the CLI or other input/output formats (YANG, etc.) needed will vary between APIs, so the YAML must be able to accomodate this. + +Any of the attribute properties can be subdivided by platform and API type by using the +combination of API type and platform type as a key. For example, interface VRF membership defaults to "" (no VRF) on both Nexus and IOS XR platforms, but the CLI is 'vrf member ' for Nexus and 'vrf ' for IOS XR. Thus, the YAML could be written as: + +```yaml +# interface.yaml +vrf: + default_value: "" + cli_nexus: + config_get_token_append: '/^vrf member (.*)/' + config_set_append: " vrf member " +``` + +and later, once we have a CLI-based API for IOS XR, this could be extended: + +```yaml +# interface.yaml +vrf: + default_value: "" + cli_nexus: + config_get_token_append: '/^vrf member (.*)/' + config_set_append: " vrf member " + cli_ios_xr: + config_get_token_append: '/^vrf (.*)/' + config_set_append: " vrf " +``` + +### Product variants + +Any of the attribute properties can be subdivided by platform product ID string +using a regexp against the product ID as a key. When one or more regexp keys +are defined thus, you can also use the special key `else` to provide values +for all products that do not match any of the given regexps: + +```yaml +# show_version.yaml +system_image: + /N9K/: + config_get_token: "kick_file_name" + test_config_get_regex: '/.*NXOS image file is: (.*)$.*/' + else: + config_get_token: "isan_file_name" + test_config_get_regex: '/.*system image file is: (.*)$.*/' +``` + +### Combinations of these + +In many cases, supporting multiple platforms and multiple products will require +using several or all of the above options. + +Using `_template` in combination with API variants: + +```yaml +# inventory.yaml +_template: + cli_ios_xr: + config_get: 'show inventory | begin "Rack 0"' + test_config_get: 'show inventory' + cli_nexus: + config_get: 'show inventory' + test_config_get: 'show inventory | no-more' + +productid: + cli_ios_xr: + config_get_token: '/PID: ([^ ,]+)/' + cli_nexus: + config_get_token: ["TABLE_inv", "ROW_inv", 0, "productid"] +``` + +Using platform variants and product variants together: + +```yaml +# inventory.yaml +description: + config_get_token: "chassis_id" + cli_nexus: + /N7K/: + test_config_get_regex: '/.*Hardware\n cisco (\w+ \w+ \(\w+ \w+\) \w+).*/' + else: + test_config_get_regex: '/Hardware\n cisco (([^(\n]+|\(\d+ Slot\))+\w+)/' + cli_ios_xr: + config_get: 'show inventory | inc "Rack 0"' + config_get_token: '/DESCR: "(.*)"/' + test_config_get: 'show inventory | inc "Rack 0"' + test_config_get_regex: '/DESCR: "(.*)"/' +``` + +## Attribute properties + +### `config_get` + +`config_get` must be a single string representing the CLI command (usually a +`show` command) to be used to display the information needed to get the +current value of this attribute. + +```yaml +# interface_ospf.yaml +area: + config_get: 'show running interface all' +``` + +### `config_get_token` + +`config_get_token` can be a single string, a single regex, an array of strings, +or an array of regexs. + +If this value is a string or array of strings, then the `config_get` command +will be executed to produce _structured_ output and the string(s) will be +used as lookup keys. + +**WARNING: structured output, although elegant, may not be supported for all commands or all platforms. Use with caution.** + +```yaml +# show_version.yaml +cpu: + config_get: 'show version' + config_get_token: 'cpu_name' + # config_get('show_version', 'cpu') returns structured_output['cpu_name'] +``` + +```yaml +# inventory.yaml +productid: + config_get: 'show inventory' + config_get_token: ['TABLE_inv', 'ROW_inv', 0, 'productid'] + # config_get('inventory', 'productid') returns + # structured_output['TABLE_inv']['ROW_inv'][0]['productid'] +``` + +If this value is a regexp or array of regexps, then the `config_get` command +will be executed to produce _plaintext_ output. + +For a single regexp, it will be used to match against the plaintext. + +```yaml +# memory.yaml +total: + config_get: 'show system resources' + config_get_token: '/Memory.* (\S+) total/' + # config_get('memory', 'total') returns + # plaintext_output.scan(/Memory.* (\S+) total/) +``` + +For an array of regex, then the plaintext is assumed to be hierarchical in +nature (like `show running-config`) and the regexs are used to filter down +through the hierarchy. + +```yaml +# interface.yaml +description: + config_get: 'show running interface all' + config_get_token: ['/^interface $/i', '/^description (.*)/'] + # config_get('interface', 'description', name: 'Ethernet1/1') gets the + # plaintext output, finds the subsection under /^interface Ethernet1/1$/i, + # then finds the line matching /^description (.*)$/ in that subsection +``` + +### `config_get_token_append` + +When using a `_template` section, an attribute can use +`config_get_token_append` to extend the `config_get_token` value provided by +the template instead of replacing it: + +```yaml +# interface.yaml +_template: + config_get: 'show running-config interface all' + config_get_token: '/^interface $/i' + +description: + config_get_token_append: '/^description (.*)$/' + # config_get_token value for 'description' is now: + # ['/^interface $/i', '/^description (.*)$/'] +``` + +This can also be used to specify conditional tokens which may or may not be +used depending on the set of parameters passed into `config_get()`: + +```yaml +# ospf.yaml +_template: + config_get: 'show running ospf all' + config_get_token: '/^router ospf $/' + config_get_token_append: + - '/^vrf $/' + +router_id: + config_get_token_append: '/^router-id (\S+)$/' +``` + +In this example, the `vrf` parameter is optional and a different +`config_get_token` value will be generated depending on its presence or absence: + +```ruby +irb(main):008:0> ref = cr.lookup('ospf', 'router_id') +irb(main):012:0> ref.config_get_token(name: 'red') +=> [/^router ospf red$/, /^router-id (\S+)?$/] +irb(main):013:0> ref.config_get_token(name: 'red', vrf: 'blue') +=> [/^router ospf red$/, /^vrf blue$/, /^router-id (\S+)?$/] +``` + +### `config_set` + +The `config_set` parameter is a string or array of strings representing the +configuration CLI command(s) used to set the value of the attribute. + +```yaml +# interface.yaml +create: + config_set: 'interface ' + +description: + config_set: ['interface ', 'description '] +``` + +### `config_set_append` + +When using a `_template` section, an attribute can use `config_set_append` to +extend the `config_set` value provided by the template instead of replacing it: + +```yaml +# interface.yaml +_template: + config_set: 'interface ' + +access_vlan: + config_set_append: 'switchport access vlan ' + # config_set value for 'access_vlan' is now: + # ['interface ', 'switchport access vlan '] +``` + +Much like `config_get_token_append`, this can also be used to specify optional +commands that can be included or omitted as needed: + +```yaml +# ospf.yaml +_template: + config_set: 'router ospf ' + config_set_append: + - 'vrf ' + +router_id: + config_set_append: 'router-id ' +``` + +```ruby +irb(main):008:0> ref = cr.lookup('ospf', 'router_id') +irb(main):017:0> ref.config_set(name: 'red', state: nil, router_id: '1.1.1.1') +=> ["router ospf red", " router-id 1.1.1.1"] +irb(main):019:0> ref.config_set(name: 'red', vrf: 'blue', + state: 'no', router_id: '1.1.1.1') +=> ["router ospf red", "vrf blue", "no router-id 1.1.1.1"] +``` + +### `default_value` + +If there is a default value for this attribute when not otherwise specified by the user, the `default_value` parameter describes it. This can be a string, boolean, integer, array, or nil. + +```yaml +description: + default_value: '' + +hello_interval: + default_value: 10 + +auto_cost: + default_value: [40, 'Gbps'] + +ipv4_address: + # YAML represents nil as ~ + default_value: ~ +``` + +By convention, a `default_value` of `''` (empty string) represents a configurable property that defaults to absent, while a default of `nil` (Ruby) or `~` (YAML) represents a property that has no meaningful default at all. + +### `test_config_get` and `test_config_get_regex` + +Test-only equivalents to `config_get` and `config_get_token` - a show command +to be executed over telnet by the minitest unit test scripts, and a regex +(or array thereof) to match in the resulting plaintext output. +Should only be referenced by test scripts, never by a feature provider itself. + +```yaml +# show_version.yaml +boot_image: + test_config_get: 'show version | no-more' + test_config_get_regex: '/NXOS image file is: (.*)$/' +``` + +### `test_config_result` + +Test-only container for input-result pairs that might differ by platform. +Should only be referenced by test scripts, never by a feature provider itself. + +```yaml +# vtp.yaml +version: + /N7K/: + test_config_result: + 3: 3 + else: + test_config_result: + 3: 'Cisco::CliError' +``` + +## Style Guide + +Please see [YAML Best Practices](../../docs/README-develop-best-practices.md#ydbp). diff --git a/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml b/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml new file mode 100644 index 00000000..df33ca53 --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml @@ -0,0 +1,21 @@ +# aaa_auth_login_service +--- +groups: + config_get: "show aaa authentication" + config_get_token: ["TABLE_AuthenMethods", "ROW_AuthenMethods"] + # this set is only used when there are groups to configure + config_set: "%s aaa authentication login %s group %s %s" + default_value: [] + +method: + config_get: "show aaa authentication" + #config_get_token: '/aaa authentication login %s (?:group (?:\S+ )+)?(local|none)$/' + config_get_token: '/^\s*%s:.*(local|none)\s*$/' + # this set is only used when there are no groups to configure + config_set: "%s aaa authentication login %s %s" + default_value: :local + +services: + config_get: "show run aaa all" + #config_get_token: '/^\s*(\S+):/' + config_get_token: '/^aaa authentication login (\S+) (?:none|group|local)/' diff --git a/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml b/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml new file mode 100644 index 00000000..532a49dd --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml @@ -0,0 +1,31 @@ +# aaa_authentication_login +--- +ascii_authentication: + config_get: "show run aaa all" + config_get_token: '/^aaa authentication login ascii-authentication/' + config_set: "%s aaa authentication login ascii-authentication" + default_value: false + +chap: + config_get: "show run aaa all" + config_get_token: '/^aaa authentication login chap enable/' + config_set: "%s aaa authentication login chap enable" + default_value: false + +error_display: + config_get: "show run aaa all" + config_get_token: '/^aaa authentication login error-enable/' + config_set: "%s aaa authentication login error-enable" + default_value: false + +mschap: + config_get: "show run aaa all" + config_get_token: '/^aaa authentication login mschap enable/' + config_set: "%s aaa authentication login mschap enable" + default_value: false + +mschapv2: + config_get: "show run aaa all" + config_get_token: '/^aaa authentication login mschapv2 enable/' + config_set: "%s aaa authentication login mschapv2 enable" + default_value: false diff --git a/lib/cisco_node_utils/cmd_ref/aaa_server_group.yaml b/lib/cisco_node_utils/cmd_ref/aaa_server_group.yaml new file mode 100644 index 00000000..220ee305 --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/aaa_server_group.yaml @@ -0,0 +1,42 @@ +# aaa_server_group +--- +deadtime: + default_value: 0 + +servers: + default_value: [] + +source_interface: + default_value: "" + +tacacs_deadtime: + config_get: "show run tacacs all" + config_get_token: ['/^aaa group server tacacs\+ %s/', '/^deadtime (\d+)/'] + config_set: ["aaa group server tacacs %s", "%s deadtime %s"] + +tacacs_group: + config_set: "%s aaa group server tacacs %s" + +tacacs_groups: + config_get: "show run tacacs all" + config_get_token: '/^aaa group server tacacs\+ (\S+)/' + +tacacs_server: + config_set: ["aaa group server tacacs %s", "%s server %s"] + +tacacs_servers: + config_get: "show run tacacs all" + config_get_token: ['/^aaa group server tacacs\+ %s/', '/^server (\S+)/'] + +tacacs_source_interface: + config_get: "show run tacacs all" + config_get_token: ['/^aaa group server tacacs\+ %s/', '/^source-interface (\S+)/'] + config_set: ["aaa group server tacacs %s", "%s source-interface %s"] + +tacacs_vrf: + config_get: "show run tacacs all" + config_get_token: ['/^aaa group server tacacs\+ %s/', '/^use-vrf (\S+)/'] + config_set: ["aaa group server tacacs %s", "%s use-vrf %s"] + +vrf: + default_value: "default" diff --git a/lib/cisco_node_utils/cmd_ref/bgp.yaml b/lib/cisco_node_utils/cmd_ref/bgp.yaml new file mode 100644 index 00000000..10cd1a82 --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/bgp.yaml @@ -0,0 +1,161 @@ +# bgp.yaml +--- +_template: + config_get: "show running bgp all" + config_get_token: '/^router bgp $/' + config_get_token_append: + - '/^vrf $/' + config_set: "router bgp " + config_set_append: + - "vrf " + +address_family: + config_set_append: ' address-family ' + +bestpath_always_compare_med: + config_get_token_append: '/^bestpath always-compare-med$/' + config_set_append: ' bestpath always-compare-med' + default_value: false + +bestpath_aspath_multipath_relax: + config_get_token_append: '/^bestpath as-path multipath-relax$/' + config_set_append: ' bestpath as-path multipath-relax' + default_value: false + +bestpath_compare_routerid: + config_get_token_append: '/^bestpath compare-routerid$/' + config_set_append: ' bestpath compare-routerid' + default_value: false + +bestpath_cost_community_ignore: + config_get_token_append: '/^bestpath cost-community ignore$/' + config_set_append: ' bestpath cost-community ignore' + default_value: false + +bestpath_med_confed: + config_get_token_append: '/^bestpath med confed$/' + config_set_append: ' bestpath med confed' + default_value: false + +bestpath_med_missing_as_worst: + config_get_token_append: '/^bestpath med missing-as-worst$/' + config_set_append: ' bestpath med missing-as-worst' + default_value: false + +bestpath_med_non_deterministic: + config_get_token_append: '/^bestpath med non-deterministic$/' + config_set_append: ' bestpath med non-deterministic' + default_value: false + +cluster_id: + config_get_token_append: '/^cluster-id (\S+)$/' + config_set_append: ' cluster-id ' + default_value: "" + +confederation_id: + config_get_token_append: '/^confederation identifier (\d+.?\d+?)$/' + config_set_append: ' confederation identifier ' + default_value: "" + +confederation_peers: + config_get_token_append: '/^confederation peers (.*)$/' + config_set_append: ' confederation peers ' + default_value: "" + +create_destroy_neighbor: + config_set_append: ' neighbor ' + +enforce_first_as: + config_get_token_append: '/^enforce-first-as$/' + config_set_append: ' enforce-first-as' + default_value: true + +feature: + config_get: "show running bgp" + config_get_token: '/^feature bgp$/' + config_set: " feature bgp" + +graceful_restart: + config_get_token_append: '/^graceful-restart$/' + config_set_append: ' graceful-restart' + default_value: true + +graceful_restart_helper: + config_get_token_append: '/^graceful-restart-helper$/' + config_set_append: ' graceful-restart-helper' + default_value: false + +graceful_restart_timers_restart: + config_get_token_append: '/^graceful-restart restart-time (\d+)$/' + config_set_append: ' graceful-restart restart-time ' + default_value: 120 + +graceful_restart_timers_stalepath_time: + config_get_token_append: '/^graceful-restart stalepath-time (\d+)$/' + config_set_append: ' graceful-restart stalepath-time ' + default_value: 300 + +log_neighbor_changes: + config_get_token_append: '/^log-neighbor-changes$/' + config_set_append: ' log-neighbor-changes' + default_value: false + +maxas_limit: + config_get_token_append: '/^maxas-limit (\d+)$/' + config_set_append: ' maxas-limit ' + default_value: false + +neighbor_fib_down_accelerate: + config_get_token_append: '/^neighbor-down fib-accelerate$/' + config_set_append: ' neighbor-down fib-accelerate' + default_value: false + +reconnect_interval: + config_get_token_append: '/^reconnect-interval (\d+)$/' + config_set_append: ' reconnect-interval ' + default_value: 60 + +router: + config_get: "show running bgp" + config_get_token: '/^router bgp (\d+)$/' + config_set: " router bgp " + +router_id: + config_get_token_append: '/^router-id (\S+)$/' + config_set_append: ' router-id ' + default_value: "" + +shutdown: + # Shutdown only applies to global bgp + config_get: "show running bgp" + config_get_token: ['/^router bgp %s$/i', '/^shutdown$/'] + config_set: ["router bgp ", " shutdown"] + default_value: false +suppress_fib_pending: + config_get_token_append: '/^suppress-fib-pending$/' + config_set_append: ' suppress-fib-pending' + default_value: false + +timer_bestpath_limit: + config_get_token_append: '/^timers bestpath-limit (\d+)(?: always)?$/' + config_set_append: ' timers bestpath-limit ' + default_value: 300 + +timer_bestpath_limit_always: + config_get_token_append: '/^timers bestpath-limit \d+ always$/' + config_set_append: ' timers bestpath-limit always' + default_value: false + +timer_bgp_hold: + default_value: 180 + +timer_bgp_keepalive: + default_value: 60 + +timer_bgp_keepalive_hold: + config_get_token_append: '/^timers bgp (\d+) (\d+)$/' + config_set_append: ' timers bgp ' + +vrf: + config_get_token_append: '/^vrf\s+(\S+)$/' + config_set: ["router bgp ", " vrf ", "end"] diff --git a/lib/cisco_node_utils/cmd_ref/bgp_af.yaml b/lib/cisco_node_utils/cmd_ref/bgp_af.yaml new file mode 100644 index 00000000..9813d421 --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/bgp_af.yaml @@ -0,0 +1,102 @@ +# bgp_af.yaml +--- +_template: + config_get: 'show running bgp all' + config_get_token: '/^router bgp $/' + config_get_token_append: + - '/^vrf $/' + - '/^address-family $/' + config_set: "router bgp " + config_set_append: + - 'vrf ' + - 'address-family ' + +additional_paths_install: + config_get_token_append: '/^additional-paths install backup$/' + config_set_append: ' additional-paths install backup' + default_value: false + +additional_paths_receive: + config_get_token_append: '/^additional-paths receive$/' + config_set_append: ' additional-paths receive' + default_value: false + +additional_paths_selection: + config_get_token_append: '/^additional-paths selection route-map (.*)$/' + config_set_append: ' additional-paths selection route-map ' + default_value: "" + +additional_paths_send: + config_get_token_append: '/^additional-paths send$/' + config_set_append: ' additional-paths send' + default_value: false + +all_afs: + config_get_token_append: '/^address-family (\S+) (\S+)$/' + +client_to_client: + config_get_token_append: '/^client-to-client reflection$/' + config_set_append: ' client-to-client reflection' + default_value: true + +dampen_igp_metric: + config_get_token_append: '/^dampen-igp-metric (\d+)$/' + config_set_append: ' dampen-igp-metric ' + default_value: 600 + +dampening: + config_get_token_append: '/^dampening(?: (?:(\d+) (\d+) (\d+) (\d+)|route-map (.*)))?$/' + config_set_append: ' dampening ' + default_value: "" + +dampening_half_time: + default_value: 15 + +dampening_max_suppress_time: + default_value: 45 + +dampening_reuse_time: + default_value: 750 + +dampening_routemap: + default_value: "" + +dampening_state: + default_value: true + +dampening_suppress_time: + default_value: 2000 + +default_information: + config_get_token_append: '/^default-information originate$/' + config_set_append: ' default-information originate' + default_value: false + +maximum_paths: + config_get_token_append: '/^maximum-paths (\d+)$/' + config_set_append: ' maximum-paths ' + default_value: 1 + +maximum_paths_ibgp: + config_get_token_append: '/^maximum-paths ibgp (\d+)$/' + config_set_append: ' maximum-paths ibgp ' + default_value: 1 + +network: + config_get_token_append: '/^network (\S+) ?(?:route-map )?(\S+)?$/' + config_set_append: ' network ' + default_value: [] + +next_hop_route_map: + config_get_token_append: '/^nexthop route-map (.*)$/' + config_set_append: ' nexthop route-map ' + default_value: "" + +redistribute: + config_get_token_append: '/^redistribute (\S+ ?\S+?) ?(?:route-map (\S+))?$/' + config_set_append: ' redistribute ' + default_value: [] + +redistribute_policy: + # route-map/policy is optional on some platforms, required on others + config_set_append: ' redistribute route-map ' diff --git a/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml b/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml new file mode 100644 index 00000000..0bad1b75 --- /dev/null +++ b/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml @@ -0,0 +1,112 @@ +# bgp_neighbor.yaml +--- +_template: + config_get: "show running bgp all" + config_get_token: '/^router bgp $/' + config_get_token_append: + - '/^vrf $/' + - '/^neighbor $/' + config_set: "router bgp " + config_set_append: + - "vrf " + - "neighbor " + +af: + config_set_append: ' address-family ' + +all_neighbors: + config_get_token_append: '/^neighbor (\S+)$/' + +capability_negotiation: + config_get_token_append: '/^dont-capability-negotiate$/' + config_set_append: ' dont-capability-negotiate' + default_value: true + +connected_check: + config_get_token_append: '/^disable-connected-check$/' + config_set_append: ' disable-connected-check' + default_value: true + +description: + config_get_token_append: '/^description (.*)/' + config_set_append: ' description ' + default_value: "" + +dynamic_capability: + config_get_token_append: '/^dynamic-capability$/' + config_set_append: ' dynamic-capability' + default_value: true + +ebgp_multihop: + config_get_token_append: '/^ebgp-multihop (\d+)$/' + config_set_append: ' ebgp-multihop ' + default_value: false + +local_as: + config_get_token_append: '/^local-as (\d*?.?\d+?)$/' + config_set_append: ' local-as ' + default_value: 0 + +log_neighbor_changes: + config_get_token_append: '/^log-neighbor-changes\s+??(\S+)?\s+??$/' + config_set_append: ' log-neighbor-changes ' + default_value: "inherit" + +low_memory_exempt: + config_get_token_append: '/^low-memory exempt$/' + config_set_append: ' low-memory exempt' + default_value: false + +maximum_peers: + config_get_token_append: '/^maximum-peers (\d+)$/' + config_set_append: ' maximum-peers ' + default_value: 0 + +password: + config_get_token_append: '/^password \d+ (\S+)$/' + config_set_append: ' password ' + default_value: "" + +password_type: + config_get_token_append: '/^password (\d+)/' + default_value: 0 + +remote_as: + config_get_token_append: '/^remote-as (\d*?.?\d+?)$/' + config_set_append: ' remote-as ' + default_value: 0 + +remove_private_as: + config_get_token_append: '/^remove-private-as\s+??(\S+)?\s+??$/' + config_set_append: ' remove-private-as