cisco_node_utils 1.1.0 → 1.2.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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/CHANGELOG.md +126 -1
  4. data/README.md +19 -12
  5. data/Rakefile +1 -0
  6. data/bin/git/hooks/commit-msg/enforce_style +8 -0
  7. data/cisco_node_utils.gemspec +4 -3
  8. data/docs/README-develop-best-practices.md +127 -109
  9. data/docs/README-develop-node-utils-APIs.md +47 -39
  10. data/docs/template-router.rb +3 -7
  11. data/lib/.rubocop.yml +4 -4
  12. data/lib/cisco_node_utils.rb +1 -1
  13. data/lib/cisco_node_utils/aaa_authentication_login.rb +96 -0
  14. data/lib/cisco_node_utils/aaa_authentication_login_service.rb +133 -0
  15. data/lib/cisco_node_utils/aaa_authorization_service.rb +150 -0
  16. data/lib/cisco_node_utils/ace.rb +196 -0
  17. data/lib/cisco_node_utils/acl.rb +100 -0
  18. data/lib/cisco_node_utils/bgp.rb +301 -163
  19. data/lib/cisco_node_utils/bgp_af.rb +187 -19
  20. data/lib/cisco_node_utils/bgp_neighbor.rb +18 -33
  21. data/lib/cisco_node_utils/bgp_neighbor_af.rb +25 -48
  22. data/lib/cisco_node_utils/cisco_cmn_utils.rb +23 -4
  23. data/lib/cisco_node_utils/cmd_ref/README_YAML.md +593 -0
  24. data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +22 -0
  25. data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +31 -0
  26. data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +22 -0
  27. data/lib/cisco_node_utils/cmd_ref/acl.yaml +43 -0
  28. data/lib/cisco_node_utils/cmd_ref/bgp.yaml +242 -0
  29. data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +164 -0
  30. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +131 -0
  31. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +179 -0
  32. data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +34 -0
  33. data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +42 -0
  34. data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +172 -0
  35. data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +35 -0
  36. data/lib/cisco_node_utils/cmd_ref/feature.yaml +42 -0
  37. data/lib/cisco_node_utils/cmd_ref/fex.yaml +9 -0
  38. data/lib/cisco_node_utils/cmd_ref/images.yaml +7 -0
  39. data/lib/cisco_node_utils/cmd_ref/interface.yaml +339 -0
  40. data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +28 -0
  41. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +61 -0
  42. data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +54 -0
  43. data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +32 -0
  44. data/lib/cisco_node_utils/cmd_ref/inventory.yaml +45 -0
  45. data/lib/cisco_node_utils/cmd_ref/memory.yaml +13 -0
  46. data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +7 -0
  47. data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +14 -0
  48. data/lib/cisco_node_utils/cmd_ref/ospf.yaml +74 -0
  49. data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +33 -0
  50. data/lib/cisco_node_utils/cmd_ref/pim.yaml +40 -0
  51. data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +69 -0
  52. data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +25 -0
  53. data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +64 -0
  54. data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +14 -0
  55. data/lib/cisco_node_utils/cmd_ref/show_system.yaml +5 -0
  56. data/lib/cisco_node_utils/cmd_ref/show_version.yaml +72 -0
  57. data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +23 -0
  58. data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +7 -0
  59. data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +50 -0
  60. data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +51 -0
  61. data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +55 -0
  62. data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +11 -0
  63. data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +18 -0
  64. data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +7 -0
  65. data/lib/cisco_node_utils/cmd_ref/system.yaml +6 -0
  66. data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +49 -0
  67. data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +33 -0
  68. data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +35 -0
  69. data/lib/cisco_node_utils/cmd_ref/vdc.yaml +38 -0
  70. data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +6 -0
  71. data/lib/cisco_node_utils/cmd_ref/vlan.yaml +56 -0
  72. data/lib/cisco_node_utils/cmd_ref/vni.yaml +76 -0
  73. data/lib/cisco_node_utils/cmd_ref/vpc.yaml +197 -0
  74. data/lib/cisco_node_utils/cmd_ref/vrf.yaml +88 -0
  75. data/lib/cisco_node_utils/cmd_ref/vtp.yaml +38 -0
  76. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +60 -0
  77. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +39 -0
  78. data/lib/cisco_node_utils/cmd_ref/yum.yaml +13 -0
  79. data/lib/cisco_node_utils/command_reference.rb +359 -187
  80. data/lib/cisco_node_utils/configparser_lib.rb +1 -1
  81. data/lib/cisco_node_utils/dns_domain.rb +19 -5
  82. data/lib/cisco_node_utils/domain_name.rb +4 -8
  83. data/lib/cisco_node_utils/evpn_vni.rb +157 -0
  84. data/lib/cisco_node_utils/fabricpath_global.rb +388 -0
  85. data/lib/cisco_node_utils/fabricpath_topology.rb +150 -0
  86. data/lib/cisco_node_utils/feature.rb +111 -0
  87. data/lib/cisco_node_utils/interface.rb +390 -97
  88. data/lib/cisco_node_utils/interface_channel_group.rb +124 -0
  89. data/lib/cisco_node_utils/interface_ospf.rb +11 -34
  90. data/lib/cisco_node_utils/interface_portchannel.rb +157 -0
  91. data/lib/cisco_node_utils/interface_service_vni.rb +132 -0
  92. data/lib/cisco_node_utils/name_server.rb +1 -1
  93. data/lib/cisco_node_utils/node.rb +55 -249
  94. data/lib/cisco_node_utils/node_util.rb +5 -1
  95. data/lib/cisco_node_utils/ntp_config.rb +2 -2
  96. data/lib/cisco_node_utils/ntp_server.rb +14 -5
  97. data/lib/cisco_node_utils/overlay_global.rb +153 -0
  98. data/lib/cisco_node_utils/pim.rb +124 -0
  99. data/lib/cisco_node_utils/pim_group_list.rb +108 -0
  100. data/lib/cisco_node_utils/pim_rp_address.rb +102 -0
  101. data/lib/cisco_node_utils/platform.rb +8 -9
  102. data/lib/cisco_node_utils/portchannel_global.rb +277 -0
  103. data/lib/cisco_node_utils/radius_global.rb +9 -19
  104. data/lib/cisco_node_utils/radius_server.rb +31 -41
  105. data/lib/cisco_node_utils/radius_server_group.rb +117 -0
  106. data/lib/cisco_node_utils/router_ospf.rb +1 -1
  107. data/lib/cisco_node_utils/router_ospf_vrf.rb +14 -19
  108. data/lib/cisco_node_utils/snmp_notification_receiver.rb +158 -0
  109. data/lib/cisco_node_utils/snmpcommunity.rb +3 -5
  110. data/lib/cisco_node_utils/snmpgroup.rb +1 -1
  111. data/lib/cisco_node_utils/snmpnotification.rb +57 -0
  112. data/lib/cisco_node_utils/snmpserver.rb +8 -17
  113. data/lib/cisco_node_utils/snmpuser.rb +67 -28
  114. data/lib/cisco_node_utils/syslog_server.rb +3 -9
  115. data/lib/cisco_node_utils/syslog_settings.rb +2 -10
  116. data/lib/cisco_node_utils/tacacs_server.rb +9 -14
  117. data/lib/cisco_node_utils/tacacs_server_group.rb +145 -0
  118. data/lib/cisco_node_utils/tacacs_server_host.rb +5 -9
  119. data/lib/cisco_node_utils/vdc.rb +88 -0
  120. data/lib/cisco_node_utils/version.rb +5 -2
  121. data/lib/cisco_node_utils/vlan.rb +71 -8
  122. data/lib/cisco_node_utils/vni.rb +227 -0
  123. data/lib/cisco_node_utils/vpc.rb +377 -0
  124. data/lib/cisco_node_utils/vrf.rb +60 -9
  125. data/lib/cisco_node_utils/vrf_af.rb +191 -0
  126. data/lib/cisco_node_utils/vtp.rb +8 -6
  127. data/lib/cisco_node_utils/vxlan_vtep.rb +151 -0
  128. data/lib/cisco_node_utils/vxlan_vtep_vni.rb +234 -0
  129. data/lib/cisco_node_utils/yum.rb +1 -1
  130. data/tests/.rubocop.yml +1 -1
  131. data/tests/basetest.rb +16 -7
  132. data/tests/ciscotest.rb +55 -13
  133. data/tests/cmd_config.yaml +2 -2
  134. data/tests/platform_info.rb +3 -2
  135. data/tests/test_aaa_authentication_login.rb +219 -0
  136. data/tests/test_aaa_authentication_login_service.rb +759 -0
  137. data/tests/test_aaa_authorization_service.rb +1041 -0
  138. data/tests/test_ace.rb +160 -0
  139. data/tests/test_acl.rb +176 -0
  140. data/tests/test_bgp_af.rb +269 -13
  141. data/tests/test_bgp_neighbor.rb +38 -40
  142. data/tests/test_bgp_neighbor_af.rb +92 -32
  143. data/tests/test_command_config.rb +5 -5
  144. data/tests/test_command_reference.rb +284 -101
  145. data/tests/test_dns_domain.rb +1 -1
  146. data/tests/test_domain_name.rb +1 -1
  147. data/tests/test_evpn_vni.rb +106 -0
  148. data/tests/test_fabricpath_global.rb +243 -0
  149. data/tests/test_fabricpath_topology.rb +98 -0
  150. data/tests/test_interface.rb +292 -74
  151. data/tests/test_interface_channel_group.rb +74 -0
  152. data/tests/test_interface_ospf.rb +9 -4
  153. data/tests/test_interface_portchannel.rb +105 -0
  154. data/tests/test_interface_service_vni.rb +232 -0
  155. data/tests/test_interface_svi.rb +77 -62
  156. data/tests/test_interface_switchport.rb +17 -5
  157. data/tests/test_name_server.rb +1 -1
  158. data/tests/test_node.rb +1 -1
  159. data/tests/test_node_ext.rb +10 -20
  160. data/tests/test_ntp_config.rb +1 -1
  161. data/tests/test_ntp_server.rb +18 -6
  162. data/tests/test_overlay_global.rb +102 -0
  163. data/tests/test_pim.rb +177 -0
  164. data/tests/test_pim_group_list.rb +181 -0
  165. data/tests/test_pim_rp_address.rb +153 -0
  166. data/tests/test_platform.rb +3 -3
  167. data/tests/test_portchannel_global.rb +202 -0
  168. data/tests/test_radius_global.rb +1 -1
  169. data/tests/test_radius_server.rb +92 -57
  170. data/tests/test_radius_server_group.rb +149 -0
  171. data/tests/test_router_bgp.rb +283 -112
  172. data/tests/test_router_ospf.rb +2 -2
  173. data/tests/test_router_ospf_vrf.rb +4 -4
  174. data/tests/test_snmp_notification_receiver.rb +167 -0
  175. data/tests/test_snmpcommunity.rb +1 -1
  176. data/tests/test_snmpgroup.rb +1 -1
  177. data/tests/test_snmpnotification.rb +72 -0
  178. data/tests/test_snmpserver.rb +29 -105
  179. data/tests/test_snmpuser.rb +32 -30
  180. data/tests/test_syslog_server.rb +36 -10
  181. data/tests/test_syslog_settings.rb +1 -1
  182. data/tests/test_tacacs_server.rb +1 -1
  183. data/tests/test_tacacs_server_group.rb +405 -0
  184. data/tests/test_tacacs_server_host.rb +1 -1
  185. data/tests/test_vdc.rb +78 -0
  186. data/tests/test_vlan.rb +74 -19
  187. data/tests/test_vlan_mt_full.rb +95 -0
  188. data/tests/test_vni.rb +106 -0
  189. data/tests/test_vpc.rb +361 -0
  190. data/tests/test_vrf.rb +172 -29
  191. data/tests/test_vtp.rb +1 -1
  192. data/tests/test_vxlan_vtep.rb +214 -0
  193. data/tests/test_vxlan_vtep_vni.rb +201 -0
  194. data/tests/test_yum.rb +1 -1
  195. metadata +120 -11
  196. data/lib/cisco_node_utils/README_YAML.md +0 -325
  197. data/lib/cisco_node_utils/command_reference_common.yaml +0 -1051
  198. data/lib/cisco_node_utils/command_reference_common_bgp.yaml +0 -535
  199. data/lib/cisco_node_utils/command_reference_n3064.yaml +0 -13
  200. data/lib/cisco_node_utils/command_reference_n7k.yaml +0 -52
  201. data/lib/cisco_node_utils/command_reference_n9k.yaml +0 -26
  202. data/tests/platform_info.yaml +0 -10
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # August 2015 Chris Van Heuveln
5
5
  #
6
- # Copyright (c) 2015 Cisco and/or its affiliates.
6
+ # Copyright (c) 2015-2016 Cisco and/or its affiliates.
7
7
  #
8
8
  # Licensed under the Apache License, Version 2.0 (the "License");
9
9
  # you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
19
19
 
20
20
  require_relative 'cisco_cmn_utils'
21
21
  require_relative 'node_util'
22
+ require_relative 'feature'
22
23
  require_relative 'bgp'
23
24
 
24
25
  module Cisco
@@ -37,7 +38,7 @@ module Cisco
37
38
  vrfs.keys.each do |vrf|
38
39
  af_hash[asn][vrf] = {}
39
40
  get_args = { asnum: asn }
40
- get_args[:vrf] = vrf unless (vrf == 'default')
41
+ get_args[:vrf] = vrf unless vrf == 'default'
41
42
 
42
43
  nbrs = config_get('bgp_neighbor', 'all_neighbors', get_args)
43
44
  next if nbrs.nil?
@@ -62,7 +63,6 @@ module Cisco
62
63
  end
63
64
 
64
65
  def validate_args(asn, vrf, nbr, af)
65
- asn = RouterBgp.process_asnum(asn)
66
66
  fail ArgumentError unless
67
67
  vrf.is_a?(String) && (vrf.length > 0)
68
68
  fail ArgumentError unless
@@ -71,7 +71,7 @@ module Cisco
71
71
  af.is_a?(Array) || af.length == 2
72
72
 
73
73
  nbr = Utils.process_network_mask(nbr)
74
- @asn = asn
74
+ @asn = RouterBgp.validate_asnum(asn)
75
75
  @vrf = vrf
76
76
  @nbr = nbr
77
77
  @afi, @safi = af
@@ -92,6 +92,7 @@ module Cisco
92
92
  # rubocop:enable Style/AccessorMethodNamefor
93
93
 
94
94
  def create
95
+ Feature.bgp_enable
95
96
  set_args_keys(state: '')
96
97
  config_set('bgp_neighbor', 'af', @set_args)
97
98
  end
@@ -110,9 +111,7 @@ module Cisco
110
111
 
111
112
  # Returns ['<map1>', '<map2>']
112
113
  def advertise_map_exist
113
- arr = config_get('bgp_neighbor_af', 'advertise_map_exist', @get_args)
114
- return default_advertise_map_exist if arr.nil?
115
- arr.shift
114
+ config_get('bgp_neighbor_af', 'advertise_map_exist', @get_args)
116
115
  end
117
116
 
118
117
  def advertise_map_exist=(arr)
@@ -135,9 +134,7 @@ module Cisco
135
134
 
136
135
  # Returns ['<map1>', '<map2>']
137
136
  def advertise_map_non_exist
138
- arr = config_get('bgp_neighbor_af', 'advertise_map_non_exist', @get_args)
139
- return default_advertise_map_non_exist if arr.nil?
140
- arr.shift
137
+ config_get('bgp_neighbor_af', 'advertise_map_non_exist', @get_args)
141
138
  end
142
139
 
143
140
  def advertise_map_non_exist=(arr)
@@ -161,7 +158,7 @@ module Cisco
161
158
  def allowas_in_get
162
159
  val = config_get('bgp_neighbor_af', 'allowas_in', @get_args)
163
160
  return nil if val.nil?
164
- val.shift.split.last.to_i
161
+ val.split.last.to_i
165
162
  end
166
163
 
167
164
  def allowas_in
@@ -213,7 +210,7 @@ module Cisco
213
210
  def additional_paths_receive
214
211
  val = config_get('bgp_neighbor_af', 'additional_paths_receive', @get_args)
215
212
  return default_additional_paths_receive if val.nil?
216
- /disable/.match(val.first) ? :disable : :enable
213
+ /disable/.match(val) ? :disable : :enable
217
214
  end
218
215
 
219
216
  def additional_paths_receive=(val)
@@ -238,7 +235,7 @@ module Cisco
238
235
  def additional_paths_send
239
236
  val = config_get('bgp_neighbor_af', 'additional_paths_send', @get_args)
240
237
  return default_additional_paths_send if val.nil?
241
- /disable/.match(val.first) ? :disable : :enable
238
+ /disable/.match(val) ? :disable : :enable
242
239
  end
243
240
 
244
241
  def additional_paths_send=(val)
@@ -260,8 +257,7 @@ module Cisco
260
257
  # Nvgens as True with optional 'route-map <map>'
261
258
  def default_originate_get
262
259
  val = config_get('bgp_neighbor_af', 'default_originate', @get_args)
263
- return nil if val.nil?
264
- val = val.shift
260
+ return nil unless val
265
261
  (val[/route-map/]) ? val.split.last : true
266
262
  end
267
263
 
@@ -308,9 +304,7 @@ module Cisco
308
304
  # -----------------------
309
305
  # <state> filter-list <str> in
310
306
  def filter_list_in
311
- str = config_get('bgp_neighbor_af', 'filter_list_in', @get_args)
312
- return default_filter_list_in if str.nil?
313
- str.shift.strip
307
+ config_get('bgp_neighbor_af', 'filter_list_in', @get_args)
314
308
  end
315
309
 
316
310
  def filter_list_in=(str)
@@ -332,9 +326,7 @@ module Cisco
332
326
  # -----------------------
333
327
  # <state> filter-list <str> out
334
328
  def filter_list_out
335
- str = config_get('bgp_neighbor_af', 'filter_list_out', @get_args)
336
- return default_filter_list_out if str.nil?
337
- str.shift.strip
329
+ config_get('bgp_neighbor_af', 'filter_list_out', @get_args)
338
330
  end
339
331
 
340
332
  def filter_list_out=(str)
@@ -366,7 +358,7 @@ module Cisco
366
358
  ' *(?<threshold>\d+)?' \
367
359
  ' *(?<opt>restart|warning-only)?' \
368
360
  ' *(?<interval>\d+)?')
369
- regexp.match(str.shift)
361
+ regexp.match(str)
370
362
  end
371
363
 
372
364
  def max_prefix_set(limit, threshold=nil, opt=nil)
@@ -454,9 +446,7 @@ module Cisco
454
446
  # -----------------------
455
447
  # <state> prefix-list <str> in
456
448
  def prefix_list_in
457
- str = config_get('bgp_neighbor_af', 'prefix_list_in', @get_args)
458
- return default_prefix_list_in if str.nil?
459
- str.shift.strip
449
+ config_get('bgp_neighbor_af', 'prefix_list_in', @get_args)
460
450
  end
461
451
 
462
452
  def prefix_list_in=(str)
@@ -478,9 +468,7 @@ module Cisco
478
468
  # -----------------------
479
469
  # <state> prefix-list <str> out
480
470
  def prefix_list_out
481
- str = config_get('bgp_neighbor_af', 'prefix_list_out', @get_args)
482
- return default_prefix_list_out if str.nil?
483
- str.shift.strip
471
+ config_get('bgp_neighbor_af', 'prefix_list_out', @get_args)
484
472
  end
485
473
 
486
474
  def prefix_list_out=(str)
@@ -501,9 +489,7 @@ module Cisco
501
489
  # -----------------------
502
490
  # <state> route-map <str> in
503
491
  def route_map_in
504
- str = config_get('bgp_neighbor_af', 'route_map_in', @get_args)
505
- return default_route_map_in if str.nil?
506
- str.shift.strip
492
+ config_get('bgp_neighbor_af', 'route_map_in', @get_args)
507
493
  end
508
494
 
509
495
  def route_map_in=(str)
@@ -525,9 +511,7 @@ module Cisco
525
511
  # -----------------------
526
512
  # <state> route-map <str> out
527
513
  def route_map_out
528
- str = config_get('bgp_neighbor_af', 'route_map_out', @get_args)
529
- return default_route_map_out if str.nil?
530
- str.shift.strip
514
+ config_get('bgp_neighbor_af', 'route_map_out', @get_args)
531
515
  end
532
516
 
533
517
  def route_map_out=(str)
@@ -548,8 +532,7 @@ module Cisco
548
532
  # -----------------------
549
533
  # <state route-reflector-client
550
534
  def route_reflector_client
551
- state = config_get('bgp_neighbor_af', 'route_reflector_client', @get_args)
552
- state ? true : false
535
+ config_get('bgp_neighbor_af', 'route_reflector_client', @get_args)
553
536
  end
554
537
 
555
538
  def route_reflector_client=(state)
@@ -568,7 +551,7 @@ module Cisco
568
551
  def send_community
569
552
  val = config_get('bgp_neighbor_af', 'send_community', @get_args)
570
553
  return default_send_community if val.nil?
571
- val = val.shift.split.last
554
+ val = val.split.last
572
555
  return 'standard' if val[/send-community/] # Workaround
573
556
  val
574
557
  end
@@ -609,7 +592,7 @@ module Cisco
609
592
  def soft_reconfiguration_in
610
593
  val = config_get('bgp_neighbor_af', 'soft_reconfiguration_in', @get_args)
611
594
  return default_soft_reconfiguration_in if val.nil?
612
- /always/.match(val.first) ? :always : :enable
595
+ /always/.match(val) ? :always : :enable
613
596
  end
614
597
 
615
598
  def soft_reconfiguration_in=(val)
@@ -629,9 +612,7 @@ module Cisco
629
612
  # -----------------------
630
613
  # <state> soo <str>
631
614
  def soo
632
- str = config_get('bgp_neighbor_af', 'soo', @get_args)
633
- return default_soo if str.nil?
634
- str.shift.strip
615
+ config_get('bgp_neighbor_af', 'soo', @get_args)
635
616
  end
636
617
 
637
618
  def soo=(str)
@@ -651,8 +632,7 @@ module Cisco
651
632
  # -----------------------
652
633
  # <state> suppress-inactive
653
634
  def suppress_inactive
654
- state = config_get('bgp_neighbor_af', 'suppress_inactive', @get_args)
655
- state ? true : false
635
+ config_get('bgp_neighbor_af', 'suppress_inactive', @get_args)
656
636
  end
657
637
 
658
638
  def suppress_inactive=(state)
@@ -667,9 +647,7 @@ module Cisco
667
647
  # -----------------------
668
648
  # <state> unsuppress-map <str>
669
649
  def unsuppress_map
670
- str = config_get('bgp_neighbor_af', 'unsuppress_map', @get_args)
671
- return default_unsuppress_map if str.nil?
672
- str.shift.strip
650
+ config_get('bgp_neighbor_af', 'unsuppress_map', @get_args)
673
651
  end
674
652
 
675
653
  def unsuppress_map=(str)
@@ -689,8 +667,7 @@ module Cisco
689
667
  # -----------------------
690
668
  # <state> weight <int>
691
669
  def weight
692
- int = config_get('bgp_neighbor_af', 'weight', @get_args)
693
- int.nil? ? default_weight : int.shift
670
+ config_get('bgp_neighbor_af', 'weight', @get_args)
694
671
  end
695
672
 
696
673
  def weight=(int)
@@ -1,6 +1,6 @@
1
1
  # Common Utilities for Puppet Resources.
2
2
  #
3
- # Copyright (c) 2014-2015 Cisco and/or its affiliates.
3
+ # Copyright (c) 2014-2016 Cisco and/or its affiliates.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -111,16 +111,35 @@ module Cisco
111
111
  # Useful for network, redistribute, etc.
112
112
  # should: an array of expected cmds (manifest/recipe)
113
113
  # current: an array of existing cmds on the device
114
- def self.delta_add_remove(should, current=[])
114
+ def self.depth(a)
115
+ return 0 unless a.is_a?(Array)
116
+ 1 + depth(a[0])
117
+ end
118
+
119
+ def self.delta_add_remove(should, current=[], opt=nil)
115
120
  # Remove nil entries from array
116
- should.each(&:compact!) unless should.empty?
121
+ should.each(&:compact!) if depth(should) > 1
117
122
  delta = { add: should - current, remove: current - should }
118
123
 
124
+ # Some cli properties cannot be updated, thus must be removed first
125
+ return delta if opt == :updates_not_allowed
126
+
119
127
  # Delete entries from :remove if f1 is an update to an existing command
120
128
  delta[:add].each do |id, _|
121
- delta[:remove].delete_if { |f1, f2| [f1, f2] if f1.to_s == id.to_s }
129
+ if depth(should) == 1
130
+ delta[:remove].delete_if { |f1| [f1] if f1.to_s == id.to_s }
131
+ else
132
+ delta[:remove].delete_if { |f1, f2| [f1, f2] if f1.to_s == id.to_s }
133
+ end
122
134
  end
123
135
  delta
124
136
  end # delta_add_remove
137
+
138
+ # Helper to 0-pad a mac address.
139
+ def self.zero_pad_macaddr(mac)
140
+ return nil if mac.nil? || mac.empty?
141
+ o1, o2, o3 = mac.split('.').map { |o| o.to_i(16).to_s(10) }
142
+ sprintf('%04x.%04x.%04x', o1, o2, o3)
143
+ end
125
144
  end # class Utils
126
145
  end # module Cisco
@@ -0,0 +1,593 @@
1
+ # Command Reference YAML
2
+
3
+ The [YAML](http://yaml.org) files in this directory are used with the
4
+ `Cisco::CommandReference` module as a way to abstract away differences
5
+ between client APIs as well as differences between platforms sharing
6
+ the same client API.
7
+
8
+ This document describes the structure and semantics of these files.
9
+
10
+ * [Introduction](#introduction)
11
+ * [Basic attribute definition](#basic-attribute-definition)
12
+ * [Wildcard substitution](#wildcard-substitution)
13
+ * [Printf-style wildcards](#printf-style-wildcards)
14
+ * [Key-value wildcards](#key-value-wildcards)
15
+ * [Advanced attribute definition](#advanced-attribute-definition)
16
+ * [`_template`](#_template)
17
+ * [Platform and API variants](#platform-and-api-variants)
18
+ * [Product variants](#product-variants)
19
+ * [`_exclude`](#_exclude)
20
+ * [Combinations of these](#combinations-of-these)
21
+ * [Attribute properties](#attribute-properties)
22
+ * [`config_get`](#config_get)
23
+ * [`config_get_token`](#config_get_token)
24
+ * [`config_get_token_append`](#config_get_token_append)
25
+ * [`config_set`](#config_set)
26
+ * [`config_set_append`](#config_set_append)
27
+ * [`default_value`](#default_value)
28
+ * [`default_only`](#default_only)
29
+ * [`kind`](#kind)
30
+ * [`multiple`](#multiple)
31
+ * [`auto_default`](#auto_default)
32
+ * [`test_config_get` and `test_config_get_regex`](#test_config_get-and-test_config_get_regex)
33
+ * [`test_config_result`](#test_config_result)
34
+ * [Style Guide](#style-guide)
35
+
36
+ ## Introduction
37
+
38
+ Each file describes a single 'feature' (a closely related set of
39
+ configurable attributes). The YAML within the file defines the set of
40
+ 'attributes' belonging to this feature. When a `CommandReference` object
41
+ is instantiated, the user can look up any given attribute using the
42
+ `lookup('feature_name', 'attribute_name')` API. Usually, instead of calling
43
+ this API directly, node utility classes will call the various `Node` APIs,
44
+ for example:
45
+
46
+ ```ruby
47
+ config_set('feature_name', 'attribute_name', *args)
48
+ value = config_get('feature_name', 'attribute_name')
49
+ default = config_get_default('feature_name', 'attribute_name')
50
+ ```
51
+
52
+ ## Basic attribute definition
53
+
54
+ The simplest definition of an attribute directly sets one or more properties
55
+ of this attribute. These properties' values can generally be set to any
56
+ basic Ruby type such as string, boolean, integer, array, or regexp.
57
+ An example:
58
+
59
+ ```yaml
60
+ # vtp.yaml
61
+ domain:
62
+ config_get: "show vtp status"
63
+ config_get_token: "domain_name"
64
+ config_set: "vtp domain <domain>"
65
+
66
+ filename:
67
+ config_get: "show running vtp"
68
+ config_get_token: '/vtp file (\S+)/'
69
+ config_set: "<state> vtp file <filename>"
70
+ default_value: ""
71
+ ```
72
+
73
+ In the above example, two attributes are defined: ('vtp', 'domain') and ('vtp',
74
+ 'filename').
75
+
76
+ Note that all attribute properties are optional and may be omitted if not
77
+ needed. In the above, example 'domain' does not have a value defined for
78
+ `default_value` but 'filename' does have a default.
79
+
80
+ ### Wildcard substitution
81
+
82
+ The `config_get_token` and `config_set` properties (and their associated
83
+ `_append` variants) all support two forms of wildcarding - printf-style and
84
+ key-value. Key-value is generally preferred, as described below.
85
+
86
+ #### Printf-style wildcards
87
+
88
+ ```yaml
89
+ # tacacs_server_host.yaml
90
+ encryption:
91
+ config_set: '%s tacacs-server host %s key %s %s'
92
+ ```
93
+
94
+ This permits parameter values to be passed as a simple sequence to generate the resulting string or regexp:
95
+
96
+ ```ruby
97
+ irb(main):009:0> ref = cr.lookup('tacacs_server_host', 'encryption')
98
+ irb(main):010:0> ref.config_set('no', 'myhost', 'md5', 'mypassword')
99
+ => ["no tacacs-server host myhost key md5 mypassword"]
100
+ ```
101
+
102
+ Printf-style wildcards are quick to implement and concise, but less flexible - in particular they cannot handle a case where different platforms (or different
103
+ client APIs!) take parameters in a different order - and less readable in
104
+ the Ruby code.
105
+
106
+ #### Key-value wildcards
107
+
108
+ ```yaml
109
+ # ospf.yaml
110
+ auto_cost:
111
+ config_set: ['router ospf <name>', 'auto-cost reference-bandwidth <cost> <type>']
112
+ ```
113
+
114
+ This requires parameter values to be passed as a hash:
115
+
116
+ ```ruby
117
+ irb(main):015:0> ref = cr.lookup('ospf', 'auto_cost')
118
+ irb(main):016:0> ref.config_set(name: 'red', cost: '40', type: 'Gbps')
119
+ => ["router ospf red", "auto-cost reference-bandwidth 40 Gbps"]
120
+ ```
121
+
122
+ Array elements that contain a parameter that is *not* included in the argument hash are not included in the result:
123
+
124
+ ```ruby
125
+ irb(main):017:0> ref.config_set(name: 'red', cost: '40')
126
+ => ["router ospf red"]
127
+ ```
128
+
129
+ If this process results in an empty array, then an `ArgumentError` is raised to indicate that not enough parameters were supplied.
130
+
131
+ Key-value wildcards are moderately more complex to implement than Printf-style wildcards but they are more readable in the Ruby code and are flexible enough to handle significant platform differences in CLI. Key-value wildcards are therefore the recommended approach for new development.
132
+
133
+ ## Advanced attribute definition
134
+
135
+ ### `_template`
136
+
137
+ The optional `_template` section can be used to define base parameters for all
138
+ attributes of a given feature. For example, all interface attributes might be
139
+ checked with the `show running-config interface all` command, and all
140
+ attributes might be set by first entering the interface configuration submode
141
+ with the `interface <name>` configuration command. Thus, you might have:
142
+
143
+ ```yaml
144
+ # interface.yaml
145
+ _template:
146
+ config_get: 'show running-config interface all'
147
+ config_get_token: '/^interface <name>$/'
148
+ config_set: 'interface <name>'
149
+
150
+ access_vlan:
151
+ config_get_token_append: '/^switchport access vlan (.*)$/'
152
+ config_set_append: 'switchport access vlan <number>'
153
+
154
+ description:
155
+ config_get_token_append: '/^description (.*)$/'
156
+ config_set_append: 'description <desc>'
157
+
158
+ ...
159
+ ```
160
+
161
+ instead of the more repetitive (but equally valid):
162
+
163
+ ```yaml
164
+ # interface.yaml
165
+ access_vlan:
166
+ config_get: 'show running interface all'
167
+ config_get_token: ['/^interface <name>$/i', '/^switchport access vlan (.*)$/']
168
+ config_set: ['interface <name>', 'switchport access vlan <number>']
169
+
170
+ description:
171
+ config_get: 'show running-config interface all'
172
+ config_get_token: ['/^interface <name>$/i', '/^description (.*)$/']
173
+ config_set: ['interface <name>', 'description <desc>']
174
+
175
+ ...
176
+ ```
177
+
178
+ ### Platform and API variants
179
+
180
+ Clients for different Cisco platforms may use different APIs. Currently the only supported API is NXAPI (CLI-based API used for Cisco Nexus platforms). Often the CLI or other input/output formats (YANG, etc.) needed will vary between APIs, so the YAML must be able to accomodate this.
181
+
182
+ Any of the attribute properties can be subdivided by platform and API type by using the
183
+ combination of API type and platform type as a key. For example, interface VRF membership defaults to "" (no VRF) on both Nexus and IOS XR platforms, but the CLI is 'vrf member <vrf>' for Nexus and 'vrf <vrf>' for IOS XR. Thus, the YAML could be written as:
184
+
185
+ ```yaml
186
+ # interface.yaml
187
+ vrf:
188
+ default_value: ""
189
+ cli_nexus:
190
+ config_get_token_append: '/^vrf member (.*)/'
191
+ config_set_append: "<state> vrf member <vrf>"
192
+ ```
193
+
194
+ and later, once we have a CLI-based API for IOS XR, this could be extended:
195
+
196
+ ```yaml
197
+ # interface.yaml
198
+ vrf:
199
+ default_value: ""
200
+ cli_nexus:
201
+ config_get_token_append: '/^vrf member (.*)/'
202
+ config_set_append: "<state> vrf member <vrf>"
203
+ cli_ios_xr:
204
+ config_get_token_append: '/^vrf (.*)/'
205
+ config_set_append: "<state> vrf <vrf>"
206
+ ```
207
+
208
+ ### Product variants
209
+
210
+ Any of the attribute properties can be subdivided by platform product ID string
211
+ using a regexp against the product ID as a key. When one or more regexp keys
212
+ are defined thus, you can also use the special key `else` to provide values
213
+ for all products that do not match any of the given regexps:
214
+
215
+ ```yaml
216
+ # show_version.yaml
217
+ system_image:
218
+ /N9/:
219
+ config_get_token: "kick_file_name"
220
+ test_config_get_regex: '/.*NXOS image file is: (.*)$.*/'
221
+ else:
222
+ config_get_token: "isan_file_name"
223
+ test_config_get_regex: '/.*system image file is: (.*)$.*/'
224
+ ```
225
+
226
+ ### `_exclude`
227
+
228
+ Related to product variants, an `_exclude` entry can be used to mark an entire feature or a given feature attribute as not applicable to a particular set of products. For example, if feature 'fabricpath' doesn't apply to the N3K or N9K platforms, it can be excluded altogether from those platforms by a single `_exclude` entry at the top of the file:
229
+
230
+ ```yaml
231
+ # fabricpath.yaml
232
+ ---
233
+ _exclude: [/N3/, /N9/]
234
+
235
+ _template:
236
+ ...
237
+ ```
238
+
239
+ Individual feature attributes can also be excluded in this way:
240
+
241
+ ```yaml
242
+ attribute:
243
+ _exclude:
244
+ - /N7/
245
+ default_value: true
246
+ config_get: 'show attribute'
247
+ config_set: 'attribute'
248
+ ```
249
+
250
+ When a feature or attribute is excluded in this way, attempting to call `config_get` or `config_set` on an excluded node will result in a `Cisco::UnsupportedError` being raised. Calling `config_get_default` on such a node will always return `nil`.
251
+
252
+ ### Combinations of these
253
+
254
+ In many cases, supporting multiple platforms and multiple products will require
255
+ using several or all of the above options.
256
+
257
+ Using `_template` in combination with API variants:
258
+
259
+ ```yaml
260
+ # inventory.yaml
261
+ _template:
262
+ cli_ios_xr:
263
+ config_get: 'show inventory | begin "Rack 0"'
264
+ test_config_get: 'show inventory'
265
+ cli_nexus:
266
+ config_get: 'show inventory'
267
+ test_config_get: 'show inventory | no-more'
268
+
269
+ productid:
270
+ cli_ios_xr:
271
+ config_get_token: '/PID: ([^ ,]+)/'
272
+ cli_nexus:
273
+ config_get_token: ["TABLE_inv", "ROW_inv", 0, "productid"]
274
+ ```
275
+
276
+ Using platform variants and product variants together:
277
+
278
+ ```yaml
279
+ # inventory.yaml
280
+ description:
281
+ config_get_token: "chassis_id"
282
+ cli_nexus:
283
+ /N7/:
284
+ test_config_get_regex: '/.*Hardware\n cisco (\w+ \w+ \(\w+ \w+\) \w+).*/'
285
+ else:
286
+ test_config_get_regex: '/Hardware\n cisco (([^(\n]+|\(\d+ Slot\))+\w+)/'
287
+ cli_ios_xr:
288
+ config_get: 'show inventory | inc "Rack 0"'
289
+ config_get_token: '/DESCR: "(.*)"/'
290
+ test_config_get: 'show inventory | inc "Rack 0"'
291
+ test_config_get_regex: '/DESCR: "(.*)"/'
292
+ ```
293
+
294
+ ## Attribute properties
295
+
296
+ ### `config_get`
297
+
298
+ `config_get` must be a single string representing the CLI command (usually a
299
+ `show` command) to be used to display the information needed to get the
300
+ current value of this attribute.
301
+
302
+ ```yaml
303
+ # interface_ospf.yaml
304
+ area:
305
+ config_get: 'show running interface all'
306
+ ```
307
+
308
+ ### `config_get_token`
309
+
310
+ `config_get_token` can be a single string, a single regex, an array of strings,
311
+ or an array of regexs.
312
+
313
+ If this value is a string or array of strings, then the `config_get` command
314
+ will be executed to produce _structured_ output and the string(s) will be
315
+ used as lookup keys.
316
+
317
+ **WARNING: structured output, although elegant, may not be supported for all commands or all platforms. Use with caution.**
318
+
319
+ ```yaml
320
+ # show_version.yaml
321
+ cpu:
322
+ config_get: 'show version'
323
+ config_get_token: 'cpu_name'
324
+ # config_get('show_version', 'cpu') returns structured_output['cpu_name']
325
+ ```
326
+
327
+ ```yaml
328
+ # inventory.yaml
329
+ productid:
330
+ config_get: 'show inventory'
331
+ config_get_token: ['TABLE_inv', 'ROW_inv', 0, 'productid']
332
+ # config_get('inventory', 'productid') returns
333
+ # structured_output['TABLE_inv']['ROW_inv'][0]['productid']
334
+ ```
335
+
336
+ If this value is a regexp or array of regexps, then the `config_get` command
337
+ will be executed to produce _plaintext_ output.
338
+
339
+ For a single regexp, it will be used to match against the plaintext.
340
+
341
+ ```yaml
342
+ # memory.yaml
343
+ total:
344
+ config_get: 'show system resources'
345
+ config_get_token: '/Memory.* (\S+) total/'
346
+ # config_get('memory', 'total') returns
347
+ # plaintext_output.scan(/Memory.* (\S+) total/)
348
+ ```
349
+
350
+ For an array of regex, then the plaintext is assumed to be hierarchical in
351
+ nature (like `show running-config`) and the regexs are used to filter down
352
+ through the hierarchy.
353
+
354
+ ```yaml
355
+ # interface.yaml
356
+ description:
357
+ config_get: 'show running interface all'
358
+ config_get_token: ['/^interface <name>$/i', '/^description (.*)/']
359
+ # config_get('interface', 'description', name: 'Ethernet1/1') gets the
360
+ # plaintext output, finds the subsection under /^interface Ethernet1/1$/i,
361
+ # then finds the line matching /^description (.*)$/ in that subsection
362
+ ```
363
+
364
+ ### `config_get_token_append`
365
+
366
+ When using a `_template` section, an attribute can use
367
+ `config_get_token_append` to extend the `config_get_token` value provided by
368
+ the template instead of replacing it:
369
+
370
+ ```yaml
371
+ # interface.yaml
372
+ _template:
373
+ config_get: 'show running-config interface all'
374
+ config_get_token: '/^interface <name>$/i'
375
+
376
+ description:
377
+ config_get_token_append: '/^description (.*)$/'
378
+ # config_get_token value for 'description' is now:
379
+ # ['/^interface <name>$/i', '/^description (.*)$/']
380
+ ```
381
+
382
+ This can also be used to specify conditional tokens which may or may not be
383
+ used depending on the set of parameters passed into `config_get()`:
384
+
385
+ ```yaml
386
+ # ospf.yaml
387
+ _template:
388
+ config_get: 'show running ospf all'
389
+ config_get_token: '/^router ospf <name>$/'
390
+ config_get_token_append:
391
+ - '/^vrf <vrf>$/'
392
+
393
+ router_id:
394
+ config_get_token_append: '/^router-id (\S+)$/'
395
+ ```
396
+
397
+ In this example, the `vrf` parameter is optional and a different
398
+ `config_get_token` value will be generated depending on its presence or absence:
399
+
400
+ ```ruby
401
+ irb(main):008:0> ref = cr.lookup('ospf', 'router_id')
402
+ irb(main):012:0> ref.config_get_token(name: 'red')
403
+ => [/^router ospf red$/, /^router-id (\S+)?$/]
404
+ irb(main):013:0> ref.config_get_token(name: 'red', vrf: 'blue')
405
+ => [/^router ospf red$/, /^vrf blue$/, /^router-id (\S+)?$/]
406
+ ```
407
+
408
+ ### `config_set`
409
+
410
+ The `config_set` parameter is a string or array of strings representing the
411
+ configuration CLI command(s) used to set the value of the attribute.
412
+
413
+ ```yaml
414
+ # interface.yaml
415
+ create:
416
+ config_set: 'interface <name>'
417
+
418
+ description:
419
+ config_set: ['interface <name>', 'description <desc>']
420
+ ```
421
+
422
+ ### `config_set_append`
423
+
424
+ When using a `_template` section, an attribute can use `config_set_append` to
425
+ extend the `config_set` value provided by the template instead of replacing it:
426
+
427
+ ```yaml
428
+ # interface.yaml
429
+ _template:
430
+ config_set: 'interface <name>'
431
+
432
+ access_vlan:
433
+ config_set_append: 'switchport access vlan <number>'
434
+ # config_set value for 'access_vlan' is now:
435
+ # ['interface <name>', 'switchport access vlan <number>']
436
+ ```
437
+
438
+ Much like `config_get_token_append`, this can also be used to specify optional
439
+ commands that can be included or omitted as needed:
440
+
441
+ ```yaml
442
+ # ospf.yaml
443
+ _template:
444
+ config_set: 'router ospf <name>'
445
+ config_set_append:
446
+ - 'vrf <vrf>'
447
+
448
+ router_id:
449
+ config_set_append: 'router-id <router_id>'
450
+ ```
451
+
452
+ ```ruby
453
+ irb(main):008:0> ref = cr.lookup('ospf', 'router_id')
454
+ irb(main):017:0> ref.config_set(name: 'red', state: nil, router_id: '1.1.1.1')
455
+ => ["router ospf red", " router-id 1.1.1.1"]
456
+ irb(main):019:0> ref.config_set(name: 'red', vrf: 'blue',
457
+ state: 'no', router_id: '1.1.1.1')
458
+ => ["router ospf red", "vrf blue", "no router-id 1.1.1.1"]
459
+ ```
460
+
461
+ ### `default_value`
462
+
463
+ If there is a default value for this attribute when not otherwise specified by the user, the `default_value` parameter describes it. This can be a string, boolean, integer, array, or nil.
464
+
465
+ ```yaml
466
+ description:
467
+ default_value: ''
468
+
469
+ hello_interval:
470
+ default_value: 10
471
+
472
+ auto_cost:
473
+ default_value: [40, 'Gbps']
474
+
475
+ ipv4_address:
476
+ # YAML represents nil as ~
477
+ default_value: ~
478
+ ```
479
+
480
+ By convention, a `default_value` of `''` (empty string) represents a configurable property that defaults to absent, while a default of `nil` (Ruby) or `~` (YAML) represents a property that has no meaningful default at all.
481
+
482
+ `config_get()` will return the defined `default_value` if the defined `config_get_token` does not match anything on the node. Normally this is desirable behavior, but you can use [`auto_default`](#auto_default) to change this behavior if needed.
483
+
484
+ ### `default_only`
485
+
486
+ Some attributes may be hard-coded in such a way that they have a meaningful default value but no relevant `config_get_token` or `config_set` behavior. For such attributes, the key `default_only` should be used as an alternative to `default_value`. The benefit of using this key is that it causes the `config_get()` API to always return the default value and `config_set()` to raise a `Cisco::UnsupportedError`.
487
+
488
+ ```yaml
489
+ negotiate_auto_ethernet:
490
+ kind: boolean
491
+ cli_nexus:
492
+ /(N7|C3064)/:
493
+ # this feature is always off on these platforms and cannot be changed
494
+ default_only: false
495
+ else:
496
+ config_get_token_append: '/^(no )?negotiate auto$/'
497
+ config_set_append: "%s negotiate auto"
498
+ default_value: true
499
+ ```
500
+
501
+ ### `kind`
502
+
503
+ The `kind` attribute is used to specify the type of value that is returned by `config_get()`. If unspecified, no attempt will be made to guess the return type and it will typically be one of string, array, or `nil`. If `kind` is specified, type conversion will automatically be performed as follows:
504
+
505
+ * `kind: boolean` - value will be coerced to `true`/`false`, and if no `default_value` is set, a `nil` result will be returned as `false`.
506
+ * `kind: int` - value will be coerced to an integer, and if no `default_value` is set, a `nil` result will be returned as `0`.
507
+ * `kind: string` - value will be coerced to a string, leading/trailing whitespace will be stripped, and if no `default_value` is set, a `nil` result will be returned as `''`.
508
+
509
+ ```yaml
510
+ # interface.yaml
511
+ ---
512
+ access_vlan:
513
+ config_get_token_append: '/^switchport access vlan (.*)$/'
514
+ config_set_append: "switchport access vlan %s"
515
+ kind: int
516
+ default_value: 1
517
+
518
+ description:
519
+ kind: string
520
+ config_get_token_append: '/^description (.*)/'
521
+ config_set_append: "%s description %s"
522
+ default_value: ""
523
+
524
+ feature_lacp:
525
+ kind: boolean
526
+ config_get: "show running | i ^feature"
527
+ config_get_token: '/^feature lacp$/'
528
+ config_set: "%s feature lacp"
529
+ ```
530
+
531
+ ### `multiple`
532
+
533
+ By default, `config_get_token` should uniquely identify a single configuration entry, and `config_get()` will raise an error if more than one match is found. For a small number of attributes, it may be desirable to permit multiple matches (in particular, '`all_*`' attributes that are used up to look up all interfaces, all VRFs, etc.). For such attributes, you must specify the key `multiple:`. When this key is present, `config_get()` will permit multiple matches and will return an array of matches (even if there is only a single match).
534
+
535
+ ```yaml
536
+ # interface.yaml
537
+ ---
538
+ all_interfaces:
539
+ multiple:
540
+ config_get_token: '/^interface (.*)/'
541
+ ```
542
+
543
+ ### `auto_default`
544
+
545
+ Normally, if `config_get_token` produces no match, `config_get()` will return the defined `default_value` for this attribute. For some attributes, this may not be desirable. Setting `auto_default: false` will force `config_get()` to return `nil` in the non-matching case instead.
546
+
547
+ ```yaml
548
+ # bgp_af.yaml
549
+ ---
550
+ dampen_igp_metric:
551
+ # dampen_igp_metric defaults to nil (disabled),
552
+ # but its default numeric value when enabled is 600.
553
+ # If disabled, we want config_get() to return nil, not 600.
554
+ default_value: 600
555
+ auto_default: false
556
+ kind: int
557
+ config_get_token_append: '/^dampen-igp-metric (\d+)$/'
558
+ config_set_append: '<state> dampen-igp-metric <num>'
559
+ ```
560
+
561
+ ### `test_config_get` and `test_config_get_regex`
562
+
563
+ Test-only equivalents to `config_get` and `config_get_token` - a show command
564
+ to be executed over telnet by the minitest unit test scripts, and a regex
565
+ (or array thereof) to match in the resulting plaintext output.
566
+ Should only be referenced by test scripts, never by a feature provider itself.
567
+
568
+ ```yaml
569
+ # show_version.yaml
570
+ boot_image:
571
+ test_config_get: 'show version | no-more'
572
+ test_config_get_regex: '/NXOS image file is: (.*)$/'
573
+ ```
574
+
575
+ ### `test_config_result`
576
+
577
+ Test-only container for input-result pairs that might differ by platform.
578
+ Should only be referenced by test scripts, never by a feature provider itself.
579
+
580
+ ```yaml
581
+ # vtp.yaml
582
+ version:
583
+ /N7/:
584
+ test_config_result:
585
+ 3: 3
586
+ else:
587
+ test_config_result:
588
+ 3: 'Cisco::CliError'
589
+ ```
590
+
591
+ ## Style Guide
592
+
593
+ Please see [YAML Best Practices](../../../docs/README-develop-best-practices.md#ydbp).