cisco_node_utils 1.3.0 → 1.4.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 +1 -0
- data/CHANGELOG.md +66 -0
- data/Gemfile +1 -0
- data/README.md +44 -43
- data/bin/.rubocop.yml +18 -0
- data/bin/show_running_yang.rb +233 -0
- data/cisco_node_utils.gemspec +1 -1
- data/docs/README-maintainers.md +1 -0
- data/docs/README-utilities.md +14 -0
- data/lib/.rubocop.yml +1 -1
- data/lib/cisco_node_utils/aaa_authentication_login_service.rb +8 -3
- data/lib/cisco_node_utils/aaa_authorization_service.rb +6 -0
- data/lib/cisco_node_utils/bfd_global.rb +300 -0
- data/lib/cisco_node_utils/bgp.rb +6 -4
- data/lib/cisco_node_utils/bgp_af.rb +2 -0
- data/lib/cisco_node_utils/bgp_neighbor.rb +14 -0
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +4 -1
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +126 -0
- data/lib/cisco_node_utils/client/client.rb +6 -2
- data/lib/cisco_node_utils/client/grpc/client.rb +120 -36
- data/lib/cisco_node_utils/client/nxapi/client.rb +6 -2
- data/lib/cisco_node_utils/cmd_ref/DEPRECATED.yaml +118 -0
- data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +14 -0
- data/lib/cisco_node_utils/cmd_ref/bfd_global.yaml +117 -0
- data/lib/cisco_node_utils/cmd_ref/bgp.yaml +7 -7
- data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +7 -0
- data/lib/cisco_node_utils/cmd_ref/dhcp_relay_global.yaml +125 -0
- data/lib/cisco_node_utils/cmd_ref/feature.yaml +10 -0
- data/lib/cisco_node_utils/cmd_ref/interface.yaml +141 -49
- data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +44 -0
- data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +6 -0
- data/lib/cisco_node_utils/cmd_ref/ospf.yaml +6 -0
- data/lib/cisco_node_utils/cmd_ref/ospf_area.yaml +91 -0
- data/lib/cisco_node_utils/cmd_ref/ospf_area_vlink.yaml +88 -0
- data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +0 -3
- data/lib/cisco_node_utils/cmd_ref/show_version.yaml +3 -3
- data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +39 -15
- data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +43 -21
- data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +48 -19
- data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +0 -0
- data/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml +30 -0
- data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +18 -6
- data/lib/cisco_node_utils/cmd_ref/vdc.yaml +4 -0
- data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +1 -0
- data/lib/cisco_node_utils/cmd_ref/vlan.yaml +23 -10
- data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +8 -2
- data/lib/cisco_node_utils/cmd_ref/yang.yaml +7 -0
- data/lib/cisco_node_utils/cmd_ref/yum.yaml +10 -1
- data/lib/cisco_node_utils/constants.rb +8 -1
- data/lib/cisco_node_utils/dhcp_relay_global.rb +302 -0
- data/lib/cisco_node_utils/exceptions.rb +29 -0
- data/lib/cisco_node_utils/feature.rb +28 -0
- data/lib/cisco_node_utils/interface.rb +493 -402
- data/lib/cisco_node_utils/interface_DEPRECATED.rb +513 -0
- data/lib/cisco_node_utils/interface_ospf.rb +126 -0
- data/lib/cisco_node_utils/interface_portchannel.rb +16 -0
- data/lib/cisco_node_utils/logger.rb +3 -0
- data/lib/cisco_node_utils/node.rb +29 -1
- data/lib/cisco_node_utils/overlay_global.rb +1 -12
- data/lib/cisco_node_utils/pim.rb +1 -0
- data/lib/cisco_node_utils/pim_group_list.rb +1 -0
- data/lib/cisco_node_utils/pim_rp_address.rb +1 -0
- data/lib/cisco_node_utils/platform.rb +9 -2
- data/lib/cisco_node_utils/router_ospf.rb +1 -1
- data/lib/cisco_node_utils/router_ospf_area.rb +416 -0
- data/lib/cisco_node_utils/router_ospf_area_vlink.rb +313 -0
- data/lib/cisco_node_utils/router_ospf_vrf.rb +17 -0
- data/lib/cisco_node_utils/snmp_notification_receiver.rb +27 -9
- data/lib/cisco_node_utils/snmpcommunity.rb +34 -8
- data/lib/cisco_node_utils/snmpserver.rb +4 -4
- data/lib/cisco_node_utils/snmpuser.rb +0 -0
- data/lib/cisco_node_utils/tacacs_global.rb +102 -0
- data/lib/cisco_node_utils/tacacs_server.rb +8 -7
- data/lib/cisco_node_utils/vdc.rb +25 -7
- data/lib/cisco_node_utils/version.rb +1 -1
- data/lib/cisco_node_utils/vlan.rb +30 -56
- data/lib/cisco_node_utils/vlan_DEPRECATED.rb +108 -0
- data/lib/cisco_node_utils/yang.rb +160 -0
- data/lib/cisco_node_utils/yum.rb +25 -32
- data/tests/.rubocop.yml +3 -0
- data/tests/ciscotest.rb +136 -19
- data/tests/cmd_config_invalid.yaml +1 -1
- data/tests/noop.rb +7 -0
- data/tests/tacacs_server.yaml.example +6 -0
- data/tests/test_aaa_authentication_login.rb +24 -1
- data/tests/test_aaa_authentication_login_service.rb +9 -16
- data/tests/test_aaa_authorization_service.rb +111 -84
- data/tests/test_bfd_global.rb +278 -0
- data/tests/test_bgp_neighbor.rb +20 -0
- data/tests/test_bridge_domain_vni.rb +2 -9
- data/tests/test_cmn_utils.rb +76 -0
- data/tests/test_dhcp_relay_global.rb +284 -0
- data/tests/test_dns_domain.rb +4 -4
- data/tests/test_domain_name.rb +2 -2
- data/tests/test_encapsulation.rb +2 -4
- data/tests/test_evpn_vni.rb +14 -7
- data/tests/test_fabricpath_global.rb +12 -13
- data/tests/test_feature.rb +35 -17
- data/tests/test_interface.rb +352 -127
- data/tests/test_interface_bdi.rb +2 -2
- data/tests/test_interface_channel_group.rb +1 -1
- data/tests/test_interface_ospf.rb +153 -23
- data/tests/test_interface_portchannel.rb +15 -6
- data/tests/test_interface_private_vlan.rb +200 -576
- data/tests/test_interface_svi.rb +5 -52
- data/tests/test_interface_switchport.rb +80 -240
- data/tests/test_itd_device_group.rb +2 -2
- data/tests/test_itd_device_group_node.rb +2 -2
- data/tests/test_itd_service.rb +1 -1
- data/tests/test_name_server.rb +3 -3
- data/tests/test_node_ext.rb +15 -17
- data/tests/test_ntp_config.rb +1 -1
- data/tests/test_ntp_server.rb +3 -3
- data/tests/test_nxapi.rb +1 -0
- data/tests/test_overlay_global.rb +15 -19
- data/tests/test_pim.rb +5 -5
- data/tests/test_pim_group_list.rb +1 -37
- data/tests/test_pim_rp_address.rb +1 -1
- data/tests/test_platform.rb +9 -11
- data/tests/test_portchannel_global.rb +43 -3
- data/tests/test_radius_server.rb +1 -1
- data/tests/test_radius_server_group.rb +1 -1
- data/tests/test_router_bgp.rb +17 -30
- data/tests/test_router_ospf_area.rb +433 -0
- data/tests/test_router_ospf_area_vlink.rb +298 -0
- data/tests/test_router_ospf_vrf.rb +17 -0
- data/tests/test_snmp_notification_receiver.rb +11 -11
- data/tests/test_snmpcommunity.rb +177 -69
- data/tests/test_snmpgroup.rb +7 -7
- data/tests/test_snmpserver.rb +164 -253
- data/tests/test_snmpuser.rb +73 -69
- data/tests/test_stp_global.rb +15 -15
- data/tests/test_syslog_settings.rb +1 -1
- data/tests/test_tacacs_global.rb +80 -0
- data/tests/test_tacacs_server.rb +129 -51
- data/tests/test_tacacs_server_group.rb +3 -29
- data/tests/test_tacacs_server_host.rb +24 -27
- data/tests/test_vlan.rb +57 -59
- data/tests/test_vlan_private.rb +271 -284
- data/tests/test_vpc.rb +10 -4
- data/tests/test_vrf.rb +2 -0
- data/tests/test_vrf_af.rb +2 -5
- data/tests/test_vtp.rb +5 -2
- data/tests/test_vxlan_vtep.rb +20 -44
- data/tests/test_vxlan_vtep_vni.rb +23 -16
- data/tests/test_yang.rb +369 -0
- data/tests/test_yum.rb +34 -42
- data/tests/yum_package.yaml +35 -0
- metadata +31 -4
- data/tests/test_vlan_mt_full.rb +0 -85
|
@@ -99,7 +99,10 @@ module Cisco
|
|
|
99
99
|
# rubocop:enable Style/AccessorMethodNamefor
|
|
100
100
|
|
|
101
101
|
def create
|
|
102
|
-
|
|
102
|
+
if platform == :nexus
|
|
103
|
+
Feature.bgp_enable
|
|
104
|
+
Feature.nv_overlay_evpn_enable if @safi[/evpn/]
|
|
105
|
+
end
|
|
103
106
|
set_args_keys(state: '')
|
|
104
107
|
config_set('bgp_neighbor', 'af', @set_args)
|
|
105
108
|
end
|
|
@@ -224,5 +224,131 @@ module Cisco
|
|
|
224
224
|
end
|
|
225
225
|
lranges.to_s.gsub('..', '-').delete('[').delete(']').delete(' ')
|
|
226
226
|
end
|
|
227
|
+
|
|
228
|
+
# normalize_range_array
|
|
229
|
+
#
|
|
230
|
+
# Given a list of ranges, merge any overlapping ranges and sort them.
|
|
231
|
+
#
|
|
232
|
+
# Note: The ranges are converted to ruby ranges for easy merging,
|
|
233
|
+
# then converted back to a cli-syntax range.
|
|
234
|
+
#
|
|
235
|
+
# Accepts an array or string:
|
|
236
|
+
# ["2-5", "9", "4-6"] -or- '2-5, 9, 4-6' -or- ["2-5, 9, 4-6"]
|
|
237
|
+
# Returns a merged and ordered range as an array or string:
|
|
238
|
+
# ["2-6", "9"] -or- '2-6,9'
|
|
239
|
+
#
|
|
240
|
+
def self.normalize_range_array(range, fmt=:array)
|
|
241
|
+
return range if range.nil? || range.empty?
|
|
242
|
+
range = range.clone
|
|
243
|
+
|
|
244
|
+
# Handle string within an array: ["2-5, 9, 4-6"] to '2-5, 9, 4-6'
|
|
245
|
+
range = range.shift if range.is_a?(Array) && range.length == 1
|
|
246
|
+
|
|
247
|
+
# Handle string only: '2-5, 9, 4-6' to ["2-5", "9", "4-6"]
|
|
248
|
+
range = range.split(',') if range.is_a?(String)
|
|
249
|
+
|
|
250
|
+
# Convert to ruby-syntax ranges
|
|
251
|
+
range = dash_range_to_ruby_range(range)
|
|
252
|
+
|
|
253
|
+
# Sort & Merge
|
|
254
|
+
merged = merge_range(range)
|
|
255
|
+
|
|
256
|
+
# Convert back to cli dash-syntax
|
|
257
|
+
merged_array = ruby_range_to_dash_range(merged)
|
|
258
|
+
|
|
259
|
+
return merged_array.join(',') if fmt == :string
|
|
260
|
+
merged_array
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Convert a cli-dash-syntax range to ruby-range. This is useful for
|
|
264
|
+
# preparing inputs to merge_range().
|
|
265
|
+
#
|
|
266
|
+
# Inputs an array or string of dash-syntax ranges -> returns an array
|
|
267
|
+
# of ruby ranges.
|
|
268
|
+
#
|
|
269
|
+
# Accepts an array or string: ["2-5", "9", "4-6"] or '2-5, 9, 4-6'
|
|
270
|
+
# Returns an array of ranges: [2..5, 9..9, 4..6]
|
|
271
|
+
#
|
|
272
|
+
def self.dash_range_to_ruby_range(range)
|
|
273
|
+
range = range.split(',') if range.is_a?(String)
|
|
274
|
+
range.map! do |rng|
|
|
275
|
+
if rng[/-/]
|
|
276
|
+
# '2-5' -> 2..5
|
|
277
|
+
rng.split('-').inject { |a, e| a.to_i..e.to_i }
|
|
278
|
+
else
|
|
279
|
+
# '9' -> 9..9
|
|
280
|
+
rng.to_i..rng.to_i
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
range
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Convert a ruby-range to cli-dash-syntax.
|
|
287
|
+
#
|
|
288
|
+
# Inputs an array of ruby ranges -> returns an array or string of
|
|
289
|
+
# dash-syntax ranges.
|
|
290
|
+
#
|
|
291
|
+
# when (:array) [2..6, 9..9] -> ['2-6', '9']
|
|
292
|
+
#
|
|
293
|
+
# when (:string) [2..6, 9..9] -> '2-6, 9'
|
|
294
|
+
#
|
|
295
|
+
def self.ruby_range_to_dash_range(range, type=:array)
|
|
296
|
+
fail unless range.is_a?(Array)
|
|
297
|
+
range.map! do |r|
|
|
298
|
+
if r.first == r.last
|
|
299
|
+
# 9..9 -> '9'
|
|
300
|
+
r.first.to_s
|
|
301
|
+
else
|
|
302
|
+
# 2..6 -> '2-6'
|
|
303
|
+
r.first.to_s + '-' + r.last.to_s
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
return range.join(', ') if type == :string
|
|
307
|
+
range
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Convert a dash-range set into individual elements.
|
|
311
|
+
# This is useful for preparing inputs to delta_add_remove().
|
|
312
|
+
#
|
|
313
|
+
# Inputs an array or string of dash-ranges:
|
|
314
|
+
# ["2-5", "9", "4-6"] or '2-5, 9, 4-6' or ['2-5, 9, 4-6']
|
|
315
|
+
# Returns an array of range elements:
|
|
316
|
+
# ["2", "3", "4", "5", "6", "9"]
|
|
317
|
+
#
|
|
318
|
+
def self.dash_range_to_elements(range)
|
|
319
|
+
return [] if range.nil?
|
|
320
|
+
range = range.shift if range.is_a?(Array) && range.length == 1
|
|
321
|
+
range = range.split(',') if range.is_a?(String)
|
|
322
|
+
|
|
323
|
+
final = []
|
|
324
|
+
range = dash_range_to_ruby_range(range)
|
|
325
|
+
range.each do |rng|
|
|
326
|
+
# 2..5 maps to ["2", "3", "4", "5"]
|
|
327
|
+
final << rng.map(&:to_s)
|
|
328
|
+
end
|
|
329
|
+
final.flatten.uniq.sort
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# Merge overlapping ranges.
|
|
333
|
+
#
|
|
334
|
+
# Inputs an array of ruby ranges: [2..5, 9..9, 4..6]
|
|
335
|
+
# Returns an array of merged ruby ranges: [2..6, 9..9]
|
|
336
|
+
#
|
|
337
|
+
def self.merge_range(range)
|
|
338
|
+
# sort to lowest range 'first' values:
|
|
339
|
+
# [2..5, 9..9, 4..6] -> [2..5, 4..6, 9..9]
|
|
340
|
+
range = range.sort_by(&:first)
|
|
341
|
+
|
|
342
|
+
*merged = range.shift
|
|
343
|
+
range.each do |r|
|
|
344
|
+
lastr = merged[-1]
|
|
345
|
+
if lastr.last >= r.first - 1
|
|
346
|
+
merged[-1] = lastr.first..[r.last, lastr.last].max
|
|
347
|
+
else
|
|
348
|
+
merged.push(r)
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
merged
|
|
352
|
+
end # merge_range
|
|
227
353
|
end # class Utils
|
|
228
354
|
end # module Cisco
|
|
@@ -167,9 +167,11 @@ class Cisco::Client
|
|
|
167
167
|
# @param data_format one of Cisco::DATA_FORMATS. Default is :cli
|
|
168
168
|
# @param context [String, Array<String>] Context for the configuration
|
|
169
169
|
# @param values [String, Array<String>] Actual configuration to set
|
|
170
|
+
# @param kwargs data-format-specific args
|
|
170
171
|
def set(data_format: :cli,
|
|
171
172
|
context: nil,
|
|
172
|
-
values: nil
|
|
173
|
+
values: nil,
|
|
174
|
+
**_kwargs)
|
|
173
175
|
# subclasses will generally want to call Client.munge_to_array()
|
|
174
176
|
# on context and/or values before calling super()
|
|
175
177
|
fail Cisco::RequestNotSupported unless self.supports?(data_format)
|
|
@@ -195,11 +197,13 @@ class Cisco::Client
|
|
|
195
197
|
# @param command [String] the get command to execute
|
|
196
198
|
# @param context [String, Array<String>] Context to refine/filter the results
|
|
197
199
|
# @param value [String, Regexp] Specific key or regexp to look up
|
|
200
|
+
# @param kwargs data-format-specific args
|
|
198
201
|
# @return [String, Hash, nil] The state found, or nil if not found.
|
|
199
202
|
def get(data_format: :cli,
|
|
200
203
|
command: nil,
|
|
201
204
|
context: nil,
|
|
202
|
-
value: nil
|
|
205
|
+
value: nil,
|
|
206
|
+
**_kwargs)
|
|
203
207
|
# subclasses will generally want to call Client.munge_to_array()
|
|
204
208
|
# on context and/or value before calling super()
|
|
205
209
|
fail Cisco::RequestNotSupported unless self.supports?(data_format)
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
|
|
19
19
|
require_relative '../client'
|
|
20
|
+
require_relative '../../constants'
|
|
20
21
|
Cisco::Client.silence_warnings do
|
|
21
22
|
require 'grpc'
|
|
22
23
|
end
|
|
@@ -37,7 +38,7 @@ class Cisco::Client::GRPC < Cisco::Client
|
|
|
37
38
|
kwargs[:host] ||= '127.0.0.1'
|
|
38
39
|
kwargs[:port] ||= 57_400
|
|
39
40
|
# rubocop:disable Style/HashSyntax
|
|
40
|
-
super(data_formats: [:cli],
|
|
41
|
+
super(data_formats: [:cli, :yang_json],
|
|
41
42
|
platform: :ios_xr,
|
|
42
43
|
**kwargs)
|
|
43
44
|
# rubocop:enable Style/HashSyntax
|
|
@@ -85,47 +86,64 @@ class Cisco::Client::GRPC < Cisco::Client
|
|
|
85
86
|
# @param data_format one of Cisco::DATA_FORMATS. Default is :cli
|
|
86
87
|
# @param context [Array<String>] Zero or more configuration commands used
|
|
87
88
|
# to enter the desired CLI sub-mode
|
|
88
|
-
# @param values [Array<String>] One or more commands to
|
|
89
|
-
#
|
|
89
|
+
# @param values [Array<String>] One or more commands to execute /
|
|
90
|
+
# config strings to send
|
|
91
|
+
# @param kwargs data-format-specific args
|
|
90
92
|
def set(data_format: :cli,
|
|
91
93
|
context: nil,
|
|
92
|
-
values: nil
|
|
94
|
+
values: nil,
|
|
95
|
+
**kwargs)
|
|
93
96
|
context = munge_to_array(context)
|
|
94
97
|
values = munge_to_array(values)
|
|
95
98
|
super
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
values
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
if data_format == :yang_json
|
|
100
|
+
mode = kwargs[:mode] || :merge_config
|
|
101
|
+
fail ArgumentError unless Cisco::YANG_SET_MODE.include? mode
|
|
102
|
+
values.each do |yang|
|
|
103
|
+
yang_req(@config, mode.to_s, ConfigArgs.new(yangjson: yang))
|
|
104
|
+
end
|
|
105
|
+
else
|
|
106
|
+
# IOS XR lets us concatenate submode commands together.
|
|
107
|
+
# This makes it possible to guarantee we are in the correct context:
|
|
108
|
+
# context: ['foo', 'bar'], values: ['baz', 'bat']
|
|
109
|
+
# ---> values: ['foo bar baz', 'foo bar bat']
|
|
110
|
+
# However, there's a special case for 'no' commands:
|
|
111
|
+
# context: ['foo', 'bar'], values: ['no baz']
|
|
112
|
+
# ---> values: ['no foo bar baz'] ---- the 'no' goes at the start
|
|
113
|
+
context = context.join(' ')
|
|
114
|
+
unless context.empty?
|
|
115
|
+
values.map! do |cmd|
|
|
116
|
+
match = cmd[/^\s*no\s+(.*)/, 1]
|
|
117
|
+
if match
|
|
118
|
+
cmd = "no #{context} #{match}"
|
|
119
|
+
else
|
|
120
|
+
cmd = "#{context} #{cmd}"
|
|
121
|
+
end
|
|
122
|
+
cmd
|
|
111
123
|
end
|
|
112
|
-
cmd
|
|
113
124
|
end
|
|
125
|
+
# CliConfigArgs wants a newline-separated string of commands
|
|
126
|
+
args = CliConfigArgs.new(cli: values.join("\n"))
|
|
127
|
+
req(@config, 'cli_config', args)
|
|
114
128
|
end
|
|
115
|
-
# CliConfigArgs wants a newline-separated string of commands
|
|
116
|
-
args = CliConfigArgs.new(cli: values.join("\n"))
|
|
117
|
-
req(@config, 'cli_config', args)
|
|
118
129
|
end
|
|
119
130
|
|
|
120
131
|
def get(data_format: :cli,
|
|
121
132
|
command: nil,
|
|
122
133
|
context: nil,
|
|
123
|
-
value: nil
|
|
134
|
+
value: nil,
|
|
135
|
+
**kwargs)
|
|
124
136
|
super
|
|
125
137
|
fail ArgumentError if command.nil?
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
138
|
+
|
|
139
|
+
if data_format == :yang_json
|
|
140
|
+
mode = kwargs[:mode] || :get_config
|
|
141
|
+
yang_req(@config, mode, ConfigGetArgs.new(yangpathjson: command))
|
|
142
|
+
else
|
|
143
|
+
args = ShowCmdArgs.new(cli: command)
|
|
144
|
+
output = req(@exec, 'show_cmd_text_output', args)
|
|
145
|
+
self.class.filter_cli(cli_output: output, context: context, value: value)
|
|
146
|
+
end
|
|
129
147
|
end
|
|
130
148
|
|
|
131
149
|
def req(stub, type, args)
|
|
@@ -170,6 +188,51 @@ class Cisco::Client::GRPC < Cisco::Client
|
|
|
170
188
|
end
|
|
171
189
|
end
|
|
172
190
|
|
|
191
|
+
# Send a YANG request via gRPC
|
|
192
|
+
def yang_req(stub, type, args)
|
|
193
|
+
debug "Sending '#{type}' request:"
|
|
194
|
+
if args.is_a?(ConfigGetArgs)
|
|
195
|
+
debug " with yangpathjson: #{args.yangpathjson}"
|
|
196
|
+
elsif args.is_a?(ConfigArgs)
|
|
197
|
+
debug " with yangjson: #{args.yangjson}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
output = Cisco::Client.silence_warnings do
|
|
201
|
+
response = stub.send(type, args,
|
|
202
|
+
timeout: @timeout,
|
|
203
|
+
username: @username,
|
|
204
|
+
password: @password)
|
|
205
|
+
# gRPC server may split the response into multiples
|
|
206
|
+
response = response.is_a?(Enumerator) ? response.to_a : [response]
|
|
207
|
+
debug "Got responses: #{response.map(&:class).join(', ')}"
|
|
208
|
+
debug "response: #{response}"
|
|
209
|
+
# Check for errors first
|
|
210
|
+
handle_errors(args, response.select { |r| !r.errors.empty? })
|
|
211
|
+
|
|
212
|
+
# If we got here, no errors occurred
|
|
213
|
+
handle_response(args, response)
|
|
214
|
+
end
|
|
215
|
+
return output
|
|
216
|
+
|
|
217
|
+
rescue ::GRPC::BadStatus => e
|
|
218
|
+
warn "gRPC error '#{e.code}' during '#{type}' request: "
|
|
219
|
+
if args.is_a?(ConfigGetArgs)
|
|
220
|
+
debug " with yangpathjson: #{args.yangpathjson}"
|
|
221
|
+
elsif args.is_a?(ConfigArgs)
|
|
222
|
+
debug " with yangjson: #{args.yangjson}"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
warn " '#{e.details}'"
|
|
226
|
+
case e.code
|
|
227
|
+
when ::GRPC::Core::StatusCodes::UNAVAILABLE
|
|
228
|
+
raise Cisco::ConnectionRefused, "Connection refused: #{e.details}"
|
|
229
|
+
when ::GRPC::Core::StatusCodes::UNAUTHENTICATED
|
|
230
|
+
raise Cisco::AuthenticationFailed, e.details
|
|
231
|
+
else
|
|
232
|
+
raise Cisco::ClientError, e.details
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
173
236
|
def handle_response(args, replies)
|
|
174
237
|
klass = replies[0].class
|
|
175
238
|
unless replies.all? { |r| r.class == klass }
|
|
@@ -189,6 +252,15 @@ class Cisco::Client::GRPC < Cisco::Client
|
|
|
189
252
|
when /CliConfigReply/
|
|
190
253
|
# nothing to process
|
|
191
254
|
output = ''
|
|
255
|
+
when /ConfigGetReply/
|
|
256
|
+
replies.each { |r| debug " yangjson:\n#{r.yangjson}" }
|
|
257
|
+
output = replies.map(&:yangjson).join('')
|
|
258
|
+
when /GetOperReply/
|
|
259
|
+
replies.each { |r| debug " yangjson:\n#{r.yangjson}" }
|
|
260
|
+
output = replies.map(&:yangjson).join('')
|
|
261
|
+
when /ConfigReply/
|
|
262
|
+
# nothing to process
|
|
263
|
+
output = ''
|
|
192
264
|
else
|
|
193
265
|
fail Cisco::ClientError, "unsupported reply class #{klass}"
|
|
194
266
|
end
|
|
@@ -242,6 +314,11 @@ class Cisco::Client::GRPC < Cisco::Client
|
|
|
242
314
|
def handle_text_error(args, msg)
|
|
243
315
|
if /^Disallowed commands:/ =~ msg
|
|
244
316
|
fail Cisco::RequestNotSupported, msg
|
|
317
|
+
elsif args.is_a?(ConfigGetArgs) || args.is_a?(ConfigArgs)
|
|
318
|
+
fail Cisco::YangError.new( # rubocop:disable Style/RaiseArgs
|
|
319
|
+
rejected_input: args.yangpathjson,
|
|
320
|
+
error: msg,
|
|
321
|
+
)
|
|
245
322
|
else
|
|
246
323
|
fail Cisco::CliError.new( # rubocop:disable Style/RaiseArgs
|
|
247
324
|
rejected_input: args.cli,
|
|
@@ -277,7 +354,8 @@ class Cisco::Client::GRPC < Cisco::Client
|
|
|
277
354
|
msg = msg['error'] unless msg.is_a?(Array)
|
|
278
355
|
msg.each do |m|
|
|
279
356
|
type = m['error-type']
|
|
280
|
-
message = m['error-message']
|
|
357
|
+
message = m['error-message'] || m['error-tag']
|
|
358
|
+
message += ': ' + m['error-path'] if m['error-path']
|
|
281
359
|
if type == 'protocol' && message == 'Failed authentication'
|
|
282
360
|
fail Cisco::AuthenticationFailed, message
|
|
283
361
|
elsif type == 'application'
|
|
@@ -293,16 +371,22 @@ class Cisco::Client::GRPC < Cisco::Client
|
|
|
293
371
|
# foo
|
|
294
372
|
# bar
|
|
295
373
|
#
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
374
|
+
if m['error-path']
|
|
375
|
+
fail Cisco::YangError.new( # rubocop:disable Style/RaiseArgs
|
|
376
|
+
message
|
|
377
|
+
)
|
|
299
378
|
else
|
|
300
|
-
|
|
379
|
+
match = /\n\n(.*)\n\n\Z/m.match(message)
|
|
380
|
+
if match.nil?
|
|
381
|
+
rejected = '(unknown, see error message)'
|
|
382
|
+
else
|
|
383
|
+
rejected = match[1].split("\n")
|
|
384
|
+
end
|
|
385
|
+
fail Cisco::CliError.new( # rubocop:disable Style/RaiseArgs
|
|
386
|
+
rejected_input: rejected,
|
|
387
|
+
clierror: message,
|
|
388
|
+
)
|
|
301
389
|
end
|
|
302
|
-
fail Cisco::CliError.new( # rubocop:disable Style/RaiseArgs
|
|
303
|
-
rejected_input: rejected,
|
|
304
|
-
clierror: message,
|
|
305
|
-
)
|
|
306
390
|
else
|
|
307
391
|
fail Cisco::ClientError, message
|
|
308
392
|
end
|
|
@@ -105,9 +105,11 @@ class Cisco::Client::NXAPI < Cisco::Client
|
|
|
105
105
|
# used to enter the desired CLI sub-mode
|
|
106
106
|
# @param values [String, Array<String>] One or more commands
|
|
107
107
|
# to enter within the CLI sub-mode.
|
|
108
|
+
# @param kwargs data-format-specific args
|
|
108
109
|
def set(data_format: :cli,
|
|
109
110
|
context: nil,
|
|
110
|
-
values: nil
|
|
111
|
+
values: nil,
|
|
112
|
+
**_kwargs)
|
|
111
113
|
# we don't currently support nxapi_structured for configuration
|
|
112
114
|
fail Cisco::RequestNotSupported if data_format == :nxapi_structured
|
|
113
115
|
context = munge_to_array(context)
|
|
@@ -130,11 +132,13 @@ class Cisco::Client::NXAPI < Cisco::Client
|
|
|
130
132
|
# @param command [String] the show command to execute
|
|
131
133
|
# @param context [String, Array<String>] Context to refine the results
|
|
132
134
|
# @param value [String] Specific key to look up
|
|
135
|
+
# @param kwargs data-format-specific args
|
|
133
136
|
# @return [String, Hash]
|
|
134
137
|
def get(data_format: :cli,
|
|
135
138
|
command: nil,
|
|
136
139
|
context: nil,
|
|
137
|
-
value: nil
|
|
140
|
+
value: nil,
|
|
141
|
+
**_kwargs)
|
|
138
142
|
context = munge_to_array(context)
|
|
139
143
|
super
|
|
140
144
|
if data_format == :cli
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# DEPRECATED
|
|
2
|
+
#
|
|
3
|
+
###############################################################################
|
|
4
|
+
# WARNING. DO NOT USE ANY OF THE YAML TAGS IN THIS FILE.
|
|
5
|
+
# These yaml tags are deprecated and will be removed in future releases.
|
|
6
|
+
###############################################################################
|
|
7
|
+
---
|
|
8
|
+
_template:
|
|
9
|
+
context: ["interface <name>"]
|
|
10
|
+
nexus:
|
|
11
|
+
get_command: "show running interface all"
|
|
12
|
+
|
|
13
|
+
private_vlan_any:
|
|
14
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'pvlan_any'
|
|
15
|
+
multiple:
|
|
16
|
+
get_value: '/switchport private-vlan/'
|
|
17
|
+
|
|
18
|
+
private_vlan_association:
|
|
19
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'pvlan_association'
|
|
20
|
+
_exclude: [N8k]
|
|
21
|
+
multiple: true
|
|
22
|
+
get_command: "show vlan private-vlan"
|
|
23
|
+
get_context: ~
|
|
24
|
+
get_value: '/^<id>\s+(\d+)/'
|
|
25
|
+
set_context: ['vlan <vlan>']
|
|
26
|
+
set_value: "<state> private-vlan association <vlans> ; end"
|
|
27
|
+
default_value: []
|
|
28
|
+
|
|
29
|
+
private_vlan_mapping:
|
|
30
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'pvlan_mapping'
|
|
31
|
+
_exclude: [ios_xr, N8k]
|
|
32
|
+
multiple: true
|
|
33
|
+
get_value: '/^private-vlan mapping (.*)$/'
|
|
34
|
+
set_value: "<state> private-vlan mapping <vlans>"
|
|
35
|
+
default_value: []
|
|
36
|
+
|
|
37
|
+
private_vlan_type:
|
|
38
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'pvlan_type'
|
|
39
|
+
_exclude: [N8k]
|
|
40
|
+
kind: string
|
|
41
|
+
get_command: 'show vlan private-vlan type'
|
|
42
|
+
get_context: ~
|
|
43
|
+
get_value: '/^<id>\s+(\S+)/'
|
|
44
|
+
set_context: ['vlan <vlan>']
|
|
45
|
+
set_value: "<state> private-vlan <type> ; end"
|
|
46
|
+
default_value: ""
|
|
47
|
+
|
|
48
|
+
switchport_mode_private_vlan_host:
|
|
49
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_host'
|
|
50
|
+
_exclude: [ios_xr, N8k]
|
|
51
|
+
get_value: '/^switchport mode private-vlan (.*)$/'
|
|
52
|
+
set_value: "<state> switchport mode private-vlan <mode>"
|
|
53
|
+
default_value: :disabled
|
|
54
|
+
|
|
55
|
+
switchport_mode_private_vlan_host_association:
|
|
56
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_host_association'
|
|
57
|
+
_exclude: [ios_xr, N8k]
|
|
58
|
+
multiple: true
|
|
59
|
+
get_value: '/^switchport private-vlan host-association (.*)$/'
|
|
60
|
+
set_value: "<state> switchport private-vlan host-association <vlan_pr> <vlan_sec>"
|
|
61
|
+
default_value: []
|
|
62
|
+
|
|
63
|
+
switchport_mode_private_vlan_host_promiscous:
|
|
64
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_promiscuous'
|
|
65
|
+
_exclude: [ios_xr, N8k]
|
|
66
|
+
multiple: true
|
|
67
|
+
get_value: '/^switchport private-vlan mapping (\d+.*)$/'
|
|
68
|
+
set_value: "<state> switchport private-vlan mapping <vlan_pr> <vlans>"
|
|
69
|
+
default_value: []
|
|
70
|
+
|
|
71
|
+
switchport_mode_private_vlan_trunk_promiscuous:
|
|
72
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_trunk_promiscuous'
|
|
73
|
+
_exclude: [ios_xr, N3k, N8k]
|
|
74
|
+
kind: boolean
|
|
75
|
+
get_value: '/^switchport mode private-vlan trunk promiscuous$/'
|
|
76
|
+
set_value: "<state> switchport mode private-vlan trunk promiscuous"
|
|
77
|
+
default_value: false
|
|
78
|
+
|
|
79
|
+
switchport_mode_private_vlan_trunk_secondary:
|
|
80
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_trunk_secondary'
|
|
81
|
+
_exclude: [ios_xr, N3k, N8k]
|
|
82
|
+
kind: boolean
|
|
83
|
+
get_value: '/^switchport mode private-vlan trunk secondary$/'
|
|
84
|
+
set_value: "<state> switchport mode private-vlan trunk secondary"
|
|
85
|
+
default_value: false
|
|
86
|
+
|
|
87
|
+
switchport_private_vlan_association_trunk:
|
|
88
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_trunk_association'
|
|
89
|
+
_exclude: [ios_xr, N3k, N8k]
|
|
90
|
+
multiple: true
|
|
91
|
+
#get_value: '/^switchport private-vlan association trunk (.*) (.*)$/'
|
|
92
|
+
get_value: '/^switchport private-vlan association trunk (.*)$/'
|
|
93
|
+
set_value: "<state> switchport private-vlan association trunk <vlan_pr> <vlan>"
|
|
94
|
+
default_value: []
|
|
95
|
+
|
|
96
|
+
switchport_private_vlan_mapping_trunk:
|
|
97
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_mapping_trunk'
|
|
98
|
+
_exclude: [ios_xr, N3k, N8k]
|
|
99
|
+
multiple: true
|
|
100
|
+
get_value: '/^switchport private-vlan mapping trunk (.*)$/'
|
|
101
|
+
set_value: "<state> switchport private-vlan mapping trunk <vlan_pr> <vlans>"
|
|
102
|
+
default_value: []
|
|
103
|
+
|
|
104
|
+
switchport_private_vlan_trunk_allowed_vlan:
|
|
105
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_trunk_allowed_vlan'
|
|
106
|
+
_exclude: [ios_xr, N8k]
|
|
107
|
+
multiple: true
|
|
108
|
+
get_value: '/^switchport private-vlan trunk allowed vlan (.*)$/'
|
|
109
|
+
set_value: "<state> switchport private-vlan trunk allowed vlan <oper> <vlans>"
|
|
110
|
+
default_value: []
|
|
111
|
+
|
|
112
|
+
switchport_private_vlan_trunk_native_vlan:
|
|
113
|
+
# DEPRECATED (REMOVING WITH RELEASE 2.0.0). USE 'switchport_pvlan_trunk_native_vlan'
|
|
114
|
+
_exclude: [ios_xr, N8k]
|
|
115
|
+
kind: int
|
|
116
|
+
get_value: '/^switchport private-vlan trunk native vlan (.*)$/'
|
|
117
|
+
set_value: "<state> switchport private-vlan trunk native vlan <vlan>"
|
|
118
|
+
default_value: 1
|