cisco_node_utils_mgx 2.1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +96 -0
- data/.travis.yml +17 -0
- data/CHANGELOG.md +676 -0
- data/CONTRIBUTING.md +43 -0
- data/Gemfile +10 -0
- data/LICENSE +201 -0
- data/README.md +246 -0
- data/Rakefile +44 -0
- data/SUPPORT.md +3 -0
- data/bin/.rubocop.yml +18 -0
- data/bin/check_metric_limits.rb +109 -0
- data/bin/git/hooks/commit-msg/enforce_style +89 -0
- data/bin/git/hooks/hook_lib +115 -0
- data/bin/git/hooks/hooks-wrapper +38 -0
- data/bin/git/hooks/post-flow-hotfix-start/update-version +24 -0
- data/bin/git/hooks/post-flow-release-finish/update-version +29 -0
- data/bin/git/hooks/post-flow-release-start/update-version +19 -0
- data/bin/git/hooks/post-merge/update-hooks +6 -0
- data/bin/git/hooks/post-rewrite/update-hooks +6 -0
- data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
- data/bin/git/hooks/pre-commit/rubocop +25 -0
- data/bin/git/hooks/pre-commit/validate-diffs +45 -0
- data/bin/git/hooks/pre-commit/validate-yaml +18 -0
- data/bin/git/hooks/pre-push/check-changelog +24 -0
- data/bin/git/hooks/pre-push/rubocop +7 -0
- data/bin/git/update-hooks +123 -0
- data/bin/show_running_yang.rb +233 -0
- data/cisco_node_utils.gemspec +41 -0
- data/docs/README-develop-best-practices.md +521 -0
- data/docs/README-develop-node-utils-APIs.md +570 -0
- data/docs/README-maintainers.md +77 -0
- data/docs/README-test-execution.md +57 -0
- data/docs/README-utilities.md +14 -0
- data/docs/agent_files.png +0 -0
- data/docs/cisco_node_utils.yaml.example +36 -0
- data/docs/template-router.rb +123 -0
- data/docs/template-test_router.rb +104 -0
- data/ext/mkrf_conf.rb +63 -0
- data/lib/.rubocop.yml +18 -0
- data/lib/cisco_node_utils/aaa_authentication_login.rb +95 -0
- data/lib/cisco_node_utils/aaa_authentication_login_service.rb +138 -0
- data/lib/cisco_node_utils/aaa_authorization_service.rb +156 -0
- data/lib/cisco_node_utils/ace.rb +467 -0
- data/lib/cisco_node_utils/acl.rb +101 -0
- data/lib/cisco_node_utils/banner.rb +63 -0
- data/lib/cisco_node_utils/bfd_global.rb +305 -0
- data/lib/cisco_node_utils/bgp.rb +988 -0
- data/lib/cisco_node_utils/bgp_af.rb +545 -0
- data/lib/cisco_node_utils/bgp_af_aggr_addr.rb +207 -0
- data/lib/cisco_node_utils/bgp_neighbor.rb +527 -0
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +780 -0
- data/lib/cisco_node_utils/bridge_domain.rb +178 -0
- data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +444 -0
- data/lib/cisco_node_utils/client/client.rb +238 -0
- data/lib/cisco_node_utils/client/grpc/client.rb +395 -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/grpc.rb +33 -0
- data/lib/cisco_node_utils/client/nxapi/client.rb +368 -0
- data/lib/cisco_node_utils/client/nxapi.rb +31 -0
- data/lib/cisco_node_utils/client/utils.rb +180 -0
- data/lib/cisco_node_utils/client.rb +35 -0
- data/lib/cisco_node_utils/cmd_ref/README_YAML.md +590 -0
- data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +38 -0
- data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +40 -0
- data/lib/cisco_node_utils/cmd_ref/acl.yaml +48 -0
- data/lib/cisco_node_utils/cmd_ref/banner.yaml +11 -0
- data/lib/cisco_node_utils/cmd_ref/bfd_global.yaml +117 -0
- data/lib/cisco_node_utils/cmd_ref/bgp.yaml +383 -0
- data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +223 -0
- data/lib/cisco_node_utils/cmd_ref/bgp_af_aa.yaml +38 -0
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +174 -0
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +236 -0
- data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +49 -0
- data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
- data/lib/cisco_node_utils/cmd_ref/dhcp_relay_global.yaml +128 -0
- data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +55 -0
- data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_multicast.yaml +12 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_multisite.yaml +18 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_stormcontrol.yaml +18 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +48 -0
- data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +183 -0
- data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +40 -0
- data/lib/cisco_node_utils/cmd_ref/feature.yaml +126 -0
- data/lib/cisco_node_utils/cmd_ref/hostname.yaml +8 -0
- data/lib/cisco_node_utils/cmd_ref/hsrp_global.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/images.yaml +8 -0
- data/lib/cisco_node_utils/cmd_ref/interface.yaml +781 -0
- data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +45 -0
- data/lib/cisco_node_utils/cmd_ref/interface_evpn_multisite.yaml +17 -0
- data/lib/cisco_node_utils/cmd_ref/interface_hsrp_group.yaml +120 -0
- data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +112 -0
- data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +87 -0
- data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +42 -0
- data/lib/cisco_node_utils/cmd_ref/inventory.yaml +45 -0
- data/lib/cisco_node_utils/cmd_ref/ip_multicast.yaml +22 -0
- 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 +24 -0
- data/lib/cisco_node_utils/cmd_ref/ntp_auth_key.yaml +10 -0
- data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +27 -0
- data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +34 -0
- data/lib/cisco_node_utils/cmd_ref/object_group.yaml +32 -0
- data/lib/cisco_node_utils/cmd_ref/ospf.yaml +91 -0
- data/lib/cisco_node_utils/cmd_ref/ospf_area.yaml +91 -0
- data/lib/cisco_node_utils/cmd_ref/ospf_area_vlink.yaml +88 -0
- data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +37 -0
- data/lib/cisco_node_utils/cmd_ref/pim.yaml +43 -0
- data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +86 -0
- data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +37 -0
- data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +100 -0
- data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +19 -0
- data/lib/cisco_node_utils/cmd_ref/route_map.yaml +601 -0
- data/lib/cisco_node_utils/cmd_ref/show_system.yaml +9 -0
- data/lib/cisco_node_utils/cmd_ref/show_version.yaml +84 -0
- data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +81 -0
- data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +9 -0
- data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +74 -0
- data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +91 -0
- data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +57 -0
- data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +23 -0
- data/lib/cisco_node_utils/cmd_ref/span_session.yaml +65 -0
- data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +235 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_facility.yaml +10 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +34 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +45 -0
- data/lib/cisco_node_utils/cmd_ref/system.yaml +7 -0
- data/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml +37 -0
- data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +63 -0
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +45 -0
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +64 -0
- data/lib/cisco_node_utils/cmd_ref/upgrade.yaml +38 -0
- data/lib/cisco_node_utils/cmd_ref/vdc.yaml +52 -0
- data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +8 -0
- data/lib/cisco_node_utils/cmd_ref/vlan.yaml +106 -0
- data/lib/cisco_node_utils/cmd_ref/vpc.yaml +233 -0
- data/lib/cisco_node_utils/cmd_ref/vrf.yaml +86 -0
- data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +139 -0
- data/lib/cisco_node_utils/cmd_ref/vtp.yaml +32 -0
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +114 -0
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +71 -0
- data/lib/cisco_node_utils/cmd_ref/yang.yaml +7 -0
- data/lib/cisco_node_utils/cmd_ref/yum.yaml +68 -0
- data/lib/cisco_node_utils/command_reference.rb +724 -0
- data/lib/cisco_node_utils/configparser_lib.rb +195 -0
- data/lib/cisco_node_utils/constants.rb +40 -0
- data/lib/cisco_node_utils/dhcp_relay_global.rb +302 -0
- data/lib/cisco_node_utils/dns_domain.rb +93 -0
- data/lib/cisco_node_utils/domain_name.rb +82 -0
- data/lib/cisco_node_utils/encapsulation.rb +112 -0
- data/lib/cisco_node_utils/environment.rb +110 -0
- data/lib/cisco_node_utils/evpn_multicast.rb +66 -0
- data/lib/cisco_node_utils/evpn_multisite.rb +96 -0
- data/lib/cisco_node_utils/evpn_stormcontrol.rb +84 -0
- data/lib/cisco_node_utils/evpn_vni.rb +159 -0
- data/lib/cisco_node_utils/exceptions.rb +140 -0
- data/lib/cisco_node_utils/fabricpath_global.rb +405 -0
- data/lib/cisco_node_utils/fabricpath_topology.rb +137 -0
- data/lib/cisco_node_utils/feature.rb +377 -0
- data/lib/cisco_node_utils/hostname.rb +62 -0
- data/lib/cisco_node_utils/hsrp_global.rb +97 -0
- data/lib/cisco_node_utils/interface.rb +2128 -0
- data/lib/cisco_node_utils/interface_channel_group.rb +142 -0
- data/lib/cisco_node_utils/interface_evpn_multisite.rb +72 -0
- data/lib/cisco_node_utils/interface_hsrp_group.rb +557 -0
- data/lib/cisco_node_utils/interface_ospf.rb +378 -0
- data/lib/cisco_node_utils/interface_portchannel.rb +180 -0
- data/lib/cisco_node_utils/interface_service_vni.rb +132 -0
- data/lib/cisco_node_utils/ip_multicast.rb +90 -0
- data/lib/cisco_node_utils/itd_device_group.rb +228 -0
- data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
- data/lib/cisco_node_utils/itd_service.rb +511 -0
- data/lib/cisco_node_utils/logger.rb +78 -0
- data/lib/cisco_node_utils/name_server.rb +64 -0
- data/lib/cisco_node_utils/node.rb +443 -0
- data/lib/cisco_node_utils/node_util.rb +111 -0
- data/lib/cisco_node_utils/ntp_auth_key.rb +67 -0
- data/lib/cisco_node_utils/ntp_config.rb +83 -0
- data/lib/cisco_node_utils/ntp_server.rb +86 -0
- data/lib/cisco_node_utils/object_group.rb +75 -0
- data/lib/cisco_node_utils/object_group_entry.rb +143 -0
- data/lib/cisco_node_utils/overlay_global.rb +142 -0
- data/lib/cisco_node_utils/pim.rb +131 -0
- data/lib/cisco_node_utils/pim_group_list.rb +109 -0
- data/lib/cisco_node_utils/pim_rp_address.rb +103 -0
- data/lib/cisco_node_utils/platform.rb +217 -0
- data/lib/cisco_node_utils/portchannel_global.rb +347 -0
- data/lib/cisco_node_utils/radius_global.rb +165 -0
- data/lib/cisco_node_utils/radius_server.rb +421 -0
- data/lib/cisco_node_utils/radius_server_group.rb +117 -0
- data/lib/cisco_node_utils/route_map.rb +2540 -0
- data/lib/cisco_node_utils/router_ospf.rb +77 -0
- data/lib/cisco_node_utils/router_ospf_area.rb +416 -0
- data/lib/cisco_node_utils/router_ospf_area_vlink.rb +313 -0
- data/lib/cisco_node_utils/router_ospf_vrf.rb +342 -0
- data/lib/cisco_node_utils/snmp_notification_receiver.rb +176 -0
- data/lib/cisco_node_utils/snmpcommunity.rb +109 -0
- data/lib/cisco_node_utils/snmpgroup.rb +54 -0
- data/lib/cisco_node_utils/snmpnotification.rb +57 -0
- data/lib/cisco_node_utils/snmpserver.rb +132 -0
- data/lib/cisco_node_utils/snmpuser.rb +403 -0
- data/lib/cisco_node_utils/span_session.rb +149 -0
- data/lib/cisco_node_utils/stp_global.rb +676 -0
- data/lib/cisco_node_utils/syslog_facility.rb +64 -0
- data/lib/cisco_node_utils/syslog_server.rb +146 -0
- data/lib/cisco_node_utils/syslog_settings.rb +174 -0
- data/lib/cisco_node_utils/tacacs_global.rb +137 -0
- data/lib/cisco_node_utils/tacacs_server.rb +173 -0
- data/lib/cisco_node_utils/tacacs_server_group.rb +149 -0
- data/lib/cisco_node_utils/tacacs_server_host.rb +216 -0
- data/lib/cisco_node_utils/upgrade.rb +122 -0
- data/lib/cisco_node_utils/vdc.rb +118 -0
- data/lib/cisco_node_utils/version.rb +21 -0
- data/lib/cisco_node_utils/vlan.rb +301 -0
- data/lib/cisco_node_utils/vpc.rb +466 -0
- data/lib/cisco_node_utils/vrf.rb +192 -0
- data/lib/cisco_node_utils/vrf_af.rb +327 -0
- data/lib/cisco_node_utils/vtp.rb +125 -0
- data/lib/cisco_node_utils/vxlan_vtep.rb +286 -0
- data/lib/cisco_node_utils/vxlan_vtep_vni.rb +331 -0
- data/lib/cisco_node_utils/yang.rb +160 -0
- data/lib/cisco_node_utils/yum.rb +213 -0
- data/lib/cisco_node_utils.rb +21 -0
- 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 +384 -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 +82 -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 +18 -0
- data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
- data/tests/basetest.rb +243 -0
- data/tests/ciscotest.rb +577 -0
- data/tests/cmd_config.yaml +75 -0
- data/tests/cmd_config_invalid.yaml +16 -0
- data/tests/n9000_sample-1.0.0-7.0.3.x86_64.rpm +0 -0
- data/tests/noop.rb +7 -0
- data/tests/platform_info.rb +63 -0
- data/tests/tacacs_server.yaml.example +6 -0
- data/tests/test_aaa_authentication_login.rb +243 -0
- data/tests/test_aaa_authentication_login_service.rb +761 -0
- data/tests/test_aaa_authorization_service.rb +874 -0
- data/tests/test_ace.rb +304 -0
- data/tests/test_acl.rb +185 -0
- data/tests/test_banner.rb +85 -0
- data/tests/test_bfd_global.rb +272 -0
- data/tests/test_bgp_af.rb +875 -0
- data/tests/test_bgp_af_aa.rb +108 -0
- data/tests/test_bgp_neighbor.rb +596 -0
- data/tests/test_bgp_neighbor_af.rb +781 -0
- data/tests/test_bridge_domain.rb +198 -0
- data/tests/test_bridge_domain_vni.rb +109 -0
- data/tests/test_client_utils.rb +111 -0
- data/tests/test_cmn_utils.rb +76 -0
- data/tests/test_command_config.rb +206 -0
- data/tests/test_command_reference.rb +669 -0
- data/tests/test_dhcp_relay_global.rb +286 -0
- data/tests/test_dns_domain.rb +123 -0
- data/tests/test_domain_name.rb +96 -0
- data/tests/test_encapsulation.rb +75 -0
- data/tests/test_evpn_multicast.rb +65 -0
- data/tests/test_evpn_multisite.rb +70 -0
- data/tests/test_evpn_stormcontrol.rb +56 -0
- data/tests/test_evpn_vni.rb +131 -0
- data/tests/test_fabricpath_global.rb +246 -0
- data/tests/test_fabricpath_topology.rb +77 -0
- data/tests/test_feature.rb +272 -0
- data/tests/test_grpc.rb +166 -0
- data/tests/test_hostname.rb +64 -0
- data/tests/test_hsrp_global.rb +79 -0
- data/tests/test_interface.rb +1958 -0
- data/tests/test_interface_bdi.rb +80 -0
- data/tests/test_interface_channel_group.rb +131 -0
- data/tests/test_interface_evpn_multisite.rb +94 -0
- data/tests/test_interface_hsrp.rb +134 -0
- data/tests/test_interface_hsrp_group.rb +570 -0
- data/tests/test_interface_ospf.rb +820 -0
- data/tests/test_interface_portchannel.rb +135 -0
- data/tests/test_interface_private_vlan.rb +365 -0
- data/tests/test_interface_service_vni.rb +203 -0
- data/tests/test_interface_svi.rb +210 -0
- data/tests/test_interface_switchport.rb +468 -0
- data/tests/test_ip_multicast.rb +80 -0
- 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 +314 -0
- data/tests/test_logger.rb +43 -0
- data/tests/test_name_server.rb +94 -0
- data/tests/test_node.rb +50 -0
- data/tests/test_node_ext.rb +406 -0
- data/tests/test_node_util.rb +119 -0
- data/tests/test_ntp_auth_key.rb +77 -0
- data/tests/test_ntp_config.rb +100 -0
- data/tests/test_ntp_server.rb +146 -0
- data/tests/test_nxapi.rb +236 -0
- data/tests/test_object_group.rb +122 -0
- data/tests/test_overlay_global.rb +108 -0
- data/tests/test_pim.rb +203 -0
- data/tests/test_pim_group_list.rb +147 -0
- data/tests/test_pim_rp_address.rb +155 -0
- data/tests/test_platform.rb +254 -0
- data/tests/test_portchannel_global.rb +322 -0
- data/tests/test_radius_global.rb +108 -0
- data/tests/test_radius_server.rb +377 -0
- data/tests/test_radius_server_group.rb +151 -0
- data/tests/test_route_map.rb +1479 -0
- data/tests/test_router_bgp.rb +1325 -0
- data/tests/test_router_ospf.rb +56 -0
- data/tests/test_router_ospf_area.rb +433 -0
- data/tests/test_router_ospf_area_vlink.rb +298 -0
- data/tests/test_router_ospf_vrf.rb +690 -0
- data/tests/test_snmp_notification_receiver.rb +169 -0
- data/tests/test_snmpcommunity.rb +422 -0
- data/tests/test_snmpgroup.rb +71 -0
- data/tests/test_snmpnotification.rb +91 -0
- data/tests/test_snmpserver.rb +251 -0
- data/tests/test_snmpuser.rb +666 -0
- data/tests/test_span_session.rb +155 -0
- data/tests/test_stp_global.rb +575 -0
- data/tests/test_syslog_facility.rb +80 -0
- data/tests/test_syslog_server.rb +119 -0
- data/tests/test_syslog_settings.rb +123 -0
- data/tests/test_tacacs_global.rb +109 -0
- data/tests/test_tacacs_server.rb +436 -0
- data/tests/test_tacacs_server_group.rb +434 -0
- data/tests/test_tacacs_server_host.rb +427 -0
- data/tests/test_upgrade.rb +105 -0
- data/tests/test_vdc.rb +64 -0
- data/tests/test_vlan.rb +386 -0
- data/tests/test_vlan_private.rb +656 -0
- data/tests/test_vpc.rb +548 -0
- data/tests/test_vrf.rb +248 -0
- data/tests/test_vrf_af.rb +288 -0
- data/tests/test_vtp.rb +278 -0
- data/tests/test_vxlan_vtep.rb +327 -0
- data/tests/test_vxlan_vtep_vni.rb +326 -0
- data/tests/test_yang.rb +369 -0
- data/tests/test_yum.rb +109 -0
- data/tests/upgrade_info.yaml.example +3 -0
- data/tests/yum_package.yaml +94 -0
- metadata +534 -0
|
@@ -0,0 +1,33 @@
|
|
|
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 }
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# NXAPI client library.
|
|
2
|
+
#
|
|
3
|
+
# November 2014, Glenn F. Matthews
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2014-2019 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 '../client'
|
|
20
|
+
require 'json'
|
|
21
|
+
require 'net/http'
|
|
22
|
+
|
|
23
|
+
include Cisco::Logger
|
|
24
|
+
|
|
25
|
+
# Class representing an HTTP client connecting to a NXAPI server.
|
|
26
|
+
class Cisco::Client::NXAPI < Cisco::Client
|
|
27
|
+
# Location of unix domain socket for NXAPI localhost
|
|
28
|
+
NXAPI_UDS = '/tmp/nginx_local/nginx_1_be_nxapi.sock'
|
|
29
|
+
# NXAPI listens for remote connections to "http://<switch IP>/ins"
|
|
30
|
+
# NXAPI listens for local connections to "http://<UDS>/ins_local"
|
|
31
|
+
NXAPI_REMOTE_URI_PATH = '/ins'
|
|
32
|
+
NXAPI_UDS_URI_PATH = '/ins_local'
|
|
33
|
+
# Latest supported version is 1.0
|
|
34
|
+
NXAPI_VERSION = '1.0'
|
|
35
|
+
|
|
36
|
+
register_client(self)
|
|
37
|
+
|
|
38
|
+
# Constructor for Client. By default this connects to the local
|
|
39
|
+
# unix domain socket. If you need to connect to a remote device,
|
|
40
|
+
# you must provide the host/username/password parameters.
|
|
41
|
+
def initialize(**kwargs)
|
|
42
|
+
# rubocop:disable Style/HashSyntax
|
|
43
|
+
super(data_formats: [:nxapi_structured, :cli],
|
|
44
|
+
platform: :nexus,
|
|
45
|
+
**kwargs)
|
|
46
|
+
# rubocop:enable Style/HashSyntax
|
|
47
|
+
# Default: connect to unix domain socket on localhost, if available
|
|
48
|
+
if @host.nil?
|
|
49
|
+
unless File.socket?(NXAPI_UDS)
|
|
50
|
+
fail Cisco::ConnectionRefused, \
|
|
51
|
+
"No host specified but no UDS found at #{NXAPI_UDS} either"
|
|
52
|
+
end
|
|
53
|
+
# net_http_unix provides NetX::HTTPUnix, a small subclass of Net::HTTP
|
|
54
|
+
# which supports connection to local unix domain sockets. We need this
|
|
55
|
+
# in order to run natively under NX-OS but it's not needed for off-box
|
|
56
|
+
# unit testing where the base Net::HTTP will meet our needs.
|
|
57
|
+
require 'net_http_unix'
|
|
58
|
+
@http = NetX::HTTPUnix.new('unix://' + NXAPI_UDS)
|
|
59
|
+
@cookie = kwargs[:cookie]
|
|
60
|
+
else
|
|
61
|
+
# Remote connection. This is primarily expected
|
|
62
|
+
# when running e.g. from a Unix server as part of Minitest.
|
|
63
|
+
@transport = kwargs[:transport] || 'http'
|
|
64
|
+
@verify_mode = kwargs[:verify_mode] || 'none'
|
|
65
|
+
@port.nil? ? @port = '' : @port = ":#{@port}"
|
|
66
|
+
uri = URI.parse("#{@transport}://#{@host}#{@port}")
|
|
67
|
+
@http = Net::HTTP.new(uri.host, uri.port)
|
|
68
|
+
end
|
|
69
|
+
# The default read time out is 60 seconds, which may be too short for
|
|
70
|
+
# scaled configuration to apply. Change it to 300 seconds, which is
|
|
71
|
+
# also used as the default config by firefox.
|
|
72
|
+
@http.read_timeout = 300
|
|
73
|
+
@address = @http.address
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.validate_args(**kwargs)
|
|
77
|
+
super
|
|
78
|
+
if kwargs[:host].nil?
|
|
79
|
+
# Connection to UDS - no username or password either
|
|
80
|
+
fail ArgumentError unless kwargs[:username].nil? && kwargs[:password].nil?
|
|
81
|
+
validate_cookie(**kwargs)
|
|
82
|
+
else
|
|
83
|
+
# Connection to remote system - username and password are required
|
|
84
|
+
fail TypeError, 'username is required' if kwargs[:username].nil?
|
|
85
|
+
fail TypeError, 'password is required' if kwargs[:password].nil?
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def self.validate_cookie(**kwargs)
|
|
90
|
+
return if kwargs[:cookie].nil?
|
|
91
|
+
format = 'Cookie format must match: <username>:local'
|
|
92
|
+
msg = "Invalid cookie: [#{kwargs[:cookie]}]. : #{format}"
|
|
93
|
+
|
|
94
|
+
fail TypeError, msg unless kwargs[:cookie].is_a?(String)
|
|
95
|
+
fail TypeError, msg unless /\S+:local/.match(kwargs[:cookie])
|
|
96
|
+
fail ArgumentError, 'empty cookie' if kwargs[:cookie].empty?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Clear the cache of CLI output results.
|
|
100
|
+
#
|
|
101
|
+
# If cache_auto is true (default) then this will be performed automatically
|
|
102
|
+
# whenever a set() is called, but providers may also call this
|
|
103
|
+
# to explicitly force the cache to be cleared.
|
|
104
|
+
def cache_flush
|
|
105
|
+
@cache_hash = {
|
|
106
|
+
'cli_conf' => {},
|
|
107
|
+
'cli_show' => {},
|
|
108
|
+
'cli_show_ascii' => {},
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Configure the given CLI command(s) on the device.
|
|
113
|
+
#
|
|
114
|
+
# @raise [RequestNotSupported] if this client doesn't support CLI config
|
|
115
|
+
#
|
|
116
|
+
# @param data_format one of Cisco::DATA_FORMATS. Default is :cli
|
|
117
|
+
# @param context [String, Array<String>] Zero or more configuration commands
|
|
118
|
+
# used to enter the desired CLI sub-mode
|
|
119
|
+
# @param values [String, Array<String>] One or more commands
|
|
120
|
+
# to enter within the CLI sub-mode.
|
|
121
|
+
# @param kwargs data-format-specific args
|
|
122
|
+
def set(data_format: :cli,
|
|
123
|
+
context: nil,
|
|
124
|
+
values: nil,
|
|
125
|
+
**_kwargs)
|
|
126
|
+
# we don't currently support nxapi_structured for configuration
|
|
127
|
+
fail Cisco::RequestNotSupported if data_format == :nxapi_structured
|
|
128
|
+
context = munge_to_array(context)
|
|
129
|
+
values = munge_to_array(values)
|
|
130
|
+
super
|
|
131
|
+
req('cli_conf', context + values)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Get the given state from the device.
|
|
135
|
+
#
|
|
136
|
+
# Unlike set() this will not clear the CLI cache;
|
|
137
|
+
# multiple calls with the same parameters may return cached data
|
|
138
|
+
# rather than querying the device repeatedly.
|
|
139
|
+
#
|
|
140
|
+
# @raise [Cisco::RequestNotSupported] if
|
|
141
|
+
# structured output is requested but the given command can't provide it.
|
|
142
|
+
# @raise [Cisco::CliError] if the command is rejected by the device
|
|
143
|
+
#
|
|
144
|
+
# @param data_format one of Cisco::DATA_FORMATS. Default is :cli
|
|
145
|
+
# @param command [String] the show command to execute
|
|
146
|
+
# @param context [String, Array<String>] Context to refine the results
|
|
147
|
+
# @param value [String] Specific key to look up
|
|
148
|
+
# @param kwargs data-format-specific args
|
|
149
|
+
# @return [String, Hash]
|
|
150
|
+
def get(data_format: :cli,
|
|
151
|
+
command: nil,
|
|
152
|
+
context: nil,
|
|
153
|
+
value: nil,
|
|
154
|
+
**_kwargs)
|
|
155
|
+
context = munge_to_array(context)
|
|
156
|
+
super
|
|
157
|
+
if data_format == :cli
|
|
158
|
+
output = req('cli_show_ascii', command)
|
|
159
|
+
return self.class.filter_cli(cli_output: output,
|
|
160
|
+
context: context,
|
|
161
|
+
value: value)
|
|
162
|
+
elsif data_format == :nxapi_structured
|
|
163
|
+
output = req('cli_show', command)
|
|
164
|
+
return self.class.filter_data(data: output,
|
|
165
|
+
keys: context + munge_to_array(value))
|
|
166
|
+
else
|
|
167
|
+
fail TypeError
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Helper method to increase the default @http.read_timeout value from
|
|
172
|
+
# the default value of 300 to accomodate commands that are known to
|
|
173
|
+
# require more time to complete.
|
|
174
|
+
def read_timeout_check(request)
|
|
175
|
+
return unless request.body[/install all|install force-all/]
|
|
176
|
+
debug("Increasing http read_timeout to 1000 for 'install all' command")
|
|
177
|
+
@http.read_timeout = 1000
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Sends a request to the NX API and returns the body of the request or
|
|
181
|
+
# handles errors that happen.
|
|
182
|
+
# @raise Cisco::ConnectionRefused if NXAPI is disabled
|
|
183
|
+
# @raise Cisco::AuthenticationFailed if username/password are invalid
|
|
184
|
+
# @raise Cisco::ClientError (should never occur)
|
|
185
|
+
# @raise Cisco::RequestNotSupported
|
|
186
|
+
# @raise Cisco::RequestFailed if any command is rejected as invalid
|
|
187
|
+
#
|
|
188
|
+
# @param type ["cli_show", "cli_show_ascii"] Specifies the type of command
|
|
189
|
+
# to be executed.
|
|
190
|
+
# @param command_or_list [String, Array<String>] The command or array of
|
|
191
|
+
# commands which should be run.
|
|
192
|
+
# @return [Hash, Array<Hash>] output when type == "cli_show"
|
|
193
|
+
# @return [String, Array<String>] output when type == "cli_show_ascii"
|
|
194
|
+
def req(type, command_or_list)
|
|
195
|
+
if command_or_list.is_a?(Array)
|
|
196
|
+
# NXAPI wants config lines to be separated by ' ; '
|
|
197
|
+
command = command_or_list.join(' ; ')
|
|
198
|
+
else
|
|
199
|
+
command = command_or_list
|
|
200
|
+
command_or_list = [command]
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
debug("Input (#{type}): \'#{command}\'")
|
|
204
|
+
if cache_enable? && @cache_hash[type] && @cache_hash[type][command]
|
|
205
|
+
return @cache_hash[type][command]
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# form the request
|
|
209
|
+
request = build_http_request(type, command)
|
|
210
|
+
|
|
211
|
+
# send the request and get the response
|
|
212
|
+
debug("Sending #{@transport} request to NX-API at #{@http.address}:\n" \
|
|
213
|
+
"#{request.to_hash}\n#{request.body}")
|
|
214
|
+
read_timeout_check(request)
|
|
215
|
+
tries = 2
|
|
216
|
+
begin
|
|
217
|
+
if @transport == 'https'
|
|
218
|
+
debug('Setting use_ssl to true')
|
|
219
|
+
@http.use_ssl = true
|
|
220
|
+
@http.verify_mode = handle_verify_mode(@verify_mode)
|
|
221
|
+
else
|
|
222
|
+
@http.use_ssl = false
|
|
223
|
+
end
|
|
224
|
+
response = @http.request(request)
|
|
225
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
|
226
|
+
emsg = 'Connection refused or reset. Is the NX-API feature enabled?'
|
|
227
|
+
raise Cisco::ConnectionRefused, emsg
|
|
228
|
+
rescue EOFError
|
|
229
|
+
tries -= 1
|
|
230
|
+
retry if tries > 0
|
|
231
|
+
raise
|
|
232
|
+
end
|
|
233
|
+
handle_http_response(response)
|
|
234
|
+
output = parse_response(response)
|
|
235
|
+
|
|
236
|
+
prev_cmds = []
|
|
237
|
+
if output.is_a?(Array)
|
|
238
|
+
output.zip(command_or_list) do |o, cmd|
|
|
239
|
+
handle_output(prev_cmds, cmd, o)
|
|
240
|
+
prev_cmds << cmd
|
|
241
|
+
end
|
|
242
|
+
output = output.each { |o| o['body'] }
|
|
243
|
+
else
|
|
244
|
+
handle_output(prev_cmds, command, output)
|
|
245
|
+
output = output['body']
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
output = '' if type == 'cli_show_ascii' && output.empty?
|
|
249
|
+
|
|
250
|
+
@cache_hash[type][command] = output if cache_enable?
|
|
251
|
+
output
|
|
252
|
+
end
|
|
253
|
+
private :req
|
|
254
|
+
|
|
255
|
+
def build_http_request(type, command_string)
|
|
256
|
+
if @username.nil? || @password.nil?
|
|
257
|
+
cookie = @cookie.nil? ? 'admin:local' : @cookie
|
|
258
|
+
request = Net::HTTP::Post.new(NXAPI_UDS_URI_PATH)
|
|
259
|
+
request['Cookie'] = "nxapi_auth=#{cookie}"
|
|
260
|
+
else
|
|
261
|
+
request = Net::HTTP::Post.new(NXAPI_REMOTE_URI_PATH)
|
|
262
|
+
request.basic_auth("#{@username}", "#{@password}")
|
|
263
|
+
end
|
|
264
|
+
request.content_type = 'application/json'
|
|
265
|
+
request.body = {
|
|
266
|
+
'ins_api' => {
|
|
267
|
+
'version' => NXAPI_VERSION,
|
|
268
|
+
'type' => "#{type}",
|
|
269
|
+
'chunk' => '0',
|
|
270
|
+
'sid' => '1',
|
|
271
|
+
'input' => "#{command_string}",
|
|
272
|
+
'output_format' => 'json',
|
|
273
|
+
}
|
|
274
|
+
}.to_json
|
|
275
|
+
request
|
|
276
|
+
end
|
|
277
|
+
private :build_http_request
|
|
278
|
+
|
|
279
|
+
# Returns the OpenSSL verify mode based on the verify_mode arguments
|
|
280
|
+
#
|
|
281
|
+
# @raise if verify_mode param is not `peer`, `client-once`, `fail-no-peer`
|
|
282
|
+
# or `none`
|
|
283
|
+
#
|
|
284
|
+
# @param String verify mode to use
|
|
285
|
+
#
|
|
286
|
+
# @return OpenSSL::SSL verification mode
|
|
287
|
+
def handle_verify_mode(verify_mode)
|
|
288
|
+
case verify_mode
|
|
289
|
+
when 'peer'
|
|
290
|
+
OpenSSL::SSL::VERIFY_PEER
|
|
291
|
+
when 'client-once'
|
|
292
|
+
OpenSSL::SSL::VERIFY_CLIENT_ONCE
|
|
293
|
+
when 'fail-no-peer'
|
|
294
|
+
OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
|
295
|
+
when 'none'
|
|
296
|
+
OpenSSL::SSL::VERIFY_NONE
|
|
297
|
+
else
|
|
298
|
+
fail "#{verify_mode} is not a valid mode, " \
|
|
299
|
+
'valid modes are: "none", "peer", ' \
|
|
300
|
+
'"client-once", "fail-no-peer"'
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
private :handle_verify_mode
|
|
304
|
+
|
|
305
|
+
def handle_http_response(response)
|
|
306
|
+
debug("HTTP Response: #{response.message}\n#{response.body}")
|
|
307
|
+
case response
|
|
308
|
+
when Net::HTTPUnauthorized
|
|
309
|
+
emsg = 'HTTP 401 Unauthorized. Are your NX-API credentials correct?'
|
|
310
|
+
fail Cisco::AuthenticationFailed, emsg
|
|
311
|
+
when Net::HTTPBadRequest
|
|
312
|
+
emsg = "HTTP 400 Bad Request\n#{response.body}"
|
|
313
|
+
fail Cisco::ClientError, emsg
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
private :handle_http_response
|
|
317
|
+
|
|
318
|
+
def parse_response(response)
|
|
319
|
+
body = JSON.parse(response.body)
|
|
320
|
+
|
|
321
|
+
# In case of an error the JSON may not be complete, so we need to
|
|
322
|
+
# proceed carefully, as blindly doing body["ins_api"]["outputs"]["output"]
|
|
323
|
+
# could throw an error otherwise.
|
|
324
|
+
output = body['ins_api']
|
|
325
|
+
fail Cisco::ClientError, "unexpected JSON output:\n#{body}" if output.nil?
|
|
326
|
+
output = output['outputs'] if output['outputs']
|
|
327
|
+
output = output['output'] if output['output']
|
|
328
|
+
|
|
329
|
+
output
|
|
330
|
+
rescue JSON::ParserError
|
|
331
|
+
raise Cisco::ClientError, "response is not JSON:\n#{response.body}"
|
|
332
|
+
end
|
|
333
|
+
private :parse_response
|
|
334
|
+
|
|
335
|
+
def handle_output(prev_cmds, command, output)
|
|
336
|
+
if output['code'] == '400'
|
|
337
|
+
# CLI error.
|
|
338
|
+
# Examples: "Invalid input", "Incomplete command", etc.
|
|
339
|
+
fail Cisco::CliError.new( # rubocop:disable Style/RaiseArgs
|
|
340
|
+
rejected_input: command,
|
|
341
|
+
clierror: output['clierror'],
|
|
342
|
+
msg: output['msg'],
|
|
343
|
+
code: output['code'],
|
|
344
|
+
successful_input: prev_cmds,
|
|
345
|
+
)
|
|
346
|
+
elsif output['code'] == '413'
|
|
347
|
+
# Request too large
|
|
348
|
+
fail Cisco::RequestNotSupported, "Error 413: #{output['msg']}"
|
|
349
|
+
elsif output['code'] == '501'
|
|
350
|
+
# if structured output is not supported for this command,
|
|
351
|
+
# raise an exception so that the calling function can
|
|
352
|
+
# handle accordingly
|
|
353
|
+
fail Cisco::RequestNotSupported, \
|
|
354
|
+
"Structured output not supported for #{command}"
|
|
355
|
+
# Error 432: Requested object does not exist
|
|
356
|
+
# Ignore 432 errors because it means that a property is not configured
|
|
357
|
+
elsif output['code'] =~ /[45]\d\d/ && output['code'] != '432'
|
|
358
|
+
fail Cisco::RequestFailed, \
|
|
359
|
+
"#{output['code']} Error: #{output['msg']}"
|
|
360
|
+
else
|
|
361
|
+
debug("Result for '#{command}': #{output['msg']}")
|
|
362
|
+
if output['body'] && !output['body'].empty?
|
|
363
|
+
debug("Output: #{output['body']}")
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
private :handle_output
|
|
368
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
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 }
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# January 2016, Glenn F. Matthews
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2015-2016 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 '../constants'
|
|
20
|
+
require_relative '../logger'
|
|
21
|
+
|
|
22
|
+
# Utility methods for clients of various RPC formats
|
|
23
|
+
class Cisco::Client
|
|
24
|
+
# Make a best effort to convert a given input value to an Array.
|
|
25
|
+
# Strings are split by newlines, and nil becomes an empty Array.
|
|
26
|
+
def self.munge_to_array(val)
|
|
27
|
+
val = [] if val.nil?
|
|
28
|
+
val = val.split("\n") if val.is_a?(String)
|
|
29
|
+
val
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def munge_to_array(val)
|
|
33
|
+
self.class.munge_to_array(val)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Helper function that subclasses may use with get(data_format: :cli)
|
|
37
|
+
# Method for working with hierarchical show command output such as
|
|
38
|
+
# "show running-config". Searches the given multi-line string
|
|
39
|
+
# for all matches to the given value query. If context is provided,
|
|
40
|
+
# the matches will be filtered to only those that are located "under"
|
|
41
|
+
# the given context sequence (as determined by indentation).
|
|
42
|
+
#
|
|
43
|
+
# @param cli_output [String] The body of text to search
|
|
44
|
+
# @param context [*Regex] zero or more regular expressions defining
|
|
45
|
+
# the parent configs to filter by.
|
|
46
|
+
# @param value [Regex] The regular expression to match
|
|
47
|
+
# @return [[String], nil] array of matching (sub)strings, else nil.
|
|
48
|
+
#
|
|
49
|
+
# @example Find all OSPF router names in the running-config
|
|
50
|
+
# ospf_names = filter_cli(cli_output: running_cfg,
|
|
51
|
+
# value: /^router ospf (\d+)/)
|
|
52
|
+
#
|
|
53
|
+
# @example Find all address-family types under the given BGP router
|
|
54
|
+
# bgp_afs = filter_cli(cli_output: show_run_bgp,
|
|
55
|
+
# context: [/^router bgp #{ASN}/],
|
|
56
|
+
# value: /^address-family (.*)/)
|
|
57
|
+
def self.filter_cli(cli_output: nil,
|
|
58
|
+
context: nil,
|
|
59
|
+
value: nil)
|
|
60
|
+
return cli_output if cli_output.nil?
|
|
61
|
+
context ||= []
|
|
62
|
+
context.each { |filter| cli_output = find_subconfig(cli_output, filter) }
|
|
63
|
+
return nil if cli_output.nil? || cli_output.empty?
|
|
64
|
+
return cli_output if value.nil?
|
|
65
|
+
value = to_regexp(value)
|
|
66
|
+
match = cli_output.scan(value)
|
|
67
|
+
return nil if match.empty?
|
|
68
|
+
# find matches and return as array of String if it only does one match.
|
|
69
|
+
# Otherwise return array of array.
|
|
70
|
+
match.flatten! if match[0].is_a?(Array) && match[0].length == 1
|
|
71
|
+
match
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Returns the subsection associated with the given
|
|
75
|
+
# line of config
|
|
76
|
+
# @param [String] the body of text to search
|
|
77
|
+
# @param [Regex] the regex key of the config for which
|
|
78
|
+
# to retrieve the subsection
|
|
79
|
+
# @return [String, nil] the subsection of body, de-indented
|
|
80
|
+
# appropriately, or nil if no such subsection exists.
|
|
81
|
+
def self.find_subconfig(body, regexp_query)
|
|
82
|
+
return nil if body.nil? || regexp_query.nil?
|
|
83
|
+
regexp_query = to_regexp(regexp_query)
|
|
84
|
+
|
|
85
|
+
rows = body.split("\n")
|
|
86
|
+
match_row_index = rows.index { |row| regexp_query =~ row }
|
|
87
|
+
return nil if match_row_index.nil?
|
|
88
|
+
|
|
89
|
+
cur = match_row_index + 1
|
|
90
|
+
subconfig = []
|
|
91
|
+
|
|
92
|
+
until (/\A\s+.*/ =~ rows[cur]).nil? || cur == rows.length
|
|
93
|
+
subconfig << rows[cur]
|
|
94
|
+
cur += 1
|
|
95
|
+
end
|
|
96
|
+
return nil if subconfig.empty?
|
|
97
|
+
# Strip an appropriate minimal amount of leading whitespace from
|
|
98
|
+
# all lines in the subconfig
|
|
99
|
+
min_leading = subconfig.map { |line| line[/\A */].size }.min
|
|
100
|
+
subconfig = subconfig.map { |line| line[min_leading..-1] }
|
|
101
|
+
subconfig.join("\n")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Helper method for CLI getters
|
|
105
|
+
#
|
|
106
|
+
# Convert a string or array of strings to a Regexp or array thereof
|
|
107
|
+
def self.to_regexp(input)
|
|
108
|
+
if input.is_a?(Regexp)
|
|
109
|
+
return input
|
|
110
|
+
elsif input.is_a?(Array)
|
|
111
|
+
return input.map { |item| to_regexp(item) }
|
|
112
|
+
else
|
|
113
|
+
# The string might be explicitly formatted as a regexp
|
|
114
|
+
# Dynamically handle modifiers
|
|
115
|
+
input.match(%r{(?<regex>^\/.*\/)(?<options>[imx]*)?}) do |m|
|
|
116
|
+
options = []
|
|
117
|
+
m['options'].each_char do |c|
|
|
118
|
+
case c
|
|
119
|
+
when 'i'
|
|
120
|
+
options << Regexp::IGNORECASE
|
|
121
|
+
when 'm'
|
|
122
|
+
options << Regexp::MULTILINE
|
|
123
|
+
when 'x'
|
|
124
|
+
options << Regexp::EXTENDED
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
return Regexp.new(m['regex'][1..-2], options.reduce(:|))
|
|
128
|
+
end
|
|
129
|
+
# otherwise this value is a regular string
|
|
130
|
+
# convert to case insensitive regex
|
|
131
|
+
# 'foo' => %r{^foo$}i
|
|
132
|
+
return Regexp.new("^#{input}$", Regexp::IGNORECASE)
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Helper method for get(data_format: :nxapi_structured).
|
|
138
|
+
#
|
|
139
|
+
# @param data [Array, Hash] structured output from node
|
|
140
|
+
# @param keys [Array] lookup sequence
|
|
141
|
+
def self.filter_data(data: nil,
|
|
142
|
+
keys: nil)
|
|
143
|
+
return nil if data.nil? || data.empty?
|
|
144
|
+
keys ||= []
|
|
145
|
+
keys.each do |filter|
|
|
146
|
+
# if filter is a Hash and data is an array, check each
|
|
147
|
+
# array index (which should return another hash) to see if
|
|
148
|
+
# it contains the matching key/value pairs specified in token,
|
|
149
|
+
# and return the first match (or nil)
|
|
150
|
+
if filter.kind_of?(Hash)
|
|
151
|
+
fail "Expected Array, got #{data.class}" unless data.is_a? Array
|
|
152
|
+
data = data.select { |x| filter.all? { |k, v| x[k] == v } }
|
|
153
|
+
fail "Multiple matches found for #{filter}" if data.length > 1
|
|
154
|
+
fail "No match found for #{filter}" if data.length == 0
|
|
155
|
+
data = data[0]
|
|
156
|
+
else # data is array or hash
|
|
157
|
+
if data.is_a? Array
|
|
158
|
+
final = []
|
|
159
|
+
data.each do |row|
|
|
160
|
+
final << row[filter]
|
|
161
|
+
end
|
|
162
|
+
return final
|
|
163
|
+
end
|
|
164
|
+
fail "No key \"#{filter}\" in #{data}" unless data.key?(filter)
|
|
165
|
+
data = data[filter]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
data
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Helper method for calls into third-party code - suppresses Ruby warnings
|
|
172
|
+
# for the given block since we have no control over that code.
|
|
173
|
+
def self.silence_warnings(&block)
|
|
174
|
+
warn_level = $VERBOSE
|
|
175
|
+
$VERBOSE = nil
|
|
176
|
+
result = block.call
|
|
177
|
+
$VERBOSE = warn_level
|
|
178
|
+
result
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|