cisco_node_utils 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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).