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.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +66 -0
  4. data/Gemfile +1 -0
  5. data/README.md +44 -43
  6. data/bin/.rubocop.yml +18 -0
  7. data/bin/show_running_yang.rb +233 -0
  8. data/cisco_node_utils.gemspec +1 -1
  9. data/docs/README-maintainers.md +1 -0
  10. data/docs/README-utilities.md +14 -0
  11. data/lib/.rubocop.yml +1 -1
  12. data/lib/cisco_node_utils/aaa_authentication_login_service.rb +8 -3
  13. data/lib/cisco_node_utils/aaa_authorization_service.rb +6 -0
  14. data/lib/cisco_node_utils/bfd_global.rb +300 -0
  15. data/lib/cisco_node_utils/bgp.rb +6 -4
  16. data/lib/cisco_node_utils/bgp_af.rb +2 -0
  17. data/lib/cisco_node_utils/bgp_neighbor.rb +14 -0
  18. data/lib/cisco_node_utils/bgp_neighbor_af.rb +4 -1
  19. data/lib/cisco_node_utils/cisco_cmn_utils.rb +126 -0
  20. data/lib/cisco_node_utils/client/client.rb +6 -2
  21. data/lib/cisco_node_utils/client/grpc/client.rb +120 -36
  22. data/lib/cisco_node_utils/client/nxapi/client.rb +6 -2
  23. data/lib/cisco_node_utils/cmd_ref/DEPRECATED.yaml +118 -0
  24. data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +14 -0
  25. data/lib/cisco_node_utils/cmd_ref/bfd_global.yaml +117 -0
  26. data/lib/cisco_node_utils/cmd_ref/bgp.yaml +7 -7
  27. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +7 -0
  28. data/lib/cisco_node_utils/cmd_ref/dhcp_relay_global.yaml +125 -0
  29. data/lib/cisco_node_utils/cmd_ref/feature.yaml +10 -0
  30. data/lib/cisco_node_utils/cmd_ref/interface.yaml +141 -49
  31. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +44 -0
  32. data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +6 -0
  33. data/lib/cisco_node_utils/cmd_ref/ospf.yaml +6 -0
  34. data/lib/cisco_node_utils/cmd_ref/ospf_area.yaml +91 -0
  35. data/lib/cisco_node_utils/cmd_ref/ospf_area_vlink.yaml +88 -0
  36. data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +0 -3
  37. data/lib/cisco_node_utils/cmd_ref/show_version.yaml +3 -3
  38. data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +39 -15
  39. data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +43 -21
  40. data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +48 -19
  41. data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +0 -0
  42. data/lib/cisco_node_utils/cmd_ref/tacacs_global.yaml +30 -0
  43. data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +18 -6
  44. data/lib/cisco_node_utils/cmd_ref/vdc.yaml +4 -0
  45. data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +1 -0
  46. data/lib/cisco_node_utils/cmd_ref/vlan.yaml +23 -10
  47. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +8 -2
  48. data/lib/cisco_node_utils/cmd_ref/yang.yaml +7 -0
  49. data/lib/cisco_node_utils/cmd_ref/yum.yaml +10 -1
  50. data/lib/cisco_node_utils/constants.rb +8 -1
  51. data/lib/cisco_node_utils/dhcp_relay_global.rb +302 -0
  52. data/lib/cisco_node_utils/exceptions.rb +29 -0
  53. data/lib/cisco_node_utils/feature.rb +28 -0
  54. data/lib/cisco_node_utils/interface.rb +493 -402
  55. data/lib/cisco_node_utils/interface_DEPRECATED.rb +513 -0
  56. data/lib/cisco_node_utils/interface_ospf.rb +126 -0
  57. data/lib/cisco_node_utils/interface_portchannel.rb +16 -0
  58. data/lib/cisco_node_utils/logger.rb +3 -0
  59. data/lib/cisco_node_utils/node.rb +29 -1
  60. data/lib/cisco_node_utils/overlay_global.rb +1 -12
  61. data/lib/cisco_node_utils/pim.rb +1 -0
  62. data/lib/cisco_node_utils/pim_group_list.rb +1 -0
  63. data/lib/cisco_node_utils/pim_rp_address.rb +1 -0
  64. data/lib/cisco_node_utils/platform.rb +9 -2
  65. data/lib/cisco_node_utils/router_ospf.rb +1 -1
  66. data/lib/cisco_node_utils/router_ospf_area.rb +416 -0
  67. data/lib/cisco_node_utils/router_ospf_area_vlink.rb +313 -0
  68. data/lib/cisco_node_utils/router_ospf_vrf.rb +17 -0
  69. data/lib/cisco_node_utils/snmp_notification_receiver.rb +27 -9
  70. data/lib/cisco_node_utils/snmpcommunity.rb +34 -8
  71. data/lib/cisco_node_utils/snmpserver.rb +4 -4
  72. data/lib/cisco_node_utils/snmpuser.rb +0 -0
  73. data/lib/cisco_node_utils/tacacs_global.rb +102 -0
  74. data/lib/cisco_node_utils/tacacs_server.rb +8 -7
  75. data/lib/cisco_node_utils/vdc.rb +25 -7
  76. data/lib/cisco_node_utils/version.rb +1 -1
  77. data/lib/cisco_node_utils/vlan.rb +30 -56
  78. data/lib/cisco_node_utils/vlan_DEPRECATED.rb +108 -0
  79. data/lib/cisco_node_utils/yang.rb +160 -0
  80. data/lib/cisco_node_utils/yum.rb +25 -32
  81. data/tests/.rubocop.yml +3 -0
  82. data/tests/ciscotest.rb +136 -19
  83. data/tests/cmd_config_invalid.yaml +1 -1
  84. data/tests/noop.rb +7 -0
  85. data/tests/tacacs_server.yaml.example +6 -0
  86. data/tests/test_aaa_authentication_login.rb +24 -1
  87. data/tests/test_aaa_authentication_login_service.rb +9 -16
  88. data/tests/test_aaa_authorization_service.rb +111 -84
  89. data/tests/test_bfd_global.rb +278 -0
  90. data/tests/test_bgp_neighbor.rb +20 -0
  91. data/tests/test_bridge_domain_vni.rb +2 -9
  92. data/tests/test_cmn_utils.rb +76 -0
  93. data/tests/test_dhcp_relay_global.rb +284 -0
  94. data/tests/test_dns_domain.rb +4 -4
  95. data/tests/test_domain_name.rb +2 -2
  96. data/tests/test_encapsulation.rb +2 -4
  97. data/tests/test_evpn_vni.rb +14 -7
  98. data/tests/test_fabricpath_global.rb +12 -13
  99. data/tests/test_feature.rb +35 -17
  100. data/tests/test_interface.rb +352 -127
  101. data/tests/test_interface_bdi.rb +2 -2
  102. data/tests/test_interface_channel_group.rb +1 -1
  103. data/tests/test_interface_ospf.rb +153 -23
  104. data/tests/test_interface_portchannel.rb +15 -6
  105. data/tests/test_interface_private_vlan.rb +200 -576
  106. data/tests/test_interface_svi.rb +5 -52
  107. data/tests/test_interface_switchport.rb +80 -240
  108. data/tests/test_itd_device_group.rb +2 -2
  109. data/tests/test_itd_device_group_node.rb +2 -2
  110. data/tests/test_itd_service.rb +1 -1
  111. data/tests/test_name_server.rb +3 -3
  112. data/tests/test_node_ext.rb +15 -17
  113. data/tests/test_ntp_config.rb +1 -1
  114. data/tests/test_ntp_server.rb +3 -3
  115. data/tests/test_nxapi.rb +1 -0
  116. data/tests/test_overlay_global.rb +15 -19
  117. data/tests/test_pim.rb +5 -5
  118. data/tests/test_pim_group_list.rb +1 -37
  119. data/tests/test_pim_rp_address.rb +1 -1
  120. data/tests/test_platform.rb +9 -11
  121. data/tests/test_portchannel_global.rb +43 -3
  122. data/tests/test_radius_server.rb +1 -1
  123. data/tests/test_radius_server_group.rb +1 -1
  124. data/tests/test_router_bgp.rb +17 -30
  125. data/tests/test_router_ospf_area.rb +433 -0
  126. data/tests/test_router_ospf_area_vlink.rb +298 -0
  127. data/tests/test_router_ospf_vrf.rb +17 -0
  128. data/tests/test_snmp_notification_receiver.rb +11 -11
  129. data/tests/test_snmpcommunity.rb +177 -69
  130. data/tests/test_snmpgroup.rb +7 -7
  131. data/tests/test_snmpserver.rb +164 -253
  132. data/tests/test_snmpuser.rb +73 -69
  133. data/tests/test_stp_global.rb +15 -15
  134. data/tests/test_syslog_settings.rb +1 -1
  135. data/tests/test_tacacs_global.rb +80 -0
  136. data/tests/test_tacacs_server.rb +129 -51
  137. data/tests/test_tacacs_server_group.rb +3 -29
  138. data/tests/test_tacacs_server_host.rb +24 -27
  139. data/tests/test_vlan.rb +57 -59
  140. data/tests/test_vlan_private.rb +271 -284
  141. data/tests/test_vpc.rb +10 -4
  142. data/tests/test_vrf.rb +2 -0
  143. data/tests/test_vrf_af.rb +2 -5
  144. data/tests/test_vtp.rb +5 -2
  145. data/tests/test_vxlan_vtep.rb +20 -44
  146. data/tests/test_vxlan_vtep_vni.rb +23 -16
  147. data/tests/test_yang.rb +369 -0
  148. data/tests/test_yum.rb +34 -42
  149. data/tests/yum_package.yaml +35 -0
  150. metadata +31 -4
  151. 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
- Feature.bgp_enable if platform == :nexus
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 enter within the
89
- # CLI sub-mode.
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
- # IOS XR lets us concatenate submode commands together.
97
- # This makes it possible to guarantee we are in the correct context:
98
- # context: ['foo', 'bar'], values: ['baz', 'bat']
99
- # ---> values: ['foo bar baz', 'foo bar bat']
100
- # However, there's a special case for 'no' commands:
101
- # context: ['foo', 'bar'], values: ['no baz']
102
- # ---> values: ['no foo bar baz'] ---- the 'no' goes at the start
103
- context = context.join(' ')
104
- unless context.empty?
105
- values.map! do |cmd|
106
- match = cmd[/^\s*no\s+(.*)/, 1]
107
- if match
108
- cmd = "no #{context} #{match}"
109
- else
110
- cmd = "#{context} #{cmd}"
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
- args = ShowCmdArgs.new(cli: command)
127
- output = req(@exec, 'show_cmd_text_output', args)
128
- self.class.filter_cli(cli_output: output, context: context, value: value)
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
- match = /\n\n(.*)\n\n\Z/m.match(message)
297
- if match.nil?
298
- rejected = '(unknown, see error message)'
374
+ if m['error-path']
375
+ fail Cisco::YangError.new( # rubocop:disable Style/RaiseArgs
376
+ message
377
+ )
299
378
  else
300
- rejected = match[1].split("\n")
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