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
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# yum
|
|
2
2
|
---
|
|
3
|
+
_exclude: [ios_xr]
|
|
4
|
+
|
|
3
5
|
install:
|
|
4
|
-
|
|
6
|
+
set_value: "install add %s %s activate"
|
|
5
7
|
|
|
6
8
|
query:
|
|
7
9
|
multiple: true
|
|
8
|
-
|
|
10
|
+
get_command: "show install packages"
|
|
9
11
|
# pass in the pkg name, retrieve version
|
|
10
|
-
|
|
12
|
+
get_value: '/^%s\S*\s+(\S+)\s+(?:installed|@\S+)/'
|
|
11
13
|
|
|
12
14
|
remove:
|
|
13
|
-
|
|
15
|
+
set_value: "install deactivate %s"
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# CommandReference module for testing.
|
|
2
|
-
#
|
|
3
1
|
# Copyright (c) 2014-2016 Cisco and/or its affiliates.
|
|
4
2
|
#
|
|
5
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -14,6 +12,7 @@
|
|
|
14
12
|
# See the License for the specific language governing permissions and
|
|
15
13
|
# limitations under the License.
|
|
16
14
|
|
|
15
|
+
require_relative 'exceptions'
|
|
17
16
|
require 'yaml'
|
|
18
17
|
|
|
19
18
|
module Cisco
|
|
@@ -26,16 +25,16 @@ module Cisco
|
|
|
26
25
|
alias_method :multiple?, :multiple
|
|
27
26
|
|
|
28
27
|
KEYS = %w(default_value default_only
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
data_format context value
|
|
29
|
+
get_data_format get_command get_context get_value
|
|
30
|
+
set_data_format set_context set_value
|
|
31
|
+
auto_default multiple kind)
|
|
33
32
|
|
|
34
33
|
def self.keys
|
|
35
34
|
KEYS
|
|
36
35
|
end
|
|
37
36
|
|
|
38
|
-
KINDS = %w(boolean int string)
|
|
37
|
+
KINDS = %w(boolean int string symbol)
|
|
39
38
|
|
|
40
39
|
# Construct a CmdRef describing the given (feature, name) pair.
|
|
41
40
|
# Param "values" is a hash with keys as described in KEYS.
|
|
@@ -45,46 +44,113 @@ module Cisco
|
|
|
45
44
|
|
|
46
45
|
@feature = feature
|
|
47
46
|
@name = name
|
|
48
|
-
@hash = {}
|
|
49
47
|
@auto_default = true
|
|
50
48
|
@default_only = false
|
|
51
49
|
@multiple = false
|
|
52
50
|
@kind = nil
|
|
53
51
|
|
|
52
|
+
values_to_hash(values, file)
|
|
53
|
+
|
|
54
|
+
if @hash['get_value'] || @hash['get_command']
|
|
55
|
+
define_helper('getter',
|
|
56
|
+
data_format: @hash['get_data_format'] || :cli,
|
|
57
|
+
command: @hash['get_command'],
|
|
58
|
+
context: @hash['get_context'] || [],
|
|
59
|
+
value: @hash['get_value'])
|
|
60
|
+
end
|
|
61
|
+
if @hash['set_value'] # rubocop:disable Style/GuardClause
|
|
62
|
+
define_helper('setter',
|
|
63
|
+
data_format: @hash['set_data_format'] || :cli,
|
|
64
|
+
context: @hash['set_context'] || [],
|
|
65
|
+
values: @hash['set_value'])
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def values_to_hash(values, file)
|
|
70
|
+
@hash = {}
|
|
54
71
|
values.each do |key, value|
|
|
55
72
|
unless KEYS.include?(key)
|
|
56
73
|
fail "Unrecognized key #{key} for #{feature}, #{name} in #{file}"
|
|
57
74
|
end
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
value = [value] unless value.is_a?(Array)
|
|
61
|
-
define_getter(key, value)
|
|
62
|
-
# We intentionally do this *after* the define_getter() call
|
|
63
|
-
@hash[key] = preprocess_value(value)
|
|
64
|
-
elsif key == 'auto_default'
|
|
75
|
+
case key
|
|
76
|
+
when 'auto_default'
|
|
65
77
|
@auto_default = value ? true : false
|
|
66
|
-
|
|
78
|
+
when 'data_format', 'get_data_format', 'set_data_format'
|
|
79
|
+
@hash[key] = value.to_sym
|
|
80
|
+
when 'default_only'
|
|
67
81
|
@default_only = true
|
|
68
82
|
# default_value overrides default_only
|
|
69
|
-
@hash['default_value'] ||=
|
|
70
|
-
|
|
83
|
+
@hash['default_value'] ||= value
|
|
84
|
+
when 'multiple'
|
|
71
85
|
@multiple = boolean_default_true(value)
|
|
72
|
-
|
|
86
|
+
when 'kind'
|
|
73
87
|
fail "Unknown 'kind': '#{value}'" unless KINDS.include?(value)
|
|
74
88
|
@kind = value.to_sym
|
|
75
89
|
else
|
|
76
90
|
# default_value overrides default_only
|
|
77
91
|
@default_only = false if key == 'default_value'
|
|
78
|
-
@hash[key] =
|
|
92
|
+
@hash[key] = value
|
|
79
93
|
end
|
|
80
94
|
end
|
|
81
95
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@hash
|
|
96
|
+
# Inherit general to specific if needed
|
|
97
|
+
if @hash.key?('data_format')
|
|
98
|
+
@hash['get_data_format'] = @hash['data_format'] \
|
|
99
|
+
unless @hash.key?('get_data_format')
|
|
100
|
+
@hash['set_data_format'] = @hash['data_format'] \
|
|
101
|
+
unless @hash.key?('set_data_format')
|
|
87
102
|
end
|
|
103
|
+
if @hash.key?('context')
|
|
104
|
+
@hash['get_context'] = @hash['context'] unless @hash.key?('get_context')
|
|
105
|
+
@hash['set_context'] = @hash['context'] unless @hash.key?('set_context')
|
|
106
|
+
end
|
|
107
|
+
if @hash.key?('value')
|
|
108
|
+
@hash['get_value'] = @hash['value'] unless @hash.key?('get_value')
|
|
109
|
+
@hash['set_value'] = @hash['value'] unless @hash.key?('set_value')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
@hash.delete_if { |key, _| key != 'default_value' } if @default_only
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Does this instance have a valid getter() function?
|
|
116
|
+
# Will be overridden at initialization if so.
|
|
117
|
+
def getter?
|
|
118
|
+
!@hash['getter'].nil?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Does this instance have a valid setter() function?
|
|
122
|
+
# Will be overridden at initialization if so.
|
|
123
|
+
def setter?
|
|
124
|
+
!@hash['setter'].nil?
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Default getter method.
|
|
128
|
+
# Will be overridden at initialization if the relevant parameters are set.
|
|
129
|
+
#
|
|
130
|
+
# A non-trivial implementation of this method will take args *or* kwargs,
|
|
131
|
+
# and will return a hash of the form:
|
|
132
|
+
# {
|
|
133
|
+
# data_format: :cli,
|
|
134
|
+
# command: string or nil,
|
|
135
|
+
# context: array<string> or array<regexp>, perhaps empty
|
|
136
|
+
# value: string or regexp,
|
|
137
|
+
# }
|
|
138
|
+
def getter(*args, **kwargs) # rubocop:disable Lint/UnusedMethodArgument
|
|
139
|
+
fail UnsupportedError.new(@feature, @name, 'getter')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Default setter method.
|
|
143
|
+
# Will be overridden at initialization if the relevant parameters are set.
|
|
144
|
+
#
|
|
145
|
+
# A non-trivial implementation of this method will take args *or* kwargs,
|
|
146
|
+
# and will return a hash of the form:
|
|
147
|
+
# {
|
|
148
|
+
# data_format: :cli,
|
|
149
|
+
# context: array<string>, perhaps empty
|
|
150
|
+
# values: array<string>,
|
|
151
|
+
# }
|
|
152
|
+
def setter(*args, **kwargs) # rubocop:disable Lint/UnusedMethodArgument
|
|
153
|
+
fail UnsupportedError.new(@feature, @name, 'setter')
|
|
88
154
|
end
|
|
89
155
|
|
|
90
156
|
# Property with an implicit value of 'true' if no value is given
|
|
@@ -92,78 +158,119 @@ module Cisco
|
|
|
92
158
|
value.nil? || value
|
|
93
159
|
end
|
|
94
160
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
161
|
+
def key_substitutor(item, kwargs)
|
|
162
|
+
result = item
|
|
163
|
+
kwargs.each do |key, value|
|
|
164
|
+
result = result.sub("<#{key}>", value.to_s)
|
|
165
|
+
end
|
|
166
|
+
unsub = result[/<(\S+)>/, 1]
|
|
167
|
+
fail ArgumentError, \
|
|
168
|
+
"No value specified for '#{unsub}' in '#{result}'" if unsub
|
|
169
|
+
result
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def printf_substitutor(item, args)
|
|
173
|
+
item = sprintf(item, *args.shift(item.scan(/%/).length))
|
|
174
|
+
[item, args]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Create a helper method for generating the getter/setter values.
|
|
178
|
+
# This method will automatically handle wildcard arguments.
|
|
179
|
+
def define_helper(method_name, base_hash)
|
|
180
|
+
# Which kind of wildcards (if any) do we need to support?
|
|
181
|
+
combined = []
|
|
182
|
+
base_hash.each_value do |v|
|
|
183
|
+
combined += v if v.is_a?(Array)
|
|
184
|
+
combined << v if v.is_a?(String)
|
|
185
|
+
end
|
|
186
|
+
key_value = combined.any? { |i| i.is_a?(String) && /<\S+>/ =~ i }
|
|
187
|
+
printf = combined.any? { |i| i.is_a?(String) && /%/ =~ i }
|
|
188
|
+
|
|
189
|
+
if key_value && printf
|
|
190
|
+
fail 'Invalid mixture of key-value and printf wildcards ' \
|
|
191
|
+
"in #{method_name}: #{combined}"
|
|
192
|
+
elsif key_value
|
|
193
|
+
define_key_value_helper(method_name, base_hash)
|
|
194
|
+
elsif printf
|
|
195
|
+
arg_count = combined.join.scan(/%/).length
|
|
196
|
+
define_printf_helper(method_name, base_hash, arg_count)
|
|
105
197
|
else
|
|
106
198
|
# simple static token(s)
|
|
107
|
-
|
|
108
|
-
define_singleton_method key.to_sym, -> { value }
|
|
199
|
+
define_static_helper(method_name, base_hash)
|
|
109
200
|
end
|
|
201
|
+
@hash[method_name] = true
|
|
110
202
|
end
|
|
111
203
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
replace = line.scan(/<(\S+)>/).flatten.map(&:to_sym)
|
|
119
|
-
replace.each do |item|
|
|
120
|
-
line = line.sub("<#{item}>", args[item].to_s) if args.key?(item)
|
|
121
|
-
end
|
|
122
|
-
result.push(line) unless /<\S+>/.match(line)
|
|
204
|
+
def define_key_value_helper(method_name, base_hash)
|
|
205
|
+
# Key-value substitution
|
|
206
|
+
define_singleton_method method_name.to_sym do |*args, **kwargs|
|
|
207
|
+
unless args.empty?
|
|
208
|
+
fail ArgumentError, "#{method_name} requires keyword args, not "\
|
|
209
|
+
'positional args'
|
|
123
210
|
end
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
211
|
+
result = {}
|
|
212
|
+
base_hash.each do |k, v|
|
|
213
|
+
if v.is_a?(String)
|
|
214
|
+
v = key_substitutor(v, kwargs)
|
|
215
|
+
elsif v.is_a?(Array)
|
|
216
|
+
output = []
|
|
217
|
+
v.each do |line|
|
|
218
|
+
# Check for (?) flag indicating optional param
|
|
219
|
+
optional_line = line[/^\(\?\)(.*)/, 1]
|
|
220
|
+
if optional_line
|
|
221
|
+
begin
|
|
222
|
+
line = key_substitutor(optional_line, kwargs)
|
|
223
|
+
rescue ArgumentError # Unsubstituted key - OK to skip this line
|
|
224
|
+
next
|
|
225
|
+
end
|
|
226
|
+
else
|
|
227
|
+
line = key_substitutor(line, kwargs)
|
|
228
|
+
end
|
|
229
|
+
output.push(line)
|
|
230
|
+
end
|
|
231
|
+
v = output
|
|
232
|
+
end
|
|
233
|
+
result[k] = v
|
|
127
234
|
end
|
|
128
|
-
|
|
235
|
+
result
|
|
129
236
|
end
|
|
130
237
|
end
|
|
131
238
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
unless args.length == arg_c
|
|
138
|
-
fail ArgumentError,
|
|
139
|
-
"Given #{args.length} args, but #{config_key} requires #{arg_c}"
|
|
239
|
+
def define_printf_helper(method_name, base_hash, arg_count)
|
|
240
|
+
define_singleton_method method_name.to_sym do |*args, **kwargs|
|
|
241
|
+
unless kwargs.empty?
|
|
242
|
+
fail ArgumentError, "#{method_name} requires positional args, not " \
|
|
243
|
+
'keyword args'
|
|
140
244
|
end
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
245
|
+
unless args.length == arg_count
|
|
246
|
+
fail ArgumentError, 'wrong number of arguments ' \
|
|
247
|
+
"(#{args.length} for #{arg_count})"
|
|
144
248
|
end
|
|
145
|
-
|
|
249
|
+
|
|
250
|
+
result = {}
|
|
251
|
+
base_hash.each do |k, v|
|
|
252
|
+
if v.is_a?(String)
|
|
253
|
+
v, args = printf_substitutor(v, args)
|
|
254
|
+
elsif v.is_a?(Array)
|
|
255
|
+
output = []
|
|
256
|
+
v.each do |line|
|
|
257
|
+
line, args = printf_substitutor(line, args)
|
|
258
|
+
output.push(line)
|
|
259
|
+
end
|
|
260
|
+
v = output
|
|
261
|
+
end
|
|
262
|
+
result[k] = v
|
|
263
|
+
end
|
|
264
|
+
result
|
|
146
265
|
end
|
|
147
266
|
end
|
|
148
267
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if value.is_a?(Array)
|
|
154
|
-
# Recurse!
|
|
155
|
-
return value.map { |item| preprocess_value(item) }
|
|
156
|
-
elsif value.is_a?(String)
|
|
157
|
-
# Some 'Strings' in YAML are actually intended to be regexps
|
|
158
|
-
if value[0] == '/' && value[-1] == '/'
|
|
159
|
-
# '/foo/' => %r{foo}
|
|
160
|
-
return Regexp.new(value[1..-2])
|
|
161
|
-
elsif value[0] == '/' && value[-2..-1] == '/i'
|
|
162
|
-
# '/foo/i' => %r{foo}i
|
|
163
|
-
return Regexp.new(value[1..-3], Regexp::IGNORECASE)
|
|
164
|
-
end
|
|
268
|
+
def define_static_helper(method_name, base_hash)
|
|
269
|
+
# rubocop:disable Lint/UnusedBlockArgument
|
|
270
|
+
define_singleton_method method_name.to_sym do |*args, **kwargs|
|
|
271
|
+
base_hash
|
|
165
272
|
end
|
|
166
|
-
|
|
273
|
+
# rubocop:enable Lint/UnusedBlockArgument
|
|
167
274
|
end
|
|
168
275
|
|
|
169
276
|
def convert_to_constant(value)
|
|
@@ -187,11 +294,6 @@ module Cisco
|
|
|
187
294
|
value
|
|
188
295
|
end
|
|
189
296
|
|
|
190
|
-
def test_config_result(value)
|
|
191
|
-
result = @hash['test_config_result'][value]
|
|
192
|
-
convert_to_constant(result)
|
|
193
|
-
end
|
|
194
|
-
|
|
195
297
|
def method_missing(method_name, *args, &block)
|
|
196
298
|
if KEYS.include?(method_name.to_s)
|
|
197
299
|
# ref.foo -> return @hash[foo] or fail IndexError
|
|
@@ -223,22 +325,6 @@ module Cisco
|
|
|
223
325
|
end
|
|
224
326
|
end
|
|
225
327
|
|
|
226
|
-
# Exception class raised when a particular feature/attribute
|
|
227
|
-
# is explicitly excluded on the given node.
|
|
228
|
-
class UnsupportedError < RuntimeError
|
|
229
|
-
def initialize(feature, name, oper=nil, msg=nil)
|
|
230
|
-
@feature = feature
|
|
231
|
-
@name = name
|
|
232
|
-
@oper = oper
|
|
233
|
-
message = "Feature '#{feature}'"
|
|
234
|
-
message += ", attribute '#{name}'" unless name.nil?
|
|
235
|
-
message += ", operation '#{oper}'" unless oper.nil?
|
|
236
|
-
message += ' is unsupported on this node'
|
|
237
|
-
message += ": #{msg}" unless msg.nil?
|
|
238
|
-
super(message)
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
|
|
242
328
|
# Placeholder for known but explicitly excluded entry
|
|
243
329
|
# For these, we have an implied default_only value of nil.
|
|
244
330
|
class UnsupportedCmdRef < CmdRef
|
|
@@ -257,21 +343,21 @@ module Cisco
|
|
|
257
343
|
@@debug = value # rubocop:disable Style/ClassVars
|
|
258
344
|
end
|
|
259
345
|
|
|
260
|
-
attr_reader :
|
|
346
|
+
attr_reader :data_formats, :files, :platform, :product_id
|
|
261
347
|
|
|
262
348
|
# Constructor.
|
|
263
|
-
# Normal usage is to pass product, platform,
|
|
264
|
-
# files will be located then the list
|
|
265
|
-
# matching the given settings.
|
|
349
|
+
# Normal usage is to pass product, platform, data_formats,
|
|
350
|
+
# in which case usual YAML files will be located then the list
|
|
351
|
+
# will be filtered down to only those matching the given settings.
|
|
266
352
|
# For testing purposes (only!) you can pass an explicit list of files to
|
|
267
353
|
# load instead. This list will NOT be filtered further by product_id.
|
|
268
|
-
def initialize(product:
|
|
269
|
-
platform:
|
|
270
|
-
|
|
271
|
-
files:
|
|
354
|
+
def initialize(product: nil,
|
|
355
|
+
platform: nil,
|
|
356
|
+
data_formats: [],
|
|
357
|
+
files: nil)
|
|
272
358
|
@product_id = product
|
|
273
359
|
@platform = platform
|
|
274
|
-
@
|
|
360
|
+
@data_formats = data_formats
|
|
275
361
|
@hash = {}
|
|
276
362
|
if files
|
|
277
363
|
@files = files
|
|
@@ -285,7 +371,6 @@ module Cisco
|
|
|
285
371
|
# Build complete reference hash.
|
|
286
372
|
def build_cmd_ref
|
|
287
373
|
# Example id's: N3K-C3048TP-1GE, N3K-C3064PQ-10GE, N7K-C7009, N7K-C7009
|
|
288
|
-
|
|
289
374
|
debug "Product: #{@product_id}"
|
|
290
375
|
debug "Files being used: #{@files.join(', ')}"
|
|
291
376
|
|
|
@@ -297,7 +382,11 @@ module Cisco
|
|
|
297
382
|
debug "Feature #{feature} is empty"
|
|
298
383
|
next
|
|
299
384
|
end
|
|
300
|
-
|
|
385
|
+
begin
|
|
386
|
+
feature_hash = filter_hash(feature_hash)
|
|
387
|
+
rescue RuntimeError => e
|
|
388
|
+
raise "#{file}: #{e}"
|
|
389
|
+
end
|
|
301
390
|
if feature_hash.empty?
|
|
302
391
|
debug "Feature #{feature} is excluded"
|
|
303
392
|
@hash[feature] = UnsupportedCmdRef.new(feature, nil, file)
|
|
@@ -322,6 +411,12 @@ module Cisco
|
|
|
322
411
|
end
|
|
323
412
|
end
|
|
324
413
|
|
|
414
|
+
def supports?(feature, property=nil)
|
|
415
|
+
value = @hash[feature]
|
|
416
|
+
value = value[property] if value.is_a?(Hash) && property
|
|
417
|
+
!(value.is_a?(UnsupportedCmdRef) || value.nil?)
|
|
418
|
+
end
|
|
419
|
+
|
|
325
420
|
# Get the command reference
|
|
326
421
|
def lookup(feature, name)
|
|
327
422
|
value = @hash[feature]
|
|
@@ -339,15 +434,30 @@ module Cisco
|
|
|
339
434
|
puts "DEBUG: #{text}" if @@debug
|
|
340
435
|
end
|
|
341
436
|
|
|
342
|
-
|
|
437
|
+
KNOWN_PLATFORMS = %w(C3064 C3132 C3172 N3k N5k N6k N7k N8k N9k XRv9k)
|
|
438
|
+
|
|
439
|
+
def self.platform_to_filter(platform)
|
|
440
|
+
if KNOWN_PLATFORMS.include?(platform)
|
|
441
|
+
case platform
|
|
442
|
+
when 'XRv9k'
|
|
443
|
+
/XRV9/
|
|
444
|
+
else
|
|
445
|
+
Regexp.new platform.tr('k', '')
|
|
446
|
+
end
|
|
447
|
+
else
|
|
448
|
+
fail IndexError, "Unknown platform key '#{platform}'"
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
KNOWN_FILTERS = %w(nexus ios_xr cli nxapi_structured)
|
|
343
453
|
|
|
344
|
-
def self.key_match(key, platform, product_id,
|
|
345
|
-
if key
|
|
346
|
-
|
|
347
|
-
return Regexp.new(key[1..-2]) =~ product_id ? true : false
|
|
454
|
+
def self.key_match(key, platform, product_id, data_formats)
|
|
455
|
+
if KNOWN_PLATFORMS.include?(key)
|
|
456
|
+
return platform_to_filter(key) =~ product_id ? true : false
|
|
348
457
|
elsif KNOWN_FILTERS.include?(key)
|
|
349
|
-
return
|
|
350
|
-
return
|
|
458
|
+
return true if data_formats && data_formats.include?(key.to_sym)
|
|
459
|
+
return true if key == platform.to_s
|
|
460
|
+
return false
|
|
351
461
|
else
|
|
352
462
|
return :unknown
|
|
353
463
|
end
|
|
@@ -355,20 +465,22 @@ module Cisco
|
|
|
355
465
|
|
|
356
466
|
# Helper method
|
|
357
467
|
# Given a Hash of command reference data as read from YAML, does:
|
|
358
|
-
# -
|
|
359
|
-
# -
|
|
468
|
+
# - Delete any platform-specific data not applicable to this platform
|
|
469
|
+
# - Delete any product-specific data not applicable to this product_id
|
|
470
|
+
# - Delete any data-model-specific data not supported by this node
|
|
360
471
|
# Returns the filtered hash (possibly empty)
|
|
361
472
|
def self.filter_hash(hash,
|
|
362
473
|
platform: nil,
|
|
363
474
|
product_id: nil,
|
|
364
|
-
|
|
475
|
+
data_formats: nil,
|
|
365
476
|
allow_unknown_keys: true)
|
|
366
477
|
result = {}
|
|
367
478
|
|
|
368
|
-
exclude = hash
|
|
479
|
+
exclude = hash['_exclude'] || []
|
|
369
480
|
exclude.each do |value|
|
|
370
|
-
|
|
371
|
-
|
|
481
|
+
# We don't allow exclusion by data_format - just platform/product
|
|
482
|
+
if key_match(value, platform, product_id, nil) == true
|
|
483
|
+
debug "Exclude this product (#{product_id}, #{value})"
|
|
372
484
|
return result
|
|
373
485
|
end
|
|
374
486
|
end
|
|
@@ -379,10 +491,11 @@ module Cisco
|
|
|
379
491
|
regexp_match = false
|
|
380
492
|
|
|
381
493
|
hash.each do |key, value|
|
|
494
|
+
next if key == '_exclude'
|
|
382
495
|
if CmdRef.keys.include?(key)
|
|
383
496
|
result[key] = value
|
|
384
497
|
elsif key != 'else'
|
|
385
|
-
match = key_match(key, platform, product_id,
|
|
498
|
+
match = key_match(key, platform, product_id, data_formats)
|
|
386
499
|
next if match == false
|
|
387
500
|
if match == :unknown
|
|
388
501
|
fail "Unrecognized key '#{key}'" unless allow_unknown_keys
|
|
@@ -404,9 +517,10 @@ module Cisco
|
|
|
404
517
|
result[key] = filter_hash(hash[key],
|
|
405
518
|
platform: platform,
|
|
406
519
|
product_id: product_id,
|
|
407
|
-
|
|
520
|
+
data_formats: data_formats,
|
|
408
521
|
allow_unknown_keys: false)
|
|
409
522
|
rescue RuntimeError => e
|
|
523
|
+
# Recursively wrap the error as needed to provide context
|
|
410
524
|
raise "[#{key}]: #{e}"
|
|
411
525
|
end
|
|
412
526
|
end
|
|
@@ -415,18 +529,17 @@ module Cisco
|
|
|
415
529
|
|
|
416
530
|
def filter_hash(input_hash)
|
|
417
531
|
CommandReference.filter_hash(input_hash,
|
|
418
|
-
platform:
|
|
419
|
-
product_id:
|
|
420
|
-
|
|
532
|
+
platform: platform,
|
|
533
|
+
product_id: product_id,
|
|
534
|
+
data_formats: data_formats)
|
|
421
535
|
end
|
|
422
536
|
|
|
423
537
|
# Helper method
|
|
424
538
|
# Given a suitably filtered Hash of command reference data, does:
|
|
425
539
|
# - Inherit data from the given base_hash (if any) and extend/override it
|
|
426
540
|
# with the given input data.
|
|
427
|
-
# - Append 'config_set_append' data to any existing 'config_set' data
|
|
428
|
-
# - Append 'config_get_token_append' data to 'config_get_token', ditto
|
|
429
541
|
def self.hash_merge(input_hash, base_hash=nil)
|
|
542
|
+
return base_hash if input_hash.nil?
|
|
430
543
|
result = base_hash
|
|
431
544
|
result ||= {}
|
|
432
545
|
# to_inspect: sub-hashes we want to recurse into
|
|
@@ -434,16 +547,11 @@ module Cisco
|
|
|
434
547
|
|
|
435
548
|
input_hash.each do |key, value|
|
|
436
549
|
if CmdRef.keys.include?(key)
|
|
437
|
-
|
|
438
|
-
result['config_set'] = value_append(result['config_set'], value)
|
|
439
|
-
elsif key == 'config_get_token_append'
|
|
440
|
-
result['config_get_token'] = value_append(
|
|
441
|
-
result['config_get_token'], value)
|
|
442
|
-
else
|
|
443
|
-
result[key] = value
|
|
444
|
-
end
|
|
550
|
+
result[key] = value
|
|
445
551
|
elsif value.is_a?(Hash)
|
|
446
552
|
to_inspect << value
|
|
553
|
+
elsif value.nil?
|
|
554
|
+
next
|
|
447
555
|
else
|
|
448
556
|
fail "Unexpected non-hash data: #{value}"
|
|
449
557
|
end
|
|
@@ -579,7 +687,18 @@ module Cisco
|
|
|
579
687
|
end
|
|
580
688
|
|
|
581
689
|
def to_s
|
|
582
|
-
@
|
|
690
|
+
@num_features ||= @hash.values.length
|
|
691
|
+
@num_attributes ||= @hash.values.inject(0) do |sum, n|
|
|
692
|
+
sum + (n.is_a?(Hash) ? n.values.length : 1)
|
|
693
|
+
end
|
|
694
|
+
"CommandReference describing #{@num_features} features " \
|
|
695
|
+
"with #{@num_attributes} attributes in total"
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
def inspect
|
|
699
|
+
"CommandReference for '#{product_id}' " \
|
|
700
|
+
"(platform:'#{platform}', data formats:#{data_formats}) " \
|
|
701
|
+
"based on #{files.length} files"
|
|
583
702
|
end
|
|
584
703
|
end
|
|
585
704
|
end
|