diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38ce9a64..d9ebb746 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,39 @@
Changelog
=========
+## [v1.10.0]
+
+### New Cisco Resources
+
+### Added
+* Added syslog_facility with attribute:
+ * `level`
+* Extend syslog_server with attribute:
+ * `facility`
+* Extend interface with attributes:
+ * `ipv6_redirects`
+* Extend ace with attributes:
+ * `proto_option`
+ * `vlan`
+ * `set_erspan_dscp`
+ * `set_erspan_gre_proto`
+* Extend network_dns with attributes:
+ * `hostname`
+* Added ability to specify environment at run time
+
+Example:
+```ruby
+env = { host: '192.168.1.1', port: nil, username: 'admin', password: 'admin123', cookie: nil }
+Cisco::Environment.add_env('default', env)
+```
+
+### Changed
+
+### Removed
+
+### Issues Addressed
+* Removed default values for authentication in `interface_hsrp_group`
+
## [v1.9.0]
### New Cisco Resources
@@ -554,6 +587,7 @@ Changelog
[git-flow]: https://github.com/petervanderdoes/gitflow-avh
[SimpleCov]: https://github.com/colszowka/simplecov
+[v1.10.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.9.0...v1.10.0
[v1.9.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.8.0...v1.9.0
[v1.8.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.7.0...v1.8.0
[v1.7.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.6.0...v1.7.0
diff --git a/README.md b/README.md
index c441d9eb..8866850d 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,14 @@ An example configuration file (illustrating each of the above scenarios) is prov
*For security purposes, it is highly recommended that access to this file be restricted to only the owning user (`chmod 0600`).*
+Configuration may also be specified at runtime and can be used in the absence of configuration files or to override them.
+
+Example:
+```ruby
+env = { host: '192.168.1.1', port: nil, username: 'admin', password: 'admin123', cookie: nil }
+Cisco::Environment.add_env('default', env)
+```
+
## Documentation
### Client
@@ -151,12 +159,18 @@ client2 = Cisco::Client.create('n9k')
# Warning: Make sure to exclude devices using the 'no_proxy' environment variable
# to ensure successful remote connections.
+# Add runtime configuration for remote device and connect
+env = { host: '192.168.1.1', port: nil, username: 'admin', password: 'admin123', cookie: nil }
+Cisco::Environment.add_env('remote', env)
+client3 = Cisco::Client.create('remote')
+
# Use connections to get and set device state.
client1.set(values: 'feature vtp')
client1.set(values: 'vtp domain mycompany.com')
puts client1.get(command: 'show vtp status | inc Domain')
puts client2.get(command: 'show version')
+puts client3.get(command: 'show version')
```
#### High-level Node API
diff --git a/ext/mkrf_conf.rb b/ext/mkrf_conf.rb
index 940c99d3..6abfcfab 100644
--- a/ext/mkrf_conf.rb
+++ b/ext/mkrf_conf.rb
@@ -37,7 +37,7 @@
os == 'ios_xr' || deps << Gem::Dependency.new('net_http_unix',
'~> 0.2', '>= 0.2.1')
# NX-OS doesn't need gRPC
- os == 'nexus' || deps << Gem::Dependency.new('grpc', '~> 0.12')
+ os == 'nexus' || deps << Gem::Dependency.new('grpc', '~> 1.14.1')
deps.each do |dep|
installed = dep.matching_specs
diff --git a/lib/cisco_node_utils/ace.rb b/lib/cisco_node_utils/ace.rb
index a88f3d34..0f4d2d95 100644
--- a/lib/cisco_node_utils/ace.rb
+++ b/lib/cisco_node_utils/ace.rb
@@ -1,4 +1,4 @@
-# Copyright (c) 2015-2016 Cisco and/or its affiliates.
+# Copyright (c) 2015-2018 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.
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+require 'ipaddr'
require_relative 'node_util'
module Cisco
@@ -73,6 +74,9 @@ def ace_get
remark = Regexp.new('(?\d+) remark (?.*)').match(str)
return remark unless remark.nil?
+ # specialized icmp protocol handling
+ return icmp_ace_get(str) if str.include?('icmp')
+
# rubocop:disable Metrics/LineLength
regexp = Regexp.new('(?\d+) (?\S+)'\
' *(?\d+|\S+)'\
@@ -95,6 +99,60 @@ def ace_get
regexp.match(str)
end
+ # icmp ace getter
+ def icmp_ace_get(str)
+ # rubocop:disable Metrics/LineLength
+ # fragments is nvgen at a different location than all other
+ # proto_option so get rid of it so as not to mess up other fields
+ str.sub!('fragments ', '')
+ regexp = Regexp.new('(?\d+) (?\S+)'\
+ ' *(?\d+|\S+)'\
+ ' *(?any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)'\
+ ' *(?any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)'\
+ ' *(?\S+)?'\
+ ' *(?precedence \S+)?'\
+ ' *(?dscp \S+)?'\
+ ' *(?time-range \S+)?'\
+ ' *(?packet-length (range \d+ \d+|(lt|eq|gt|neq) \d+))?'\
+ ' *(?ttl \d+)?'\
+ ' *(?vlan \d+)?'\
+ ' *(?set-erspan-gre-proto \d+)?'\
+ ' *(?set-erspan-dscp \d+)?'\
+ ' *(?redirect \S+)?')
+ regexp_no_proto_option = Regexp.new('(?\d+) (?\S+)'\
+ ' *(?\d+|\S+)'\
+ ' *(?any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)'\
+ ' *(?any|host \S+|[:\.0-9a-fA-F]+ [:\.0-9a-fA-F]+|[:\.0-9a-fA-F]+\/\d+|addrgroup \S+)'\
+ ' *(?precedence \S+)?'\
+ ' *(?dscp \S+)?'\
+ ' *(?time-range \S+)?'\
+ ' *(?packet-length (range \d+ \d+|(lt|eq|gt|neq) \d+))?'\
+ ' *(?ttl \d+)?'\
+ ' *(?vlan \d+)?'\
+ ' *(?set-erspan-gre-proto \d+)?'\
+ ' *(?set-erspan-dscp \d+)?'\
+ ' *(?redirect \S+)?')
+ temp = regexp.match(str)
+ po = temp[:proto_option]
+ if po.nil?
+ return temp
+ # redirect can be proto_option or an actual redirect to interface
+ elsif po.strip.match(/redirect$/)
+ if str.match(/Ethernet|port-channel/)
+ # if proto_option is given as redirect and also redirect to intf
+ # we need to do extra processing
+ return temp if check_redirect_repeat(str)
+ return regexp_no_proto_option.match(str)
+ end
+ # the reserved keywords check
+ elsif po.strip.match(/precedence$|dscp$|time-range$|packet-length$|ttl$|vlan$|set-erspan-gre-proto$|set-erspan-dscp$|log$/)
+ return regexp_no_proto_option.match(str)
+ else
+ return temp
+ end
+ # rubocop:enable Metrics/LineLength
+ end
+
# common ace setter. Put the values you need in a hash and pass it in.
# attrs = {:action=>'permit', :proto=>'tcp', :src =>'host 1.1.1.1'}
def ace_set(attrs)
@@ -130,6 +188,10 @@ def ace_set(attrs)
:tcp_option_length,
:redirect,
:log,
+ :proto_option,
+ :set_erspan_dscp,
+ :set_erspan_gre_proto,
+ :vlan,
].each do |p|
attrs[p] = '' if attrs[p].nil?
send(p.to_s + '=', attrs[p])
@@ -139,6 +201,21 @@ def ace_set(attrs)
config_set('acl', cmd, @set_args)
end
+ def valid_ipv6?(addr)
+ begin
+ ret = IPAddr.new(addr.split[0]).ipv6?
+ rescue
+ ret = false
+ end
+ ret
+ end
+
+ def check_redirect_repeat(str)
+ return false unless str.include?('redirect')
+ nstr = str.sub('redirect', '').strip
+ nstr.include?('redirect') ? true : false
+ end
+
# PROPERTIES
# ----------
def seqno
@@ -182,7 +259,7 @@ def src_addr
return nil if match.nil? || !match.names.include?('src_addr')
addr = match[:src_addr]
# Normalize addr. Some platforms zero_pad ipv6 addrs.
- addr.gsub!(/^0*/, '').gsub!(/:0*/, ':')
+ addr.gsub!(/^0*/, '').gsub!(/:0*/, ':') if valid_ipv6?(addr)
addr
end
@@ -205,7 +282,7 @@ def dst_addr
return nil if match.nil? || !match.names.include?('dst_addr')
addr = match[:dst_addr]
# Normalize addr. Some platforms zero_pad ipv6 addrs.
- addr.gsub!(/^0*/, '').gsub!(/:0*/, ':')
+ addr.gsub!(/^0*/, '').gsub!(/:0*/, ':') if valid_ipv6?(addr)
addr
end
@@ -261,6 +338,49 @@ def dscp=(dscp)
@set_args[:dscp] = Utils.attach_prefix(dscp, :dscp)
end
+ def vlan
+ Utils.extract_value(ace_get, 'vlan')
+ end
+
+ def vlan=(vlan)
+ @set_args[:vlan] = Utils.attach_prefix(vlan, :vlan)
+ end
+
+ def set_erspan_dscp
+ ret = Utils.extract_value(ace_get, 'set_erspan_dscp', 'set-erspan-dscp')
+ return ret if ret
+ # position of set_erspan_dscp is different in older release so check again
+ str = config_get('acl', 'ace', @get_args)
+ sstr = str.split
+ return sstr[sstr.index('set-erspan-dscp') + 1] if
+ sstr.include?('set-erspan-dscp')
+ end
+
+ def set_erspan_dscp=(set_erspan_dscp)
+ @set_args[:set_erspan_dscp] = Utils.attach_prefix(set_erspan_dscp,
+ :set_erspan_dscp,
+ 'set-erspan-dscp')
+ end
+
+ def set_erspan_gre_proto
+ ret = Utils.extract_value(ace_get, 'set_erspan_gre_proto',
+ 'set-erspan-gre-proto')
+ return ret if ret
+ # position of set_erspan_gre_proto is different in older release
+ # so check again
+ str = config_get('acl', 'ace', @get_args)
+ sstr = str.split
+ return sstr[sstr.index('set-erspan-gre-proto') + 1] if
+ sstr.include?('set-erspan-gre-proto')
+ end
+
+ def set_erspan_gre_proto=(set_erspan_gre_proto)
+ @set_args[:set_erspan_gre_proto] =
+ Utils.attach_prefix(set_erspan_gre_proto,
+ :set_erspan_gre_proto,
+ 'set-erspan-gre-proto')
+ end
+
def time_range
Utils.extract_value(ace_get, 'time_range', 'time-range')
end
@@ -317,12 +437,27 @@ def redirect=(redirect)
@set_args[:redirect] = Utils.attach_prefix(redirect, :redirect)
end
- def log
+ def proto_option
match = ace_get
+ return nil if match.nil? || proto != 'icmp' || !remark.nil?
+ # fragments is nvgen at a different location than all other
+ # proto_option
+ if config_get('acl', 'ace', @get_args).include?('fragments')
+ return 'fragments'
+ end
+ # log is special case
+ return nil if !match.names.include?('proto_option') ||
+ match[:proto_option] == 'log'
+ match[:proto_option]
+ end
+
+ def proto_option=(proto_option)
+ @set_args[:proto_option] = proto_option
+ end
+
+ def log
return nil unless remark.nil?
- return false if match.nil?
- return false unless match.names.include?('log')
- match[:log] == 'log' ? true : false
+ config_get('acl', 'ace', @get_args).include?('log') ? true : false
end
def log=(log)
diff --git a/lib/cisco_node_utils/banner.rb b/lib/cisco_node_utils/banner.rb
new file mode 100644
index 00000000..015e9636
--- /dev/null
+++ b/lib/cisco_node_utils/banner.rb
@@ -0,0 +1,63 @@
+# Banner provider class
+#
+# Rick Sherman et al., August 2018
+#
+# Copyright (c) 2014-2018 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
+ # Banner - node utility class for Banner configuration management
+ class Banner < NodeUtil
+ attr_reader :name
+
+ def initialize(name)
+ fail TypeError unless name.is_a?(String)
+ fail ArgumentError,
+ "This provider only accepts an id of 'default'" \
+ unless name.eql?('default')
+ @name = name
+ end
+
+ def self.banners
+ hash = {}
+ hash['default'] = Banner.new('default')
+ hash
+ end
+
+ def ==(other)
+ name == other.name
+ end
+
+ def motd
+ config_get('banner', 'motd')
+ end
+
+ def motd=(val)
+ if val.nil? && (motd != default_motd)
+ config_set('banner', 'motd', state: 'no', motd: '')
+ elsif !val.nil?
+ config_set('banner',
+ 'motd',
+ state: '',
+ motd: "^#{val.gsub(/\n/, '\\n')}^")
+ end
+ end
+
+ def default_motd
+ config_get_default('banner', 'motd')
+ end
+ end # class
+end # module
diff --git a/lib/cisco_node_utils/bridge_domain.rb b/lib/cisco_node_utils/bridge_domain.rb
index 0d02167c..bbf80557 100644
--- a/lib/cisco_node_utils/bridge_domain.rb
+++ b/lib/cisco_node_utils/bridge_domain.rb
@@ -144,7 +144,7 @@ def default_bd_name
# This type property can be defined only for one bd
def fabric_control
match = config_get('bridge_domain', 'fabric_control', bd: @bd_ids)
- match == @bd_ids ? true : false
+ match.to_s == @bd_ids ? true : false
end
def fabric_control=(val)
diff --git a/lib/cisco_node_utils/cisco_cmn_utils.rb b/lib/cisco_node_utils/cisco_cmn_utils.rb
index 14513084..2e03cc04 100644
--- a/lib/cisco_node_utils/cisco_cmn_utils.rb
+++ b/lib/cisco_node_utils/cisco_cmn_utils.rb
@@ -362,7 +362,7 @@ def self.merge_range(range)
end # merge_range
def self.add_quotes(value)
- return value if image_version?(/7.3.0/)
+ return value if image_version?(/7.3/)
value = "\"#{value}\"" unless
value.start_with?('"') && value.end_with?('"')
value
diff --git a/lib/cisco_node_utils/client/utils.rb b/lib/cisco_node_utils/client/utils.rb
index ef7bbbcc..776b59c5 100644
--- a/lib/cisco_node_utils/client/utils.rb
+++ b/lib/cisco_node_utils/client/utils.rb
@@ -111,16 +111,26 @@ def self.to_regexp(input)
return input.map { |item| to_regexp(item) }
else
# The string might be explicitly formatted as a regexp
- if input[0] == '/' && input[-1] == '/'
- # '/foo/' => %r{foo}
- return Regexp.new(input[1..-2])
- elsif input[0] == '/' && input[-2..-1] == '/i'
- # '/foo/i' => %r{foo}i
- return Regexp.new(input[1..-3], Regexp::IGNORECASE)
- else
- # 'foo' => %r{^foo$}i
- return Regexp.new("^#{input}$", Regexp::IGNORECASE)
+ # Dynamically handle modifiers
+ input.match(%r{(?^\/.*\/)(?[imx]*)?}) do |m|
+ options = []
+ m['options'].each_char do |c|
+ case c
+ when 'i'
+ options << Regexp::IGNORECASE
+ when 'm'
+ options << Regexp::MULTILINE
+ when 'x'
+ options << Regexp::EXTENDED
+ end
+ end
+ return Regexp.new(m['regex'][1..-2], options.reduce(:|))
end
+ # otherwise this value is a regular string
+ # convert to case insensitive regex
+ # 'foo' => %r{^foo$}i
+ return Regexp.new("^#{input}$", Regexp::IGNORECASE)
+
end
end
@@ -151,7 +161,7 @@ def self.filter_data(data: nil,
end
return final
end
- fail "No key \"#{filter}\" in #{data}" if data[filter].nil?
+ fail "No key \"#{filter}\" in #{data}" unless data.key?(filter)
data = data[filter]
end
end
diff --git a/lib/cisco_node_utils/cmd_ref/acl.yaml b/lib/cisco_node_utils/cmd_ref/acl.yaml
index 8a5eafcc..246229c6 100644
--- a/lib/cisco_node_utils/cmd_ref/acl.yaml
+++ b/lib/cisco_node_utils/cmd_ref/acl.yaml
@@ -12,7 +12,7 @@ _template:
ace:
get_value: '/^ .+$/'
- set_value: ' '
+ set_value: ' '
ace_destroy:
set_value: 'no '
diff --git a/lib/cisco_node_utils/cmd_ref/banner.yaml b/lib/cisco_node_utils/cmd_ref/banner.yaml
new file mode 100644
index 00000000..149b0b11
--- /dev/null
+++ b/lib/cisco_node_utils/cmd_ref/banner.yaml
@@ -0,0 +1,7 @@
+# banner
+---
+motd:
+ default_value: "User Access Verification\n"
+ get_command: 'show banner motd'
+ get_value: '/^.*$/m'
+ set_value: ' banner motd '
diff --git a/lib/cisco_node_utils/cmd_ref/fabricpath.yaml b/lib/cisco_node_utils/cmd_ref/fabricpath.yaml
index 6b873726..a14321ed 100644
--- a/lib/cisco_node_utils/cmd_ref/fabricpath.yaml
+++ b/lib/cisco_node_utils/cmd_ref/fabricpath.yaml
@@ -82,7 +82,7 @@ loadbalance_multicast_has_vlan:
_exclude: [N5k, N6k]
kind: boolean
auto_default: false
- get_command: "show fabricpath load-balance | begin Ftag"
+ get_command: "show fabricpath load-balance | begin ignore-case Ftag"
get_value: '/^Use VLAN: TRUE/'
default_value: true
@@ -93,7 +93,7 @@ loadbalance_multicast_reset:
loadbalance_multicast_rotate:
_exclude: [N5k, N6k]
kind: int
- get_command: "show fabricpath load-balance | begin Ftag"
+ get_command: "show fabricpath load-balance | begin ignore-case Ftag"
get_value: '/^Rotate amount: (\d+)/'
# default_value: n/a. The default rotate amount is randomized to avoid polarization.
diff --git a/lib/cisco_node_utils/cmd_ref/hostname.yaml b/lib/cisco_node_utils/cmd_ref/hostname.yaml
new file mode 100644
index 00000000..c3e60cc0
--- /dev/null
+++ b/lib/cisco_node_utils/cmd_ref/hostname.yaml
@@ -0,0 +1,8 @@
+# hostname
+---
+
+name:
+ get_command: "show running-config all | include 'hostname '"
+ get_value: '/^hostname (\S+)$/'
+ set_value: " hostname "
+ default_value: ""
diff --git a/lib/cisco_node_utils/cmd_ref/interface.yaml b/lib/cisco_node_utils/cmd_ref/interface.yaml
index 3d7c9698..49b9b04d 100644
--- a/lib/cisco_node_utils/cmd_ref/interface.yaml
+++ b/lib/cisco_node_utils/cmd_ref/interface.yaml
@@ -127,7 +127,7 @@ hsrp_mac_refresh:
kind: int
get_value: '/^hsrp mac-refresh (\d+)$/'
set_value: ' hsrp mac-refresh '
- default_value: false
+ default_value: ~
hsrp_use_bia:
_exclude: [ios_xr, N5k, N6k]
@@ -137,7 +137,7 @@ hsrp_use_bia:
# optional match to get the whole config
get_value: '/^hsrp use-bia(?:\s+\S+\s+\S+)?$/'
set_value: ' hsrp use-bia'
- default_value: false
+ default_value: ~
hsrp_version:
_exclude: [ios_xr, N5k, N6k]
@@ -211,7 +211,7 @@ ipv4_dhcp_relay_src_intf:
_exclude: [ios_xr]
get_value: '/^ip dhcp relay source-interface (.*)$/'
set_value: " ip dhcp relay source-interface "
- default_value: false
+ default_value: ~
ipv4_dhcp_relay_subnet_broadcast:
_exclude: [ios_xr]
@@ -258,7 +258,7 @@ ipv4_proxy_arp:
ipv4_redirects_loopback:
kind: boolean
nexus:
- default_only: false
+ default_only: ~
ios_xr:
get_value: '/^((?:no )?ipv4 redirects)$/'
set_value: " ipv4 redirects"
@@ -304,7 +304,14 @@ ipv6_dhcp_relay_src_intf:
_exclude: [ios_xr]
get_value: '/^ipv6 dhcp relay source-interface (.*)$/'
set_value: " ipv6 dhcp relay source-interface "
- default_value: false
+ default_value: ~
+
+ipv6_redirects:
+ _exclude: [ios_xr]
+ kind: boolean
+ get_value: '/^((?:no )?ipv6 redirects)$/'
+ set_value: " ipv6 redirects"
+ default_value: true
load_interval_counter_1_delay:
_exclude: [ios_xr]
@@ -329,7 +336,7 @@ load_interval_counter_3_delay:
kind: int
get_value: '/^load-interval counter 3 (\d+)$/'
set_value: " load-interval counter 3 "
- default_value: false
+ default_value: ~
mtu_loopback:
kind: boolean
@@ -377,6 +384,7 @@ purge_config:
set_value: "default interface "
get_command: "show running interface"
get_value: '/(.*)/'
+ default_value: ~
pvlan_any:
multiple:
@@ -462,13 +470,13 @@ stp_bpdufilter:
kind: string
get_value: '/^spanning-tree bpdufilter (.*)$/'
set_value: " spanning-tree bpdufilter "
- default_value: false
+ default_value: ~
stp_bpduguard:
kind: string
get_value: '/^spanning-tree bpduguard (.*)$/'
set_value: " spanning-tree bpduguard "
- default_value: false
+ default_value: ~
stp_cost:
kind: string
@@ -480,7 +488,7 @@ stp_guard:
kind: string
get_value: '/^spanning-tree guard (.*)$/'
set_value: " spanning-tree guard "
- default_value: false
+ default_value: ~
stp_link_type:
kind: string
@@ -517,7 +525,7 @@ stp_port_type:
get_command: "show running interface"
get_value: '/^spanning-tree port type (.*)$/'
set_value: " spanning-tree port type "
- default_value: false
+ default_value: ~
stp_vlan_cost:
multiple:
@@ -625,7 +633,7 @@ switchport_pvlan_trunk_allowed_vlan:
multiple: true
get_value: '/^switchport private-vlan trunk allowed vlan (?:add )?(\S+)$/'
set_value: "switchport private-vlan trunk allowed vlan "
- default_value: 'none'
+ default_value: none
switchport_pvlan_trunk_association:
_exclude: [ios_xr, N3k, N3k-F, N9k-F]
@@ -728,7 +736,7 @@ vpc_id:
kind: int
get_value: '/^vpc (\d+)$/'
set_value: ' vpc '
- default_value: false
+ default_value: ~
vpc_peer_link:
kind: boolean
diff --git a/lib/cisco_node_utils/cmd_ref/interface_hsrp_group.yaml b/lib/cisco_node_utils/cmd_ref/interface_hsrp_group.yaml
index b68e77a8..d308f1f1 100644
--- a/lib/cisco_node_utils/cmd_ref/interface_hsrp_group.yaml
+++ b/lib/cisco_node_utils/cmd_ref/interface_hsrp_group.yaml
@@ -23,14 +23,14 @@ authentication_enc_type:
default_value: '0'
authentication_key_type:
- default_value: 'key-chain'
+ default_value: ~
authentication_string:
- default_value: ''
+ default_value: ~
authentication_timeout:
kind: int
- default_value: 0
+ default_value: ~
group_name:
get_value: '/^name (\S+)/'
diff --git a/lib/cisco_node_utils/cmd_ref/ip_multicast.yaml b/lib/cisco_node_utils/cmd_ref/ip_multicast.yaml
index bfd0e330..191432f4 100644
--- a/lib/cisco_node_utils/cmd_ref/ip_multicast.yaml
+++ b/lib/cisco_node_utils/cmd_ref/ip_multicast.yaml
@@ -7,12 +7,16 @@ _template:
overlay_distributed_dr:
context: ~
+ kind: boolean
get_value: '^ip multicast overlay-distributed-dr$'
set_value: " ip multicast overlay-distributed-dr"
default_value: false
overlay_spt_only:
context: ~
- get_value: '^ip multicast overlay-spt-only$'
+ kind: boolean
+ auto_default: false
+ get_command: "show fabric multicast globals"
+ get_value: '^Overlay spt-only:\s+TRUE$'
set_value: " ip multicast overlay-spt-only"
- default_value: false
+ default_value: true
diff --git a/lib/cisco_node_utils/cmd_ref/snmp_server.yaml b/lib/cisco_node_utils/cmd_ref/snmp_server.yaml
index f7ed92e0..69e64527 100644
--- a/lib/cisco_node_utils/cmd_ref/snmp_server.yaml
+++ b/lib/cisco_node_utils/cmd_ref/snmp_server.yaml
@@ -62,7 +62,10 @@ packet_size:
# the n3|9k behavior when the issue is resolved.
default_value: 0
N6k: *n5k_default_packet_size
- N7k: *n5k_default_packet_size
+ # On recent versions, packet size is fixed,
+ # so this change will take care of the fix but
+ # it could still fail in the older versions.
+ N7k: *n3k_default_packet_size
# On recent versions, packet size is fixed,
# so this change will take care of the fix but
# it could still fail in the older versions.
diff --git a/lib/cisco_node_utils/cmd_ref/syslog_facility.yaml b/lib/cisco_node_utils/cmd_ref/syslog_facility.yaml
new file mode 100644
index 00000000..0dbed45d
--- /dev/null
+++ b/lib/cisco_node_utils/cmd_ref/syslog_facility.yaml
@@ -0,0 +1,10 @@
+# syslog_facility
+---
+_exclude: [ios_xr]
+
+facility:
+ multiple: true
+ get_command: "show running-config | include '^logging level'"
+ # Returns ,
+ get_value: '/^(?:logging level)\s+(.*)\s+([0-7])/'
+ set_value: ' logging level '
diff --git a/lib/cisco_node_utils/cmd_ref/syslog_server.yaml b/lib/cisco_node_utils/cmd_ref/syslog_server.yaml
index 256b176a..97c20aee 100644
--- a/lib/cisco_node_utils/cmd_ref/syslog_server.yaml
+++ b/lib/cisco_node_utils/cmd_ref/syslog_server.yaml
@@ -15,9 +15,9 @@ server:
multiple: true
nexus:
get_command: "show running-config all | include '^logging server'"
- # Returns , , ,
- get_value: '/^(?:logging server )([^\s]+)(?: (\d+))?(?: port (\d+))?(?: use-vrf (\S+))?/'
- set_value: ' logging server '
+ # Returns , , , ,
+ get_value: '/^(?:logging server )([^\s]+)(?: (\d+))?(?: port (\d+))?(?: use-vrf (\S+))?(?: facility (\S+))?/'
+ set_value: ' logging server '
ios_xr:
get_command: "show running-config logging"
get_value: '/^logging (\S+).*/'
diff --git a/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml b/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml
index c17966e7..4deaed86 100644
--- a/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml
+++ b/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml
@@ -9,6 +9,22 @@ console:
get_value: '/^(no)?\s*logging console\s*(\d)?/'
set_value: ' logging console '
+logfile_name:
+ get_command: "show running-config all | include 'logging'"
+ # Returns and
+ get_value: '/^(no)?\s*logging logfile\s(\S*)\s*?/'
+ set_value: ' logging logfile '
+
+logfile_severity_level:
+ get_command: "show running-config all | include 'logging'"
+ # Returns and
+ get_value: '/^(no)?\s*logging logfile\s\S*\s*(\d)?/'
+
+logfile_size:
+ get_command: "show running-config all | include 'logging'"
+ # Returns and
+ get_value: '/^(no)?\s*logging logfile.*size\s(\d*)/'
+
monitor:
default_value: 5
get_command: "show running-config all | include 'logging'"
diff --git a/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml b/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml
index 53cc155a..6adcf6c2 100644
--- a/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml
+++ b/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml
@@ -48,7 +48,7 @@ hosts:
port:
default_value: 49
kind: int
- get_value: '/^tacacs-server host .* port (\d+).*$/'
+ get_value: '/^tacacs-server host \s.*port (\d+).*$/'
nexus:
set_value: "tacacs-server host port "
@@ -56,7 +56,7 @@ timeout:
default_value: 0
kind: int
nexus:
- get_value: '/^tacacs-server host .*timeout (\d+)/'
+ get_value: '/^tacacs-server host \s.*timeout (\d+)/'
set_value: " tacacs-server host timeout "
ios_xr:
context: ["tacacs-server host port "]
diff --git a/lib/cisco_node_utils/environment.rb b/lib/cisco_node_utils/environment.rb
index e3b84df3..7d0ad910 100644
--- a/lib/cisco_node_utils/environment.rb
+++ b/lib/cisco_node_utils/environment.rb
@@ -1,6 +1,7 @@
+# August 2018
# March 2016, Glenn F. Matthews
#
-# Copyright (c) 2016 Cisco and/or its affiliates.
+# Copyright (c) 2016-2018 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.
@@ -90,6 +91,12 @@ def self.data_from_file(path)
{}
end
+ def self.add_env(env_name, env_hash)
+ fail ArgumentError, 'empty environment name' if env_name.empty?
+ fail TypeError, 'invalid environment hash' unless env_hash.is_a?(Hash)
+ @environments[env_name] = env_hash
+ end
+
def self.strings_to_symbols(hash)
Hash[hash.map { |k, v| [k.to_sym, v] }]
end
diff --git a/lib/cisco_node_utils/hostname.rb b/lib/cisco_node_utils/hostname.rb
new file mode 100644
index 00000000..a4242d43
--- /dev/null
+++ b/lib/cisco_node_utils/hostname.rb
@@ -0,0 +1,62 @@
+# Hostname provider class
+#
+# September 2018
+#
+# Copyright (c) 2014-2018 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
+ # Hostname- node utility class for hostname configuration
+ class HostName < NodeUtil
+ attr_reader :name
+
+ def initialize(name, instantiate=true)
+ @name = name
+ create if instantiate
+ end
+
+ def self.hostname
+ hash = {}
+ hostname = config_get('hostname', 'name')
+ hash[hostname] = HostName.new(hostname, false)
+ hash
+ end
+
+ def hostname=(host)
+ if host
+ config_set(
+ 'hostname', 'name',
+ state: '', name: host)
+ else
+ config_set(
+ 'hostname', 'name',
+ state: 'no', name: '')
+ end
+ end
+
+ def ==(other)
+ name == other.name
+ end
+
+ def create
+ config_set('hostname', 'name', state: '', name: @name)
+ end
+
+ def destroy
+ config_set('hostname', 'name', state: 'no', name: @name)
+ end
+ end # class
+end # module
diff --git a/lib/cisco_node_utils/interface.rb b/lib/cisco_node_utils/interface.rb
index a25d8e1a..e2dd3d95 100644
--- a/lib/cisco_node_utils/interface.rb
+++ b/lib/cisco_node_utils/interface.rb
@@ -1,6 +1,6 @@
# November 2015, Chris Van Heuveln
#
-# Copyright (c) 2015-2017 Cisco and/or its affiliates.
+# Copyright (c) 2015-2018 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.
@@ -192,6 +192,7 @@ def pvlan_enable
# are left untouched.
def access_vlan
+ return nil if switchport_mode == :disabled
config_get('interface', 'access_vlan', name: @name)
end
@@ -275,6 +276,7 @@ def fabric_forwarding_anycast_gateway
end
def fabric_forwarding_anycast_gateway=(state)
+ return if fabric_forwarding_anycast_gateway == state
no_cmd = (state ? '' : 'no')
config_set('interface',
'fabric_forwarding_anycast_gateway',
@@ -325,6 +327,7 @@ def default_hsrp_delay
end
def hsrp_delay_minimum
+ return nil if switchport_mode != :disabled || @name[/loop/i]
minimum, _reload = hsrp_delay
minimum.nil? ? default_hsrp_delay_minimum : minimum
end
@@ -342,6 +345,7 @@ def default_hsrp_delay_minimum
end
def hsrp_delay_reload
+ return nil if switchport_mode != :disabled || @name[/loop/i]
_minimum, reload = hsrp_delay
reload.nil? ? default_hsrp_delay_reload : reload
end
@@ -413,6 +417,7 @@ def default_hsrp_use_bia
end
def hsrp_version
+ return nil if switchport_mode != :disabled || @name[/loop/i]
config_get('interface', 'hsrp_version', name: @name)
end
@@ -604,6 +609,7 @@ def default_ipv4_dhcp_relay_addr
end
def ipv4_dhcp_relay_info_trust
+ return nil if @name[/loop/i] || switchport_mode != :disabled
config_get('interface', 'ipv4_dhcp_relay_info_trust', name: @name)
end
@@ -654,6 +660,7 @@ def default_ipv4_dhcp_relay_src_intf
end
def ipv4_dhcp_relay_subnet_broadcast
+ return nil if @name[/loop/i] || switchport_mode != :disabled
config_get('interface', 'ipv4_dhcp_relay_subnet_broadcast', name: @name)
end
@@ -669,6 +676,7 @@ def default_ipv4_dhcp_relay_subnet_broadcast
end
def ipv4_dhcp_smart_relay
+ return nil if @name[/loop/i] || switchport_mode != :disabled
config_get('interface', 'ipv4_dhcp_smart_relay', name: @name)
end
@@ -698,6 +706,7 @@ def default_ipv4_forwarding
end
def ipv4_pim_sparse_mode
+ return nil unless switchport_mode == :disabled
config_get('interface', 'ipv4_pim_sparse_mode', name: @name)
end
@@ -713,6 +722,7 @@ def default_ipv4_pim_sparse_mode
end
def ipv4_proxy_arp
+ return nil if @name[/loop/i] || switchport_mode != :disabled
config_get('interface', 'ipv4_proxy_arp', name: @name)
end
@@ -736,6 +746,7 @@ def ipv4_redirects_lookup_string
end
def ipv4_redirects
+ return nil unless switchport_mode == :disabled
config_get('interface', ipv4_redirects_lookup_string, name: @name)
end
@@ -834,6 +845,22 @@ def default_ipv6_dhcp_relay_src_intf
config_get_default('interface', 'ipv6_dhcp_relay_src_intf')
end
+ def ipv6_redirects
+ return nil if @name[/loop/i] || switchport_mode != :disabled
+ config_get('interface', 'ipv6_redirects', name: @name)
+ end
+
+ def ipv6_redirects=(redirects)
+ check_switchport(:disabled)
+ no_cmd = (redirects ? '' : 'no')
+ config_set('interface', 'ipv6_redirects',
+ name: @name, state: no_cmd)
+ end
+
+ def default_ipv6_redirects
+ config_get_default('interface', 'ipv6_redirects')
+ end
+
def feature_lacp?
config_get('interface', 'feature_lacp')
end
@@ -913,6 +940,7 @@ def mtu
end
def mtu=(val)
+ return if mtu == val
check_switchport(:disabled)
config_set('interface', mtu_lookup_string,
name: @name, state: '', mtu: val)
@@ -923,6 +951,7 @@ def default_mtu
end
def speed
+ return nil if @name[/loop|vlan/i]
config_get('interface', 'speed', name: @name)
end
@@ -935,6 +964,7 @@ def default_speed
end
def duplex
+ return nil if @name[/loop|vlan/i]
config_get('interface', 'duplex', name: @name)
end
@@ -958,6 +988,7 @@ def negotiate_auto_lookup_string
end
def negotiate_auto
+ return nil if @name[/loop|vlan/]
config_get('interface', negotiate_auto_lookup_string, name: @name)
end
@@ -1032,10 +1063,12 @@ def default_pim_bfd
end
def storm_control_broadcast
+ return nil if @name[/loop|vlan/i]
config_get('interface', 'storm_control_broadcast', name: @name)
end
def storm_control_broadcast=(val)
+ return if val == storm_control_broadcast
state = val == default_storm_control_broadcast ? 'no' : ''
level = val == default_storm_control_broadcast ? '' : val
config_set('interface', 'storm_control_broadcast',
@@ -1047,10 +1080,12 @@ def default_storm_control_broadcast
end
def storm_control_multicast
+ return nil if @name[/loop|vlan/i]
config_get('interface', 'storm_control_multicast', name: @name)
end
def storm_control_multicast=(val)
+ return if val == storm_control_broadcast
state = val == default_storm_control_multicast ? 'no' : ''
level = val == default_storm_control_multicast ? '' : val
config_set('interface', 'storm_control_multicast',
@@ -1062,10 +1097,12 @@ def default_storm_control_multicast
end
def storm_control_unicast
+ return nil if @name[/loop|vlan/i]
config_get('interface', 'storm_control_unicast', name: @name)
end
def storm_control_unicast=(val)
+ return if val == storm_control_broadcast
state = val == default_storm_control_unicast ? 'no' : ''
level = val == default_storm_control_unicast ? '' : val
config_set('interface', 'storm_control_unicast',
@@ -1116,6 +1153,7 @@ def default_stp_bpduguard
end
def stp_cost
+ return nil if switchport_mode == :disabled
cost = config_get('interface', 'stp_cost', name: @name)
cost == 'auto' ? cost : cost.to_i
end
@@ -1150,6 +1188,7 @@ def default_stp_guard
end
def stp_link_type
+ return nil if switchport_mode == :disabled
config_get('interface', 'stp_link_type', name: @name)
end
@@ -1163,6 +1202,7 @@ def default_stp_link_type
end
def stp_port_priority
+ return nil if switchport_mode == :disabled
config_get('interface', 'stp_port_priority', name: @name)
end
@@ -1294,6 +1334,7 @@ def switchport_enable(val=true)
# switchport_autostate_exclude is exclusive to switchport interfaces
def switchport_autostate_exclude
+ return nil if switchport_mode == :disabled
config_get('interface',
'switchport_autostate_exclude', name: @name)
end
@@ -1384,6 +1425,7 @@ def default_switchport_mode
end
def switchport_trunk_allowed_vlan
+ return nil if switchport_mode == :disabled
vlans = config_get('interface', 'switchport_trunk_allowed_vlan',
name: @name)
vlans = vlans.join(',') if vlans.is_a?(Array)
@@ -1406,6 +1448,7 @@ def default_switchport_trunk_allowed_vlan
end
def switchport_trunk_native_vlan
+ return nil if switchport_mode == :disabled
config_get('interface', 'switchport_trunk_native_vlan', name: @name)
end
@@ -1442,6 +1485,7 @@ def cli_error_check(result)
# --------------------------
# switchport mode private-vlan host
def switchport_pvlan_host
+ return nil if switchport_mode == :disabled
config_get('interface', 'switchport_pvlan_host', name: @name)
end
@@ -1458,6 +1502,7 @@ def default_switchport_pvlan_host
# --------------------------
# switchport mode private-vlan promiscuous
def switchport_pvlan_promiscuous
+ return nil if switchport_mode == :disabled
config_get('interface', 'switchport_pvlan_promiscuous', name: @name)
end
@@ -1650,6 +1695,7 @@ def default_switchport_pvlan_trunk_association
# --------------------------
# switchport mode private-vlan trunk promiscuous
def switchport_pvlan_trunk_promiscuous
+ return nil if switchport_mode == :disabled
config_get('interface', 'switchport_pvlan_trunk_promiscuous', name: @name)
end
@@ -1666,6 +1712,7 @@ def default_switchport_pvlan_trunk_promiscuous
# --------------------------
# switchport mode private-vlan trunk secondary
def switchport_pvlan_trunk_secondary
+ return nil if switchport_mode == :disabled
config_get('interface', 'switchport_pvlan_trunk_secondary', name: @name)
end
@@ -1684,6 +1731,7 @@ def default_switchport_pvlan_trunk_secondary
# Note that range is handled as a string because the entire range is
# replaced instead of individually adding or removing vlans from the range.
def switchport_pvlan_trunk_allowed_vlan
+ return nil if switchport_mode == :disabled
vlans = config_get('interface', 'switchport_pvlan_trunk_allowed_vlan',
name: @name)
vlans = vlans.join(',') if vlans.is_a?(Array)
@@ -1708,6 +1756,7 @@ def default_switchport_pvlan_trunk_allowed_vlan
# --------------------------
# switchport trunk native vlan
def switchport_pvlan_trunk_native_vlan
+ return nil if switchport_mode == :disabled
config_get('interface', 'switchport_pvlan_trunk_native_vlan', name: @name)
end
@@ -1971,10 +2020,12 @@ def default_vpc_id
end
def vpc_peer_link
+ return nil unless @name[/port-channel/i] && switchport_mode != :disabled
config_get('interface', 'vpc_peer_link', name: @name)
end
def vpc_peer_link=(state)
+ return if vpc_peerlink == state
no_cmd = (state ? '' : 'no')
config_set('interface', 'vpc_peer_link', name: @name, state: no_cmd)
end
@@ -2037,8 +2088,14 @@ def purge_config=(val)
end
def purge_config
+ # This getter is only supported on ethernet interfaces
+ return nil unless @name[/ethernet/]
state = config_get('interface', 'purge_config', name: @name)
- state.nil? ? true : false
+ state.nil? ? true : default_purge_config
+ end
+
+ def default_purge_config
+ config_get_default('interface', 'purge_config')
end
end # Class
end # Module
diff --git a/lib/cisco_node_utils/interface_DEPRECATED.rb b/lib/cisco_node_utils/interface_DEPRECATED.rb
index 38e46b38..652d9961 100644
--- a/lib/cisco_node_utils/interface_DEPRECATED.rb
+++ b/lib/cisco_node_utils/interface_DEPRECATED.rb
@@ -65,6 +65,7 @@ def switchport_enable_and_mode_private_vlan_host(mode_set)
end
def switchport_mode_private_vlan_host
+ return nil if switchport_mode == :disabled
mode = config_get('DEPRECATED',
'switchport_mode_private_vlan_host',
name: @name)
@@ -299,6 +300,7 @@ def default_switchport_mode_private_vlan_host_promisc
end
def switchport_mode_private_vlan_trunk_promiscuous
+ return nil if switchport_mode == :disabled
config_get('DEPRECATED',
'switchport_mode_private_vlan_trunk_promiscuous',
name: @name)
@@ -331,6 +333,7 @@ def default_switchport_mode_private_vlan_trunk_promiscuous
end
def switchport_mode_private_vlan_trunk_secondary
+ return nil if switchport_mode == :disabled
config_get('DEPRECATED',
'switchport_mode_private_vlan_trunk_secondary',
name: @name)
@@ -361,6 +364,7 @@ def default_switchport_mode_private_vlan_trunk_secondary
end
def switchport_private_vlan_trunk_allowed_vlan
+ return nil if switchport_mode == :disabled
result = config_get('DEPRECATED',
'switchport_private_vlan_trunk_allowed_vlan',
name: @name)
@@ -400,6 +404,7 @@ def default_switchport_private_vlan_trunk_allowed_vlan
end
def switchport_private_vlan_trunk_native_vlan
+ return nil if switchport_mode == :disabled
config_get('DEPRECATED',
'switchport_private_vlan_trunk_native_vlan',
name: @name)
diff --git a/lib/cisco_node_utils/interface_hsrp_group.rb b/lib/cisco_node_utils/interface_hsrp_group.rb
index 1b8c5421..f2a33b30 100644
--- a/lib/cisco_node_utils/interface_hsrp_group.rb
+++ b/lib/cisco_node_utils/interface_hsrp_group.rb
@@ -1,7 +1,7 @@
#
# October 2016, Sai Chintalapudi
#
-# Copyright (c) 2016 Cisco and/or its affiliates.
+# Copyright (c) 2016-2018 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.
@@ -96,6 +96,12 @@ def destroy
# authentication md5 key-string ABCXYZ timeout 22
# authentication md5 key-string 7 12345678901234567890 timeout 22
# authentication md5 key-string 7 123456789 compatibility timeout 22
+ # if passwd
+ # req auth_enc_type
+ # if encrypted
+ # req authentication_key_type, authentication_enc_type
+ # if key-string
+ # optional compat and timeout
def authentication
hash = {}
hash[:auth_type] = default_authentication_auth_type
@@ -203,8 +209,13 @@ def authentication_timeout
end
def authentication_timeout=(val)
- @set_args[:tval] = val
- @set_args[:timeout] = 'timeout'
+ if val.nil?
+ @set_args[:tval] = ''
+ @set_args[:timeout] = ''
+ else
+ @set_args[:tval] = val
+ @set_args[:timeout] = 'timeout'
+ end
end
def default_authentication_timeout
@@ -227,14 +238,14 @@ def authentication_set(attrs)
:authentication_compatibility,
:authentication_timeout,
].each do |p|
- send(p.to_s + '=', attrs[p]) unless attrs[p].nil?
+ send(p.to_s + '=', attrs[p])
end
- return if @set_args[:passwd] == default_authentication_string
+ return if @set_args[:passwd].nil? || @set_args[:passwd].empty?
@set_args[:state] = ''
if @set_args[:authtype] == 'text'
@set_args[:keytype] = @set_args[:enctype] = ''
@set_args[:compatible] = @set_args[:timeout] = @set_args[:tval] = ''
- elsif @set_args[:keytype] == default_authentication_key_type
+ elsif @set_args[:keytype] == 'key-chain'
@set_args[:enctype] = @set_args[:compatible] = ''
@set_args[:timeout] = @set_args[:tval] = ''
end
diff --git a/lib/cisco_node_utils/ip_multicast.rb b/lib/cisco_node_utils/ip_multicast.rb
index 56e5f8db..d4e2215b 100644
--- a/lib/cisco_node_utils/ip_multicast.rb
+++ b/lib/cisco_node_utils/ip_multicast.rb
@@ -64,23 +64,27 @@ def default_overlay_distributed_dr
end
def overlay_spt_only
- config_get('ip_multicast', 'overlay_spt_only')
+ result = config_get('ip_multicast', 'overlay_spt_only')
+ result.nil? ? false : result
end
def overlay_spt_only=(bool)
fail TypeError unless [true, false].include?(bool)
@set_args[:state] = bool ? '' : 'no'
- if @set_args[:state] == 'no'
- unless overlay_spt_only == default_overlay_spt_only
- config_set('ip_multicast', 'overlay_spt_only', @set_args)
- end
- else
- config_set('ip_multicast', 'overlay_spt_only', @set_args)
- end
+ config_set('ip_multicast', 'overlay_spt_only', @set_args)
end
def default_overlay_spt_only
- config_get_default('ip_multicast', 'overlay_spt_only')
+ val = config_get_default('ip_multicast', 'overlay_spt_only')
+ # The default value for this property is different for older
+ # Nexus software verions.
+ #
+ # Versions: 7.0(3)I7(1), 7.0(3)I7(2), 7.0(3)I7(3)
+ # Default State: false
+ #
+ # Versions: 7.0(3)I7(4) and later
+ # Default State: true
+ node.os_version[/7\.0\(3\)I7\([1-3]\)/] ? !val : val
end
end
end
diff --git a/lib/cisco_node_utils/node.rb b/lib/cisco_node_utils/node.rb
index 5e200775..bde05460 100644
--- a/lib/cisco_node_utils/node.rb
+++ b/lib/cisco_node_utils/node.rb
@@ -122,7 +122,10 @@ def drill_down_structured(value, ref)
value = value.is_a?(Hash) ? [value] : value
data = nil
value.each do |row|
- data = row[data_key] if row[row_key].to_s[/#{row_index}/]
+ if row[row_key].to_s[/#{row_index}/]
+ data = row[data_key]
+ data = data.nil? ? '' : data
+ end
end
return value if data.nil?
if regexp_filter
diff --git a/lib/cisco_node_utils/syslog_facility.rb b/lib/cisco_node_utils/syslog_facility.rb
new file mode 100644
index 00000000..ff975a5e
--- /dev/null
+++ b/lib/cisco_node_utils/syslog_facility.rb
@@ -0,0 +1,64 @@
+# Syslog facility provider class
+#
+# Rick Sherman et al., August 2018
+#
+# Copyright (c) 2014-2018 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
+ # SyslogFacility - node utility class for Syslog facility severity management
+ class SyslogFacility < NodeUtil
+ attr_reader :facility, :level
+
+ def initialize(opts, instantiate=true)
+ @facility = opts['facility']
+ @level = opts['level']
+
+ create if instantiate
+ end
+
+ def self.facilities
+ keys = %w(facility level)
+ hash = {}
+ facility_key_list = config_get('syslog_facility', 'facility')
+ return hash if facility_key_list.nil?
+
+ facility_key_list.each do |id|
+ hash[id[0]] = SyslogFacility.new(Hash[keys.zip(id)], false)
+ end
+
+ hash
+ end
+
+ def ==(other)
+ facility == other.facility && level == other.level
+ end
+
+ def create
+ config_set('syslog_facility', 'facility', state: '', facility: @facility,
+ level: @level)
+ end
+
+ def destroy
+ config_set('syslog_facility', 'facility', state: 'no',
+ facility: @facility, level: @level)
+ end
+
+ def level
+ @level.to_i
+ end
+ end # class
+end # module
diff --git a/lib/cisco_node_utils/syslog_server.rb b/lib/cisco_node_utils/syslog_server.rb
index 7f2e990f..385c7785 100644
--- a/lib/cisco_node_utils/syslog_server.rb
+++ b/lib/cisco_node_utils/syslog_server.rb
@@ -1,8 +1,9 @@
# Syslog Server provider class
#
+# June 2018
# Jonathan Tripathy et al., September 2015
#
-# Copyright (c) 2014-2017 Cisco and/or its affiliates.
+# Copyright (c) 2014-2018 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.
@@ -22,7 +23,7 @@
module Cisco
# SyslogServer - node utility class for syslog server configuration management
class SyslogServer < NodeUtil
- attr_reader :name, :level, :port, :vrf, :severity_level
+ attr_reader :name, :level, :port, :vrf, :severity_level, :facility
LEVEL_TO_NUM = { 'emergencies' => 0,
'alerts' => 1,
@@ -40,6 +41,7 @@ def initialize(opts, instantiate=true)
@port = opts['port']
@vrf = opts['vrf']
@severity_level = opts['severity_level'] || opts['level']
+ @facility = opts['facility']
hostname_regex = /^(?=.{1,255}$)[0-9A-Za-z]
(?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?
@@ -56,7 +58,7 @@ def initialize(opts, instantiate=true)
end
def self.syslogservers
- keys = %w(name level port vrf severity_level)
+ keys = %w(name level port vrf facility severity_level)
hash = {}
syslogservers_list = config_get('syslog_server', 'server')
return hash if syslogservers_list.nil?
@@ -65,6 +67,7 @@ def self.syslogservers
value_hash = Hash[keys.zip(id)]
value_hash['severity_level'] = value_hash['level']
value_hash['vrf'] = 'default' if value_hash['vrf'].nil?
+ value_hash['facility'] = 'local7' if value_hash['facility'].nil?
hash[id[0]] = SyslogServer.new(value_hash, false)
end
@@ -93,11 +96,12 @@ def create
else
config_set('syslog_server',
'server',
- state: '',
- ip: @name,
- level: @level ? "#{@level}" : '',
- port: @port ? "port #{@port}" : '',
- vrf: @vrf ? "use-vrf #{@vrf}" : '',
+ state: '',
+ ip: @name,
+ level: @level ? "#{@level}" : '',
+ port: @port ? "port #{@port}" : '',
+ vrf: @vrf ? "use-vrf #{@vrf}" : '',
+ facility: @facility ? "facility #{@facility}" : '',
)
end
end
@@ -129,11 +133,12 @@ def destroy(duplicate_vrfs=[])
else
config_set('syslog_server',
'server',
- state: 'no',
- ip: @name,
- level: '',
- port: '',
- vrf: '',
+ state: 'no',
+ ip: @name,
+ level: '',
+ port: '',
+ vrf: '',
+ facility: '',
)
end
end
diff --git a/lib/cisco_node_utils/syslog_settings.rb b/lib/cisco_node_utils/syslog_settings.rb
index d91c39a0..13693dbb 100644
--- a/lib/cisco_node_utils/syslog_settings.rb
+++ b/lib/cisco_node_utils/syslog_settings.rb
@@ -1,8 +1,9 @@
# Syslog Settings provider class
#
+# August 2018
# Jonathan Tripathy et al., September 2015
#
-# Copyright (c) 2014-2017 Cisco and/or its affiliates.
+# Copyright (c) 2014-2018 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.
@@ -126,6 +127,47 @@ def timestamp=(val)
units: val)
end
+ def logfile_severity_level
+ logfile_severity_level =
+ config_get('syslog_settings', 'logfile_severity_level')
+ if logfile_severity_level.is_a?(Array)
+ if logfile_severity_level[0] == 'no'
+ logfile_severity_level = nil
+ else
+ logfile_severity_level = logfile_severity_level[1]
+ end
+ end
+ logfile_severity_level
+ end
+
+ def logfile_name=(logname, severity, size)
+ if logname
+ config_set(
+ 'syslog_settings', 'logfile_name',
+ state: '', logname: logname, severity: severity, size: size)
+ else
+ config_set(
+ 'syslog_settings', 'logfile_name',
+ state: 'no', logname: logname, severity: severity, size: size)
+ end
+ end
+
+ def logfile_name
+ logfile_name = config_get('syslog_settings', 'logfile_name')
+ if logfile_name.is_a?(Array)
+ logfile_name = (logfile_name[0] == 'no') ? 'unset' : logfile_name[1]
+ end
+ logfile_name
+ end
+
+ def logfile_size
+ logfile_size = config_get('syslog_settings', 'logfile_size')
+ if logfile_size.is_a?(Array)
+ logfile_size = (logfile_size[0] == 'no') ? nil : logfile_size[1]
+ end
+ logfile_size
+ end
+
alias_method :time_stamp_units, :timestamp
alias_method :time_stamp_units=, :timestamp=
end # class
diff --git a/lib/cisco_node_utils/version.rb b/lib/cisco_node_utils/version.rb
index 5d761ab4..60a7c43c 100644
--- a/lib/cisco_node_utils/version.rb
+++ b/lib/cisco_node_utils/version.rb
@@ -14,7 +14,7 @@
# Container module for version number only.
module CiscoNodeUtils
- VERSION = '1.9.0'
+ VERSION = '1.10.0'
gem_version = Gem::Version.new(Gem::VERSION)
min_gem_version = Gem::Version.new('2.1.0')
fail 'Required rubygems version >= 2.1.0' if gem_version < min_gem_version
diff --git a/lib/cisco_node_utils/vlan.rb b/lib/cisco_node_utils/vlan.rb
index e142d8cd..d00d73fc 100644
--- a/lib/cisco_node_utils/vlan.rb
+++ b/lib/cisco_node_utils/vlan.rb
@@ -47,7 +47,7 @@ def self.vlans
return hash if vlan_list.nil?
vlan_list.each do |id|
- hash[id] = Vlan.new(id, false)
+ hash[id.to_s] = Vlan.new(id, false)
end
hash
end
diff --git a/lib/cisco_node_utils/vxlan_vtep_vni.rb b/lib/cisco_node_utils/vxlan_vtep_vni.rb
index ace6784b..913c7846 100644
--- a/lib/cisco_node_utils/vxlan_vtep_vni.rb
+++ b/lib/cisco_node_utils/vxlan_vtep_vni.rb
@@ -112,20 +112,33 @@ def ingress_replication
config_get('vxlan_vtep_vni', 'ingress_replication', @get_args)
end
+ def set_host_reachability(vtep_name, protocol)
+ # This is a helper method for the ingress_replication setter.
+ # In later versions of Nexus, a check was added to make sure
+ # the host_reachability setting is correct for the desired
+ # ingress_replication setting.
+ #
+ case protocol
+ when 'bgp'
+ host_reachability = 'evpn'
+ when 'static'
+ host_reachability = 'flood'
+ else
+ fail "Protocol #{protocol} currently not supported"
+ end
+ VxlanVtep.new(vtep_name).host_reachability = host_reachability
+ end
+
def remove_add_ingress_replication(protocol)
# Note: ingress-replication is not supported on all platforms.
# Use to_s.empty check to also handle nil check.
- if ingress_replication.to_s.empty?
- set_args_keys(state: '', protocol: protocol)
- config_set('vxlan_vtep_vni', 'ingress_replication', @set_args)
- else
- # Sadly, the only way to change between protocols is to
- # first remove the existing protocol.
+ unless ingress_replication.to_s.empty?
set_args_keys(state: 'no', protocol: ingress_replication)
config_set('vxlan_vtep_vni', 'ingress_replication', @set_args)
- set_args_keys(state: '', protocol: protocol)
- config_set('vxlan_vtep_vni', 'ingress_replication', @set_args)
end
+ set_host_reachability(@set_args[:name], protocol)
+ set_args_keys(state: '', protocol: protocol)
+ config_set('vxlan_vtep_vni', 'ingress_replication', @set_args)
end
def ingress_replication=(protocol)
diff --git a/spec/environment_spec.rb b/spec/environment_spec.rb
index 8ed8fd30..1b0ffc0f 100644
--- a/spec/environment_spec.rb
+++ b/spec/environment_spec.rb
@@ -70,6 +70,37 @@ class << Cisco::Environment
end
end
+ describe '.add_env' do
+ it 'rejects empty environment name' do
+ expect { described_class.add_env('', {}) }.to \
+ raise_error(ArgumentError, 'empty environment name')
+ end
+
+ it 'rejects incorrectly typed environment hash' do
+ expect { described_class.add_env('default', 'hash') }.to \
+ raise_error(TypeError, 'invalid environment hash')
+ end
+
+ context 'environment can be loaded by funcion' do
+ expected = {
+ host: '192.168.1.1',
+ port: nil,
+ username: 'admin',
+ password: 'admin',
+ cookie: nil,
+ }
+ it 'can be loaded explicitly by name' do
+ described_class.add_env('test', expected)
+ expect(Cisco::Environment.environment('test')).to eq(expected)
+ end
+
+ it 'can be default' do
+ described_class.add_env('default', expected)
+ expect(Cisco::Environment.environment).to eq(expected)
+ end
+ end
+ end
+
describe '.environments' do
before(:each) do
allow(Cisco::Environment).to receive(:data_from_file).and_return({})
@@ -162,6 +193,82 @@ class << Cisco::Environment
},
)
end
+
+ it 'loaded file can be overridden by add_env' do
+ expect(Cisco::Environment).to receive(:data_from_file).with(
+ '/etc/cisco_node_utils.yaml').and_return(global_config)
+ expect(Cisco::Environment).to receive(:data_from_file).with(
+ '~/cisco_node_utils.yaml').and_return(user_config)
+ expect(Cisco::Environment.environments).to eq(
+ 'default' => {
+ host: '127.0.0.1', # global config
+ port: 57_799, # user overrides global
+ username: 'user', # user config
+ password: nil, # auto-populated with nil
+ cookie: nil,
+ },
+ 'global' => { # global config
+ host: nil,
+ port: nil,
+ username: 'global',
+ password: 'global',
+ cookie: nil,
+ },
+ 'user' => { # user config
+ host: nil,
+ port: nil,
+ username: 'user',
+ password: 'user',
+ cookie: nil,
+ },
+ )
+ added_env = {
+ host: '192.168.1.1',
+ port: nil,
+ username: 'admin',
+ password: 'admin',
+ cookie: nil,
+ }
+ overide_defult = {
+ host: '192.168.2.2',
+ port: nil,
+ username: 'overridden',
+ password: 'overridden',
+ cookie: nil,
+ }
+ described_class.add_env('added', added_env)
+ described_class.add_env('default', overide_defult)
+ expect(Cisco::Environment.environments).to eq(
+ 'added' => { # added by method
+ host: '192.168.1.1',
+ port: nil,
+ username: 'admin',
+ password: 'admin',
+ cookie: nil,
+ },
+ 'default' => {
+ host: '192.168.2.2', # method overrides files
+ port: nil, # method overrides files
+ username: 'overridden', # method overrides files
+ password: 'overridden', # method overrides files
+ cookie: nil, # auto-popuplated with nil
+ },
+ 'global' => { # global config
+ host: nil,
+ port: nil,
+ username: 'global',
+ password: 'global',
+ cookie: nil,
+ },
+ 'user' => { # user config
+ host: nil,
+ port: nil,
+ username: 'user',
+ password: 'user',
+ cookie: nil,
+ },
+ )
+ end
end
context '.environment' do
diff --git a/tests/ciscotest.rb b/tests/ciscotest.rb
index a3225f39..6cd6ad27 100644
--- a/tests/ciscotest.rb
+++ b/tests/ciscotest.rb
@@ -223,8 +223,15 @@ def system_image
end
def skip_legacy_defect?(pattern, msg)
+ if pattern.is_a?(String)
+ pattern = [pattern]
+ elsif !pattern.is_a?(Array)
+ fail 'Argument: pattern must be a String or Array object'
+ end
msg = "Defect in legacy image: [#{msg}]"
- skip(msg) if Utils.image_version?(Regexp.new(pattern))
+ pattern.each do |pat|
+ skip(msg) if Utils.image_version?(Regexp.new(pat))
+ end
end
def step_unless_legacy_defect(pattern, msg)
diff --git a/tests/test_ace.rb b/tests/test_ace.rb
index 59e8aefe..1d84529a 100644
--- a/tests/test_ace.rb
+++ b/tests/test_ace.rb
@@ -1,4 +1,4 @@
-# Copyright (c) 2015-2016 Cisco and/or its affiliates.
+# Copyright (c) 2015-2018 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.
@@ -57,7 +57,7 @@ def ace_helper(afi, props=nil)
end
rescue CliError => e
skip('This property is not supported on this platform') if
- e.message[/(Invalid parameter detected|Invalid command)/]
+ e.message[/(Invalid parameter detected|Invalid command|Invalid number)/]
flunk(e.message)
end
@@ -83,7 +83,7 @@ def test_action
def test_proto
%w(ipv4 ipv6).each do |afi|
# Sampling of proto's
- %w(ip tcp udp).each do |val|
+ %w(ip tcp udp icmp).each do |val|
val = 'ipv6' if val[/ip/] && afi[/ipv6/]
a = ace_helper(afi, proto: val)
assert_equal(val, a.proto)
@@ -149,6 +149,15 @@ def test_dscp
end
end
+ def test_vlan
+ %w(ipv4 ipv6).each do |afi|
+ %w(10 100).each do |val|
+ a = ace_helper(afi, proto: 'icmp', vlan: val)
+ assert_equal(val, a.vlan)
+ end
+ end
+ end
+
def test_tcp_flags
%w(ipv4 ipv6).each do |afi|
%w(ack fin urg syn psh rst) + [
@@ -187,6 +196,34 @@ def test_log
end
end
+ def test_log_proto_option
+ %w(ipv4 ipv6).each do |afi|
+ refute(ace_helper(afi).log)
+ a = ace_helper(afi, proto: 'icmp', proto_option: 'redirect', log: true)
+ assert(a.log)
+ end
+ end
+
+ def test_proto_option
+ %w(ipv4 ipv6).each do |afi|
+ refute(ace_helper(afi).log)
+ a = ace_helper(afi, proto: 'icmp', proto_option: 'time-exceeded')
+ assert_equal(a.proto_option, 'time-exceeded')
+ a = ace_helper(afi, proto: 'icmp', dscp: 'af11', proto_option: 'echo-reply')
+ assert_equal(a.proto_option, 'echo-reply')
+ assert_equal(a.dscp, 'af11')
+ end
+ end
+
+ def test_redirect_proto_option
+ afi = 'ipv4'
+ val = 'port-channel1,port-channel2'
+ a = ace_helper(afi, proto: 'icmp', proto_option: 'redirect',
+ redirect: val, log: true, set_erspan_dscp: '3', set_erspan_gre_proto: '33')
+ assert_equal(val, a.redirect)
+ assert_equal('redirect', a.proto_option)
+ end
+
def test_precedence
afi = 'ipv4'
%w(critical flash flash-override immediate internet network
@@ -244,4 +281,24 @@ def test_ttl_ipv6
'CSCuy47463: access-list ttl does not nvgen') if a.ttl.nil?
assert_equal(val, a.ttl)
end
+
+ def test_set_erspan_dscp
+ afi = 'ipv4'
+ val = 'port-channel1,port-channel2'
+ a = ace_helper(afi, proto: 'icmp', proto_option: 'redirect',
+ redirect: val, log: true, set_erspan_dscp: '3', set_erspan_gre_proto: '33')
+ assert_equal('redirect', a.proto_option)
+ assert_equal(val, a.redirect)
+ assert_equal('3', a.set_erspan_dscp)
+ end
+
+ def test_set_erspan_gre_proto
+ afi = 'ipv4'
+ val = 'port-channel1,port-channel2'
+ a = ace_helper(afi, proto: 'icmp', proto_option: 'redirect',
+ redirect: val, log: true, set_erspan_gre_proto: '33')
+ assert_equal('redirect', a.proto_option)
+ assert_equal(val, a.redirect)
+ assert_equal('33', a.set_erspan_gre_proto)
+ end
end
diff --git a/tests/test_banner.rb b/tests/test_banner.rb
new file mode 100644
index 00000000..3d5b853c
--- /dev/null
+++ b/tests/test_banner.rb
@@ -0,0 +1,85 @@
+#
+# Minitest for Banner class
+#
+# Copyright (c) 2014-2018 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/banner'
+
+# TestBanner - Minitest for Banner node utility.
+class TestBanner < CiscoTestCase
+ def setup
+ # setup runs at the beginning of each test
+ super
+ no_motd
+ end
+
+ def teardown
+ # teardown runs at the end of each test
+ no_motd
+ super
+ end
+
+ def no_motd
+ # Turn the feature off for a clean test.
+ config('no banner motd')
+ end
+
+ # TESTS
+
+ def test_single_motd
+ id = 'default'
+
+ banner = Cisco::Banner.new(id)
+ assert_includes(Cisco::Banner.banners, id)
+ assert_equal(Cisco::Banner.banners[id], banner)
+
+ assert_equal(banner.default_motd, Cisco::Banner.banners['default'].motd)
+ assert_equal(banner.default_motd, banner.motd)
+
+ banner.motd = 'Test banner!'
+ assert_equal(Cisco::Banner.banners['default'].motd,
+ 'Test banner!')
+ assert_equal(Cisco::Banner.banners['default'].motd,
+ banner.motd)
+
+ banner.motd = nil
+ assert_equal(banner.default_motd, Cisco::Banner.banners['default'].motd)
+ assert_equal(banner.default_motd, banner.motd)
+ end
+
+ def test_multiline_motd
+ skip_versions = ['7.0.3.I[2-6]', '7.0.3.I7.[1-3]', '7.3', '8.[1-3]']
+ skip_legacy_defect?(skip_versions, 'multiline banner configuration using nxapi not supported')
+ id = 'default'
+
+ banner = Cisco::Banner.new(id)
+ assert_includes(Cisco::Banner.banners, id)
+ assert_equal(Cisco::Banner.banners[id], banner)
+
+ assert_equal(banner.default_motd, Cisco::Banner.banners['default'].motd)
+ assert_equal(banner.default_motd, banner.motd)
+
+ banner.motd = 'This is\na sweet\n\nmultiline\nbanner!\n'
+ assert_equal(Cisco::Banner.banners['default'].motd,
+ "This is\na sweet\n\nmultiline\nbanner!\n")
+ assert_equal(Cisco::Banner.banners['default'].motd,
+ banner.motd)
+
+ banner.motd = nil
+ assert_equal(banner.default_motd, Cisco::Banner.banners['default'].motd)
+ assert_equal(banner.default_motd, banner.motd)
+ end
+end
diff --git a/tests/test_bgp_af.rb b/tests/test_bgp_af.rb
index 120167cc..4dae7284 100644
--- a/tests/test_bgp_af.rb
+++ b/tests/test_bgp_af.rb
@@ -175,7 +175,7 @@ def check_test_exceptions(test_, os_, vrf_, af_)
expect = :runtime if test == :additional_paths_receive && Platform.image_version[/8.0|8.1/]
when /I5.2|I5.3|I6/
expect = :success if test == :maximum_paths || test == :maximum_paths_ibgp
- when /I7/
+ when /I7|9\.2/
expect = :success if test == :maximum_paths ||
test == :maximum_paths_ibgp ||
test == :additional_paths_send ||
diff --git a/tests/test_hostname.rb b/tests/test_hostname.rb
new file mode 100644
index 00000000..097451f9
--- /dev/null
+++ b/tests/test_hostname.rb
@@ -0,0 +1,64 @@
+#
+# Minitest for HostName class
+#
+# Copyright (c) 2014-2018 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/hostname'
+
+# TestHostname - Minitest for SyslogSetting node utility.
+class TestHostName < CiscoTestCase
+ def setup
+ # setup runs at the beginning of each test
+ super
+ hostname_setup
+ end
+
+ def teardown
+ # teardown runs at the end of each test
+ hostname_teardown
+ super
+ end
+
+ @current_hostname = ''
+
+ def hostname_setup
+ hostname_output = Cisco::Client.filter_cli(
+ cli_output: config('show running-config | include ^hostname'),
+ value: /hostname (.*)/)
+ @current_hostname = hostname_output.first unless hostname_output.nil?
+ # Turn the feature off for a clean test.
+ config('no hostname')
+ end
+
+ def hostname_teardown
+ if @current_hostname != ''
+ config("hostname #{@current_hostname}")
+ else
+ config('no hostname')
+ end
+ end
+
+ # TESTS
+
+ def test_hostname_name
+ hostname_setting = Cisco::HostName.new('testhost')
+ assert_equal(Cisco::HostName.hostname['testhost'], hostname_setting)
+ hostname_setting = Cisco::HostName.new('testhost2')
+ assert_equal(Cisco::HostName.hostname['testhost2'], hostname_setting)
+ hostname_setting.send('hostname=', nil)
+ assert_nil(Cisco::HostName.hostname['testhost2'])
+ end
+end
diff --git a/tests/test_interface.rb b/tests/test_interface.rb
index 73457173..8966b449 100755
--- a/tests/test_interface.rb
+++ b/tests/test_interface.rb
@@ -1,4 +1,4 @@
-# Copyright (c) 2013-2017 Cisco and/or its affiliates.
+# Copyright (c) 2013-2018 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.
@@ -1250,6 +1250,27 @@ def test_ipv4_redirects
'Error: ip redirects default get value mismatch')
end
+ def test_ipv6_redirects
+ interface = create_interface
+ interface.switchport_mode = :disabled if platform == :nexus
+
+ # check default value
+ assert_equal(interface.default_ipv6_redirects, interface.ipv6_redirects,
+ 'Error: ipv6 redirects default get value mismatch')
+
+ # set with value false
+ interface.ipv6_redirects = false
+ assert_equal(interface.ipv6_redirects, false)
+
+ # set with value true
+ interface.ipv6_redirects = true
+ assert_equal(interface.ipv6_redirects, true)
+
+ # get default and set
+ interface.ipv6_redirects = interface.default_ipv6_redirects
+ assert_equal(interface.ipv6_redirects, interface.default_ipv6_redirects)
+ end
+
def config_from_hash(inttype_h)
inttype_h.each do |k, v|
config('feature interface-vlan') if (/^Vlan\d./).match(k.to_s)
diff --git a/tests/test_interface_hsrp_group.rb b/tests/test_interface_hsrp_group.rb
index 4481d26f..967a32c6 100644
--- a/tests/test_interface_hsrp_group.rb
+++ b/tests/test_interface_hsrp_group.rb
@@ -109,8 +109,7 @@ def test_mac_addr
def test_auth_type_clear
skip_legacy_defect?('7.3.0.D1.1', 'CSCuh90262: hsrp indentation')
ihg = create_interface_hsrp_group_ipv4
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
attrs = {}
attrs[:authentication_auth_type] = 'cleartext'
attrs[:authentication_string] = 'Test'
@@ -119,8 +118,7 @@ def test_auth_type_clear
assert_equal('Test', ihg.authentication_string)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
ihg = create_interface_hsrp_group_ipv6
attrs[:authentication_auth_type] = 'cleartext'
@@ -130,8 +128,7 @@ def test_auth_type_clear
assert_equal('Test', ihg.authentication_string)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_auth_type_md5
@@ -147,8 +144,7 @@ def test_auth_type_md5
assert_equal('MyMD5Password', ihg.authentication_string)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
ihg = create_interface_hsrp_group_ipv6
attrs[:authentication_string] = 'MyMD5Password'
ihg.authentication_set(attrs)
@@ -157,8 +153,7 @@ def test_auth_type_md5
assert_equal('MyMD5Password', ihg.authentication_string)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_auth_key_string_enc_0
@@ -178,8 +173,7 @@ def test_auth_key_string_enc_0
assert_equal('7', ihg.authentication_string)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
ihg = create_interface_hsrp_group_ipv6
attrs[:authentication_string] = '7'
ihg.authentication_set(attrs)
@@ -189,8 +183,7 @@ def test_auth_key_string_enc_0
assert_equal('7', ihg.authentication_string)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_auth_key_string_enc_7
@@ -217,8 +210,7 @@ def test_auth_key_string_enc_7
assert_equal('12345678901234567890', ihg.authentication_string)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_auth_key_string_enc_7_compat_timeout_ipv4
@@ -250,8 +242,7 @@ def test_auth_key_string_enc_7_compat_timeout_ipv4
assert_equal(false, ihg.authentication_compatibility)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_auth_key_string_enc_7_compat_timeout_ipv6
@@ -283,8 +274,7 @@ def test_auth_key_string_enc_7_compat_timeout_ipv6
assert_equal(false, ihg.authentication_compatibility)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_auth_key_string_enc_0_compat_timeout_ipv4
@@ -315,8 +305,7 @@ def test_auth_key_string_enc_0_compat_timeout_ipv4
assert_equal(3333, ihg.authentication_timeout)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_auth_key_string_enc_0_compat_timeout_ipv6
@@ -347,8 +336,7 @@ def test_auth_key_string_enc_0_compat_timeout_ipv6
assert_equal(3333, ihg.authentication_timeout)
attrs[:authentication_string] = ihg.default_authentication_string
ihg.authentication_set(attrs)
- assert_equal(ihg.default_authentication_string,
- ihg.authentication_string)
+ assert_nil(ihg.authentication_string)
end
def test_preempt_ipv4
diff --git a/tests/test_ip_multicast.rb b/tests/test_ip_multicast.rb
index 4d3391b6..02eb5826 100644
--- a/tests/test_ip_multicast.rb
+++ b/tests/test_ip_multicast.rb
@@ -38,31 +38,42 @@ def teardown
super
end
- def test_ip_multicast
+ def test_overlay_distributed_dr
+ skip_legacy_defect?('7.0.3.I7.4', 'CSCvk01535')
+
+ ipm = IpMulticast.new
+
+ # Test Defaults
+ have = ipm.overlay_distributed_dr
+ should = ipm.default_overlay_distributed_dr
+ assert_equal(have, should, 'overlay_distributed_dr does not match default value')
+
+ # Test property set
+ ipm.overlay_distributed_dr = true
+ assert_equal(ipm.overlay_distributed_dr, true, 'overlay_distributed_dr was not set')
+
+ # Test property unset
+ ipm.overlay_distributed_dr = false
+ assert_equal(ipm.overlay_distributed_dr, false, 'overlay_distributed_dr was not unset')
+
+ ipm.destroy
+ end
+
+ def test_overlay_spt_only
ipm = IpMulticast.new
- opts = %w(overlay_distributed_dr overlay_spt_only)
- # test defaults
- opts.each do |opt|
- have = ipm.send("#{opt}")
- should = ipm.send("default_#{opt}")
- assert_equal(have, should, "#{opt} doesn't match the default")
- end
+ # Test Defaults
+ have = ipm.overlay_spt_only
+ should = ipm.default_overlay_spt_only
+ assert_equal(have, should, 'overlay_spt_only does not match default value')
- # test property set
- opts.each do |opt|
- ipm.send("#{opt}=", true)
- should = 'ip multicast ' + opt.tr('_', '-')
- assert_equal(ipm.send("#{opt}"), should, "#{opt} was not set")
- end
+ # Test property set
+ ipm.overlay_spt_only = true
+ assert_equal(ipm.overlay_spt_only, true, 'overlay_spt_only was not set')
- # unset property
- opts.each do |opt|
- ipm.send("#{opt}=", false)
- should = false
- assert_equal(ipm.send("#{opt}"), should, "#{opt} was not unset")
- assert_equal(ipm.send("#{opt}"), ipm.send("default_#{opt}"), "#{opt} doesn't match default")
- end
+ # Test property unset
+ ipm.overlay_spt_only = false
+ assert_equal(ipm.overlay_spt_only, false, 'overlay_spt_only was not unset')
ipm.destroy
end
diff --git a/tests/test_nxapi.rb b/tests/test_nxapi.rb
index 94ee27f0..ff8b1235 100644
--- a/tests/test_nxapi.rb
+++ b/tests/test_nxapi.rb
@@ -34,11 +34,19 @@ def all_skipped
def setup
super
+ @device.cmd('configure terminal')
+ @device.cmd('feature nxapi')
+ @device.cmd('nxapi http port 80')
+ @device.cmd('end')
@product_id = Cisco::Node.new.product_id if @product_id.nil?
cleanup
end
def teardown
+ @device.cmd('configure terminal')
+ @device.cmd('feature nxapi')
+ @device.cmd('nxapi http port 80')
+ @device.cmd('end')
cleanup
super
end
@@ -179,10 +187,6 @@ def test_connection_refused
assert_raises Cisco::ConnectionRefused do
client.set(values: 'interface loopback41')
end
- ensure
- @device.cmd('configure terminal')
- @device.cmd('feature nxapi')
- @device.cmd('end')
end
def test_unauthorized
diff --git a/tests/test_syslog_facility.rb b/tests/test_syslog_facility.rb
new file mode 100644
index 00000000..74f4789d
--- /dev/null
+++ b/tests/test_syslog_facility.rb
@@ -0,0 +1,80 @@
+#
+# Minitest for SyslogFacility class
+#
+# Copyright (c) 2014-2018 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/syslog_facility'
+
+# TestSyslogFacility - Minitest for SyslogFacility node utility.
+class TestSyslogFacility < CiscoTestCase
+ def setup
+ # setup runs at the beginning of each test
+ super
+ no_syslogfacility
+ end
+
+ def teardown
+ # teardown runs at the end of each test
+ no_syslogfacility
+ super
+ end
+
+ def no_syslogfacility
+ # Turn the feature off for a clean test.
+ config('no logging level aaa 6',
+ 'no logging level ip igmp 6',
+ 'no logging level routing ipv4 multicast 7')
+ end
+
+ # TESTS
+
+ def test_create_destroy
+ id = 'aaa'
+ refute_includes(Cisco::SyslogFacility.facilities, id)
+
+ facility = Cisco::SyslogFacility.new({ 'facility' => id, 'level' => 6 }, true)
+ assert_includes(Cisco::SyslogFacility.facilities, id)
+ assert_equal(Cisco::SyslogFacility.facilities[id], facility)
+ assert_equal(id, Cisco::SyslogFacility.facilities[id].facility)
+ assert_equal(6, Cisco::SyslogFacility.facilities[id].level)
+
+ facility.destroy
+ refute_includes(Cisco::SyslogFacility.facilities, id)
+ end
+
+ def test_create_destroy_extended
+ id = 'ip igmp'
+ id2 = 'routing ipv4 multicast'
+ refute_includes(Cisco::SyslogFacility.facilities, id)
+ refute_includes(Cisco::SyslogFacility.facilities, id2)
+
+ facility = Cisco::SyslogFacility.new({ 'facility' => id, 'level' => 6 }, true)
+ facility2 = Cisco::SyslogFacility.new({ 'facility' => id2, 'level' => 7 }, true)
+ assert_includes(Cisco::SyslogFacility.facilities, id)
+ assert_equal(Cisco::SyslogFacility.facilities[id], facility)
+ assert_equal(id, Cisco::SyslogFacility.facilities[id].facility)
+ assert_equal(6, Cisco::SyslogFacility.facilities[id].level)
+ assert_includes(Cisco::SyslogFacility.facilities, id2)
+ assert_equal(Cisco::SyslogFacility.facilities[id2], facility2)
+ assert_equal(id2, Cisco::SyslogFacility.facilities[id2].facility)
+ assert_equal(7, Cisco::SyslogFacility.facilities[id2].level)
+
+ facility.destroy
+ facility2.destroy
+ refute_includes(Cisco::SyslogFacility.facilities, id)
+ refute_includes(Cisco::SyslogFacility.facilities, id2)
+ end
+end
diff --git a/tests/test_syslog_server.rb b/tests/test_syslog_server.rb
index c101e3bd..7d188234 100644
--- a/tests/test_syslog_server.rb
+++ b/tests/test_syslog_server.rb
@@ -1,7 +1,7 @@
#
# Minitest for SyslogServer class
#
-# Copyright (c) 2014-2016 Cisco and/or its affiliates.
+# Copyright (c) 2014-2018 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.
@@ -101,7 +101,7 @@ def test_create_options
end
id = '1.2.3.4'
- options = { 'name' => id, 'level' => '4', 'port' => '2154', 'vrf' => 'red' }
+ options = { 'name' => id, 'level' => '4', 'port' => '2154', 'vrf' => 'red', 'facility' => 'local5' }
refute_includes(Cisco::SyslogServer.syslogservers, id)
@@ -111,6 +111,7 @@ def test_create_options
assert_equal('4', Cisco::SyslogServer.syslogservers[id].level)
assert_equal('2154', Cisco::SyslogServer.syslogservers[id].port)
assert_equal('red', Cisco::SyslogServer.syslogservers[id].vrf)
+ assert_equal('local5', Cisco::SyslogServer.syslogservers[id].facility)
server.destroy
refute_includes(Cisco::SyslogServer.syslogservers, id)
diff --git a/tests/test_syslog_settings.rb b/tests/test_syslog_settings.rb
index 542e3d54..144de1f0 100644
--- a/tests/test_syslog_settings.rb
+++ b/tests/test_syslog_settings.rb
@@ -39,7 +39,8 @@ def default_syslogsettings
config('no logging timestamp seconds',
'logging console 2',
'logging monitor 5',
- 'no logging source-interface')
+ 'no logging source-interface',
+ 'no logging logfile')
end
# TESTS
@@ -105,4 +106,18 @@ def test_source_interface
syslog_setting.source_interface = nil
assert_nil(syslog_setting.source_interface)
end
+
+ def test_logfile
+ syslog_setting = Cisco::SyslogSettings.new('default')
+
+ assert_equal('unset', syslog_setting.logfile_name)
+ syslog_setting.send('logfile_name=', 'testlog', 5, 'size 4097')
+ assert_equal('testlog', syslog_setting.logfile_name)
+ assert_equal('5', syslog_setting.logfile_severity_level)
+ assert_equal('4097', syslog_setting.logfile_size)
+ syslog_setting.send('logfile_name=', nil, nil, nil)
+ assert_equal('unset', syslog_setting.logfile_name)
+ assert_nil(syslog_setting.logfile_severity_level)
+ assert_nil(syslog_setting.logfile_size)
+ end
end
diff --git a/tests/yum_package.yaml b/tests/yum_package.yaml
index 1d674469..1e209259 100644
--- a/tests/yum_package.yaml
+++ b/tests/yum_package.yaml
@@ -78,6 +78,11 @@
name: 'nxos.sample-n9k_ALL'
version: '1.0.0-7.0.3.I7.3'
+7_0_3_I7_4_:
+ filename: 'nxos.sample-n9k_ALL-1.0.0-7.0.3.I7.4.lib32_n9000.rpm'
+ name: 'nxos.sample-n9k_ALL'
+ version: '1.0.0-7.0.3.I7.4'
+
7_0_3_F1_1_:
filename: 'nxos.sample-n8k_EOR-1.0.0-7.0.3.F1.1.lib32_nxos.rpm'
name: 'nxos.sample-n8k_EOR'