cisco_node_utils 1.2.0 → 1.3.0
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 +4 -4
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -1
- data/CHANGELOG.md +81 -2
- data/CONTRIBUTING.md +2 -17
- data/Gemfile +5 -0
- data/README.md +92 -47
- data/Rakefile +23 -1
- data/bin/git/hooks/hook_lib +7 -0
- data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
- data/bin/git/hooks/pre-commit/rubocop +7 -2
- data/bin/git/hooks/pre-commit/validate-diffs +18 -4
- data/bin/git/hooks/pre-commit/validate-yaml +18 -0
- data/bin/git/update-hooks +64 -6
- data/cisco_node_utils.gemspec +9 -6
- data/docs/README-develop-best-practices.md +149 -50
- data/docs/README-develop-node-utils-APIs.md +92 -42
- data/docs/README-maintainers.md +7 -4
- data/docs/README-test-execution.md +57 -0
- data/docs/cisco_node_utils.yaml.example +30 -0
- data/docs/template-router.rb +4 -0
- data/ext/mkrf_conf.rb +63 -0
- data/lib/.rubocop.yml +2 -2
- data/lib/cisco_node_utils.rb +5 -0
- data/lib/cisco_node_utils/aaa_authentication_login.rb +5 -6
- data/lib/cisco_node_utils/aaa_authorization_service.rb +1 -1
- data/lib/cisco_node_utils/ace.rb +165 -12
- data/lib/cisco_node_utils/acl.rb +2 -1
- data/lib/cisco_node_utils/bgp.rb +184 -21
- data/lib/cisco_node_utils/bgp_af.rb +94 -249
- data/lib/cisco_node_utils/bgp_neighbor.rb +94 -14
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +75 -8
- data/lib/cisco_node_utils/bridge_domain.rb +183 -0
- data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +85 -2
- data/lib/cisco_node_utils/client.rb +35 -0
- data/lib/cisco_node_utils/client/client.rb +234 -0
- data/lib/cisco_node_utils/client/grpc.rb +33 -0
- data/lib/cisco_node_utils/client/grpc/client.rb +311 -0
- data/lib/cisco_node_utils/client/grpc/ems.proto +148 -0
- data/lib/cisco_node_utils/client/grpc/ems.rb +111 -0
- data/lib/cisco_node_utils/client/grpc/ems_services.rb +49 -0
- data/lib/cisco_node_utils/client/nxapi.rb +31 -0
- data/lib/cisco_node_utils/client/nxapi/client.rb +305 -0
- data/lib/cisco_node_utils/client/utils.rb +164 -0
- data/lib/cisco_node_utils/cmd_ref/README_YAML.md +222 -254
- data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +22 -15
- data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/acl.yaml +21 -16
- data/lib/cisco_node_utils/cmd_ref/bgp.yaml +239 -109
- data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +114 -55
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +76 -52
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +106 -62
- data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +71 -0
- data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
- data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +35 -14
- data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +23 -17
- data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +94 -83
- data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +22 -17
- data/lib/cisco_node_utils/cmd_ref/feature.yaml +76 -26
- data/lib/cisco_node_utils/cmd_ref/images.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/interface.yaml +381 -153
- data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +21 -21
- data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +30 -21
- data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +18 -13
- data/lib/cisco_node_utils/cmd_ref/inventory.yaml +26 -31
- data/lib/cisco_node_utils/cmd_ref/itd_device_group.yaml +83 -0
- data/lib/cisco_node_utils/cmd_ref/itd_service.yaml +119 -0
- data/lib/cisco_node_utils/cmd_ref/memory.yaml +17 -6
- data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +10 -3
- data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +17 -5
- data/lib/cisco_node_utils/cmd_ref/ospf.yaml +33 -29
- data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +12 -10
- data/lib/cisco_node_utils/cmd_ref/pim.yaml +16 -19
- data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +40 -25
- data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +17 -12
- data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +71 -35
- data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +10 -5
- data/lib/cisco_node_utils/cmd_ref/show_system.yaml +6 -2
- data/lib/cisco_node_utils/cmd_ref/show_version.yaml +47 -43
- data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +13 -11
- data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +4 -2
- data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +23 -21
- data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +26 -22
- data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +19 -17
- data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +18 -6
- data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +234 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +24 -9
- data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +5 -3
- data/lib/cisco_node_utils/cmd_ref/system.yaml +4 -3
- data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +22 -20
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +27 -15
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +45 -16
- data/lib/cisco_node_utils/cmd_ref/vdc.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/vlan.yaml +60 -32
- data/lib/cisco_node_utils/cmd_ref/vpc.yaml +118 -101
- data/lib/cisco_node_utils/cmd_ref/vrf.yaml +54 -58
- data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +118 -0
- data/lib/cisco_node_utils/cmd_ref/vtp.yaml +19 -25
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +28 -18
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +34 -17
- data/lib/cisco_node_utils/cmd_ref/yum.yaml +6 -4
- data/lib/cisco_node_utils/command_reference.rb +261 -142
- data/lib/cisco_node_utils/constants.rb +33 -0
- data/lib/cisco_node_utils/encapsulation.rb +112 -0
- data/lib/cisco_node_utils/environment.rb +102 -0
- data/lib/cisco_node_utils/evpn_vni.rb +5 -3
- data/lib/cisco_node_utils/exceptions.rb +111 -0
- data/lib/cisco_node_utils/fabricpath_global.rb +52 -35
- data/lib/cisco_node_utils/fabricpath_topology.rb +44 -57
- data/lib/cisco_node_utils/feature.rb +165 -3
- data/lib/cisco_node_utils/interface.rb +1051 -260
- data/lib/cisco_node_utils/interface_channel_group.rb +11 -10
- data/lib/cisco_node_utils/interface_ospf.rb +1 -2
- data/lib/cisco_node_utils/interface_portchannel.rb +4 -12
- data/lib/cisco_node_utils/interface_service_vni.rb +7 -7
- data/lib/cisco_node_utils/itd_device_group.rb +248 -0
- data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
- data/lib/cisco_node_utils/itd_service.rb +523 -0
- data/lib/cisco_node_utils/logger.rb +75 -0
- data/lib/cisco_node_utils/node.rb +62 -192
- data/lib/cisco_node_utils/node_util.rb +56 -10
- data/lib/cisco_node_utils/overlay_global.rb +2 -2
- data/lib/cisco_node_utils/pim.rb +2 -13
- data/lib/cisco_node_utils/pim_group_list.rb +1 -1
- data/lib/cisco_node_utils/pim_rp_address.rb +1 -1
- data/lib/cisco_node_utils/platform.rb +52 -21
- data/lib/cisco_node_utils/portchannel_global.rb +89 -19
- data/lib/cisco_node_utils/radius_server.rb +168 -37
- data/lib/cisco_node_utils/router_ospf.rb +20 -35
- data/lib/cisco_node_utils/router_ospf_vrf.rb +4 -4
- data/lib/cisco_node_utils/snmpserver.rb +1 -6
- data/lib/cisco_node_utils/snmpuser.rb +6 -4
- data/lib/cisco_node_utils/stp_global.rb +676 -0
- data/lib/cisco_node_utils/syslog_server.rb +77 -18
- data/lib/cisco_node_utils/syslog_settings.rb +1 -1
- data/lib/cisco_node_utils/tacacs_server_group.rb +8 -4
- data/lib/cisco_node_utils/tacacs_server_host.rb +115 -25
- data/lib/cisco_node_utils/vdc.rb +12 -0
- data/lib/cisco_node_utils/version.rb +1 -1
- data/lib/cisco_node_utils/vlan.rb +147 -29
- data/lib/cisco_node_utils/vpc.rb +55 -3
- data/lib/cisco_node_utils/vrf.rb +72 -11
- data/lib/cisco_node_utils/vrf_af.rb +114 -29
- data/lib/cisco_node_utils/vtp.rb +34 -52
- data/lib/cisco_node_utils/vxlan_vtep.rb +34 -8
- data/lib/cisco_node_utils/vxlan_vtep_vni.rb +36 -4
- data/lib/minitest/environment_plugin.rb +31 -0
- data/lib/minitest/log_level_plugin.rb +41 -0
- data/spec/client_spec.rb +7 -0
- data/spec/environment_spec.rb +263 -0
- data/spec/grpc_client_spec.rb +23 -0
- data/spec/isolate/all_clients_spec.rb +9 -0
- data/spec/isolate/grpc_only_spec.rb +16 -0
- data/spec/isolate/no_clients_spec.rb +26 -0
- data/spec/isolate/nxapi_only_spec.rb +16 -0
- data/spec/nxapi_client_spec.rb +42 -0
- data/spec/schema.yaml +75 -0
- data/spec/shared_examples_for_clients.rb +14 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/whitespace_spec.rb +10 -0
- data/spec/yaml_spec.rb +42 -0
- data/tests/.rubocop.yml +2 -2
- data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
- data/tests/basetest.rb +96 -36
- data/tests/ciscotest.rb +220 -12
- data/tests/cmd_config.yaml +71 -49
- data/tests/cmd_config_invalid.yaml +1 -1
- data/tests/test_aaa_authentication_login.rb +1 -0
- data/tests/test_aaa_authentication_login_service.rb +9 -0
- data/tests/test_aaa_authorization_service.rb +173 -367
- data/tests/test_ace.rb +171 -100
- data/tests/test_acl.rb +10 -1
- data/tests/test_bgp_af.rb +395 -728
- data/tests/test_bgp_neighbor.rb +274 -115
- data/tests/test_bgp_neighbor_af.rb +178 -77
- data/tests/test_bridge_domain.rb +191 -0
- data/tests/test_bridge_domain_vni.rb +116 -0
- data/tests/test_client_utils.rb +111 -0
- data/tests/test_command_config.rb +9 -5
- data/tests/test_command_reference.rb +380 -102
- data/tests/test_dns_domain.rb +13 -3
- data/tests/test_domain_name.rb +13 -3
- data/tests/test_encapsulation.rb +77 -0
- data/tests/test_evpn_vni.rb +25 -7
- data/tests/test_fabricpath_global.rb +167 -163
- data/tests/test_fabricpath_topology.rb +12 -33
- data/tests/test_feature.rb +215 -0
- data/tests/test_grpc.rb +166 -0
- data/tests/test_interface.rb +585 -344
- data/tests/test_interface_bdi.rb +80 -0
- data/tests/test_interface_channel_group.rb +6 -3
- data/tests/test_interface_ospf.rb +26 -24
- data/tests/test_interface_portchannel.rb +1 -0
- data/tests/test_interface_private_vlan.rb +724 -0
- data/tests/test_interface_service_vni.rb +37 -66
- data/tests/test_interface_svi.rb +98 -101
- data/tests/test_interface_switchport.rb +419 -549
- data/tests/test_itd_device_group.rb +145 -0
- data/tests/test_itd_device_group_node.rb +199 -0
- data/tests/test_itd_service.rb +298 -0
- data/tests/test_logger.rb +43 -0
- data/tests/test_name_server.rb +11 -2
- data/tests/test_node.rb +16 -75
- data/tests/test_node_ext.rb +174 -163
- data/tests/test_node_util.rb +119 -0
- data/tests/test_ntp_config.rb +5 -1
- data/tests/test_ntp_server.rb +2 -2
- data/tests/test_nxapi.rb +221 -0
- data/tests/test_overlay_global.rb +47 -38
- data/tests/test_pim.rb +2 -0
- data/tests/test_pim_group_list.rb +2 -0
- data/tests/test_pim_rp_address.rb +2 -0
- data/tests/test_platform.rb +86 -39
- data/tests/test_portchannel_global.rb +211 -135
- data/tests/test_radius_global.rb +13 -5
- data/tests/test_radius_server.rb +256 -104
- data/tests/test_radius_server_group.rb +2 -0
- data/tests/test_router_bgp.rb +781 -485
- data/tests/test_router_ospf.rb +26 -103
- data/tests/test_router_ospf_vrf.rb +52 -57
- data/tests/test_snmp_notification_receiver.rb +2 -0
- data/tests/test_snmpcommunity.rb +2 -0
- data/tests/test_snmpgroup.rb +2 -0
- data/tests/test_snmpnotification.rb +40 -21
- data/tests/test_snmpserver.rb +2 -0
- data/tests/test_snmpuser.rb +2 -0
- data/tests/test_stp_global.rb +563 -0
- data/tests/test_syslog_server.rb +32 -8
- data/tests/test_syslog_settings.rb +22 -9
- data/tests/test_tacacs_server.rb +32 -27
- data/tests/test_tacacs_server_group.rb +100 -45
- data/tests/test_tacacs_server_host.rb +135 -43
- data/tests/test_vdc.rb +2 -16
- data/tests/test_vlan.rb +106 -54
- data/tests/test_vlan_mt_full.rb +11 -21
- data/tests/test_vlan_private.rb +669 -0
- data/tests/test_vpc.rb +312 -159
- data/tests/test_vrf.rb +122 -113
- data/tests/test_vrf_af.rb +238 -0
- data/tests/test_vtp.rb +58 -102
- data/tests/test_vxlan_vtep.rb +38 -17
- data/tests/test_vxlan_vtep_vni.rb +61 -9
- data/tests/test_yum.rb +49 -25
- metadata +122 -36
- data/lib/cisco_node_utils/cmd_ref/fex.yaml +0 -9
- data/lib/cisco_node_utils/cmd_ref/vni.yaml +0 -76
- data/lib/cisco_node_utils/vni.rb +0 -227
- data/tests/test_vni.rb +0 -106
|
@@ -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,311 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# October 2015, 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 '../client'
|
|
20
|
+
Cisco::Client.silence_warnings do
|
|
21
|
+
require 'grpc'
|
|
22
|
+
end
|
|
23
|
+
require 'json'
|
|
24
|
+
require_relative 'ems_services'
|
|
25
|
+
|
|
26
|
+
include IOSXRExtensibleManagabilityService
|
|
27
|
+
include Cisco::Logger
|
|
28
|
+
|
|
29
|
+
# Client implementation using gRPC API for IOS XR
|
|
30
|
+
class Cisco::Client::GRPC < Cisco::Client
|
|
31
|
+
register_client(self)
|
|
32
|
+
|
|
33
|
+
attr_accessor :timeout
|
|
34
|
+
|
|
35
|
+
def initialize(**kwargs)
|
|
36
|
+
# Defaults for gRPC:
|
|
37
|
+
kwargs[:host] ||= '127.0.0.1'
|
|
38
|
+
kwargs[:port] ||= 57_400
|
|
39
|
+
# rubocop:disable Style/HashSyntax
|
|
40
|
+
super(data_formats: [:cli],
|
|
41
|
+
platform: :ios_xr,
|
|
42
|
+
**kwargs)
|
|
43
|
+
# rubocop:enable Style/HashSyntax
|
|
44
|
+
@config = GRPCConfigOper::Stub.new(@address, :this_channel_is_insecure)
|
|
45
|
+
@exec = GRPCExec::Stub.new(@address, :this_channel_is_insecure)
|
|
46
|
+
|
|
47
|
+
# Make sure we can actually connect
|
|
48
|
+
@timeout = 10
|
|
49
|
+
begin
|
|
50
|
+
base_msg = 'gRPC client creation failure: '
|
|
51
|
+
get(command: 'show clock')
|
|
52
|
+
rescue Cisco::ClientError => e
|
|
53
|
+
error 'initial connect failed: ' + e.to_s
|
|
54
|
+
if e.message[/deadline exceeded/i]
|
|
55
|
+
raise Cisco::ConnectionRefused, \
|
|
56
|
+
base_msg + 'timed out during initial connection: ' + e.message
|
|
57
|
+
end
|
|
58
|
+
raise e.class, base_msg + e.message
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Let commands in general take up to 2 minutes
|
|
62
|
+
@timeout = 120
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.validate_args(**kwargs)
|
|
66
|
+
super
|
|
67
|
+
base_msg = 'gRPC client creation failure: '
|
|
68
|
+
# Connection to remote system - username and password are required
|
|
69
|
+
fail TypeError, base_msg + 'username must be specified' \
|
|
70
|
+
if kwargs[:username].nil?
|
|
71
|
+
fail TypeError, base_msg + 'password must be specified' \
|
|
72
|
+
if kwargs[:password].nil?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def cache_flush
|
|
76
|
+
@cache_hash = {
|
|
77
|
+
'cli_config' => {},
|
|
78
|
+
'show_cmd_text_output' => {},
|
|
79
|
+
'show_cmd_json_output' => {},
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Configure the given CLI command(s) on the device.
|
|
84
|
+
#
|
|
85
|
+
# @param data_format one of Cisco::DATA_FORMATS. Default is :cli
|
|
86
|
+
# @param context [Array<String>] Zero or more configuration commands used
|
|
87
|
+
# to enter the desired CLI sub-mode
|
|
88
|
+
# @param values [Array<String>] One or more commands to enter within the
|
|
89
|
+
# CLI sub-mode.
|
|
90
|
+
def set(data_format: :cli,
|
|
91
|
+
context: nil,
|
|
92
|
+
values: nil)
|
|
93
|
+
context = munge_to_array(context)
|
|
94
|
+
values = munge_to_array(values)
|
|
95
|
+
super
|
|
96
|
+
# IOS XR lets us concatenate submode commands together.
|
|
97
|
+
# This makes it possible to guarantee we are in the correct context:
|
|
98
|
+
# context: ['foo', 'bar'], values: ['baz', 'bat']
|
|
99
|
+
# ---> values: ['foo bar baz', 'foo bar bat']
|
|
100
|
+
# However, there's a special case for 'no' commands:
|
|
101
|
+
# context: ['foo', 'bar'], values: ['no baz']
|
|
102
|
+
# ---> values: ['no foo bar baz'] ---- the 'no' goes at the start
|
|
103
|
+
context = context.join(' ')
|
|
104
|
+
unless context.empty?
|
|
105
|
+
values.map! do |cmd|
|
|
106
|
+
match = cmd[/^\s*no\s+(.*)/, 1]
|
|
107
|
+
if match
|
|
108
|
+
cmd = "no #{context} #{match}"
|
|
109
|
+
else
|
|
110
|
+
cmd = "#{context} #{cmd}"
|
|
111
|
+
end
|
|
112
|
+
cmd
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
# CliConfigArgs wants a newline-separated string of commands
|
|
116
|
+
args = CliConfigArgs.new(cli: values.join("\n"))
|
|
117
|
+
req(@config, 'cli_config', args)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def get(data_format: :cli,
|
|
121
|
+
command: nil,
|
|
122
|
+
context: nil,
|
|
123
|
+
value: nil)
|
|
124
|
+
super
|
|
125
|
+
fail ArgumentError if command.nil?
|
|
126
|
+
args = ShowCmdArgs.new(cli: command)
|
|
127
|
+
output = req(@exec, 'show_cmd_text_output', args)
|
|
128
|
+
self.class.filter_cli(cli_output: output, context: context, value: value)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def req(stub, type, args)
|
|
132
|
+
if cache_enable? && @cache_hash[type] && @cache_hash[type][args.cli]
|
|
133
|
+
return @cache_hash[type][args.cli]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
debug "Sending '#{type}' request:"
|
|
137
|
+
if args.is_a?(ShowCmdArgs) || args.is_a?(CliConfigArgs)
|
|
138
|
+
debug " with cli: '#{args.cli}'"
|
|
139
|
+
end
|
|
140
|
+
output = Cisco::Client.silence_warnings do
|
|
141
|
+
response = stub.send(type, args,
|
|
142
|
+
timeout: @timeout,
|
|
143
|
+
username: @username,
|
|
144
|
+
password: @password)
|
|
145
|
+
# gRPC server may split the response into multiples
|
|
146
|
+
response = response.is_a?(Enumerator) ? response.to_a : [response]
|
|
147
|
+
debug "Got responses: #{response.map(&:class).join(', ')}"
|
|
148
|
+
# Check for errors first
|
|
149
|
+
handle_errors(args, response.select { |r| !r.errors.empty? })
|
|
150
|
+
|
|
151
|
+
# If we got here, no errors occurred
|
|
152
|
+
handle_response(args, response)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
@cache_hash[type][args.cli] = output if cache_enable? && !output.empty?
|
|
156
|
+
return output
|
|
157
|
+
rescue ::GRPC::BadStatus => e
|
|
158
|
+
warn "gRPC error '#{e.code}' during '#{type}' request: "
|
|
159
|
+
if args.is_a?(ShowCmdArgs) || args.is_a?(CliConfigArgs)
|
|
160
|
+
warn " with cli: '#{args.cli}'"
|
|
161
|
+
end
|
|
162
|
+
warn " '#{e.details}'"
|
|
163
|
+
case e.code
|
|
164
|
+
when ::GRPC::Core::StatusCodes::UNAVAILABLE
|
|
165
|
+
raise Cisco::ConnectionRefused, "Connection refused: #{e.details}"
|
|
166
|
+
when ::GRPC::Core::StatusCodes::UNAUTHENTICATED
|
|
167
|
+
raise Cisco::AuthenticationFailed, e.details
|
|
168
|
+
else
|
|
169
|
+
raise Cisco::ClientError, e.details
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def handle_response(args, replies)
|
|
174
|
+
klass = replies[0].class
|
|
175
|
+
unless replies.all? { |r| r.class == klass }
|
|
176
|
+
fail Cisco::ClientError, 'reply class inconsistent: ' +
|
|
177
|
+
replies.map(&:class).join(', ')
|
|
178
|
+
end
|
|
179
|
+
debug "Handling #{replies.length} '#{klass}' reply(s):"
|
|
180
|
+
case klass.to_s
|
|
181
|
+
when /ShowCmdTextReply/
|
|
182
|
+
replies.each { |r| debug " output:\n#{r.output}" }
|
|
183
|
+
output = replies.map(&:output).join('')
|
|
184
|
+
output = handle_text_output(args, output)
|
|
185
|
+
when /ShowCmdJSONReply/
|
|
186
|
+
# TODO: not yet supported by server to test against
|
|
187
|
+
replies.each { |r| debug " jsonoutput:\n#{r.jsonoutput}" }
|
|
188
|
+
output = replies.map(&:jsonoutput).join("\n---\n")
|
|
189
|
+
when /CliConfigReply/
|
|
190
|
+
# nothing to process
|
|
191
|
+
output = ''
|
|
192
|
+
else
|
|
193
|
+
fail Cisco::ClientError, "unsupported reply class #{klass}"
|
|
194
|
+
end
|
|
195
|
+
debug "Success with output:\n#{output}"
|
|
196
|
+
output
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def handle_text_output(args, output)
|
|
200
|
+
# For a successful show command, gRPC presents the output as:
|
|
201
|
+
# \n--------- <cmd> ----------
|
|
202
|
+
# \n<output of command>
|
|
203
|
+
# \n\n
|
|
204
|
+
|
|
205
|
+
# For an invalid CLI, gRPC presents the output as:
|
|
206
|
+
# \n--------- <cmd> --------
|
|
207
|
+
# \n<cmd>
|
|
208
|
+
# \n<error output>
|
|
209
|
+
# \n\n
|
|
210
|
+
|
|
211
|
+
# Discard the leading whitespace, header, and trailing whitespace
|
|
212
|
+
output = output.split("\n").drop(2)
|
|
213
|
+
return '' if output.nil? || output.empty?
|
|
214
|
+
|
|
215
|
+
# Now we have either [<output_line_1>, <output_line_2>, ...] or
|
|
216
|
+
# [<cmd>, <error_line_1>, <error_line_2>, ...]
|
|
217
|
+
if output[0].strip == args.cli.strip
|
|
218
|
+
fail Cisco::CliError.new( # rubocop:disable Style/RaiseArgs
|
|
219
|
+
rejected_input: args.cli,
|
|
220
|
+
clierror: output.join("\n"),
|
|
221
|
+
)
|
|
222
|
+
end
|
|
223
|
+
output.join("\n")
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def handle_errors(args, error_responses)
|
|
227
|
+
return if error_responses.empty?
|
|
228
|
+
debug "#{error_responses.length} response(s) had errors:"
|
|
229
|
+
error_responses.each { |r| debug " error:\n#{r.errors}" }
|
|
230
|
+
first_error = error_responses.first.errors
|
|
231
|
+
# Conveniently for us, all *Reply protobufs in EMS have an errors field
|
|
232
|
+
# Less conveniently, some are JSON and some are not.
|
|
233
|
+
begin
|
|
234
|
+
msg = JSON.parse(first_error)
|
|
235
|
+
handle_json_error(msg)
|
|
236
|
+
rescue JSON::ParserError
|
|
237
|
+
handle_text_error(args, first_error)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Generate an error from a failed request
|
|
242
|
+
def handle_text_error(args, msg)
|
|
243
|
+
if /^Disallowed commands:/ =~ msg
|
|
244
|
+
fail Cisco::RequestNotSupported, msg
|
|
245
|
+
else
|
|
246
|
+
fail Cisco::CliError.new( # rubocop:disable Style/RaiseArgs
|
|
247
|
+
rejected_input: args.cli,
|
|
248
|
+
clierror: msg,
|
|
249
|
+
)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Generate a CliError from a failed CliConfigReply
|
|
254
|
+
def handle_json_error(msg)
|
|
255
|
+
# {
|
|
256
|
+
# "cisco-grpc:errors": {
|
|
257
|
+
# "error": [
|
|
258
|
+
# {
|
|
259
|
+
# "error-type": "application",
|
|
260
|
+
# "error-tag": "operation-failed",
|
|
261
|
+
# "error-severity": "error",
|
|
262
|
+
# "error-message": "....",
|
|
263
|
+
# },
|
|
264
|
+
# {
|
|
265
|
+
# ...
|
|
266
|
+
|
|
267
|
+
# {
|
|
268
|
+
# "cisco-grpc:errors": [
|
|
269
|
+
# {
|
|
270
|
+
# "error-type": "protocol",
|
|
271
|
+
# "error-message": "Failed authentication"
|
|
272
|
+
# }
|
|
273
|
+
# ]
|
|
274
|
+
# }
|
|
275
|
+
|
|
276
|
+
msg = msg['cisco-grpc:errors']
|
|
277
|
+
msg = msg['error'] unless msg.is_a?(Array)
|
|
278
|
+
msg.each do |m|
|
|
279
|
+
type = m['error-type']
|
|
280
|
+
message = m['error-message']
|
|
281
|
+
if type == 'protocol' && message == 'Failed authentication'
|
|
282
|
+
fail Cisco::AuthenticationFailed, message
|
|
283
|
+
elsif type == 'application'
|
|
284
|
+
# Example message:
|
|
285
|
+
# !! SYNTAX/AUTHORIZATION ERRORS: This configuration failed due to
|
|
286
|
+
# !! one or more of the following reasons:
|
|
287
|
+
# !! - the entered commands do not exist,
|
|
288
|
+
# !! - the entered commands have errors in their syntax,
|
|
289
|
+
# !! - the software packages containing the commands are not active,
|
|
290
|
+
# !! - the current user is not a member of a task-group that has
|
|
291
|
+
# !! permissions to use the commands.
|
|
292
|
+
#
|
|
293
|
+
# foo
|
|
294
|
+
# bar
|
|
295
|
+
#
|
|
296
|
+
match = /\n\n(.*)\n\n\Z/m.match(message)
|
|
297
|
+
if match.nil?
|
|
298
|
+
rejected = '(unknown, see error message)'
|
|
299
|
+
else
|
|
300
|
+
rejected = match[1].split("\n")
|
|
301
|
+
end
|
|
302
|
+
fail Cisco::CliError.new( # rubocop:disable Style/RaiseArgs
|
|
303
|
+
rejected_input: rejected,
|
|
304
|
+
clierror: message,
|
|
305
|
+
)
|
|
306
|
+
else
|
|
307
|
+
fail Cisco::ClientError, message
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package IOSXRExtensibleManagabilityService;
|
|
4
|
+
|
|
5
|
+
service gRPCConfigOper {
|
|
6
|
+
|
|
7
|
+
// Configuration related commands
|
|
8
|
+
|
|
9
|
+
rpc GetConfig(ConfigGetArgs) returns(stream ConfigGetReply) {};
|
|
10
|
+
// 6.0 Config commands do implicit commits
|
|
11
|
+
rpc MergeConfig(ConfigArgs) returns(ConfigReply) {};
|
|
12
|
+
|
|
13
|
+
rpc DeleteConfig(ConfigArgs) returns(ConfigReply) {};
|
|
14
|
+
|
|
15
|
+
rpc ReplaceConfig(ConfigArgs) returns(ConfigReply) {};
|
|
16
|
+
|
|
17
|
+
rpc CliConfig(CliConfigArgs) returns(CliConfigReply) {};
|
|
18
|
+
|
|
19
|
+
// not implemented for 6.0
|
|
20
|
+
rpc CommitReplace(CommitReplaceArgs) returns (CommitReplaceReply) {};
|
|
21
|
+
// not implemented for 6.0
|
|
22
|
+
rpc CommitConfig(CommitArgs) returns(CommitReply) {};
|
|
23
|
+
// not implemented for 6.0
|
|
24
|
+
rpc ConfigDiscardChanges(DiscardChangesArgs) returns(DiscardChangesReply) {};
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
// Get only returns oper data
|
|
28
|
+
//
|
|
29
|
+
rpc GetOper(GetOperArgs) returns(stream GetOperReply) {};
|
|
30
|
+
// Do we need "Get" also to give combined oper and config?
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//
|
|
34
|
+
// Should we seperate Exec from Config/Oper?
|
|
35
|
+
//
|
|
36
|
+
|
|
37
|
+
service gRPCExec {
|
|
38
|
+
// Exec commands
|
|
39
|
+
rpc ShowCmdTextOutput(ShowCmdArgs) returns(stream ShowCmdTextReply) {};
|
|
40
|
+
rpc ShowCmdJSONOutput(ShowCmdArgs) returns(stream ShowCmdJSONReply) {};
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
message ConfigGetArgs {
|
|
46
|
+
int64 ReqId = 1;
|
|
47
|
+
string yangpathjson = 2;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
message ConfigGetReply {
|
|
51
|
+
int64 ResReqId = 1;
|
|
52
|
+
string yangjson = 2;
|
|
53
|
+
string errors = 3;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
message GetOperArgs {
|
|
57
|
+
int64 ReqId = 1;
|
|
58
|
+
string yangpathjson = 2;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
message GetOperReply {
|
|
62
|
+
int64 ResReqId = 1;
|
|
63
|
+
string yangjson = 2;
|
|
64
|
+
string errors = 3;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
message ConfigArgs {
|
|
69
|
+
int64 ReqId = 1;
|
|
70
|
+
string yangjson = 2;
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
message ConfigReply {
|
|
75
|
+
int64 ResReqId = 1;
|
|
76
|
+
string errors = 2;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
message CliConfigArgs {
|
|
80
|
+
int64 ReqId = 1;
|
|
81
|
+
string cli = 2;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
message CliConfigReply {
|
|
85
|
+
int64 ResReqId = 1;
|
|
86
|
+
string errors = 2;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
message CommitReplaceArgs {
|
|
91
|
+
int64 ReqId = 1;
|
|
92
|
+
string cli = 2;
|
|
93
|
+
string yangjson = 3;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
message CommitReplaceReply {
|
|
97
|
+
int64 ResReqId = 1;
|
|
98
|
+
string errors = 2;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
message CommitMsg {
|
|
102
|
+
string label = 1;
|
|
103
|
+
string comment = 2;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
enum CommitResult {
|
|
107
|
+
CHANGE = 0;
|
|
108
|
+
NO_CHANGE = 1;
|
|
109
|
+
FAIL = 2;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
message CommitArgs {
|
|
113
|
+
CommitMsg msg = 1;
|
|
114
|
+
int64 ReqId = 2;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
message CommitReply {
|
|
118
|
+
CommitResult result = 1;
|
|
119
|
+
int64 ResReqId = 2;
|
|
120
|
+
string errors = 3;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
message DiscardChangesArgs {
|
|
125
|
+
int64 ReqId = 1;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
message DiscardChangesReply {
|
|
129
|
+
int64 ResReqId = 1;
|
|
130
|
+
string errors = 2;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
message ShowCmdArgs {
|
|
135
|
+
int64 ReqId = 1;
|
|
136
|
+
string cli = 2;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
message ShowCmdTextReply {
|
|
140
|
+
int64 ResReqId =1;
|
|
141
|
+
string output = 2;
|
|
142
|
+
string errors = 3;
|
|
143
|
+
}
|
|
144
|
+
message ShowCmdJSONReply {
|
|
145
|
+
int64 ResReqId =1;
|
|
146
|
+
string jsonoutput = 2;
|
|
147
|
+
string errors = 3;
|
|
148
|
+
}
|