├── .gitignore ├── .rspec ├── .rubocop.yml ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── SUPPORT.md ├── bin ├── .rubocop.yml ├── check_metric_limits.rb ├── git │ ├── hooks │ │ ├── commit-msg │ │ │ └── enforce_style │ │ ├── hook_lib │ │ ├── hooks-wrapper │ │ ├── post-flow-hotfix-start │ │ │ └── update-version │ │ ├── post-flow-release-finish │ │ │ └── update-version │ │ ├── post-flow-release-start │ │ │ └── update-version │ │ ├── post-merge │ │ │ └── update-hooks │ │ ├── post-rewrite │ │ │ └── update-hooks │ │ ├── pre-commit │ │ │ ├── check_unstaged_changes │ │ │ ├── rubocop │ │ │ ├── validate-diffs │ │ │ └── validate-yaml │ │ └── pre-push │ │ │ ├── check-changelog │ │ │ └── rubocop │ └── update-hooks └── show_running_yang.rb ├── cisco_node_utils.gemspec ├── docs ├── README-develop-best-practices.md ├── README-develop-node-utils-APIs.md ├── README-maintainers.md ├── README-test-execution.md ├── README-utilities.md ├── agent_files.png ├── cisco_node_utils.yaml.example ├── template-router.rb └── template-test_router.rb ├── ext └── mkrf_conf.rb ├── lib ├── .rubocop.yml ├── cisco_node_utils.rb ├── cisco_node_utils │ ├── aaa_authentication_login.rb │ ├── aaa_authentication_login_service.rb │ ├── aaa_authorization_service.rb │ ├── ace.rb │ ├── acl.rb │ ├── banner.rb │ ├── bfd_global.rb │ ├── bgp.rb │ ├── bgp_af.rb │ ├── bgp_af_aggr_addr.rb │ ├── bgp_neighbor.rb │ ├── bgp_neighbor_af.rb │ ├── bridge_domain.rb │ ├── bridge_domain_vni.rb │ ├── cisco_cmn_utils.rb │ ├── client.rb │ ├── client │ │ ├── client.rb │ │ ├── grpc.rb │ │ ├── grpc │ │ │ ├── client.rb │ │ │ ├── ems.proto │ │ │ ├── ems.rb │ │ │ └── ems_services.rb │ │ ├── nxapi.rb │ │ ├── nxapi │ │ │ └── client.rb │ │ └── utils.rb │ ├── cmd_ref │ │ ├── README_YAML.md │ │ ├── aaa_auth_login_service.yaml │ │ ├── aaa_authentication_login.yaml │ │ ├── aaa_authorization_service.yaml │ │ ├── acl.yaml │ │ ├── banner.yaml │ │ ├── bfd_global.yaml │ │ ├── bgp.yaml │ │ ├── bgp_af.yaml │ │ ├── bgp_af_aa.yaml │ │ ├── bgp_neighbor.yaml │ │ ├── bgp_neighbor_af.yaml │ │ ├── bridge_domain.yaml │ │ ├── bridge_domain_vni.yaml │ │ ├── dhcp_relay_global.yaml │ │ ├── dnsclient.yaml │ │ ├── encapsulation.yaml │ │ ├── evpn_multicast.yaml │ │ ├── evpn_multisite.yaml │ │ ├── evpn_stormcontrol.yaml │ │ ├── evpn_vni.yaml │ │ ├── fabricpath.yaml │ │ ├── fabricpath_topology.yaml │ │ ├── feature.yaml │ │ ├── hostname.yaml │ │ ├── hsrp_global.yaml │ │ ├── images.yaml │ │ ├── interface.yaml │ │ ├── interface_channel_group.yaml │ │ ├── interface_evpn_multisite.yaml │ │ ├── interface_hsrp_group.yaml │ │ ├── interface_ospf.yaml │ │ ├── interface_portchannel.yaml │ │ ├── interface_service_vni.yaml │ │ ├── inventory.yaml │ │ ├── ip_multicast.yaml │ │ ├── itd_device_group.yaml │ │ ├── itd_service.yaml │ │ ├── memory.yaml │ │ ├── ntp_auth_key.yaml │ │ ├── ntp_config.yaml │ │ ├── ntp_server.yaml │ │ ├── object_group.yaml │ │ ├── ospf.yaml │ │ ├── ospf_area.yaml │ │ ├── ospf_area_vlink.yaml │ │ ├── overlay_global.yaml │ │ ├── pim.yaml │ │ ├── portchannel_global.yaml │ │ ├── radius_global.yaml │ │ ├── radius_server.yaml │ │ ├── radius_server_group.yaml │ │ ├── route_map.yaml │ │ ├── show_system.yaml │ │ ├── show_version.yaml │ │ ├── snmp_community.yaml │ │ ├── snmp_group.yaml │ │ ├── snmp_notification_receiver.yaml │ │ ├── snmp_server.yaml │ │ ├── snmp_user.yaml │ │ ├── snmpnotification.yaml │ │ ├── span_session.yaml │ │ ├── stp_global.yaml │ │ ├── syslog_facility.yaml │ │ ├── syslog_server.yaml │ │ ├── syslog_settings.yaml │ │ ├── system.yaml │ │ ├── tacacs_global.yaml │ │ ├── tacacs_server.yaml │ │ ├── tacacs_server_group.yaml │ │ ├── tacacs_server_host.yaml │ │ ├── upgrade.yaml │ │ ├── vdc.yaml │ │ ├── virtual_service.yaml │ │ ├── vlan.yaml │ │ ├── vpc.yaml │ │ ├── vrf.yaml │ │ ├── vrf_af.yaml │ │ ├── vtp.yaml │ │ ├── vxlan_vtep.yaml │ │ ├── vxlan_vtep_vni.yaml │ │ ├── yang.yaml │ │ └── yum.yaml │ ├── command_reference.rb │ ├── configparser_lib.rb │ ├── constants.rb │ ├── dhcp_relay_global.rb │ ├── dns_domain.rb │ ├── domain_name.rb │ ├── encapsulation.rb │ ├── environment.rb │ ├── evpn_multicast.rb │ ├── evpn_multisite.rb │ ├── evpn_stormcontrol.rb │ ├── evpn_vni.rb │ ├── exceptions.rb │ ├── fabricpath_global.rb │ ├── fabricpath_topology.rb │ ├── feature.rb │ ├── hostname.rb │ ├── hsrp_global.rb │ ├── interface.rb │ ├── interface_channel_group.rb │ ├── interface_evpn_multisite.rb │ ├── interface_hsrp_group.rb │ ├── interface_ospf.rb │ ├── interface_portchannel.rb │ ├── interface_service_vni.rb │ ├── ip_multicast.rb │ ├── itd_device_group.rb │ ├── itd_device_group_node.rb │ ├── itd_service.rb │ ├── logger.rb │ ├── name_server.rb │ ├── node.rb │ ├── node_util.rb │ ├── ntp_auth_key.rb │ ├── ntp_config.rb │ ├── ntp_server.rb │ ├── object_group.rb │ ├── object_group_entry.rb │ ├── overlay_global.rb │ ├── pim.rb │ ├── pim_group_list.rb │ ├── pim_rp_address.rb │ ├── platform.rb │ ├── portchannel_global.rb │ ├── radius_global.rb │ ├── radius_server.rb │ ├── radius_server_group.rb │ ├── route_map.rb │ ├── router_ospf.rb │ ├── router_ospf_area.rb │ ├── router_ospf_area_vlink.rb │ ├── router_ospf_vrf.rb │ ├── snmp_notification_receiver.rb │ ├── snmpcommunity.rb │ ├── snmpgroup.rb │ ├── snmpnotification.rb │ ├── snmpserver.rb │ ├── snmpuser.rb │ ├── span_session.rb │ ├── stp_global.rb │ ├── syslog_facility.rb │ ├── syslog_server.rb │ ├── syslog_settings.rb │ ├── tacacs_global.rb │ ├── tacacs_server.rb │ ├── tacacs_server_group.rb │ ├── tacacs_server_host.rb │ ├── upgrade.rb │ ├── vdc.rb │ ├── version.rb │ ├── vlan.rb │ ├── vpc.rb │ ├── vrf.rb │ ├── vrf_af.rb │ ├── vtp.rb │ ├── vxlan_vtep.rb │ ├── vxlan_vtep_vni.rb │ ├── yang.rb │ └── yum.rb └── minitest │ ├── environment_plugin.rb │ └── log_level_plugin.rb ├── spec ├── client_spec.rb ├── environment_spec.rb ├── grpc_client_spec.rb ├── isolate │ ├── all_clients_spec.rb │ ├── grpc_only_spec.rb │ ├── no_clients_spec.rb │ └── nxapi_only_spec.rb ├── nxapi_client_spec.rb ├── schema.yaml ├── shared_examples_for_clients.rb ├── spec_helper.rb ├── whitespace_spec.rb └── yaml_spec.rb └── tests ├── .rubocop.yml ├── CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm ├── basetest.rb ├── ciscotest.rb ├── cmd_config.yaml ├── cmd_config_invalid.yaml ├── n9000_sample-1.0.0-7.0.3.x86_64.rpm ├── noop.rb ├── platform_info.rb ├── tacacs_server.yaml.example ├── test_aaa_authentication_login.rb ├── test_aaa_authentication_login_service.rb ├── test_aaa_authorization_service.rb ├── test_ace.rb ├── test_acl.rb ├── test_banner.rb ├── test_bfd_global.rb ├── test_bgp_af.rb ├── test_bgp_af_aa.rb ├── test_bgp_neighbor.rb ├── test_bgp_neighbor_af.rb ├── test_bridge_domain.rb ├── test_bridge_domain_vni.rb ├── test_client_utils.rb ├── test_cmn_utils.rb ├── test_command_config.rb ├── test_command_reference.rb ├── test_dhcp_relay_global.rb ├── test_dns_domain.rb ├── test_domain_name.rb ├── test_encapsulation.rb ├── test_evpn_multicast.rb ├── test_evpn_multisite.rb ├── test_evpn_stormcontrol.rb ├── test_evpn_vni.rb ├── test_fabricpath_global.rb ├── test_fabricpath_topology.rb ├── test_feature.rb ├── test_grpc.rb ├── test_hostname.rb ├── test_hsrp_global.rb ├── test_interface.rb ├── test_interface_bdi.rb ├── test_interface_channel_group.rb ├── test_interface_evpn_multisite.rb ├── test_interface_hsrp.rb ├── test_interface_hsrp_group.rb ├── test_interface_ospf.rb ├── test_interface_portchannel.rb ├── test_interface_private_vlan.rb ├── test_interface_service_vni.rb ├── test_interface_svi.rb ├── test_interface_switchport.rb ├── test_ip_multicast.rb ├── test_itd_device_group.rb ├── test_itd_device_group_node.rb ├── test_itd_service.rb ├── test_logger.rb ├── test_name_server.rb ├── test_node.rb ├── test_node_ext.rb ├── test_node_util.rb ├── test_ntp_auth_key.rb ├── test_ntp_config.rb ├── test_ntp_server.rb ├── test_nxapi.rb ├── test_object_group.rb ├── test_overlay_global.rb ├── test_pim.rb ├── test_pim_group_list.rb ├── test_pim_rp_address.rb ├── test_platform.rb ├── test_portchannel_global.rb ├── test_radius_global.rb ├── test_radius_server.rb ├── test_radius_server_group.rb ├── test_route_map.rb ├── test_router_bgp.rb ├── test_router_ospf.rb ├── test_router_ospf_area.rb ├── test_router_ospf_area_vlink.rb ├── test_router_ospf_vrf.rb ├── test_snmp_notification_receiver.rb ├── test_snmpcommunity.rb ├── test_snmpgroup.rb ├── test_snmpnotification.rb ├── test_snmpserver.rb ├── test_snmpuser.rb ├── test_span_session.rb ├── test_stp_global.rb ├── test_syslog_facility.rb ├── test_syslog_server.rb ├── test_syslog_settings.rb ├── test_tacacs_global.rb ├── test_tacacs_server.rb ├── test_tacacs_server_group.rb ├── test_tacacs_server_host.rb ├── test_upgrade.rb ├── test_vdc.rb ├── test_vlan.rb ├── test_vlan_private.rb ├── test_vpc.rb ├── test_vrf.rb ├── test_vrf_af.rb ├── test_vtp.rb ├── test_vxlan_vtep.rb ├── test_vxlan_vtep_vni.rb ├── test_yang.rb ├── test_yum.rb ├── upgrade_info.yaml.example └── yum_package.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/* 2 | pkg/* 3 | vendor/* 4 | coverage 5 | ext/Rakefile 6 | tests/tacacs_server.yaml 7 | Gemfile.lock 8 | *.gem 9 | *.swp 10 | TAGS 11 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | # Rubocop configuration 2 | AllCops: 3 | Exclude: 4 | # Auto-generated files 5 | - lib/cisco_node_utils/client/grpc/ems.rb 6 | - lib/cisco_node_utils/client/grpc/ems_services.rb 7 | # Files we don't own 8 | - vendor/**/* 9 | 10 | # Code complexity metrics are tracked separately for lib/ vs. tests/ 11 | # See lib/.rubocop.yml and tests/.rubocop.yml 12 | Metrics/AbcSize: 13 | Enabled: true 14 | 15 | Metrics/CyclomaticComplexity: 16 | Enabled: true 17 | 18 | Metrics/MethodLength: 19 | Enabled: true 20 | Exclude: 21 | - docs/*.rb 22 | 23 | Metrics/ParameterLists: 24 | Enabled: true 25 | 26 | Metrics/PerceivedComplexity: 27 | Enabled: true 28 | 29 | # Template files have long lines before tag replacement 30 | Metrics/LineLength: 31 | Exclude: 32 | - docs/*.rb 33 | 34 | # 35 | # Team preferences different from Rubocop defaults: 36 | # 37 | 38 | # We don't find either of these to be useful: 39 | Metrics/ClassLength: 40 | Enabled: false 41 | 42 | Metrics/ModuleLength: 43 | Enabled: false 44 | 45 | # We like table alignment for readability 46 | Style/AlignHash: 47 | EnforcedHashRocketStyle: table 48 | EnforcedColonStyle: table 49 | 50 | Style/ClassAndModuleChildren: 51 | Enabled: false 52 | 53 | # Template files have wildcard strings in class names 54 | Style/ClassAndModuleCamelCase: 55 | Exclude: 56 | - docs/*.rb 57 | 58 | # Permit is_a? and kind_of? interchangeably 59 | Style/ClassCheck: 60 | Enabled: false 61 | 62 | # Template files have atypical file names on purpose 63 | Style/FileName: 64 | Exclude: 65 | - docs/*.rb 66 | 67 | # As a team we like 'sprintf' rather than 'format' 68 | Style/FormatString: 69 | EnforcedStyle: sprintf 70 | 71 | # Mixed keys are ugly. Use one or the other as needed 72 | Style/HashSyntax: 73 | EnforcedStyle: ruby19_no_mixed_keys 74 | 75 | # Template files have wildcard strings in method names 76 | Style/MethodName: 77 | Exclude: 78 | - docs/*.rb 79 | 80 | # "def foo(bar=baz)" not "def foo(bar = baz)" 81 | Style/SpaceAroundEqualsInParameterDefault: 82 | EnforcedStyle: no_space 83 | 84 | # Make it neater to extend multi-line arrays and hashes 85 | Style/TrailingComma: 86 | EnforcedStyleForMultiline: comma 87 | 88 | Style/TrivialAccessors: 89 | AllowPredicates: true 90 | 91 | # Because an SnmpServer cannot be destroyed, we end most of the SnmpServer 92 | # test cases by explicitly returning the configuration to default. 93 | # Rubocop thinks this is a no-op but it isn't. 94 | Lint/UselessSetterCall: 95 | Exclude: 96 | - 'tests/test_snmpserver.rb' 97 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Use Docker infrastructure 2 | sudo: false 3 | 4 | language: ruby 5 | cache: bundler 6 | rvm: 7 | - 2.2.2 8 | - 2.1.6 9 | - 2.0.0-p648 # specify non-clang version of ruby 10 | before_install: 11 | - gem install bundler -v '< 2' 12 | 13 | script: 14 | - bundle exec rake 15 | env: 16 | global: 17 | - "BUNDLE_FORCE_RUBY_PLATFORM=1" 18 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in cisco_node_utils.gemspec 4 | gemspec 5 | 6 | # These are optional dependencies in the Gem itself, 7 | # but we need them for Bundler to use. 8 | gem 'net_http_unix' 9 | gem 'grpc', '= 1.2.5' 10 | gem 'pry' 11 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rubocop/rake_task' 3 | require 'rake/testtask' 4 | require 'rspec/core/rake_task' 5 | 6 | # test task is not part of default task list, 7 | # because it requires a node to test against 8 | task default: %w(rubocop spec build) 9 | 10 | RuboCop::RakeTask.new 11 | 12 | RSpec::Core::RakeTask.new(:spec_common) do |t| 13 | t.pattern = 'spec/*_spec.rb' 14 | t.rspec_opts = '--format documentation' 15 | t.verbose = false 16 | end 17 | spec_tasks = [:spec_common] 18 | 19 | # Because each of the below specs requires a clean Ruby environment, 20 | # they need to be run individually instead of as a single RSpec task. 21 | Dir.glob('spec/isolate/*_spec.rb').each do |f| 22 | task = File.basename(f, '.rb').to_sym 23 | RSpec::Core::RakeTask.new(task) do |t| 24 | t.pattern = f 25 | t.rspec_opts = '--format documentation' 26 | t.verbose = false 27 | end 28 | spec_tasks << task 29 | end 30 | 31 | task spec: spec_tasks 32 | 33 | task :build do 34 | system 'gem build cisco_node_utils.gemspec' 35 | end 36 | 37 | Rake::TestTask.new do |t| 38 | t.libs << 'lib' 39 | t.libs << 'tests' 40 | t.pattern = 'tests/test_*.rb' 41 | t.warning = true 42 | t.verbose = true 43 | t.options = '-v' 44 | end 45 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | Cisco Node Utils GEM is supported by Cisco Partners and Cisco Systems. 2 | 3 | Please report any issues with this module to [https://github.com/cisco/cisco-network-node-utils/issues](https://github.com/cisco/cisco-network-node-utils/issues) 4 | -------------------------------------------------------------------------------- /bin/.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: ../.rubocop.yml 2 | 3 | # Baseline code complexity metrics for the bin/ subdirectory: 4 | 5 | Metrics/AbcSize: 6 | Max: 49 7 | 8 | Metrics/CyclomaticComplexity: 9 | Max: 23 10 | 11 | Metrics/MethodLength: 12 | Max: 50 13 | 14 | Metrics/ParameterLists: 15 | Max: 9 16 | 17 | Metrics/PerceivedComplexity: 18 | Max: 24 19 | -------------------------------------------------------------------------------- /bin/git/hooks/commit-msg/enforce_style: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # Enforce rules of good commit message style 4 | # http://chris.beams.io/posts/git-commit/#seven-rules 5 | 6 | message_file = ARGV[0] 7 | full_message = File.read(message_file) 8 | message_lines = full_message.split("\n") 9 | # Omit comment lines - they don't need to be validated! 10 | message_lines = message_lines.select { |i| i.empty? || i[/^[^#]/] } 11 | 12 | $errors = 0 # rubocop:disable Style/GlobalVars 13 | 14 | def failure(msg) 15 | if STDOUT.tty? 16 | puts "\t...[ \033[31mFAIL\033[0m ] #{msg}" 17 | else 18 | puts msg 19 | end 20 | $errors += 1 # rubocop:disable Style/GlobalVars 21 | end 22 | 23 | # 1. Separate subject from body with a blank line 24 | if message_lines.length > 1 25 | unless message_lines[1].empty? 26 | failure 'Separate subject (first line) from body with a blank line' 27 | end 28 | end 29 | 30 | # 2. Limit the subject line to 50 characters 31 | if message_lines.first.length > 50 32 | failure 'First line of commit message should be no more than 50 characters' 33 | puts message_lines.first 34 | puts '^' * 50 35 | end 36 | 37 | # 3. Capitalize the subject line 38 | unless message_lines.first =~ /^[A-Z]/ 39 | failure 'Begin commit message subject line with a capital letter' 40 | end 41 | 42 | # 4. Do not end the subject line with a period 43 | if message_lines.first =~ /[!.,;]\s*$/ 44 | failure 'Do not end the subject line with punctuation' 45 | end 46 | 47 | # 5. Use the imperative mood in the subject line 48 | # This is very hard to enforce by automation, so 49 | # let's just check some likely cases: 50 | non_imperatives = [/adds$/, 51 | /added$/, 52 | /change[ds]$/, 53 | /fixe[ds]$/, 54 | /merge[ds]$/, 55 | /remove[ds]$/, 56 | /update[ds]$/, 57 | ] 58 | s = message_lines.first.split(' ').first.downcase 59 | if non_imperatives.any? { |re| re.match(s) } 60 | failure 'Use the imperative mood in the subject line' 61 | end 62 | 63 | # 6. Wrap the body at 72 characters 64 | if message_lines.any? { |line| line.length > 72 } 65 | failure 'Wrap the body at 72 characters' 66 | puts '-' * 72 67 | puts message_lines.select { |line| line.length > 72 }.join("\n") 68 | puts '-' * 72 69 | end 70 | 71 | # 7. Use the body to explain what and why vs. how 72 | # The user will just need to exercise judgment on this one :) 73 | 74 | if $errors > 0 # rubocop:disable Style/GlobalVars 75 | puts 'Rejected commit message:' 76 | puts '{' 77 | puts message_lines.join("\n") 78 | puts '}' 79 | 80 | fd = IO.sysopen('/dev/tty', 'w+') 81 | a = IO.new(fd, 'w+') 82 | a.puts 'Continue anyway? [y/N] ' 83 | response = a.gets.chomp 84 | # rubocop:disable Style/GlobalVars 85 | $errors = 0 if response.downcase[0] == 'y' 86 | # rubocop:enable Style/GlobalVars 87 | end 88 | 89 | exit $errors # rubocop:disable Style/GlobalVars 90 | -------------------------------------------------------------------------------- /bin/git/hooks/hooks-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Generic git hook. Calls all associated helper scripts. 4 | # 5 | # Based on: 6 | # http://stackoverflow.com/questions/8730514/chaining-git-hooks 7 | # https://github.com/henrik/dotfiles/blob/master/git_template/hooks/pre-commit 8 | 9 | [ -n "$GIT_DIR" ] || export GIT_DIR="$(git rev-parse --show-toplevel 2>/dev/null)/.git" 10 | 11 | . "$GIT_DIR"/hooks/hook_lib 12 | 13 | # What hook are we supposed to be? 14 | hookname=`basename $0` 15 | 16 | debug "Running wrapper script for '$hookname'..." 17 | 18 | exitcodes=() 19 | 20 | # Run each hook, passing through STDIN and storing the exit code. 21 | # We don't want to bail at the first failure, so the user can see everything. 22 | 23 | for hook in "$GIT_DIR"/hooks/$hookname-*; do 24 | debug "Checking hook '$hook'" 25 | test -x "$hook" || continue 26 | script_name "${hook##*/}" 27 | "$hook" "$@" 28 | rc=$? 29 | [ "$rc" == 0 ] && success 30 | exitcodes+=($rc) 31 | done 32 | 33 | # If any exit code isn't 0, bail. 34 | for i in "${exitcodes[@]}"; do 35 | [ "$i" == 0 ] || fail $i "One or more hook scripts reported an error" 36 | done 37 | debug "Wrapper script executed successfully" 38 | exit 0 39 | -------------------------------------------------------------------------------- /bin/git/hooks/post-flow-hotfix-start/update-version: -------------------------------------------------------------------------------- 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 | VERSION=$1 7 | debug "Detected VERSION as '$VERSION'" 8 | STRIP_VERSION=$(echo "$VERSION" | tr -c -d '0-9.') 9 | debug "Detected STRIP_VERSION as '$STRIP_VERSION'" 10 | 11 | LAST_VERSION=get_last_version 12 | 13 | step_name "Adding new release subheading in CHANGELOG.md" 14 | 15 | # Automatically update the CHANGELOG to mark the new release. 16 | # Unlike our post-flow-release-start script, there is no'Unreleased' tag 17 | # so we just insert the new version number immediately after the header 18 | sed -i "/^=========$/ a\ 19 | \\\n## [$VERSION] - $(date +%Y-%m-%d)\nTODO 20 | " "$REPO_DIR/CHANGELOG.md" 21 | 22 | add_changelog_diff_link "$LAST_VERSION" "$STRIP_VERSION" 23 | 24 | set_gem_version "$STRIP_VERSION" 25 | -------------------------------------------------------------------------------- /bin/git/hooks/post-flow-release-finish/update-version: -------------------------------------------------------------------------------- 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 | VERSION=$1 7 | debug "Detected VERSION as '$VERSION'" 8 | STRIP_VERSION=$(echo "$VERSION" | tr -c -d '0-9.') 9 | debug "Detected STRIP_VERSION as '$STRIP_VERSION'" 10 | 11 | step_name "Adding 'Unreleased' subheader to CHANGELOG.md in development branch." 12 | 13 | # Add new 'Unreleased' section header to the CHANGELOG 14 | sed -i "/^=========$/ a\ 15 | \\\n## [Unreleased]\n 16 | " $REPO_DIR/CHANGELOG.md 17 | 18 | # Bump the minor version number 19 | BUGFIX_NUM=$(($(echo $STRIP_VERSION | cut -d. -f 3)+1)) 20 | NEW_VERSION="$(echo $STRIP_VERSION | cut -d. -f 1-2).$BUGFIX_NUM-dev" 21 | 22 | echo "New development version will be $NEW_VERSION" 23 | 24 | set_gem_version "$NEW_VERSION" 25 | 26 | step_name "Commit CHANGELOG.md and version.rb to develop branch" 27 | 28 | git commit -a -m "Post-release fixup" 29 | check_rc "Git commit to develop failed?" 30 | -------------------------------------------------------------------------------- /bin/git/hooks/post-flow-release-start/update-version: -------------------------------------------------------------------------------- 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 | VERSION=$1 7 | debug "Detected VERSION as '$VERSION'" 8 | STRIP_VERSION=$(echo "$VERSION" | tr -c -d '0-9.') 9 | debug "Detected STRIP_VERSION as '$STRIP_VERSION'" 10 | 11 | LAST_VERSION=get_last_version 12 | 13 | step_name "Change 'Unreleased' subhead to '$VERSION' in CHANGELOG.md" 14 | 15 | sed -i -e "s/^## \[Unreleased\]$/## [$VERSION] - $(date +%Y-%m-%d)/" "$REPO_DIR"/CHANGELOG.md 16 | 17 | add_changelog_diff_link "$LAST_VERSION" "$STRIP_VERSION" 18 | 19 | set_gem_version "$STRIP_VERSION" 20 | -------------------------------------------------------------------------------- /bin/git/hooks/post-merge/update-hooks: -------------------------------------------------------------------------------- 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 | [ -x "$REPO_DIR"/bin/git/update-hooks ] && "$REPO_DIR"/bin/git/update-hooks 7 | -------------------------------------------------------------------------------- /bin/git/hooks/post-rewrite/update-hooks: -------------------------------------------------------------------------------- 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 | [ -x "$REPO_DIR"/bin/git/update-hooks ] && "$REPO_DIR"/bin/git/update-hooks 7 | -------------------------------------------------------------------------------- /bin/git/hooks/pre-commit/check_unstaged_changes: -------------------------------------------------------------------------------- 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 19 | -------------------------------------------------------------------------------- /bin/git/hooks/pre-commit/rubocop: -------------------------------------------------------------------------------- 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 rubocop lint checks (only). 7 | # We don't enforce a full rubocop run here because we want to let people 8 | # commit work-in-progress code to their local branch. We will do a full 9 | # rubocop run of all checks as part of the pre-push hook 10 | 11 | step_name "Running RuboCop lint checks" 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 18 | check_rc "Please fix RuboCop lint failures before committing." 19 | 20 | # Do a full rubocop run to warn the user, but don't block a commit by it. 21 | step_name "Running all RuboCop checks" 22 | rubocop $staged_ruby_files 23 | check_rc_optional "Fix all RuboCop failures before pushing upstream" 24 | 25 | exit 0 26 | -------------------------------------------------------------------------------- /bin/git/hooks/pre-commit/validate-diffs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Hook script to verify what is about to be committed. 4 | # Called by "git commit" with no arguments. The hook should 5 | # exit with non-zero status after issuing an appropriate message if 6 | # it wants to stop the commit. 7 | 8 | [ -n "$GIT_DIR" ] || export GIT_DIR="$(git rev-parse --show-toplevel 2>/dev/null)/.git" 9 | . "$GIT_DIR"/hooks/hook_lib 10 | 11 | # What are we diffing this commit against? 12 | if git rev-parse --verify HEAD >/dev/null 2>&1 13 | then 14 | against=HEAD 15 | else 16 | # Initial commit: diff against an empty tree object 17 | against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 18 | fi 19 | 20 | step_name 'Checking for non-ASCII filenames' 21 | # We exploit the fact that the printable range starts at the space character 22 | # and ends with tilde. 23 | # Note that the use of brackets around a tr range is ok here, (it's 24 | # even required, for portability to Solaris 10's /usr/bin/tr), since 25 | # the square bracket bytes happen to fall in the designated range. 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)) 35 | check_rc "Rename non-ASCII file name(s) before committing" 36 | 37 | step_name 'Checking for trailing whitespace in non-Ruby files' 38 | # If there are whitespace errors, print the offending file names and fail. 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 46 | -------------------------------------------------------------------------------- /bin/git/hooks/pre-commit/validate-yaml: -------------------------------------------------------------------------------- 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 19 | -------------------------------------------------------------------------------- /bin/git/hooks/pre-push/check-changelog: -------------------------------------------------------------------------------- 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 | z40=0000000000000000000000000000000000000000 7 | 8 | IFS=' ' 9 | 10 | # Information about the commits which are being pushed is supplied as lines to 11 | # the standard input in the form: 12 | # 13 | # 14 | while read local_ref local_sha remote_ref remote_sha 15 | do 16 | # do nothing if we're creating or deleting a new branch. 17 | if [ "$local_sha" != $z40 ] && [ "$remote_sha" != $z40 ] ; then 18 | # Make sure CHANGELOG.md is updated 19 | step_name "Checking CHANGELOG.md..." 20 | git diff --name-only --diff-filter=ACM $remote_sha $local_sha | 21 | grep 'CHANGELOG.md' >> /dev/null 22 | check_rc_optional "Please update CHANGELOG.md before pushing code upstream" 23 | fi 24 | done 25 | -------------------------------------------------------------------------------- /bin/git/hooks/pre-push/rubocop: -------------------------------------------------------------------------------- 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 | rubocop 7 | check_rc "Please fix RuboCop failures before pushing code upstream." 8 | -------------------------------------------------------------------------------- /cisco_node_utils.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'cisco_node_utils/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'cisco_node_utils' 8 | spec.version = CiscoNodeUtils::VERSION 9 | spec.authors = ['Rob Gries', 'Alex Hunsberger', 'Glenn Matthews', 10 | 'Chris Van Heuveln', 'Rich Wellum', 'Mike Wiebe', 11 | 'Jie Yang', 'Sai Chintalapudi'] 12 | spec.email = 'cisco_agent_gem@cisco.com' 13 | spec.summary = 'Utilities for management of Cisco network nodes' 14 | spec.description = <<-EOF 15 | Utilities for management of Cisco network nodes. 16 | Designed to work with Puppet and Chef. 17 | Currently supports NX-OS nodes. 18 | EOF 19 | spec.license = 'Apache-2.0' 20 | spec.homepage = 'https://github.com/cisco/cisco-network-node-utils' 21 | 22 | spec.files = `git ls-files -z`.split("\x0") 23 | # Files in bin/git are not executables as far as the Gem is concerned 24 | spec.executables = [] 25 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 26 | spec.require_paths = ['lib'] 27 | 28 | spec.required_ruby_version = '>= 2.0.0' 29 | spec.required_rubygems_version = '>= 2.1.0' 30 | 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' 34 | spec.add_development_dependency 'net-telnet', '~> 0.1.1' 35 | spec.add_development_dependency 'rake', '~> 10.0' 36 | spec.add_development_dependency 'rspec', '~> 3.0' 37 | spec.add_development_dependency 'rubocop', '= 0.35.1' 38 | spec.add_development_dependency 'simplecov', '~> 0.9' 39 | 40 | spec.extensions = ['ext/mkrf_conf.rb'] 41 | end 42 | -------------------------------------------------------------------------------- /docs/README-test-execution.md: -------------------------------------------------------------------------------- 1 | # Executing the tests provided for this gem 2 | 3 | ## RSpec tests 4 | 5 | The test files located in the `spec/` directory use [RSpec](http://rspec.info/) as their test framework. These tests are generally standalone and do not generally require any actual Cisco hardware or virtual machines to test against. 6 | 7 | ### Running a single RSpec test 8 | 9 | You can execute a single spec file by name: 10 | 11 | ```bash 12 | rspec spec/environment_spec.rb 13 | ``` 14 | 15 | ### Running all RSpec tests 16 | 17 | 18 | ```bash 19 | rake spec 20 | ``` 21 | 22 | ## Minitest tests 23 | 24 | The test files located in the `tests/` directory use [minitest](https://github.com/seattlerb/minitest/) as their test framework. These tests generally require one or more Cisco routers, switches, or virtual machines to test against. 25 | 26 | It is recommended that you create a `cisco_node_utils.yaml` file (as described in [README.md](../README.md#configuration) to specify the node(s) under test, but if you do not create such a file, the test will prompt you to enter the required information at runtime: 27 | 28 | ```bash 29 | $ rake test 30 | Enter address or hostname of node under test: 192.168.100.1 31 | Enter username for node under test: user 32 | Enter password for node under test: password 33 | ``` 34 | 35 | ### Running a single minitest test 36 | 37 | You can execute a single test file by name. If you do not specify the `-e` / `--environment` option, the node labeled as `default` in `cisco_node_utils.yaml` will be used (or, if no such entry exists, you will be prompted to enter the required information as shown above): 38 | 39 | ```bash 40 | # Run test against the 'default' node: 41 | $ ruby tests/test_node.rb 42 | # Run test against node 'n7k': 43 | $ ruby tests/test_node.rb --environment n7k 44 | # Run test against node 'n9k': 45 | $ ruby tests/test_node.rb -e n9k 46 | ``` 47 | 48 | ### Running all minitest tests 49 | 50 | As above, if you do not specify the `--environment` option, the `default` node will be used or you will be prompted if necessary. 51 | 52 | ```bash 53 | # Run all tests against the 'default' node: 54 | $ rake test 55 | # Run all tests against 'n7k': 56 | $ rake test TEST_OPTS='--environment=n7k' 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/README-utilities.md: -------------------------------------------------------------------------------- 1 | # Executable utilities included in this gem 2 | 3 | ## check_metric_limits.rb 4 | 5 | This is a helper script for developers. If you're doing refactoring work to 6 | reduce the code complexity metrics, you can run this script to report the 7 | worst offenders for each metric and whether you've managed to improve any 8 | metrics compared to the baseline. Run this script from the base 9 | cisco-network-node-utils directory to report metrics of code in the 10 | ./lib and ./tests directories. 11 | 12 | ```bash 13 | [cisco-network-node-utils]$ ruby bin/check_metric_limits.rb 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/agent_files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cisco/cisco-network-node-utils/3a6e4ce482777e93af6318f335e22c222b9e2728/docs/agent_files.png -------------------------------------------------------------------------------- /docs/cisco_node_utils.yaml.example: -------------------------------------------------------------------------------- 1 | # The entry labeled 'default' will be used by default. 2 | # The user can select a different entry by name if desired. 3 | # 4 | # default: 5 | # host: foo 6 | 7 | # Example config for running NXAPI remotely: 8 | nxapi_remote: 9 | host: 192.168.1.100 10 | username: devops 11 | password: devops 12 | 13 | # Example config for running NXAPI on a node: 14 | nxapi_local: 15 | # (none needed) 16 | 17 | # Example config for running NXAPI on a node with default cookie override: 18 | # User 'nxapi' must be configured with requisite privilages to configure the device. 19 | # This will override the default 'admin:local' cookie and use 'nxapi:local' instead. 20 | default: 21 | cookie: 'nxapi:local' 22 | 23 | # Example config for running gRPC remotely: 24 | grpc_remote: 25 | host: 192.168.1.100 26 | # gRPC port defaults to 57400 if unset 27 | # port: 57400 28 | username: admin 29 | password: admin 30 | 31 | # Example config for running gRPC on a node: 32 | grpc_local: 33 | port: 57999 34 | username: admin 35 | password: admin 36 | 37 | -------------------------------------------------------------------------------- /ext/mkrf_conf.rb: -------------------------------------------------------------------------------- 1 | # Inspired by: 2 | # https://github.com/ruby-debug/ruby-debug-ide/blob/master/ext/mkrf_conf.rb 3 | 4 | # This file needs to be named mkrf_conf.rb 5 | # so that rubygems will recognize it as a ruby extension 6 | # file and not think it is a C extension file 7 | 8 | require 'rubygems/specification' 9 | require 'rubygems/dependency' 10 | require 'rubygems/dependency_installer' 11 | 12 | # Load up the rubygems dependency installer to install the dependencies 13 | # we need based on the platform we are running under. 14 | installer = Gem::DependencyInstaller.new 15 | deps = [] 16 | begin 17 | # Try to detect Cisco NX-OS and IOS XR environments 18 | os = nil 19 | if File.exist?('/etc/os-release') 20 | cisco_release_file = nil 21 | File.foreach('/etc/os-release') do |line| 22 | next unless line[/^CISCO_RELEASE_INFO=/] 23 | cisco_release_file = line[/^CISCO_RELEASE_INFO=(.*)$/, 1] 24 | break 25 | end 26 | unless cisco_release_file.nil? 27 | File.foreach(cisco_release_file) do |line| 28 | next unless line[/^ID=/] 29 | os = line[/^ID=(.*)$/, 1] 30 | break 31 | end 32 | end 33 | end 34 | puts "Detected client OS as '#{os}'" unless os.nil? 35 | 36 | # IOS XR doesn't need net_http_unix 37 | os == 'ios_xr' || deps << Gem::Dependency.new('net_http_unix', 38 | '~> 0.2', '>= 0.2.1') 39 | # NX-OS doesn't need gRPC 40 | os == 'nexus' || deps << Gem::Dependency.new('grpc', '~> 1.14.1') 41 | 42 | deps.each do |dep| 43 | installed = dep.matching_specs 44 | if installed.empty? 45 | puts "Installing #{dep}" 46 | installed = installer.install dep 47 | fail installer.errors[0] unless installer.errors.empty? 48 | fail "Did not install #{dep}" if installed.empty? 49 | else 50 | puts "Found installed gems matching #{dep}:" 51 | installed.each { |i| puts " #{i.name} (#{i.version})" } 52 | end 53 | end 54 | rescue StandardError => e 55 | puts e 56 | puts e.backtrace.join("\n ") 57 | exit(1) 58 | end 59 | 60 | # Create a dummy Rakefile to report successful 'compilation' 61 | f = File.open(File.join(File.dirname(__FILE__), 'Rakefile'), 'w') 62 | f.write("task :default\n") 63 | f.close 64 | -------------------------------------------------------------------------------- /lib/.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: ../.rubocop.yml 2 | 3 | # Baseline code complexity metrics for the lib/ subdirectory: 4 | 5 | Metrics/AbcSize: 6 | Max: 49 7 | 8 | Metrics/CyclomaticComplexity: 9 | Max: 23 10 | 11 | Metrics/MethodLength: 12 | Max: 50 13 | 14 | Metrics/ParameterLists: 15 | Max: 10 16 | 17 | Metrics/PerceivedComplexity: 18 | Max: 24 19 | -------------------------------------------------------------------------------- /lib/cisco_node_utils.rb: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014-2016 Cisco and/or its affiliates. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Declare module here as files referenced in glob-order below may assume 16 | # module already exists. 17 | module Cisco 18 | end 19 | 20 | # Automatically load all Ruby files in the cisco_node_utils subdirectory 21 | Dir.glob(__dir__ + '/cisco_node_utils/*.rb') { |file| require file } 22 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/banner.rb: -------------------------------------------------------------------------------- 1 | # Banner provider class 2 | # 3 | # Rick Sherman et al., August 2018 4 | # 5 | # Copyright (c) 2014-2018 Cisco and/or its affiliates. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | require_relative 'node_util' 20 | 21 | module Cisco 22 | # Banner - node utility class for Banner configuration management 23 | class Banner < NodeUtil 24 | attr_reader :name 25 | 26 | def initialize(name) 27 | fail TypeError unless name.is_a?(String) 28 | fail ArgumentError, 29 | "This provider only accepts an id of 'default'" \ 30 | unless name.eql?('default') 31 | @name = name 32 | end 33 | 34 | def self.banners 35 | hash = {} 36 | hash['default'] = Banner.new('default') 37 | hash 38 | end 39 | 40 | def ==(other) 41 | name == other.name 42 | end 43 | 44 | def motd 45 | config_get('banner', 'motd') 46 | end 47 | 48 | def motd=(val) 49 | if val.nil? && (motd != default_motd) 50 | config_set('banner', 'motd', state: 'no', motd: '') 51 | elsif !val.nil? 52 | config_set('banner', 53 | 'motd', 54 | state: '', 55 | motd: "^#{val.gsub(/\n/, '\\n')}^") 56 | end 57 | end 58 | 59 | def default_motd 60 | config_get_default('banner', 'motd') 61 | end 62 | end # class 63 | end # module 64 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/client.rb: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Cisco and/or its affiliates. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Namespace for Cisco-specific code 16 | module Cisco 17 | # Namespace for Cisco Client shim 18 | class Client 19 | end 20 | end 21 | 22 | require_relative 'client/client' 23 | 24 | # Try to load known extensions 25 | extensions = ['client/nxapi', 26 | 'client/grpc', 27 | ] 28 | extensions.each do |ext| 29 | begin 30 | require_relative ext 31 | rescue LoadError => e 32 | # ignore missing client-(grpc|nxapi), they're not always required 33 | raise unless e.message =~ /#{Regexp.escape(ext)}/ 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/client/grpc.rb: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Cisco and/or its affiliates. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | require_relative 'client' 16 | 17 | # Fail gracefully if submodule dependencies are not met 18 | begin 19 | Cisco::Client.silence_warnings do 20 | require 'grpc' 21 | end 22 | rescue LoadError => e 23 | raise unless e.message =~ /-- grpc/ 24 | # If grpc is not installed, raise an error that client understands. 25 | raise LoadError, "Unable to load client/grpc -- #{e}" 26 | end 27 | 28 | # Namespace for Cisco EMS gRPC-specific code 29 | class Cisco::Client::GRPC < Cisco::Client 30 | end 31 | 32 | # Auto-load all Ruby files in the subdirectory 33 | Dir.glob(__dir__ + '/grpc/*.rb') { |file| require file } 34 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/client/grpc/ems_services.rb: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # Source: ems.proto for package 'IOSXRExtensibleManagabilityService' 3 | 4 | require 'grpc' 5 | require_relative 'ems' 6 | 7 | module IOSXRExtensibleManagabilityService 8 | module GRPCConfigOper 9 | 10 | # TODO: add proto service documentation here 11 | class Service 12 | 13 | include GRPC::GenericService 14 | 15 | self.marshal_class_method = :encode 16 | self.unmarshal_class_method = :decode 17 | self.service_name = 'IOSXRExtensibleManagabilityService.gRPCConfigOper' 18 | 19 | rpc :GetConfig, ConfigGetArgs, stream(ConfigGetReply) 20 | rpc :MergeConfig, ConfigArgs, ConfigReply 21 | rpc :DeleteConfig, ConfigArgs, ConfigReply 22 | rpc :ReplaceConfig, ConfigArgs, ConfigReply 23 | rpc :CliConfig, CliConfigArgs, CliConfigReply 24 | rpc :CommitReplace, CommitReplaceArgs, CommitReplaceReply 25 | rpc :CommitConfig, CommitArgs, CommitReply 26 | rpc :ConfigDiscardChanges, DiscardChangesArgs, DiscardChangesReply 27 | rpc :GetOper, GetOperArgs, stream(GetOperReply) 28 | end 29 | 30 | Stub = Service.rpc_stub_class 31 | end 32 | module GRPCExec 33 | 34 | # TODO: add proto service documentation here 35 | class Service 36 | 37 | include GRPC::GenericService 38 | 39 | self.marshal_class_method = :encode 40 | self.unmarshal_class_method = :decode 41 | self.service_name = 'IOSXRExtensibleManagabilityService.gRPCExec' 42 | 43 | rpc :ShowCmdTextOutput, ShowCmdArgs, stream(ShowCmdTextReply) 44 | rpc :ShowCmdJSONOutput, ShowCmdArgs, stream(ShowCmdJSONReply) 45 | end 46 | 47 | Stub = Service.rpc_stub_class 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/client/nxapi.rb: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Cisco and/or its affiliates. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | require_relative 'client' 16 | 17 | # Fail gracefully if submodule dependencies are not met 18 | begin 19 | require 'net_http_unix' 20 | rescue LoadError => e 21 | raise unless e.message =~ /-- net_http_unix/ 22 | # If net_http_unix is not installed, raise an error that client understands. 23 | raise LoadError, "Unable to load client/nxapi -- #{e}" 24 | end 25 | 26 | # Namespace for Cisco NXAPI-specific code 27 | class Cisco::Client::NXAPI < Cisco::Client 28 | end 29 | 30 | # Auto-load all Ruby files in the subdirectory 31 | Dir.glob(__dir__ + '/nxapi/*.rb') { |file| require file } 32 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml: -------------------------------------------------------------------------------- 1 | # aaa_auth_login_service 2 | --- 3 | _exclude: [ios_xr] 4 | 5 | groups: 6 | get_data_format: nxapi_structured 7 | get_command: "show aaa authentication" 8 | get_context: ["TABLE_AuthenMethods", "ROW_AuthenMethods"] 9 | # this set is only used when there are groups to configure 10 | set_value: "%s aaa authentication login %s group %s %s" 11 | default_value: [] 12 | multiple: 13 | 14 | method: 15 | auto_default: false 16 | get_command: "show aaa authentication" 17 | get_value: '/^\s*%s:.*(local|none)\s*$/' 18 | # this set is only used when there are no groups to configure 19 | set_value: "%s aaa authentication login %s %s" 20 | default_value: :local 21 | 22 | services: 23 | get_command: "show run aaa all" 24 | get_value: '/^aaa authentication login (\S+) (?:none|group|local)/' 25 | multiple: 26 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml: -------------------------------------------------------------------------------- 1 | # aaa_authentication_login 2 | --- 3 | _exclude: [ios_xr] 4 | 5 | ascii_authentication: 6 | kind: boolean 7 | get_command: "show run aaa all" 8 | get_value: '/^aaa authentication login ascii-authentication/' 9 | set_value: "%s aaa authentication login ascii-authentication" 10 | default_value: false 11 | 12 | chap: 13 | kind: boolean 14 | get_command: "show run aaa all" 15 | get_value: '/^aaa authentication login chap enable/' 16 | set_value: "%s aaa authentication login chap enable" 17 | default_value: false 18 | 19 | error_display: 20 | kind: boolean 21 | get_command: "show run aaa all" 22 | get_value: '/^aaa authentication login error-enable/' 23 | set_value: "%s aaa authentication login error-enable" 24 | default_value: false 25 | 26 | mschap: 27 | kind: boolean 28 | get_command: "show run aaa all" 29 | get_value: '/^aaa authentication login mschap enable/' 30 | set_value: "%s aaa authentication login mschap enable" 31 | default_value: false 32 | 33 | mschapv2: 34 | kind: boolean 35 | get_command: "show run aaa all" 36 | get_value: '/^aaa authentication login mschapv2 enable/' 37 | set_value: "%s aaa authentication login mschapv2 enable" 38 | default_value: false 39 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml: -------------------------------------------------------------------------------- 1 | # aaa_authorization_service 2 | --- 3 | _exclude: [ios_xr] 4 | 5 | groups: 6 | get_data_format: nxapi_structured 7 | get_command: "show aaa authorization all" 8 | get_context: ["TABLE_cmd_methods", "ROW_cmd_methods"] 9 | # this set is only used when there are groups to configure 10 | set_value: "%s aaa authorization %s %s group %s %s" 11 | default_value: [] 12 | multiple: 13 | 14 | method: 15 | auto_default: false 16 | get_command: "show aaa authorization all" 17 | get_value: '/^\s+%s authorization for %s:.*(local) ?$/' 18 | # this set is only used when there are no groups to configure 19 | set_value: "%s aaa authorization %s %s local" 20 | default_value: :local 21 | 22 | remove_local_auth: 23 | # Used for determining if removal of authentication method 24 | # 'local' is permitted. 25 | # TBD: remove local should be allowed on all platforms. 26 | # Change once CSCva88188 is resolved 27 | kind: boolean 28 | N3k: &remove_local_allowed 29 | default_only: true 30 | N9k: *remove_local_allowed 31 | N3k-F: *remove_local_allowed 32 | N9k-F: *remove_local_allowed 33 | N5k: *remove_local_allowed 34 | N6k: *remove_local_allowed 35 | N7k: *remove_local_allowed 36 | 37 | services: 38 | get_command: "show run aaa all" 39 | get_value: '/^aaa authorization (\S+) (\S+) .*(?:local)? ?$/' 40 | multiple: 41 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/acl.yaml: -------------------------------------------------------------------------------- 1 | # Command Reference Common ACL 2 | # 3 | # For documentation please see: 4 | # - README_YAML.md 5 | # 6 | --- 7 | _exclude: [ios_xr] 8 | 9 | _template: 10 | get_command: 'show run aclmgr' 11 | context: [' access-list '] 12 | 13 | ace: 14 | get_value: '/^ .+$/' 15 | set_value: ' ' 16 | 17 | ace_destroy: 18 | set_value: 'no ' 19 | 20 | ace_remark: 21 | set_value: ' remark ' 22 | 23 | acl: 24 | context: ~ 25 | get_value: '/^ access-list (\S+)$/' 26 | set_value: ' access-list ' 27 | 28 | all_aces: 29 | multiple: 30 | get_value: '/^(\d+) .+$/' 31 | 32 | all_acls: 33 | multiple: 34 | get_context: ~ 35 | get_value: '/^ access-list (\S+)$/' 36 | 37 | fragments: 38 | # Note: The ACL 'fragments' keyword is independent of ACE 'fragments' 39 | _exclude: [N5k, N6k, N3k-F, N9k-F] 40 | get_value: '/fragments (\S+)$/' 41 | set_value: ' fragments ' 42 | default_value: ~ 43 | 44 | stats_per_entry: 45 | kind: boolean 46 | get_value: '/statistics per-entry$/' 47 | set_value: ' statistics per-entry' 48 | default_value: false 49 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/banner.yaml: -------------------------------------------------------------------------------- 1 | # banner 2 | --- 3 | motd: 4 | N5k: &N6000 5 | default_value: "Nexus 6000 Switch\n" 6 | N6k: *N6000 7 | else: 8 | default_value: "User Access Verification\n" 9 | get_command: 'show banner motd' 10 | get_value: '/^.*$/m' 11 | set_value: ' banner motd ' 12 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/bgp_af_aa.yaml: -------------------------------------------------------------------------------- 1 | # bgp_af_aa.yaml 2 | --- 3 | _exclude: [ios_xr] 4 | 5 | _template: 6 | context: 7 | - "router bgp " 8 | - '(?)vrf ' 9 | - 'address-family ' 10 | get_command: 'show running bgp all' 11 | 12 | advertise_map: 13 | kind: string 14 | default_value: '' 15 | 16 | aggr_addr: 17 | get_value: '/^aggregate-address
(.*)$/' 18 | set_value: " aggregate-address
" 19 | 20 | all_aa: 21 | multiple: true 22 | get_value: '/^aggregate-address (\S+)/' 23 | 24 | as_set: 25 | kind: boolean 26 | default_value: false 27 | 28 | attribute_map: 29 | kind: string 30 | default_value: '' 31 | 32 | summary_only: 33 | kind: boolean 34 | default_value: false 35 | 36 | suppress_map: 37 | kind: string 38 | default_value: '' 39 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/bridge_domain.yaml: -------------------------------------------------------------------------------- 1 | # bridge_domain 2 | # bridge_domain feature is available only on n7k 3 | --- 4 | _exclude: [N3k, N5k, N6k, N3k-F, N9k-F, N9k, ios_xr] 5 | 6 | _template: 7 | get_command: "show running-config bridge-domain" 8 | get_context: ~ 9 | set_context: ["(?)bridge-domain "] 10 | 11 | all_bds: 12 | multiple: true 13 | get_value: '/^bridge-domain (\S+)/' 14 | 15 | bd_name: 16 | get_data_format: nxapi_structured 17 | get_command: "show bridge-domain " 18 | get_context: ["TABLE_bd", "ROW_bd"] 19 | get_value: ["bd-name"] 20 | set_value: " name " 21 | 22 | create: 23 | set_value: "bridge-domain " 24 | 25 | destroy: 26 | set_value: "no bridge-domain " 27 | 28 | # Configured fabric-control Bridge-Domain/VLAN : 100 29 | fabric_control: 30 | get_data_format: nxapi_structured 31 | get_command: "show bridge-domain summary" 32 | get_context: ~ 33 | get_value: ["fabric-control-bd"] 34 | set_value: " fabric-control" 35 | default_value: false 36 | 37 | shutdown: 38 | get_data_format: nxapi_structured 39 | get_command: "show bridge-domain " 40 | get_context: ["TABLE_bd", "ROW_bd"] 41 | get_value: ["bd-admin-state"] 42 | set_value: " shutdown" 43 | default_value: false 44 | 45 | system_bridge_domain: 46 | get_value: '/^system bridge-domain (\S+)/' 47 | set_context: ~ 48 | set_value: "system bridge-domain " 49 | default_value: "" 50 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml: -------------------------------------------------------------------------------- 1 | # bridge_domain 2 | --- 3 | _exclude: [N3k, N5k, N6k, N3k-F, N9k-F, N9k, ios_xr] 4 | 5 | create: 6 | set_value: "bridge-domain " 7 | 8 | member_vni: 9 | get_command: "show running-config bridge-domain | inc 'member vni'" 10 | get_value: '/^ member vni (.*)/' 11 | set_value: "bridge-domain ; member vni " 12 | default_value: '' 13 | 14 | member_vni_bd: 15 | get_command: "show running-config bridge-domain | inc 'member vni' prev 1" 16 | get_value: '/^bridge-domain (.*)/' 17 | 18 | range_bds: 19 | multiple: true 20 | get_command: "show running-config bridge-domain | inc 'member vni' prev 1" 21 | get_value: '/^bridge-domain (.*)/' 22 | 23 | system_bridge_domain: 24 | get_command: "show running-config bridge-domain" 25 | get_value: '/^system bridge-domain (\S+)/' 26 | set_value: "system bridge-domain " 27 | default_value: "" 28 | 29 | vni: 30 | get_command: "show running-config bridge-domain" 31 | get_value: '/^vni (\d+)/' 32 | set_value: " vni " 33 | default_value: '' 34 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/dnsclient.yaml: -------------------------------------------------------------------------------- 1 | # dnsclient 2 | --- 3 | _template: 4 | get_command: "show running-config all" 5 | 6 | domain_list: 7 | multiple: true 8 | nexus: 9 | get_value: '/^ip domain-list (\S+)$/' 10 | set_value: ' ip domain-list ' 11 | ios_xr: 12 | get_value: '/^domain list (\S+)$/' 13 | set_value: ' domain list ' 14 | default_value: [] 15 | 16 | domain_list_vrf: 17 | multiple: true 18 | nexus: 19 | context: ['vrf context '] 20 | get_value: '/ip domain-list (\S+)/' 21 | set_value: ' ip domain-list ' 22 | ios_xr: 23 | get_value: '/^domain vrf list (\S+)/' 24 | set_value: ' domain vrf list ' 25 | default_value: [] 26 | 27 | domain_name: 28 | default_value: '' 29 | nexus: 30 | set_value: ' ip domain-name ' 31 | get_value: '/^ip domain-name (\S+)$/' 32 | ios_xr: 33 | set_value: ' domain name ' 34 | get_value: '/^domain name (\S+)$/' 35 | 36 | domain_name_vrf: 37 | nexus: 38 | context: ['vrf context '] 39 | get_value: '/ip domain-name (\S+)/' 40 | set_value: ' ip domain-name ' 41 | ios_xr: 42 | get_value: '/^domain vrf name (\S+)$/' 43 | set_value: ' domain vrf name ' 44 | default_value: '' 45 | 46 | name_server: 47 | multiple: true 48 | default_value: [] 49 | nexus: 50 | get_command: "show running-config all | include 'ip name-server' | exclude 'use-vrf'" 51 | get_value: '/^ip name-server ([\s\d\.:]+)$/' 52 | set_value: ' ip name-server ' 53 | ios_xr: 54 | get_value: '/^domain name-server (\S+)$/' 55 | set_value: ' domain name-server ' 56 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/encapsulation.yaml: -------------------------------------------------------------------------------- 1 | # encapsulation_profile_vni 2 | # encapsulation_profile_vni feature is available only on n7k 3 | --- 4 | _exclude: [N3k, N5k, N6k, N3k-F, N9k-F, N9k, ios_xr] 5 | 6 | all_encaps: 7 | multiple: true 8 | get_command: "show running-config vni" 9 | get_value: '/^encapsulation profile vni (\S+)/' 10 | 11 | create: 12 | set_value: "encapsulation profile vni " 13 | 14 | destroy: 15 | set_value: "no encapsulation profile vni " 16 | 17 | # Eg: 18 | # encapsulation profile vni my_vni_profile 19 | # [no] dot1q 100-200, 300 vni 5000-5100, 5300 20 | dot1q_map: 21 | get_command: "show encapsulation profile" 22 | get_value: '/^.* vni \s+dot1q ([\d\s,-]+) vni ([\d\s,-]+)$/' 23 | set_context: ['encapsulation profile vni '] 24 | set_value: ' dot1q vni ' 25 | default_value: [] 26 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/evpn_multicast.yaml: -------------------------------------------------------------------------------- 1 | # evpn_multicast.yaml 2 | --- 3 | _exclude: [ios_xr, N3k, N3k-F, N5k, N6k, N7k, N9k-F] 4 | 5 | _template: 6 | get_command: "show running-config | section advertise" 7 | 8 | multicast: 9 | context: ~ 10 | get_value: '^advertise evpn multicast$' 11 | set_value: " advertise evpn multicast" 12 | default_value: '' 13 | -------------------------------------------------------------------------------- /lib/cisco_node_utils/cmd_ref/evpn_multisite.yaml: -------------------------------------------------------------------------------- 1 | # evpn_multisite.yaml 2 | --- 3 | _exclude: [ios_xr, N3k, N3k-F, N5k, N6k, N7k, N9k-F] 4 | 5 | _template: 6 | get_command: "show running-config | section multisite" 7 | 8 | delay_restore: 9 | default_value: "" 10 | get_context: ['/^evpn multisite border-gateway $/'] 11 | get_value: '/^delay-restore\s+time\s+(\d+)$/' 12 | set_context: ['evpn multisite border-gateway '] 13 | set_value: " delay-restore time