cisco_node_utils 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -1
- data/CHANGELOG.md +81 -2
- data/CONTRIBUTING.md +2 -17
- data/Gemfile +5 -0
- data/README.md +92 -47
- data/Rakefile +23 -1
- data/bin/git/hooks/hook_lib +7 -0
- data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
- data/bin/git/hooks/pre-commit/rubocop +7 -2
- data/bin/git/hooks/pre-commit/validate-diffs +18 -4
- data/bin/git/hooks/pre-commit/validate-yaml +18 -0
- data/bin/git/update-hooks +64 -6
- data/cisco_node_utils.gemspec +9 -6
- data/docs/README-develop-best-practices.md +149 -50
- data/docs/README-develop-node-utils-APIs.md +92 -42
- data/docs/README-maintainers.md +7 -4
- data/docs/README-test-execution.md +57 -0
- data/docs/cisco_node_utils.yaml.example +30 -0
- data/docs/template-router.rb +4 -0
- data/ext/mkrf_conf.rb +63 -0
- data/lib/.rubocop.yml +2 -2
- data/lib/cisco_node_utils.rb +5 -0
- data/lib/cisco_node_utils/aaa_authentication_login.rb +5 -6
- data/lib/cisco_node_utils/aaa_authorization_service.rb +1 -1
- data/lib/cisco_node_utils/ace.rb +165 -12
- data/lib/cisco_node_utils/acl.rb +2 -1
- data/lib/cisco_node_utils/bgp.rb +184 -21
- data/lib/cisco_node_utils/bgp_af.rb +94 -249
- data/lib/cisco_node_utils/bgp_neighbor.rb +94 -14
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +75 -8
- data/lib/cisco_node_utils/bridge_domain.rb +183 -0
- data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +85 -2
- data/lib/cisco_node_utils/client.rb +35 -0
- data/lib/cisco_node_utils/client/client.rb +234 -0
- data/lib/cisco_node_utils/client/grpc.rb +33 -0
- data/lib/cisco_node_utils/client/grpc/client.rb +311 -0
- data/lib/cisco_node_utils/client/grpc/ems.proto +148 -0
- data/lib/cisco_node_utils/client/grpc/ems.rb +111 -0
- data/lib/cisco_node_utils/client/grpc/ems_services.rb +49 -0
- data/lib/cisco_node_utils/client/nxapi.rb +31 -0
- data/lib/cisco_node_utils/client/nxapi/client.rb +305 -0
- data/lib/cisco_node_utils/client/utils.rb +164 -0
- data/lib/cisco_node_utils/cmd_ref/README_YAML.md +222 -254
- data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +22 -15
- data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +11 -8
- data/lib/cisco_node_utils/cmd_ref/acl.yaml +21 -16
- data/lib/cisco_node_utils/cmd_ref/bgp.yaml +239 -109
- data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +114 -55
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +76 -52
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +106 -62
- data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +71 -0
- data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
- data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +35 -14
- data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
- data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +23 -17
- data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +94 -83
- data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +22 -17
- data/lib/cisco_node_utils/cmd_ref/feature.yaml +76 -26
- data/lib/cisco_node_utils/cmd_ref/images.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/interface.yaml +381 -153
- data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +21 -21
- data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +30 -21
- data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +18 -13
- data/lib/cisco_node_utils/cmd_ref/inventory.yaml +26 -31
- data/lib/cisco_node_utils/cmd_ref/itd_device_group.yaml +83 -0
- data/lib/cisco_node_utils/cmd_ref/itd_service.yaml +119 -0
- data/lib/cisco_node_utils/cmd_ref/memory.yaml +17 -6
- data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +10 -3
- data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +17 -5
- data/lib/cisco_node_utils/cmd_ref/ospf.yaml +33 -29
- data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +12 -10
- data/lib/cisco_node_utils/cmd_ref/pim.yaml +16 -19
- data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +40 -25
- data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +17 -12
- data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +71 -35
- data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +10 -5
- data/lib/cisco_node_utils/cmd_ref/show_system.yaml +6 -2
- data/lib/cisco_node_utils/cmd_ref/show_version.yaml +47 -43
- data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +13 -11
- data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +4 -2
- data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +23 -21
- data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +26 -22
- data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +19 -17
- data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +18 -6
- data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +234 -0
- data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +24 -9
- data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +5 -3
- data/lib/cisco_node_utils/cmd_ref/system.yaml +4 -3
- data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +22 -20
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +27 -15
- data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +45 -16
- data/lib/cisco_node_utils/cmd_ref/vdc.yaml +21 -11
- data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +3 -2
- data/lib/cisco_node_utils/cmd_ref/vlan.yaml +60 -32
- data/lib/cisco_node_utils/cmd_ref/vpc.yaml +118 -101
- data/lib/cisco_node_utils/cmd_ref/vrf.yaml +54 -58
- data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +118 -0
- data/lib/cisco_node_utils/cmd_ref/vtp.yaml +19 -25
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +28 -18
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +34 -17
- data/lib/cisco_node_utils/cmd_ref/yum.yaml +6 -4
- data/lib/cisco_node_utils/command_reference.rb +261 -142
- data/lib/cisco_node_utils/constants.rb +33 -0
- data/lib/cisco_node_utils/encapsulation.rb +112 -0
- data/lib/cisco_node_utils/environment.rb +102 -0
- data/lib/cisco_node_utils/evpn_vni.rb +5 -3
- data/lib/cisco_node_utils/exceptions.rb +111 -0
- data/lib/cisco_node_utils/fabricpath_global.rb +52 -35
- data/lib/cisco_node_utils/fabricpath_topology.rb +44 -57
- data/lib/cisco_node_utils/feature.rb +165 -3
- data/lib/cisco_node_utils/interface.rb +1051 -260
- data/lib/cisco_node_utils/interface_channel_group.rb +11 -10
- data/lib/cisco_node_utils/interface_ospf.rb +1 -2
- data/lib/cisco_node_utils/interface_portchannel.rb +4 -12
- data/lib/cisco_node_utils/interface_service_vni.rb +7 -7
- data/lib/cisco_node_utils/itd_device_group.rb +248 -0
- data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
- data/lib/cisco_node_utils/itd_service.rb +523 -0
- data/lib/cisco_node_utils/logger.rb +75 -0
- data/lib/cisco_node_utils/node.rb +62 -192
- data/lib/cisco_node_utils/node_util.rb +56 -10
- data/lib/cisco_node_utils/overlay_global.rb +2 -2
- data/lib/cisco_node_utils/pim.rb +2 -13
- data/lib/cisco_node_utils/pim_group_list.rb +1 -1
- data/lib/cisco_node_utils/pim_rp_address.rb +1 -1
- data/lib/cisco_node_utils/platform.rb +52 -21
- data/lib/cisco_node_utils/portchannel_global.rb +89 -19
- data/lib/cisco_node_utils/radius_server.rb +168 -37
- data/lib/cisco_node_utils/router_ospf.rb +20 -35
- data/lib/cisco_node_utils/router_ospf_vrf.rb +4 -4
- data/lib/cisco_node_utils/snmpserver.rb +1 -6
- data/lib/cisco_node_utils/snmpuser.rb +6 -4
- data/lib/cisco_node_utils/stp_global.rb +676 -0
- data/lib/cisco_node_utils/syslog_server.rb +77 -18
- data/lib/cisco_node_utils/syslog_settings.rb +1 -1
- data/lib/cisco_node_utils/tacacs_server_group.rb +8 -4
- data/lib/cisco_node_utils/tacacs_server_host.rb +115 -25
- data/lib/cisco_node_utils/vdc.rb +12 -0
- data/lib/cisco_node_utils/version.rb +1 -1
- data/lib/cisco_node_utils/vlan.rb +147 -29
- data/lib/cisco_node_utils/vpc.rb +55 -3
- data/lib/cisco_node_utils/vrf.rb +72 -11
- data/lib/cisco_node_utils/vrf_af.rb +114 -29
- data/lib/cisco_node_utils/vtp.rb +34 -52
- data/lib/cisco_node_utils/vxlan_vtep.rb +34 -8
- data/lib/cisco_node_utils/vxlan_vtep_vni.rb +36 -4
- data/lib/minitest/environment_plugin.rb +31 -0
- data/lib/minitest/log_level_plugin.rb +41 -0
- data/spec/client_spec.rb +7 -0
- data/spec/environment_spec.rb +263 -0
- data/spec/grpc_client_spec.rb +23 -0
- data/spec/isolate/all_clients_spec.rb +9 -0
- data/spec/isolate/grpc_only_spec.rb +16 -0
- data/spec/isolate/no_clients_spec.rb +26 -0
- data/spec/isolate/nxapi_only_spec.rb +16 -0
- data/spec/nxapi_client_spec.rb +42 -0
- data/spec/schema.yaml +75 -0
- data/spec/shared_examples_for_clients.rb +14 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/whitespace_spec.rb +10 -0
- data/spec/yaml_spec.rb +42 -0
- data/tests/.rubocop.yml +2 -2
- data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
- data/tests/basetest.rb +96 -36
- data/tests/ciscotest.rb +220 -12
- data/tests/cmd_config.yaml +71 -49
- data/tests/cmd_config_invalid.yaml +1 -1
- data/tests/test_aaa_authentication_login.rb +1 -0
- data/tests/test_aaa_authentication_login_service.rb +9 -0
- data/tests/test_aaa_authorization_service.rb +173 -367
- data/tests/test_ace.rb +171 -100
- data/tests/test_acl.rb +10 -1
- data/tests/test_bgp_af.rb +395 -728
- data/tests/test_bgp_neighbor.rb +274 -115
- data/tests/test_bgp_neighbor_af.rb +178 -77
- data/tests/test_bridge_domain.rb +191 -0
- data/tests/test_bridge_domain_vni.rb +116 -0
- data/tests/test_client_utils.rb +111 -0
- data/tests/test_command_config.rb +9 -5
- data/tests/test_command_reference.rb +380 -102
- data/tests/test_dns_domain.rb +13 -3
- data/tests/test_domain_name.rb +13 -3
- data/tests/test_encapsulation.rb +77 -0
- data/tests/test_evpn_vni.rb +25 -7
- data/tests/test_fabricpath_global.rb +167 -163
- data/tests/test_fabricpath_topology.rb +12 -33
- data/tests/test_feature.rb +215 -0
- data/tests/test_grpc.rb +166 -0
- data/tests/test_interface.rb +585 -344
- data/tests/test_interface_bdi.rb +80 -0
- data/tests/test_interface_channel_group.rb +6 -3
- data/tests/test_interface_ospf.rb +26 -24
- data/tests/test_interface_portchannel.rb +1 -0
- data/tests/test_interface_private_vlan.rb +724 -0
- data/tests/test_interface_service_vni.rb +37 -66
- data/tests/test_interface_svi.rb +98 -101
- data/tests/test_interface_switchport.rb +419 -549
- data/tests/test_itd_device_group.rb +145 -0
- data/tests/test_itd_device_group_node.rb +199 -0
- data/tests/test_itd_service.rb +298 -0
- data/tests/test_logger.rb +43 -0
- data/tests/test_name_server.rb +11 -2
- data/tests/test_node.rb +16 -75
- data/tests/test_node_ext.rb +174 -163
- data/tests/test_node_util.rb +119 -0
- data/tests/test_ntp_config.rb +5 -1
- data/tests/test_ntp_server.rb +2 -2
- data/tests/test_nxapi.rb +221 -0
- data/tests/test_overlay_global.rb +47 -38
- data/tests/test_pim.rb +2 -0
- data/tests/test_pim_group_list.rb +2 -0
- data/tests/test_pim_rp_address.rb +2 -0
- data/tests/test_platform.rb +86 -39
- data/tests/test_portchannel_global.rb +211 -135
- data/tests/test_radius_global.rb +13 -5
- data/tests/test_radius_server.rb +256 -104
- data/tests/test_radius_server_group.rb +2 -0
- data/tests/test_router_bgp.rb +781 -485
- data/tests/test_router_ospf.rb +26 -103
- data/tests/test_router_ospf_vrf.rb +52 -57
- data/tests/test_snmp_notification_receiver.rb +2 -0
- data/tests/test_snmpcommunity.rb +2 -0
- data/tests/test_snmpgroup.rb +2 -0
- data/tests/test_snmpnotification.rb +40 -21
- data/tests/test_snmpserver.rb +2 -0
- data/tests/test_snmpuser.rb +2 -0
- data/tests/test_stp_global.rb +563 -0
- data/tests/test_syslog_server.rb +32 -8
- data/tests/test_syslog_settings.rb +22 -9
- data/tests/test_tacacs_server.rb +32 -27
- data/tests/test_tacacs_server_group.rb +100 -45
- data/tests/test_tacacs_server_host.rb +135 -43
- data/tests/test_vdc.rb +2 -16
- data/tests/test_vlan.rb +106 -54
- data/tests/test_vlan_mt_full.rb +11 -21
- data/tests/test_vlan_private.rb +669 -0
- data/tests/test_vpc.rb +312 -159
- data/tests/test_vrf.rb +122 -113
- data/tests/test_vrf_af.rb +238 -0
- data/tests/test_vtp.rb +58 -102
- data/tests/test_vxlan_vtep.rb +38 -17
- data/tests/test_vxlan_vtep_vni.rb +61 -9
- data/tests/test_yum.rb +49 -25
- metadata +122 -36
- data/lib/cisco_node_utils/cmd_ref/fex.yaml +0 -9
- data/lib/cisco_node_utils/cmd_ref/vni.yaml +0 -76
- data/lib/cisco_node_utils/vni.rb +0 -227
- data/tests/test_vni.rb +0 -106
@@ -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
|