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
data/lib/cisco_node_utils/vtp.rb
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
# limitations under the License.
|
|
16
16
|
|
|
17
17
|
require_relative 'node_util'
|
|
18
|
+
require_relative 'logger'
|
|
18
19
|
|
|
19
20
|
module Cisco
|
|
20
21
|
# Vtp - node utility class for VTP configuration management
|
|
@@ -26,29 +27,22 @@ module Cisco
|
|
|
26
27
|
|
|
27
28
|
# Constructor for Vtp
|
|
28
29
|
def initialize(instantiate=true)
|
|
29
|
-
|
|
30
|
+
Feature.vtp_enable if instantiate
|
|
30
31
|
end
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def enable
|
|
41
|
-
config_set('vtp', 'feature', '')
|
|
33
|
+
# Get vtp domain name
|
|
34
|
+
def self.domain
|
|
35
|
+
if Feature.vtp_enabled?
|
|
36
|
+
config_get('vtp', 'domain')
|
|
37
|
+
else
|
|
38
|
+
config_get_default('vtp', 'domain')
|
|
39
|
+
end
|
|
42
40
|
end
|
|
43
41
|
|
|
44
|
-
#
|
|
42
|
+
# The only way to remove a vtp domain is to turn the vtp
|
|
43
|
+
# feature off.
|
|
45
44
|
def destroy
|
|
46
|
-
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Get vtp domain name
|
|
50
|
-
def self.domain
|
|
51
|
-
enabled ? config_get('vtp', 'domain') : ''
|
|
45
|
+
Feature.vtp_disable
|
|
52
46
|
end
|
|
53
47
|
|
|
54
48
|
def domain
|
|
@@ -57,23 +51,22 @@ module Cisco
|
|
|
57
51
|
|
|
58
52
|
# Set vtp domain name
|
|
59
53
|
def domain=(d)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
begin
|
|
64
|
-
config_set('vtp', 'domain', d)
|
|
65
|
-
rescue Cisco::CliError => e
|
|
66
|
-
# cmd will syntax reject when setting name to same name
|
|
67
|
-
raise unless e.clierror =~ /ERROR: Domain name already set to /
|
|
68
|
-
end
|
|
54
|
+
d = d.to_s
|
|
55
|
+
fail ArgumentError unless d.length.between?(1, MAX_VTP_DOMAIN_NAME_SIZE)
|
|
56
|
+
config_set('vtp', 'domain', domain: d)
|
|
69
57
|
end
|
|
70
58
|
|
|
71
59
|
# Get vtp password
|
|
72
60
|
def password
|
|
73
61
|
# Unfortunately nxapi returns "\\" when the password is not set
|
|
74
|
-
password = config_get('vtp', 'password') if
|
|
62
|
+
password = config_get('vtp', 'password') if Feature.vtp_enabled?
|
|
75
63
|
return '' if password.nil? || password == '\\'
|
|
76
64
|
password
|
|
65
|
+
rescue Cisco::RequestNotSupported => e
|
|
66
|
+
# Certain platforms generate a Cisco::RequestNotSupported when the
|
|
67
|
+
# vtp password is not set. We catch this specific error and
|
|
68
|
+
# return empty '' for the password.
|
|
69
|
+
return '' if e.message[/Structured output not supported/]
|
|
77
70
|
end
|
|
78
71
|
|
|
79
72
|
# Set vtp password
|
|
@@ -81,19 +74,9 @@ module Cisco
|
|
|
81
74
|
fail TypeError if password.nil?
|
|
82
75
|
fail TypeError unless password.is_a? String
|
|
83
76
|
fail ArgumentError if password.length > MAX_VTP_PASSWORD_SIZE
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
config_set('vtp', 'password', 'no', '')
|
|
88
|
-
else
|
|
89
|
-
config_set('vtp', 'password', '', password)
|
|
90
|
-
end
|
|
91
|
-
rescue Cisco::CliError => e
|
|
92
|
-
raise unless e.clierror =~ /password cannot be set for NULL domain/
|
|
93
|
-
unless password == default_password
|
|
94
|
-
raise 'Setting VTP password requires first setting VTP domain'
|
|
95
|
-
end
|
|
96
|
-
end
|
|
77
|
+
Feature.vtp_enable
|
|
78
|
+
state = (password == default_password) ? 'no' : ''
|
|
79
|
+
config_set('vtp', 'password', state: state, password: password)
|
|
97
80
|
end
|
|
98
81
|
|
|
99
82
|
# Get default vtp password
|
|
@@ -103,18 +86,17 @@ module Cisco
|
|
|
103
86
|
|
|
104
87
|
# Get vtp filename
|
|
105
88
|
def filename
|
|
106
|
-
config_get('vtp', 'filename')
|
|
89
|
+
filename = config_get('vtp', 'filename') if Feature.vtp_enabled?
|
|
90
|
+
filename.nil? ? default_filename : filename
|
|
107
91
|
end
|
|
108
92
|
|
|
109
93
|
# Set vtp filename
|
|
110
94
|
def filename=(uri)
|
|
111
95
|
fail TypeError if uri.nil?
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
config_set('vtp', 'filename', '', uri)
|
|
117
|
-
end
|
|
96
|
+
Feature.vtp_enable
|
|
97
|
+
uri = uri.to_s
|
|
98
|
+
state = uri.empty? ? 'no' : ''
|
|
99
|
+
config_set('vtp', 'filename', state: state, uri: uri)
|
|
118
100
|
end
|
|
119
101
|
|
|
120
102
|
# Get default vtp filename
|
|
@@ -124,13 +106,13 @@ module Cisco
|
|
|
124
106
|
|
|
125
107
|
# Get vtp version
|
|
126
108
|
def version
|
|
127
|
-
|
|
109
|
+
Feature.vtp_enabled? ? config_get('vtp', 'version') : default_version
|
|
128
110
|
end
|
|
129
111
|
|
|
130
112
|
# Set vtp version
|
|
131
|
-
def version=(
|
|
132
|
-
|
|
133
|
-
config_set('vtp', 'version',
|
|
113
|
+
def version=(v)
|
|
114
|
+
Feature.vtp_enable
|
|
115
|
+
config_set('vtp', 'version', version: v)
|
|
134
116
|
end
|
|
135
117
|
|
|
136
118
|
# Get default vtp version
|
|
@@ -55,15 +55,19 @@ module Cisco
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def create
|
|
58
|
+
if FabricpathGlobal.fabricpath_feature == :enabled &&
|
|
59
|
+
node.product_id[/N(5|6)K/]
|
|
60
|
+
fail 'VxLAN cannot be enabled with Fabricpath configured'
|
|
61
|
+
end
|
|
58
62
|
Feature.nv_overlay_enable
|
|
59
63
|
Feature.vn_segment_vlan_based_enable if VxlanVtep.mt_lite_support
|
|
60
64
|
# re-use the "interface command ref hooks"
|
|
61
|
-
config_set('interface', 'create', @name)
|
|
65
|
+
config_set('interface', 'create', name: @name)
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
def destroy
|
|
65
69
|
# re-use the "interface command ref hooks"
|
|
66
|
-
config_set('interface', 'destroy', @name)
|
|
70
|
+
config_set('interface', 'destroy', name: @name)
|
|
67
71
|
end
|
|
68
72
|
|
|
69
73
|
def ==(other)
|
|
@@ -75,16 +79,14 @@ module Cisco
|
|
|
75
79
|
########################################################
|
|
76
80
|
|
|
77
81
|
def description
|
|
78
|
-
config_get('interface', 'description', @name)
|
|
82
|
+
config_get('interface', 'description', name: @name)
|
|
79
83
|
end
|
|
80
84
|
|
|
81
85
|
def description=(desc)
|
|
82
86
|
fail TypeError unless desc.is_a?(String)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
config_set('interface', 'description', @name, '', desc)
|
|
87
|
-
end
|
|
87
|
+
state = desc.empty? ? 'no' : ''
|
|
88
|
+
config_set('interface', 'description',
|
|
89
|
+
name: @name, state: state, desc: desc)
|
|
88
90
|
end
|
|
89
91
|
|
|
90
92
|
def default_description
|
|
@@ -135,6 +137,30 @@ module Cisco
|
|
|
135
137
|
config_get_default('vxlan_vtep', 'source_intf')
|
|
136
138
|
end
|
|
137
139
|
|
|
140
|
+
def source_interface_hold_down_time
|
|
141
|
+
config_get('vxlan_vtep', 'source_intf_hold_down_time', name: @name)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def source_interface_hold_down_time=(time)
|
|
145
|
+
state = time == default_source_interface_hold_down_time ? 'no' : ''
|
|
146
|
+
# Cli rejects removing hold-down-time without an argument, so make
|
|
147
|
+
# sure it is configured before attempting to remove it
|
|
148
|
+
if state == 'no'
|
|
149
|
+
time = source_interface_hold_down_time
|
|
150
|
+
unless time == default_source_interface_hold_down_time
|
|
151
|
+
config_set('vxlan_vtep', 'source_intf_hold_down_time', name: @name,
|
|
152
|
+
state: state, time: time)
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
config_set('vxlan_vtep', 'source_intf_hold_down_time', name: @name,
|
|
156
|
+
state: state, time: time)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def default_source_interface_hold_down_time
|
|
161
|
+
config_get_default('vxlan_vtep', 'source_intf_hold_down_time')
|
|
162
|
+
end
|
|
163
|
+
|
|
138
164
|
def shutdown
|
|
139
165
|
config_get('vxlan_vtep', 'shutdown', name: @name)
|
|
140
166
|
end
|
|
@@ -104,12 +104,18 @@ module Cisco
|
|
|
104
104
|
# PROPERTIES #
|
|
105
105
|
########################################################
|
|
106
106
|
|
|
107
|
+
def ingress_replication_supported?
|
|
108
|
+
node.cmd_ref.supports?('vxlan_vtep_vni', 'ingress_replication')
|
|
109
|
+
end
|
|
110
|
+
|
|
107
111
|
def ingress_replication
|
|
108
112
|
config_get('vxlan_vtep_vni', 'ingress_replication', @get_args)
|
|
109
113
|
end
|
|
110
114
|
|
|
111
115
|
def remove_add_ingress_replication(protocol)
|
|
112
|
-
|
|
116
|
+
# Note: ingress-replication is not supported on all platforms.
|
|
117
|
+
# Use to_s.empty check to also handle nil check.
|
|
118
|
+
if ingress_replication.to_s.empty?
|
|
113
119
|
set_args_keys(state: '', protocol: protocol)
|
|
114
120
|
config_set('vxlan_vtep_vni', 'ingress_replication', @set_args)
|
|
115
121
|
else
|
|
@@ -171,7 +177,7 @@ module Cisco
|
|
|
171
177
|
ip_end = '' if ip_end.nil?
|
|
172
178
|
# Since multicast group and ingress replication are exclusive
|
|
173
179
|
# properties, remove ingress replication first
|
|
174
|
-
|
|
180
|
+
if ingress_replication_supported? && !ingress_replication.empty?
|
|
175
181
|
set_args_keys(state: 'no', protocol: ingress_replication)
|
|
176
182
|
config_set('vxlan_vtep_vni', 'ingress_replication', @set_args)
|
|
177
183
|
end
|
|
@@ -191,7 +197,7 @@ module Cisco
|
|
|
191
197
|
delta_hash = Utils.delta_add_remove(should_list, peer_list)
|
|
192
198
|
return if delta_hash.values.flatten.empty?
|
|
193
199
|
[:add, :remove].each do |action|
|
|
194
|
-
|
|
200
|
+
Cisco::Logger.debug('peer_list' \
|
|
195
201
|
"#{@get_args}\n #{action}: #{delta_hash[action]}")
|
|
196
202
|
delta_hash[action].each do |peer|
|
|
197
203
|
state = (action == :add) ? '' : 'no'
|
|
@@ -214,7 +220,9 @@ module Cisco
|
|
|
214
220
|
if state
|
|
215
221
|
set_args_keys(state: '')
|
|
216
222
|
# Host reachability must be enabled for this property
|
|
217
|
-
VxlanVtep.new(@name).host_reachability
|
|
223
|
+
unless VxlanVtep.new(@name).host_reachability == 'evpn'
|
|
224
|
+
fail "Dependency: vxlan_vtep host_reachability must be 'evpn'."
|
|
225
|
+
end
|
|
218
226
|
config_set('vxlan_vtep_vni', 'suppress_arp', @set_args)
|
|
219
227
|
else
|
|
220
228
|
set_args_keys(state: 'no')
|
|
@@ -230,5 +238,29 @@ module Cisco
|
|
|
230
238
|
def default_suppress_arp
|
|
231
239
|
config_get_default('vxlan_vtep_vni', 'suppress_arp')
|
|
232
240
|
end
|
|
241
|
+
|
|
242
|
+
def suppress_uuc
|
|
243
|
+
config_get('vxlan_vtep_vni', 'suppress_uuc', @get_args)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def suppress_uuc=(state)
|
|
247
|
+
if state
|
|
248
|
+
set_args_keys(state: '')
|
|
249
|
+
# Host reachability must be enabled for this property
|
|
250
|
+
unless VxlanVtep.new(@name).host_reachability == 'evpn'
|
|
251
|
+
fail "Dependency: vxlan_vtep host_reachability must be 'evpn'"
|
|
252
|
+
end
|
|
253
|
+
config_set('vxlan_vtep_vni', 'suppress_uuc', @set_args)
|
|
254
|
+
else
|
|
255
|
+
set_args_keys(state: 'no')
|
|
256
|
+
# Remove suppress-uuc only if it is configured. Note that for
|
|
257
|
+
# suppress-uuc, default is 'false' which is no suppress-uuc.
|
|
258
|
+
config_set('vxlan_vtep_vni', 'suppress_uuc', @set_args) if suppress_uuc
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def default_suppress_uuc
|
|
263
|
+
config_get_default('vxlan_vtep_vni', 'suppress_uuc')
|
|
264
|
+
end
|
|
233
265
|
end
|
|
234
266
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# March 2016, Glenn F. Matthews
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2016 Cisco and/or its affiliates.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative '../cisco_node_utils/environment'
|
|
18
|
+
|
|
19
|
+
# Add environment option to minitest
|
|
20
|
+
module Minitest
|
|
21
|
+
def self.plugin_environment_options(opts, options)
|
|
22
|
+
opts.on('-e', '--environment NAME', 'Select environment by name') do |name|
|
|
23
|
+
options[:environment] = name
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.plugin_environment_init(options)
|
|
28
|
+
name = options[:environment]
|
|
29
|
+
Cisco::Environment.default_environment_name = name unless name.nil?
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# March 2016, Glenn F. Matthews
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2016 Cisco and/or its affiliates.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require 'logger'
|
|
18
|
+
require_relative '../cisco_node_utils/logger'
|
|
19
|
+
|
|
20
|
+
# Add logging level option to minitest
|
|
21
|
+
module Minitest
|
|
22
|
+
LEVEL_ALIASES = {
|
|
23
|
+
'debug' => Logger::DEBUG,
|
|
24
|
+
'info' => Logger::INFO,
|
|
25
|
+
'warning' => Logger::WARN,
|
|
26
|
+
'error' => Logger::ERROR,
|
|
27
|
+
}
|
|
28
|
+
def self.plugin_log_level_options(opts, options)
|
|
29
|
+
opts.on(
|
|
30
|
+
'-l', '--log-level LEVEL', LEVEL_ALIASES,
|
|
31
|
+
'Configure logging level for tests',
|
|
32
|
+
"(#{LEVEL_ALIASES.keys.join(', ')})"
|
|
33
|
+
) do |level|
|
|
34
|
+
options[:log_level] = level
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.plugin_log_level_init(options)
|
|
39
|
+
Cisco::Logger.level = options[:log_level] if options[:log_level]
|
|
40
|
+
end
|
|
41
|
+
end
|
data/spec/client_spec.rb
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
require_relative 'spec_helper.rb'
|
|
2
|
+
require 'cisco_node_utils/environment'
|
|
3
|
+
require 'cisco_node_utils/client'
|
|
4
|
+
|
|
5
|
+
class << Cisco::Environment
|
|
6
|
+
attr_writer :environments
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe Cisco::Environment do
|
|
10
|
+
after(:each) do
|
|
11
|
+
# Revert to default environment data
|
|
12
|
+
Cisco::Environment.environments = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe '.data_from_file' do
|
|
16
|
+
it 'handles File.expand_path errors' do
|
|
17
|
+
expect(File).to receive(:expand_path).and_raise(ArgumentError)
|
|
18
|
+
expect(Cisco::Environment.data_from_file('~/foo/bar.yaml')).to be_empty
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'handles nonexistent files' do
|
|
22
|
+
expect(File).to receive(:file?).and_return(false)
|
|
23
|
+
expect(Cisco::Environment.data_from_file('/foo/bar.yaml')).to be_empty
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'handles unreadable files' do
|
|
27
|
+
expect(File).to receive(:file?).and_return(true)
|
|
28
|
+
expect(File).to receive(:readable?).and_return(false)
|
|
29
|
+
expect(Cisco::Environment.data_from_file('/foo/bar.yaml')).to be_empty
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'handles YAML errors' do
|
|
33
|
+
expect(File).to receive(:file?).and_return(true)
|
|
34
|
+
expect(File).to receive(:readable?).and_return(true)
|
|
35
|
+
error = Psych::SyntaxError.new('/foo/bar.yaml', 1, 1, 0, 'foo', 'bar')
|
|
36
|
+
expect(YAML).to receive(:load_file).and_raise(error)
|
|
37
|
+
# Catch the error log message Environment will generate:
|
|
38
|
+
expect(Cisco::Logger).to receive(:error).once
|
|
39
|
+
expect(Cisco::Environment.data_from_file('/foo/bar.yaml')).to eq({})
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '.merge_config' do
|
|
44
|
+
it 'merges valid content' do
|
|
45
|
+
base = { 'hello' => {
|
|
46
|
+
host: '2.2.2.2',
|
|
47
|
+
port: 57_799,
|
|
48
|
+
username: nil,
|
|
49
|
+
password: nil,
|
|
50
|
+
} }
|
|
51
|
+
expect(Cisco::Environment).to receive(:data_from_file).and_return(
|
|
52
|
+
'hello' => { host: '1.1.1.1' }, 'goodbye' => { password: 'foo' })
|
|
53
|
+
expect(Cisco::Environment.merge_config('/foo/bar.yaml', base)).to eq(
|
|
54
|
+
'hello' => {
|
|
55
|
+
host: '1.1.1.1',
|
|
56
|
+
port: 57_799,
|
|
57
|
+
username: nil,
|
|
58
|
+
password: nil,
|
|
59
|
+
},
|
|
60
|
+
'goodbye' => {
|
|
61
|
+
host: nil,
|
|
62
|
+
port: nil,
|
|
63
|
+
username: nil,
|
|
64
|
+
password: 'foo',
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe '.environments' do
|
|
71
|
+
before(:each) do
|
|
72
|
+
allow(Cisco::Environment).to receive(:data_from_file).and_return({})
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'is empty by default' do
|
|
76
|
+
expect(Cisco::Environment.environments).to be_empty
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
global_config = {
|
|
80
|
+
'default' => {
|
|
81
|
+
host: '127.0.0.1',
|
|
82
|
+
port: 57_400,
|
|
83
|
+
},
|
|
84
|
+
'global' => {
|
|
85
|
+
username: 'global',
|
|
86
|
+
password: 'global',
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
user_config = {
|
|
91
|
+
'default' => {
|
|
92
|
+
port: 57_799,
|
|
93
|
+
username: 'user',
|
|
94
|
+
},
|
|
95
|
+
'user' => {
|
|
96
|
+
username: 'user',
|
|
97
|
+
password: 'user',
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
it 'loads data from global config if present' do
|
|
102
|
+
expect(Cisco::Environment).to receive(:data_from_file).with(
|
|
103
|
+
'/etc/cisco_node_utils.yaml').and_return(global_config)
|
|
104
|
+
env = Cisco::Environment.environments
|
|
105
|
+
env.each do |key, hash|
|
|
106
|
+
# The env hash should be fully populated with keys
|
|
107
|
+
# Any keys unspecified in the data should be nil
|
|
108
|
+
%I(host port username password).each do |hash_key|
|
|
109
|
+
expect(hash.fetch(hash_key)).to \
|
|
110
|
+
eq(global_config[key].fetch(hash_key, nil))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'loads data from user config if present' do
|
|
116
|
+
expect(Cisco::Environment).to receive(:data_from_file).with(
|
|
117
|
+
'~/cisco_node_utils.yaml').and_return(user_config)
|
|
118
|
+
env = Cisco::Environment.environments
|
|
119
|
+
env.each do |key, hash|
|
|
120
|
+
# The env hash should be fully populated with keys
|
|
121
|
+
# Any keys unspecified in the data should be nil
|
|
122
|
+
%I(host port username password).each do |hash_key|
|
|
123
|
+
expect(hash.fetch(hash_key)).to \
|
|
124
|
+
eq(user_config[key].fetch(hash_key, nil))
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it 'uses both files if present but user data takes precedence' do
|
|
130
|
+
expect(Cisco::Environment).to receive(:data_from_file).with(
|
|
131
|
+
'/etc/cisco_node_utils.yaml').and_return(global_config)
|
|
132
|
+
expect(Cisco::Environment).to receive(:data_from_file).with(
|
|
133
|
+
'~/cisco_node_utils.yaml').and_return(user_config)
|
|
134
|
+
expect(Cisco::Environment.environments).to eq(
|
|
135
|
+
'default' => {
|
|
136
|
+
host: '127.0.0.1', # global config
|
|
137
|
+
port: 57_799, # user overrides global
|
|
138
|
+
username: 'user', # user config
|
|
139
|
+
password: nil, # auto-populated with nil
|
|
140
|
+
},
|
|
141
|
+
'global' => { # global config
|
|
142
|
+
host: nil,
|
|
143
|
+
port: nil,
|
|
144
|
+
username: 'global',
|
|
145
|
+
password: 'global',
|
|
146
|
+
},
|
|
147
|
+
'user' => { # user config
|
|
148
|
+
host: nil,
|
|
149
|
+
port: nil,
|
|
150
|
+
username: 'user',
|
|
151
|
+
password: 'user',
|
|
152
|
+
},
|
|
153
|
+
)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
context '.environment' do
|
|
158
|
+
context 'with no config files available' do
|
|
159
|
+
before(:each) do
|
|
160
|
+
allow(Cisco::Environment).to receive(:data_from_file).and_return({})
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it 'returns DEFAULT_ENVIRONMENT when called with no args' do
|
|
164
|
+
expect(Cisco::Environment.environment).to \
|
|
165
|
+
eq(Cisco::Environment::DEFAULT_ENVIRONMENT)
|
|
166
|
+
end
|
|
167
|
+
it 'returns DEFAULT_ENVIRONMENT when requested by name as "default"' do
|
|
168
|
+
expect(Cisco::Environment.environment('default')).to \
|
|
169
|
+
eq(Cisco::Environment::DEFAULT_ENVIRONMENT)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context 'with examples in docs/cisco_node_utils.yaml.example' do
|
|
174
|
+
before(:each) do
|
|
175
|
+
allow(File).to receive(:file?).and_return(true)
|
|
176
|
+
allow(File).to receive(:readable?).and_return(true)
|
|
177
|
+
allow(YAML).to receive(:load_file).and_wrap_original do |orig|
|
|
178
|
+
orig.call(File.expand_path('docs/cisco_node_utils.yaml.example'))
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
context 'the "nxapi_local" example' do
|
|
183
|
+
expected = {
|
|
184
|
+
host: nil,
|
|
185
|
+
port: nil,
|
|
186
|
+
username: nil,
|
|
187
|
+
password: nil,
|
|
188
|
+
}
|
|
189
|
+
it 'can be loaded explicitly by name' do
|
|
190
|
+
expect(Cisco::Environment.environment('nxapi_local')).to eq(expected)
|
|
191
|
+
end
|
|
192
|
+
it 'can be specified as the default then loaded implicitly' do
|
|
193
|
+
Cisco::Environment.default_environment_name = 'nxapi_local'
|
|
194
|
+
expect(Cisco::Environment.environment).to eq(expected)
|
|
195
|
+
end
|
|
196
|
+
it 'is valid configuration for the NXAPI client' do
|
|
197
|
+
hash = Cisco::Environment.environment('nxapi_local')
|
|
198
|
+
Cisco::Client::NXAPI.validate_args(hash)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
context 'the "nxapi_remote" example' do
|
|
203
|
+
expected = {
|
|
204
|
+
host: '192.168.1.100',
|
|
205
|
+
port: nil,
|
|
206
|
+
username: 'devops',
|
|
207
|
+
password: 'devops',
|
|
208
|
+
}
|
|
209
|
+
it 'can be loaded explicitly by name' do
|
|
210
|
+
expect(Cisco::Environment.environment('nxapi_remote')).to eq(expected)
|
|
211
|
+
end
|
|
212
|
+
it 'can be specified as the default then loaded implicitly' do
|
|
213
|
+
Cisco::Environment.default_environment_name = 'nxapi_remote'
|
|
214
|
+
expect(Cisco::Environment.environment).to eq(expected)
|
|
215
|
+
end
|
|
216
|
+
it 'is valid configuration for the NXAPI client' do
|
|
217
|
+
hash = Cisco::Environment.environment('nxapi_remote')
|
|
218
|
+
Cisco::Client::NXAPI.validate_args(hash)
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
context 'the "grpc_local" example' do
|
|
223
|
+
expected = {
|
|
224
|
+
host: nil,
|
|
225
|
+
port: 57_999,
|
|
226
|
+
username: 'admin',
|
|
227
|
+
password: 'admin',
|
|
228
|
+
}
|
|
229
|
+
it 'can be loaded explicitly by name' do
|
|
230
|
+
expect(Cisco::Environment.environment('grpc_local')).to eq(expected)
|
|
231
|
+
end
|
|
232
|
+
it 'can be specified as default then loaded implicitly' do
|
|
233
|
+
Cisco::Environment.default_environment_name = 'grpc_local'
|
|
234
|
+
expect(Cisco::Environment.environment).to eq(expected)
|
|
235
|
+
end
|
|
236
|
+
it 'is valid configuration for the gRPC client' do
|
|
237
|
+
hash = Cisco::Environment.environment('grpc_local')
|
|
238
|
+
Cisco::Client::GRPC.validate_args(hash)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
context 'the "grpc_remote" example' do
|
|
243
|
+
expected = {
|
|
244
|
+
host: '192.168.1.100',
|
|
245
|
+
port: nil,
|
|
246
|
+
username: 'admin',
|
|
247
|
+
password: 'admin',
|
|
248
|
+
}
|
|
249
|
+
it 'can be loaded explicitly by name' do
|
|
250
|
+
expect(Cisco::Environment.environment('grpc_remote')).to eq(expected)
|
|
251
|
+
end
|
|
252
|
+
it 'can be specified as default then loaded implicitly' do
|
|
253
|
+
Cisco::Environment.default_environment_name = 'grpc_remote'
|
|
254
|
+
expect(Cisco::Environment.environment).to eq(expected)
|
|
255
|
+
end
|
|
256
|
+
it 'is valid configuration for the gRPC client' do
|
|
257
|
+
hash = Cisco::Environment.environment('grpc_remote')
|
|
258
|
+
Cisco::Client::GRPC.validate_args(hash)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|