cisco_node_utils 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -1
- data/CHANGELOG.md +81 -2
- data/CONTRIBUTING.md +2 -17
- data/Gemfile +5 -0
- data/README.md +92 -47
- data/Rakefile +23 -1
- data/bin/git/hooks/hook_lib +7 -0
- data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
- data/bin/git/hooks/pre-commit/rubocop +7 -2
- data/bin/git/hooks/pre-commit/validate-diffs +18 -4
- data/bin/git/hooks/pre-commit/validate-yaml +18 -0
- data/bin/git/update-hooks +64 -6
- data/cisco_node_utils.gemspec +9 -6
- data/docs/README-develop-best-practices.md +149 -50
- data/docs/README-develop-node-utils-APIs.md +92 -42
- data/docs/README-maintainers.md +7 -4
- data/docs/README-test-execution.md +57 -0
- data/docs/cisco_node_utils.yaml.example +30 -0
- data/docs/template-router.rb +4 -0
- data/ext/mkrf_conf.rb +63 -0
- data/lib/.rubocop.yml +2 -2
- data/lib/cisco_node_utils.rb +5 -0
- data/lib/cisco_node_utils/aaa_authentication_login.rb +5 -6
- data/lib/cisco_node_utils/aaa_authorization_service.rb +1 -1
- data/lib/cisco_node_utils/ace.rb +165 -12
- data/lib/cisco_node_utils/acl.rb +2 -1
- data/lib/cisco_node_utils/bgp.rb +184 -21
- data/lib/cisco_node_utils/bgp_af.rb +94 -249
- data/lib/cisco_node_utils/bgp_neighbor.rb +94 -14
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +75 -8
- data/lib/cisco_node_utils/bridge_domain.rb +183 -0
- data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +85 -2
- data/lib/cisco_node_utils/client.rb +35 -0
- data/lib/cisco_node_utils/client/client.rb +234 -0
- data/lib/cisco_node_utils/client/grpc.rb +33 -0
- data/lib/cisco_node_utils/client/grpc/client.rb +311 -0
- data/lib/cisco_node_utils/client/grpc/ems.proto +148 -0
- data/lib/cisco_node_utils/client/grpc/ems.rb +111 -0
- data/lib/cisco_node_utils/client/grpc/ems_services.rb +49 -0
- data/lib/cisco_node_utils/client/nxapi.rb +31 -0
- data/lib/cisco_node_utils/client/nxapi/client.rb +305 -0
- data/lib/cisco_node_utils/client/utils.rb +164 -0
- data/lib/cisco_node_utils/cmd_ref/README_YAML.md +222 -254
- data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +22 -15
- data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/acl.yaml +21 -16
- data/lib/cisco_node_utils/cmd_ref/bgp.yaml +239 -109
- data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +114 -55
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +76 -52
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +106 -62
- data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +71 -0
- data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
- data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +35 -14
- data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +23 -17
- data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +94 -83
- data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +22 -17
- data/lib/cisco_node_utils/cmd_ref/feature.yaml +76 -26
- data/lib/cisco_node_utils/cmd_ref/images.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/interface.yaml +381 -153
- data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +21 -21
- data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +30 -21
- data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +18 -13
- data/lib/cisco_node_utils/cmd_ref/inventory.yaml +26 -31
- data/lib/cisco_node_utils/cmd_ref/itd_device_group.yaml +83 -0
- data/lib/cisco_node_utils/cmd_ref/itd_service.yaml +119 -0
- data/lib/cisco_node_utils/cmd_ref/memory.yaml +17 -6
- data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +10 -3
- data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +17 -5
- data/lib/cisco_node_utils/cmd_ref/ospf.yaml +33 -29
- data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +12 -10
- data/lib/cisco_node_utils/cmd_ref/pim.yaml +16 -19
- data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +40 -25
- data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +17 -12
- data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +71 -35
- data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +10 -5
- data/lib/cisco_node_utils/cmd_ref/show_system.yaml +6 -2
- data/lib/cisco_node_utils/cmd_ref/show_version.yaml +47 -43
- data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +13 -11
- data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +4 -2
- data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +23 -21
- data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +26 -22
- data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +19 -17
- data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +18 -6
- data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +234 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +24 -9
- data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +5 -3
- data/lib/cisco_node_utils/cmd_ref/system.yaml +4 -3
- data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +22 -20
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +27 -15
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +45 -16
- data/lib/cisco_node_utils/cmd_ref/vdc.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/vlan.yaml +60 -32
- data/lib/cisco_node_utils/cmd_ref/vpc.yaml +118 -101
- data/lib/cisco_node_utils/cmd_ref/vrf.yaml +54 -58
- data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +118 -0
- data/lib/cisco_node_utils/cmd_ref/vtp.yaml +19 -25
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +28 -18
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +34 -17
- data/lib/cisco_node_utils/cmd_ref/yum.yaml +6 -4
- data/lib/cisco_node_utils/command_reference.rb +261 -142
- data/lib/cisco_node_utils/constants.rb +33 -0
- data/lib/cisco_node_utils/encapsulation.rb +112 -0
- data/lib/cisco_node_utils/environment.rb +102 -0
- data/lib/cisco_node_utils/evpn_vni.rb +5 -3
- data/lib/cisco_node_utils/exceptions.rb +111 -0
- data/lib/cisco_node_utils/fabricpath_global.rb +52 -35
- data/lib/cisco_node_utils/fabricpath_topology.rb +44 -57
- data/lib/cisco_node_utils/feature.rb +165 -3
- data/lib/cisco_node_utils/interface.rb +1051 -260
- data/lib/cisco_node_utils/interface_channel_group.rb +11 -10
- data/lib/cisco_node_utils/interface_ospf.rb +1 -2
- data/lib/cisco_node_utils/interface_portchannel.rb +4 -12
- data/lib/cisco_node_utils/interface_service_vni.rb +7 -7
- data/lib/cisco_node_utils/itd_device_group.rb +248 -0
- data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
- data/lib/cisco_node_utils/itd_service.rb +523 -0
- data/lib/cisco_node_utils/logger.rb +75 -0
- data/lib/cisco_node_utils/node.rb +62 -192
- data/lib/cisco_node_utils/node_util.rb +56 -10
- data/lib/cisco_node_utils/overlay_global.rb +2 -2
- data/lib/cisco_node_utils/pim.rb +2 -13
- data/lib/cisco_node_utils/pim_group_list.rb +1 -1
- data/lib/cisco_node_utils/pim_rp_address.rb +1 -1
- data/lib/cisco_node_utils/platform.rb +52 -21
- data/lib/cisco_node_utils/portchannel_global.rb +89 -19
- data/lib/cisco_node_utils/radius_server.rb +168 -37
- data/lib/cisco_node_utils/router_ospf.rb +20 -35
- data/lib/cisco_node_utils/router_ospf_vrf.rb +4 -4
- data/lib/cisco_node_utils/snmpserver.rb +1 -6
- data/lib/cisco_node_utils/snmpuser.rb +6 -4
- data/lib/cisco_node_utils/stp_global.rb +676 -0
- data/lib/cisco_node_utils/syslog_server.rb +77 -18
- data/lib/cisco_node_utils/syslog_settings.rb +1 -1
- data/lib/cisco_node_utils/tacacs_server_group.rb +8 -4
- data/lib/cisco_node_utils/tacacs_server_host.rb +115 -25
- data/lib/cisco_node_utils/vdc.rb +12 -0
- data/lib/cisco_node_utils/version.rb +1 -1
- data/lib/cisco_node_utils/vlan.rb +147 -29
- data/lib/cisco_node_utils/vpc.rb +55 -3
- data/lib/cisco_node_utils/vrf.rb +72 -11
- data/lib/cisco_node_utils/vrf_af.rb +114 -29
- data/lib/cisco_node_utils/vtp.rb +34 -52
- data/lib/cisco_node_utils/vxlan_vtep.rb +34 -8
- data/lib/cisco_node_utils/vxlan_vtep_vni.rb +36 -4
- data/lib/minitest/environment_plugin.rb +31 -0
- data/lib/minitest/log_level_plugin.rb +41 -0
- data/spec/client_spec.rb +7 -0
- data/spec/environment_spec.rb +263 -0
- data/spec/grpc_client_spec.rb +23 -0
- data/spec/isolate/all_clients_spec.rb +9 -0
- data/spec/isolate/grpc_only_spec.rb +16 -0
- data/spec/isolate/no_clients_spec.rb +26 -0
- data/spec/isolate/nxapi_only_spec.rb +16 -0
- data/spec/nxapi_client_spec.rb +42 -0
- data/spec/schema.yaml +75 -0
- data/spec/shared_examples_for_clients.rb +14 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/whitespace_spec.rb +10 -0
- data/spec/yaml_spec.rb +42 -0
- data/tests/.rubocop.yml +2 -2
- data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
- data/tests/basetest.rb +96 -36
- data/tests/ciscotest.rb +220 -12
- data/tests/cmd_config.yaml +71 -49
- data/tests/cmd_config_invalid.yaml +1 -1
- data/tests/test_aaa_authentication_login.rb +1 -0
- data/tests/test_aaa_authentication_login_service.rb +9 -0
- data/tests/test_aaa_authorization_service.rb +173 -367
- data/tests/test_ace.rb +171 -100
- data/tests/test_acl.rb +10 -1
- data/tests/test_bgp_af.rb +395 -728
- data/tests/test_bgp_neighbor.rb +274 -115
- data/tests/test_bgp_neighbor_af.rb +178 -77
- data/tests/test_bridge_domain.rb +191 -0
- data/tests/test_bridge_domain_vni.rb +116 -0
- data/tests/test_client_utils.rb +111 -0
- data/tests/test_command_config.rb +9 -5
- data/tests/test_command_reference.rb +380 -102
- data/tests/test_dns_domain.rb +13 -3
- data/tests/test_domain_name.rb +13 -3
- data/tests/test_encapsulation.rb +77 -0
- data/tests/test_evpn_vni.rb +25 -7
- data/tests/test_fabricpath_global.rb +167 -163
- data/tests/test_fabricpath_topology.rb +12 -33
- data/tests/test_feature.rb +215 -0
- data/tests/test_grpc.rb +166 -0
- data/tests/test_interface.rb +585 -344
- data/tests/test_interface_bdi.rb +80 -0
- data/tests/test_interface_channel_group.rb +6 -3
- data/tests/test_interface_ospf.rb +26 -24
- data/tests/test_interface_portchannel.rb +1 -0
- data/tests/test_interface_private_vlan.rb +724 -0
- data/tests/test_interface_service_vni.rb +37 -66
- data/tests/test_interface_svi.rb +98 -101
- data/tests/test_interface_switchport.rb +419 -549
- data/tests/test_itd_device_group.rb +145 -0
- data/tests/test_itd_device_group_node.rb +199 -0
- data/tests/test_itd_service.rb +298 -0
- data/tests/test_logger.rb +43 -0
- data/tests/test_name_server.rb +11 -2
- data/tests/test_node.rb +16 -75
- data/tests/test_node_ext.rb +174 -163
- data/tests/test_node_util.rb +119 -0
- data/tests/test_ntp_config.rb +5 -1
- data/tests/test_ntp_server.rb +2 -2
- data/tests/test_nxapi.rb +221 -0
- data/tests/test_overlay_global.rb +47 -38
- data/tests/test_pim.rb +2 -0
- data/tests/test_pim_group_list.rb +2 -0
- data/tests/test_pim_rp_address.rb +2 -0
- data/tests/test_platform.rb +86 -39
- data/tests/test_portchannel_global.rb +211 -135
- data/tests/test_radius_global.rb +13 -5
- data/tests/test_radius_server.rb +256 -104
- data/tests/test_radius_server_group.rb +2 -0
- data/tests/test_router_bgp.rb +781 -485
- data/tests/test_router_ospf.rb +26 -103
- data/tests/test_router_ospf_vrf.rb +52 -57
- data/tests/test_snmp_notification_receiver.rb +2 -0
- data/tests/test_snmpcommunity.rb +2 -0
- data/tests/test_snmpgroup.rb +2 -0
- data/tests/test_snmpnotification.rb +40 -21
- data/tests/test_snmpserver.rb +2 -0
- data/tests/test_snmpuser.rb +2 -0
- data/tests/test_stp_global.rb +563 -0
- data/tests/test_syslog_server.rb +32 -8
- data/tests/test_syslog_settings.rb +22 -9
- data/tests/test_tacacs_server.rb +32 -27
- data/tests/test_tacacs_server_group.rb +100 -45
- data/tests/test_tacacs_server_host.rb +135 -43
- data/tests/test_vdc.rb +2 -16
- data/tests/test_vlan.rb +106 -54
- data/tests/test_vlan_mt_full.rb +11 -21
- data/tests/test_vlan_private.rb +669 -0
- data/tests/test_vpc.rb +312 -159
- data/tests/test_vrf.rb +122 -113
- data/tests/test_vrf_af.rb +238 -0
- data/tests/test_vtp.rb +58 -102
- data/tests/test_vxlan_vtep.rb +38 -17
- data/tests/test_vxlan_vtep_vni.rb +61 -9
- data/tests/test_yum.rb +49 -25
- metadata +122 -36
- data/lib/cisco_node_utils/cmd_ref/fex.yaml +0 -9
- data/lib/cisco_node_utils/cmd_ref/vni.yaml +0 -76
- data/lib/cisco_node_utils/vni.rb +0 -227
- data/tests/test_vni.rb +0 -106
data/bin/git/hooks/hook_lib
CHANGED
@@ -86,6 +86,13 @@ get_last_version() {
|
|
86
86
|
}
|
87
87
|
export -f get_last_version
|
88
88
|
|
89
|
+
get_staged_ruby_files() {
|
90
|
+
rubocop_target=$(rubocop --list-target-files)
|
91
|
+
staged_files=$(git diff --name-only --staged)
|
92
|
+
echo $(printf "$rubocop_target $staged_files " | tr ' ' '\n' | sort | uniq -d)
|
93
|
+
}
|
94
|
+
export -f get_staged_ruby_files
|
95
|
+
|
89
96
|
add_changelog_diff_link() {
|
90
97
|
local OLD_VERSION=$1
|
91
98
|
local NEW_VERSION=$2
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Check if a staged file has unstaged changes and print a warning
|
4
|
+
|
5
|
+
staged_files = `git diff --name-only --staged`.split(' ')
|
6
|
+
unstaged_files = `git diff --name-only`.split(' ')
|
7
|
+
files = (staged_files << unstaged_files).flatten!
|
8
|
+
|
9
|
+
if files.length != files.uniq.length
|
10
|
+
puts 'Warning: a staged file has unstaged changes!'
|
11
|
+
fd = IO.sysopen('/dev/tty', 'w+')
|
12
|
+
a = IO.new(fd, 'w+')
|
13
|
+
a.print 'Continue anyway? [y/N] '
|
14
|
+
input = a.gets.chomp
|
15
|
+
exit input =~ /^y/i ? 0 : -1
|
16
|
+
end
|
17
|
+
|
18
|
+
exit 0
|
@@ -9,12 +9,17 @@
|
|
9
9
|
# rubocop run of all checks as part of the pre-push hook
|
10
10
|
|
11
11
|
step_name "Running RuboCop lint checks"
|
12
|
-
|
12
|
+
staged_ruby_files=$(get_staged_ruby_files)
|
13
|
+
if [ -z "$staged_ruby_files" ]; then
|
14
|
+
# quit since there are no ruby files to check
|
15
|
+
exit 0
|
16
|
+
fi
|
17
|
+
rubocop --lint $staged_ruby_files
|
13
18
|
check_rc "Please fix RuboCop lint failures before committing."
|
14
19
|
|
15
20
|
# Do a full rubocop run to warn the user, but don't block a commit by it.
|
16
21
|
step_name "Running all RuboCop checks"
|
17
|
-
rubocop
|
22
|
+
rubocop $staged_ruby_files
|
18
23
|
check_rc_optional "Fix all RuboCop failures before pushing upstream"
|
19
24
|
|
20
25
|
exit 0
|
@@ -17,15 +17,29 @@ else
|
|
17
17
|
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
18
18
|
fi
|
19
19
|
|
20
|
+
step_name 'Checking for non-ASCII filenames'
|
20
21
|
# We exploit the fact that the printable range starts at the space character
|
21
22
|
# and ends with tilde.
|
22
23
|
# Note that the use of brackets around a tr range is ok here, (it's
|
23
24
|
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
24
25
|
# the square bracket bytes happen to fall in the designated range.
|
25
|
-
git diff --cached --name-only --diff-filter=A -z $against |
|
26
|
-
|
26
|
+
added_files=$(git diff --cached --name-only --diff-filter=A -z $against | tr '\0' ' ')
|
27
|
+
added_files_array=(`echo $added_files`)
|
28
|
+
# Print the files that have non-ascii text
|
29
|
+
for i in ${added_files_array[@]}; do
|
30
|
+
bad_chars=$(echo -n $i | LC_ALL=C tr -d '[ -~]\0')
|
31
|
+
if [ -n "$bad_chars" ]; then echo $i; fi
|
32
|
+
done
|
33
|
+
# Fail if any non-ASCII characters are discovered
|
34
|
+
(echo -n $added_files | LC_ALL=C tr -d '[ -~]\0' | exit $(wc -c))
|
27
35
|
check_rc "Rename non-ASCII file name(s) before committing"
|
28
36
|
|
37
|
+
step_name 'Checking for trailing whitespace in non-Ruby files'
|
29
38
|
# If there are whitespace errors, print the offending file names and fail.
|
30
|
-
|
31
|
-
|
39
|
+
# Ignore .rb files, as whitespace in these files is managed by Rubocop
|
40
|
+
# Ignore .proto files, as they are generated code
|
41
|
+
non_ruby_files=`git diff --staged --name-only | grep -v \.rb | grep -v \.proto`
|
42
|
+
if [ -n "$non_ruby_files" ]; then
|
43
|
+
! git grep -n -I '\s$' -- $non_ruby_files
|
44
|
+
check_rc "Fix trailing whitespace before committing"
|
45
|
+
fi
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
[ -n "$GIT_DIR" ] || export GIT_DIR="$(git rev-parse --show-toplevel 2>/dev/null)/.git"
|
4
|
+
. "$GIT_DIR"/hooks/hook_lib
|
5
|
+
|
6
|
+
# Run the Kwalify YAML schema validation
|
7
|
+
|
8
|
+
step_name "Validating YAML files"
|
9
|
+
rspec "$REPO_DIR"/spec/yaml_spec.rb
|
10
|
+
check_rc "Please fix YAML schema validation failures before committing"
|
11
|
+
|
12
|
+
# Ensure that command_reference can parse all the YAML as well
|
13
|
+
|
14
|
+
step_name "Checking command_reference YAML parsing"
|
15
|
+
ruby "$REPO_DIR"/tests/test_command_reference.rb
|
16
|
+
check_rc "Please fix command_reference unit test failures before committing"
|
17
|
+
|
18
|
+
exit 0
|
data/bin/git/update-hooks
CHANGED
@@ -12,6 +12,52 @@ HOOK_DIR="$(git rev-parse --show-toplevel)/.git/hooks"
|
|
12
12
|
|
13
13
|
. "$SRC_DIR/hook_lib"
|
14
14
|
|
15
|
+
usage() {
|
16
|
+
echo "Usage: update-hooks [OPTION]"
|
17
|
+
echo "Update the hooks in the local git repository to match those"
|
18
|
+
echo "under version control."
|
19
|
+
echo
|
20
|
+
echo "Options:"
|
21
|
+
echo " --dry-run Do not make any updates"
|
22
|
+
echo " -v --verbose Verbose output, including diffs of updated files"
|
23
|
+
echo " --[no-]pager Explicity request or suppress pagination in git diff"
|
24
|
+
echo " -h --help Display this help text"
|
25
|
+
}
|
26
|
+
|
27
|
+
# Flags that can be set from the command line, with default values
|
28
|
+
make_updates=1 # the inverse of --dry-run
|
29
|
+
verbose=0
|
30
|
+
pager= # default to whatever defaults git has configured
|
31
|
+
|
32
|
+
# parse command line options
|
33
|
+
while [ "$#" -gt 0 ]; do
|
34
|
+
case "$1" in
|
35
|
+
(-h|--help)
|
36
|
+
usage
|
37
|
+
exit 0
|
38
|
+
;;
|
39
|
+
(-v|--verbose)
|
40
|
+
verbose=1
|
41
|
+
;;
|
42
|
+
(--pager)
|
43
|
+
pager=--paginate
|
44
|
+
;;
|
45
|
+
(--no-pager)
|
46
|
+
pager=--no-pager
|
47
|
+
;;
|
48
|
+
(--dry-run)
|
49
|
+
make_updates=0
|
50
|
+
;;
|
51
|
+
(*)
|
52
|
+
echo "Unrecognized option: $1"
|
53
|
+
usage
|
54
|
+
exit 1
|
55
|
+
;;
|
56
|
+
esac
|
57
|
+
shift 1
|
58
|
+
done
|
59
|
+
|
60
|
+
|
15
61
|
install_hook_wrapper() {
|
16
62
|
local hook=$1
|
17
63
|
# Does the symlink exist?
|
@@ -19,11 +65,15 @@ install_hook_wrapper() {
|
|
19
65
|
# If a hook already exists and is a file:
|
20
66
|
if [ -f $HOOK_DIR/$hook ]; then
|
21
67
|
step_name "Moving existing '$hook' script to '$hook-local'"
|
22
|
-
|
68
|
+
if [ $make_updates == 1 ]; then
|
69
|
+
mv $HOOK_DIR/$hook $HOOK_DIR/$hook-local
|
70
|
+
fi
|
23
71
|
fi
|
24
72
|
# create the symlink to our wrapper script
|
25
73
|
step_name "Installing hook wrapper script for '$hook'"
|
26
|
-
|
74
|
+
if [ $make_updates == 1 ]; then
|
75
|
+
ln -s -f ./hooks-wrapper $HOOK_DIR/$hook
|
76
|
+
fi
|
27
77
|
fi
|
28
78
|
}
|
29
79
|
|
@@ -32,14 +82,22 @@ check_update() {
|
|
32
82
|
local dest=$2
|
33
83
|
if [ ! -e "$dest" ] ; then
|
34
84
|
step_name "Creating new file at '$dest':"
|
35
|
-
|
36
|
-
|
85
|
+
if [ $verbose == 1 ]; then
|
86
|
+
git ${pager} diff --color --no-index /dev/null $src
|
87
|
+
fi
|
88
|
+
if [ $make_updates == 1 ]; then
|
89
|
+
cp $src $dest
|
90
|
+
fi
|
37
91
|
else
|
38
92
|
diff $src $dest >> /dev/null
|
39
93
|
if [ $? -ne 0 ] ; then
|
40
94
|
step_name "File '$dest' will be updated: "
|
41
|
-
|
42
|
-
|
95
|
+
if [ $verbose == 1 ]; then
|
96
|
+
git ${pager} diff --color --no-index $dest $src
|
97
|
+
fi
|
98
|
+
if [ $make_updates == 1 ]; then
|
99
|
+
cp -f $src $dest
|
100
|
+
fi
|
43
101
|
fi
|
44
102
|
fi
|
45
103
|
}
|
data/cisco_node_utils.gemspec
CHANGED
@@ -6,15 +6,15 @@ require 'cisco_node_utils/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'cisco_node_utils'
|
8
8
|
spec.version = CiscoNodeUtils::VERSION
|
9
|
-
spec.authors = ['Alex Hunsberger', 'Glenn Matthews',
|
10
|
-
'Chris Van Heuveln', '
|
11
|
-
'
|
9
|
+
spec.authors = ['Rob Gries', 'Alex Hunsberger', 'Glenn Matthews',
|
10
|
+
'Chris Van Heuveln', 'Rich Wellum', 'Mike Wiebe',
|
11
|
+
'Jie Yang']
|
12
12
|
spec.email = 'cisco_agent_gem@cisco.com'
|
13
13
|
spec.summary = 'Utilities for management of Cisco network nodes'
|
14
14
|
spec.description = <<-EOF
|
15
15
|
Utilities for management of Cisco network nodes.
|
16
16
|
Designed to work with Puppet and Chef.
|
17
|
-
Currently supports NX-OS nodes.
|
17
|
+
Currently supports NX-OS and IOS XR nodes.
|
18
18
|
EOF
|
19
19
|
spec.license = 'Apache-2.0'
|
20
20
|
spec.homepage = 'https://github.com/cisco/cisco-network-node-utils'
|
@@ -28,10 +28,13 @@ Currently supports NX-OS nodes.
|
|
28
28
|
spec.required_ruby_version = '>= 2.0.0'
|
29
29
|
spec.required_rubygems_version = '>= 2.1.0'
|
30
30
|
|
31
|
-
spec.add_development_dependency 'minitest', '~> 5.0'
|
32
31
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
32
|
+
spec.add_development_dependency 'kwalify', '~> 0.7.2'
|
33
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
33
34
|
spec.add_development_dependency 'rake', '~> 10.0'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
34
36
|
spec.add_development_dependency 'rubocop', '= 0.35.1'
|
35
37
|
spec.add_development_dependency 'simplecov', '~> 0.9'
|
36
|
-
|
38
|
+
|
39
|
+
spec.extensions = ['ext/mkrf_conf.rb']
|
37
40
|
end
|
@@ -14,24 +14,25 @@ This document is intended to assist in developing cisco_node_utils API's that ar
|
|
14
14
|
|
15
15
|
* [Y1](#yaml1): One feature per YAML file
|
16
16
|
* [Y2](#yaml2): All attribute entries must be kept in alphabetical order.
|
17
|
-
* [Y3](#yaml3): Use *regexp* anchors where needed for `
|
17
|
+
* [Y3](#yaml3): Use *regexp* anchors where needed for CLI `get_context` and `get_value` entries.
|
18
18
|
* [Y4](#yaml4): Avoid nested optional matches.
|
19
19
|
* [Y5](#yaml5): Use the `_template` feature when getting/setting the same property value at multiple levels.
|
20
20
|
* [Y6](#yaml6): When possible include a `default_value` that represents the system default value.
|
21
|
-
* [Y7](#yaml7): When possible, use the same `
|
21
|
+
* [Y7](#yaml7): When possible, use the same `get_command` for all properties and document any anomalies.
|
22
22
|
* [Y8](#yaml8): Use Key-value wildcards instead of Printf-style wildcards.
|
23
|
-
* [Y9](#yaml9): Selection of `show` commands for `
|
23
|
+
* [Y9](#yaml9): Selection of `show` commands for `get_command`.
|
24
24
|
* [Y10](#yaml10): Use `true` and `false` for boolean values.
|
25
|
-
|
26
|
-
|
25
|
+
* [Y11](#yaml11): Use YAML anchors and aliases to avoid redundant entries.
|
26
|
+
* [Y12](#yaml12): Use `_exclude` to return `nil` for unsupported properties.
|
27
27
|
|
28
28
|
## <a name="odbp">Common Object Development Best Practices</a>
|
29
29
|
|
30
30
|
* [CO1](#co1): Features that can be configured under the global and non-global vrfs need to account for this in the object design.
|
31
31
|
* [CO2](#co2): Make use of the equality operator allowing proper `instance1 == instance2` checks in the minitests.
|
32
32
|
* [CO3](#co3): Use `''` rather than `nil` to represent "property is absent entirely"
|
33
|
-
* [CO4](#co4): Make sure all new
|
33
|
+
* [CO4](#co4): Make sure all new properties have a `getter`, `setter` and `default_getter` method.
|
34
34
|
* [CO5](#co5): Use singleton-like design for resources that cannot have multiple instances.
|
35
|
+
* [CO6](#co6): Implement a meaningful `to_s` method
|
35
36
|
|
36
37
|
## <a name="mdbp">MiniTest Development Best Practices</a>
|
37
38
|
|
@@ -40,7 +41,7 @@ This document is intended to assist in developing cisco_node_utils API's that ar
|
|
40
41
|
* [MT3](#mt3): Do not hardcode interface names.
|
41
42
|
* [MT4](#mt4): Make use of the `config` helper method for device configuration instead of `@device.cmd`.
|
42
43
|
* [MT5](#mt5): Make use of the `assert_show_match` and `refute_show_match` helper methods to validate expected outcomes in the CLI instead of `@device.cmd("show...")`.
|
43
|
-
|
44
|
+
* [MT6](#mt6): Unsupported properties must include negative test cases.
|
44
45
|
|
45
46
|
|
46
47
|
## YAML Best Practices:
|
@@ -55,16 +56,18 @@ All attribute entries in a given YAML file must be kept in alphabetical order. A
|
|
55
56
|
|
56
57
|
This rule is enforced by the `Cisco::CommandReference` class itself - it will raise an exception if it detects any out-of-order entries.
|
57
58
|
|
58
|
-
### <a name="yaml3">Y3: Use *regexp* anchors where needed for `
|
59
|
+
### <a name="yaml3">Y3: Use *regexp* anchors where needed for CLI `get_context` and `get_value` entries.
|
59
60
|
|
60
|
-
|
61
|
+
By default, CLI clients assume that `get_context` and `get_value` are to be treated as Regexps, and implicitly add regexp anchors and case-insensitivity (i.e., a `get_value` of `'router bgp 100'` becomes the regexp `/^router bgp 100$/i`). If you want to explicitly specify a regexp (perhaps because the default behavior does not meet your needs for a specific property), be sure to add the `^` and `$` anchors to ensure you match the correct feature information in the `show` output and do not unexpectedly match similar but undesired CLI strings.
|
61
62
|
|
62
63
|
```yaml
|
63
64
|
# syslog_settings.yaml
|
64
65
|
timestamp:
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
get_command: "show running-config all | include '^logging timestamp'"
|
67
|
+
get_value: 'logging timestamp (.*)'
|
68
|
+
# this is equivalent to:
|
69
|
+
# get_value: '/^logging timestamp (.*)$/'
|
70
|
+
set_value: '<state> logging timestamp <units>'
|
68
71
|
default_value: 'seconds'
|
69
72
|
```
|
70
73
|
|
@@ -77,18 +80,20 @@ One case where this may crop up is in trying to match both affirmative and
|
|
77
80
|
negative variants of a config command:
|
78
81
|
|
79
82
|
```yaml
|
80
|
-
|
83
|
+
get_context: ['interface <name>']
|
84
|
+
get_value: '((no )?switchport)'
|
81
85
|
|
82
|
-
|
86
|
+
get_value: '(no)? ?ip tacacs source-interface ?(\S+)?'
|
83
87
|
```
|
84
88
|
|
85
89
|
Instead, match the affirmative form of a command and treat its absence as
|
86
90
|
confirmation of the negative form:
|
87
91
|
|
88
92
|
```yaml
|
89
|
-
|
93
|
+
get_context: ['interface <name>']
|
94
|
+
get_value: 'switchport'
|
90
95
|
|
91
|
-
|
96
|
+
get_value: 'tacacs-server source-interface (\S+)'
|
92
97
|
```
|
93
98
|
|
94
99
|
### <a name="yaml5">Y5: Use the `_template` feature when getting/setting the same property value at multiple levels.
|
@@ -98,22 +103,19 @@ Using the template below, `auto_cost` and `default_metric` can be set under `rou
|
|
98
103
|
```yaml
|
99
104
|
# ospf.yaml
|
100
105
|
_template:
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
- '
|
105
|
-
config_set: "router ospf <name>"
|
106
|
-
config_set_append:
|
107
|
-
- "vrf <vrf>"
|
106
|
+
get_command: "show running ospf all"
|
107
|
+
context:
|
108
|
+
- 'router ospf <name>'
|
109
|
+
- '(?)vrf <vrf>'
|
108
110
|
|
109
111
|
auto_cost:
|
110
|
-
|
111
|
-
|
112
|
+
get_value: 'auto-cost reference-bandwidth (\d+)\s*(\S+)?'
|
113
|
+
set_value: "auto-cost reference-bandwidth <cost> <type>"
|
112
114
|
default_value: [40, "Gbps"]
|
113
115
|
|
114
116
|
default_metric:
|
115
|
-
|
116
|
-
|
117
|
+
get_value: 'default-metric (\d+)?'
|
118
|
+
set_value: "<state> default-metric <metric>"
|
117
119
|
default_value: 0
|
118
120
|
```
|
119
121
|
|
@@ -126,20 +128,22 @@ Default value for `message_digest_alg_type` is `md5`
|
|
126
128
|
|
127
129
|
```yaml
|
128
130
|
message_digest_alg_type:
|
129
|
-
|
130
|
-
|
131
|
+
get_command: 'show running interface all'
|
132
|
+
get_context: 'interface <name>'
|
133
|
+
get_value: '/^\s*ip ospf message-digest-key \d+ (\S+)/'
|
131
134
|
default_value: 'md5'
|
132
135
|
```
|
133
136
|
|
134
137
|
**NOTE1: Use strings rather then symbols when applicable**.
|
135
138
|
|
136
|
-
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
|
139
|
+
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:
|
137
140
|
|
138
141
|
```yaml
|
139
142
|
message_digest_alg_type:
|
140
|
-
|
141
|
-
|
142
|
-
/
|
143
|
+
get_command: 'show running interface all'
|
144
|
+
get_context: 'interface <name>'
|
145
|
+
get_value: '/^\s*ip ospf message-digest-key \d+ (\S+)/'
|
146
|
+
N9k:
|
143
147
|
default_value: 'sha2'
|
144
148
|
else:
|
145
149
|
default_value: 'md5'
|
@@ -147,33 +151,33 @@ message_digest_alg_type:
|
|
147
151
|
|
148
152
|
See [README_YAML](../lib/cisco_node_utils/cmd_ref/README_YAML.md) for more details about this advanced feature.
|
149
153
|
|
150
|
-
### <a name="yaml7">Y7: When possible, use the same `
|
154
|
+
### <a name="yaml7">Y7: When possible, use the same `get_command` for all properties and document any anomalies.
|
151
155
|
|
152
156
|
All properties below use the `show run tacacs all` command except `directed_request` which is documented.
|
153
157
|
|
154
158
|
```yaml
|
155
159
|
# tacacs_server.yaml
|
160
|
+
_template:
|
161
|
+
get_command: "show run tacacs all"
|
162
|
+
|
156
163
|
deadtime:
|
157
|
-
|
158
|
-
|
159
|
-
config_set: "<state> tacacs-server deadtime <time>"
|
164
|
+
get_value: '/^tacacs-server deadtime\s+(\d+)/'
|
165
|
+
set_value: "<state> tacacs-server deadtime <time>"
|
160
166
|
default_value: 0
|
161
167
|
|
162
168
|
directed_request:
|
163
169
|
# oddly, directed request must be retrieved from aaa output
|
164
|
-
|
165
|
-
|
166
|
-
|
170
|
+
get_command: "show running aaa all"
|
171
|
+
get_value: '/(?:no)?\s*tacacs-server directed-request/'
|
172
|
+
set_value: "<state> tacacs-server directed-request"
|
167
173
|
default_value: false
|
168
174
|
|
169
175
|
encryption_type:
|
170
|
-
|
171
|
-
config_get_token: '/^tacacs-server key (\d+)\s+(\S+)/'
|
176
|
+
get_value: '/^tacacs-server key (\d+)\s+(\S+)/'
|
172
177
|
default_value: 0
|
173
178
|
|
174
179
|
encryption_password:
|
175
|
-
|
176
|
-
config_get_token: '/^tacacs-server key (\d+)\s+(\S+)/'
|
180
|
+
get_value: '/^tacacs-server key (\d+)\s+(\S+)/'
|
177
181
|
default_value: ""
|
178
182
|
```
|
179
183
|
|
@@ -184,7 +188,7 @@ Key-value wildcards are moderately more complex to implement than Printf-style w
|
|
184
188
|
**Key-value wildcards**
|
185
189
|
|
186
190
|
```yaml
|
187
|
-
|
191
|
+
get_value: "<state> log-adjacency-changes <type>"
|
188
192
|
```
|
189
193
|
|
190
194
|
This following 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.
|
@@ -192,10 +196,10 @@ This following approach is quick to implement and concise, but less flexible - i
|
|
192
196
|
**Printf-style wildcards**
|
193
197
|
|
194
198
|
```yaml
|
195
|
-
|
199
|
+
get_value: "%s log-adjacency-changes %s"
|
196
200
|
```
|
197
201
|
|
198
|
-
### <a name="yaml9">Y9: Selection of `show` commands for `
|
202
|
+
### <a name="yaml9">Y9: Selection of `show` commands for `get_command`.
|
199
203
|
|
200
204
|
The following commands should be preferred over `show [feature]` commands since not all `show [feature]` commands behave in the same manner across cisco platforms.
|
201
205
|
|
@@ -206,6 +210,48 @@ The following commands should be preferred over `show [feature]` commands since
|
|
206
210
|
|
207
211
|
YAML allows various synonyms for `true` and `false` such as `yes` and `no`, but for consistency and readability (especially to users more familiar with Ruby than with YAML), we recommend using `true` and `false` rather than any of their synonyms.
|
208
212
|
|
213
|
+
### <a name="yaml11">Y11: Use YAML anchors and aliases to avoid redundant entries.
|
214
|
+
|
215
|
+
Use the standard YAML functionality of [node anchors](http://www.yaml.org/spec/1.2/spec.html#id2785586) and [node aliases](http://www.yaml.org/spec/1.2/spec.html#id2786196) to avoid redundant entries. In other words, instead of:
|
216
|
+
|
217
|
+
```yaml
|
218
|
+
vn_segment_vlan_based:
|
219
|
+
# MT-lite only
|
220
|
+
N3k:
|
221
|
+
kind: boolean
|
222
|
+
config_get: 'show running section feature'
|
223
|
+
config_get_token: '/^feature vn-segment-vlan-based$/'
|
224
|
+
config_set: 'feature vn-segment-vlan-based'
|
225
|
+
default_value: false
|
226
|
+
N9k:
|
227
|
+
# same as N3k
|
228
|
+
kind: boolean
|
229
|
+
config_get: 'show running section feature'
|
230
|
+
config_get_token: '/^feature vn-segment-vlan-based$/'
|
231
|
+
config_set: 'feature vn-segment-vlan-based'
|
232
|
+
default_value: false
|
233
|
+
```
|
234
|
+
|
235
|
+
instead you can do:
|
236
|
+
|
237
|
+
```yaml
|
238
|
+
vn_segment_vlan_based:
|
239
|
+
# MT-lite only
|
240
|
+
N3k: &vn_segment_vlan_based_mt_lite
|
241
|
+
kind: boolean
|
242
|
+
config_get: 'show running section feature'
|
243
|
+
config_get_token: '/^feature vn-segment-vlan-based$/'
|
244
|
+
config_set: 'feature vn-segment-vlan-based'
|
245
|
+
default_value: false
|
246
|
+
N9k: *vn_segment_vlan_based_mt_lite
|
247
|
+
```
|
248
|
+
|
249
|
+
### <a name="yaml12">Y12: Use `_exclude` to return `nil` for unsupported properties.
|
250
|
+
|
251
|
+
Some properties are only applicable to specific platforms. Rather than using `default_only` to specify an 'unconfigured' default like `''` or `false`, it is more accurate to return `nil` for a property that is not applicable at all. By returning `nil`, the property will not even appear in commands like `puppet resource`, which is the desired outcome.
|
252
|
+
|
253
|
+
Rather than specifying `default_only: nil`, the most straightforward and self-evident way to mark a property as unsupported is to use the `_exclude: [my_platform]` YAML tag. See [README_YAML.md](../lib/cisco_node_utils/cmd_ref/README_YAML.md#_exclude) for more details about the `_exclude` tag.
|
254
|
+
|
209
255
|
## Common Object Best Practices:
|
210
256
|
|
211
257
|
### <a name="co1">CO1: Features that can be configured under the global and non-global vrfs need to account for this in the object design.
|
@@ -319,7 +365,7 @@ def access_vlan=(vlan)
|
|
319
365
|
config_set('interface', 'access_vlan', @name, vlan)
|
320
366
|
```
|
321
367
|
|
322
|
-
### <a name="co4">CO4: Make sure all new
|
368
|
+
### <a name="co4">CO4: Make sure all new properties have a `getter`, `setter` and `default_getter` method.
|
323
369
|
|
324
370
|
In order to have a complete set of api's for each property it is important that all properties have a `getter`, `setter` and `default_getter` method.
|
325
371
|
|
@@ -356,10 +402,49 @@ end
|
|
356
402
|
|
357
403
|
See [TacacsServer](../lib/cisco_node_utils/tacacs_server.rb) and [SnmpServer](../lib/cisco_node_utils/snmpserver.rb) for examples.
|
358
404
|
|
405
|
+
### <a name="co6">CO6: Implement a meaningful `to_s` method
|
406
|
+
|
407
|
+
Request errors generated by a `NodeUtil` subclass calling `config_get` or `config_set` will automatically prepend the output of the class's `to_s` method. The default output of this method is not especially helpful as it just identifies the class name:
|
408
|
+
|
409
|
+
```
|
410
|
+
Cisco::CliError: [#<Cisco::Bgp:0x007f1b3b7af5a0>] The command 'foobar shutdown' was rejected with error:
|
411
|
+
...
|
412
|
+
```
|
413
|
+
|
414
|
+
But by implementing the `to_s` method:
|
415
|
+
|
416
|
+
```ruby
|
417
|
+
module Cisco
|
418
|
+
# RouterBgp - node utility class for BGP general config management
|
419
|
+
class RouterBgp < NodeUtil
|
420
|
+
attr_reader :asnum, :vrf
|
421
|
+
...
|
422
|
+
def to_s
|
423
|
+
"BGP #{asnum} VRF '#{vrf}'"
|
424
|
+
end
|
425
|
+
```
|
426
|
+
|
427
|
+
The error output can now clearly identify the instance that failed:
|
428
|
+
|
429
|
+
```
|
430
|
+
Cisco::CliError: [BGP 100 VRF 'red'] The command 'foobar shutdown' was rejected with error:
|
431
|
+
...
|
432
|
+
```
|
433
|
+
|
359
434
|
## MiniTest Best Practices:
|
360
435
|
|
361
436
|
### <a name="mt1">MT1: Ensure that *all new API's* have minitest coverage.
|
362
437
|
|
438
|
+
Running minitest will automatically produce code coverage results using the [SimpleCov](http://www.rubydoc.info/gems/simplecov) Gem:
|
439
|
+
|
440
|
+
```
|
441
|
+
test_interface:
|
442
|
+
39 runs, 316 assertions, 0 failures, 0 errors, 2 skips
|
443
|
+
Coverage report generated for MiniTest to cisco-network-node-utils/coverage. 602 / 814 LOC (73.96%) covered.
|
444
|
+
```
|
445
|
+
|
446
|
+
If you are adding new APIs, after running the tests, you should inspect the coverage results (open `coverage/index.html` with a web browser) to ensure that your new APIs are being exercised appropriately by your new tests.
|
447
|
+
|
363
448
|
### <a name="mt2">MT2: Use appropriate `assert_foo` and `refute_foo` statements rather than `assert_equal`.
|
364
449
|
|
365
450
|
|
@@ -377,8 +462,7 @@ The more specific assertions also produce more helpful failure messages if somet
|
|
377
462
|
|
378
463
|
### <a name="mt3">MT3: Do not hardcode interface names.
|
379
464
|
|
380
|
-
Rather then hardcode an interface name that may or may not exist, instead use
|
381
|
-
the `interfaces[]` array.
|
465
|
+
Rather then hardcode an interface name that may or may not exist, instead use the `interfaces[]` array.
|
382
466
|
|
383
467
|
```ruby
|
384
468
|
def create_interface(ifname=interfaces[0])
|
@@ -420,3 +504,18 @@ refute_output_match(pattern: /interface port-channel 11/)
|
|
420
504
|
refute_output_match(pattern: /interface port-channel 12/)
|
421
505
|
assert_output_match(pattern: /interface port-channel 13/)
|
422
506
|
```
|
507
|
+
|
508
|
+
### <a name="mt6">MT6: Unsupported properties must include negative test cases.
|
509
|
+
|
510
|
+
Some properties are only applicable to a particular platform and are unsupported on other platforms. To ensure that this lack of support is properly validated, at least one of the test cases for this property should include tests of the getter and default methods and a negative test for the setter method. If you followed [Y11](#yaml11), this means checking that the getter and default methods return `nil` and the setter method raises a `Cisco::UnsupportedError`:
|
511
|
+
|
512
|
+
```ruby
|
513
|
+
def test_foo_bar
|
514
|
+
if platform == :platform_not_supporting_bar
|
515
|
+
assert_nil(foo.bar)
|
516
|
+
assert_nil(foo.default_bar)
|
517
|
+
assert_raises(Cisco::UnsupportedError) { foo.bar = baz }
|
518
|
+
else
|
519
|
+
# tests for foo.bar on a platform that supports this
|
520
|
+
...
|
521
|
+
```
|