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
@@ -88,6 +88,35 @@ module Cisco
88
88
  end
89
89
  end
90
90
 
91
+ # Extension of RequestFailed class specifically for YANG errors
92
+ class YangError < RequestFailed
93
+ def initialize(message=nil,
94
+ error: nil,
95
+ rejected_input: nil,
96
+ successful_input: [],
97
+ **kwargs)
98
+ unless message
99
+ if rejected_input.is_a?(Array)
100
+ if rejected_input.length > 1
101
+ message = "The following configs were rejected:\n"
102
+ message += " #{rejected_input.join("\n ")}\n"
103
+ else
104
+ message = "The config '#{rejected_input.first}' was rejected "
105
+ end
106
+ else
107
+ message = "The config '#{rejected_input}' was rejected "
108
+ end
109
+
110
+ message += "with error:\n#{error}"
111
+ end
112
+ super(message,
113
+ :error => error,
114
+ :rejected_input => rejected_input,
115
+ :successful_input => successful_input,
116
+ **kwargs)
117
+ end
118
+ end
119
+
91
120
  # RequestNotSupported means we made a request that was validly
92
121
  # constructed but includes options that are unsupported.
93
122
  #
@@ -22,6 +22,20 @@ module Cisco
22
22
  # Note that in most cases the enable methods should only enable;
23
23
  # however, for test purposes it is sometimes convenient to support
24
24
  # feature disablement for cleanup purposes.
25
+ # ---------------------------
26
+ def self.bfd_enable
27
+ return if bfd_enabled?
28
+ config_set('feature', 'bfd')
29
+ end
30
+
31
+ def self.bfd_enabled?
32
+ config_get('feature', 'bfd')
33
+ rescue Cisco::CliError => e
34
+ # cmd will syntax reject when feature is not enabled.
35
+ raise unless e.clierror =~ /Syntax error/
36
+ return false
37
+ end
38
+
25
39
  # ---------------------------
26
40
  def self.bgp_enable
27
41
  return if bgp_enabled?
@@ -32,6 +46,20 @@ module Cisco
32
46
  config_get('feature', 'bgp')
33
47
  end
34
48
 
49
+ # ---------------------------
50
+ def self.dhcp_enable
51
+ return if dhcp_enabled?
52
+ config_set('feature', 'dhcp')
53
+ end
54
+
55
+ def self.dhcp_enabled?
56
+ config_get('feature', 'dhcp')
57
+ rescue Cisco::CliError => e
58
+ # cmd will syntax reject when feature is not enabled.
59
+ raise unless e.clierror =~ /Syntax error/
60
+ return false
61
+ end
62
+
35
63
  # ---------------------------
36
64
  def self.fabric_enable
37
65
  # install feature-set and enable it
@@ -18,31 +18,29 @@ require_relative 'cisco_cmn_utils'
18
18
  require_relative 'node_util'
19
19
  require_relative 'vrf'
20
20
  require_relative 'overlay_global'
21
+ require_relative 'interface_DEPRECATED'
21
22
 
22
- # Add some interface-specific constants to the Cisco namespace
23
+ # Cisco provider module
23
24
  module Cisco
24
25
  IF_SWITCHPORT_MODE = {
25
- disabled: '',
26
- access: 'access',
27
- trunk: 'trunk',
28
- fex_fabric: 'fex-fabric',
29
- tunnel: 'dot1q-tunnel',
30
- fabricpath: 'fabricpath',
26
+ disabled: '',
27
+ access: 'access',
28
+ trunk: 'trunk',
29
+ fex_fabric: 'fex-fabric',
30
+ tunnel: 'dot1q-tunnel',
31
+ fabricpath: 'fabricpath',
32
+ }
33
+
34
+ # REMOVE THIS HASH WITH RELEASE 2.0.0
35
+ IF_DEPRECATED = {
31
36
  host: 'host',
32
37
  promiscuous: 'promiscuous',
33
38
  secondary: 'secondary',
34
39
  }
35
-
36
- PVLAN_PROPERTY = {
37
- host_promisc: 'switchport_mode_private_vlan_host_promiscous',
38
- allow_vlan: 'switchport_private_vlan_trunk_allowed_vlan',
39
- trunk_assoc: 'switchport_private_vlan_association_trunk',
40
- mapping_trunk: 'switchport_private_vlan_mapping_trunk',
41
- vlan_mapping: 'private_vlan_mapping',
42
- }
40
+ IF_SWITCHPORT_MODE.merge!(IF_DEPRECATED)
43
41
 
44
42
  # Interface - node utility class for general interface config management
45
- class Interface < NodeUtil
43
+ class Interface < Cisco::InterfaceDeprecated
46
44
  # Regexp to match various Ethernet interface variants:
47
45
  # Ethernet
48
46
  # GigabitEthernet
@@ -83,14 +81,17 @@ module Cisco
83
81
  end
84
82
 
85
83
  # General-purpose filter for Interface.interfaces().
86
- # opt: Identifies the filter. This may be overloaded in the future to
87
- # allow a hash of filter conditions.
84
+ # filter: This may be overloaded in the future to allow a hash of filters.
88
85
  # id: The interface name
89
86
  # Return: true if the interface should be filtered out, false to keep it.
90
- def self.filter(opt, id)
91
- case opt
92
- when :private_vlan_any
93
- return false if config_get('interface', 'private_vlan_any', name: id)
87
+ def self.filter(filter, id)
88
+ case filter
89
+ when :pvlan_any
90
+ return false if config_get('interface', 'pvlan_any', name: id)
91
+
92
+ else
93
+ # Just a basic pattern filter (:ethernet, :loopback, etc)
94
+ return false if id.match(filter.to_s)
94
95
  end
95
96
  true
96
97
  end
@@ -121,6 +122,7 @@ module Cisco
121
122
  next if k.nil? || v.nil?
122
123
  k.gsub!(/ \(.*\)/, '') # Remove any parenthetical text from key
123
124
  v.strip!
125
+ v.gsub!(%r{half/full}, 'half,full') if k == 'Duplex'
124
126
  hash[k] = v
125
127
  end
126
128
  end
@@ -142,6 +144,11 @@ module Cisco
142
144
  config_set('interface', 'destroy', name: @name)
143
145
  end
144
146
 
147
+ def pvlan_enable
148
+ switchport_enable
149
+ Feature.private_vlan_enable
150
+ end
151
+
145
152
  ########################################################
146
153
  # PROPERTIES #
147
154
  ########################################################
@@ -167,6 +174,28 @@ module Cisco
167
174
  config_get_default('interface', 'access_vlan')
168
175
  end
169
176
 
177
+ def bfd_echo
178
+ return nil unless Feature.bfd_enabled?
179
+ return nil if @name[/loop/i]
180
+ config_get('interface', 'bfd_echo', name: @name)
181
+ end
182
+
183
+ def bfd_echo=(val)
184
+ fail ArgumentError, 'Interface cannot be loopback' if
185
+ @name[/loop/i]
186
+ return if val == bfd_echo
187
+ state = (val ? '' : 'no')
188
+ Feature.bfd_enable
189
+ config_set('interface', 'bfd_echo',
190
+ name: @name, state: state)
191
+ end
192
+
193
+ def default_bfd_echo
194
+ return nil unless Feature.bfd_enabled?
195
+ return nil if @name[/loop/i]
196
+ config_get_default('interface', 'bfd_echo')
197
+ end
198
+
170
199
  def description
171
200
  config_get('interface', 'description', name: @name)
172
201
  end
@@ -391,6 +420,105 @@ module Cisco
391
420
  config_get_default('interface', ipv4_arp_timeout_lookup_string)
392
421
  end
393
422
 
423
+ def ipv4_dhcp_relay_addr
424
+ config_get('interface', 'ipv4_dhcp_relay_addr', name: @name)
425
+ end
426
+
427
+ def ipv4_dhcp_relay_addr=(list)
428
+ cur_list = ipv4_dhcp_relay_addr
429
+ # remove the current addresses first
430
+ unless cur_list.empty?
431
+ cur_list.each do |addr|
432
+ config_set('interface', 'ipv4_dhcp_relay_addr',
433
+ name: @name, state: 'no', addr: addr)
434
+ end
435
+ end
436
+ Feature.dhcp_enable unless list.empty?
437
+ list.each do |addr|
438
+ config_set('interface', 'ipv4_dhcp_relay_addr',
439
+ name: @name, state: '', addr: addr)
440
+ end
441
+ end
442
+
443
+ def default_ipv4_dhcp_relay_addr
444
+ config_get_default('interface', 'ipv4_dhcp_relay_addr')
445
+ end
446
+
447
+ def ipv4_dhcp_relay_info_trust
448
+ config_get('interface', 'ipv4_dhcp_relay_info_trust', name: @name)
449
+ end
450
+
451
+ def ipv4_dhcp_relay_info_trust=(state)
452
+ Feature.dhcp_enable if state
453
+ config_set('interface', 'ipv4_dhcp_relay_info_trust',
454
+ name: @name, state: state ? '' : 'no')
455
+ end
456
+
457
+ def default_ipv4_dhcp_relay_info_trust
458
+ config_get_default('interface', 'ipv4_dhcp_relay_info_trust')
459
+ end
460
+
461
+ def ipv4_dhcp_relay_src_addr_hsrp
462
+ config_get('interface', 'ipv4_dhcp_relay_src_addr_hsrp', name: @name)
463
+ end
464
+
465
+ def ipv4_dhcp_relay_src_addr_hsrp=(state)
466
+ Feature.dhcp_enable if state
467
+ config_set('interface', 'ipv4_dhcp_relay_src_addr_hsrp',
468
+ name: @name, state: state ? '' : 'no')
469
+ end
470
+
471
+ def default_ipv4_dhcp_relay_src_addr_hsrp
472
+ config_get_default('interface', 'ipv4_dhcp_relay_src_addr_hsrp')
473
+ end
474
+
475
+ def ipv4_dhcp_relay_src_intf
476
+ intf = config_get('interface', 'ipv4_dhcp_relay_src_intf', name: @name)
477
+ # Normalize by downcasing and removing white space
478
+ intf = intf.downcase.delete(' ') if intf
479
+ intf
480
+ end
481
+
482
+ def ipv4_dhcp_relay_src_intf=(val)
483
+ state = val == default_ipv4_dhcp_relay_src_intf ? 'no' : ''
484
+ intf = val == default_ipv4_dhcp_relay_src_intf ? '' : val
485
+ Feature.dhcp_enable if state.empty?
486
+ config_set('interface', 'ipv4_dhcp_relay_src_intf',
487
+ name: @name, state: state, intf: intf)
488
+ end
489
+
490
+ def default_ipv4_dhcp_relay_src_intf
491
+ config_get_default('interface', 'ipv4_dhcp_relay_src_intf')
492
+ end
493
+
494
+ def ipv4_dhcp_relay_subnet_broadcast
495
+ config_get('interface', 'ipv4_dhcp_relay_subnet_broadcast', name: @name)
496
+ end
497
+
498
+ def ipv4_dhcp_relay_subnet_broadcast=(state)
499
+ Feature.dhcp_enable if state
500
+ config_set('interface', 'ipv4_dhcp_relay_subnet_broadcast',
501
+ name: @name, state: state ? '' : 'no')
502
+ end
503
+
504
+ def default_ipv4_dhcp_relay_subnet_broadcast
505
+ config_get_default('interface', 'ipv4_dhcp_relay_subnet_broadcast')
506
+ end
507
+
508
+ def ipv4_dhcp_smart_relay
509
+ config_get('interface', 'ipv4_dhcp_smart_relay', name: @name)
510
+ end
511
+
512
+ def ipv4_dhcp_smart_relay=(state)
513
+ Feature.dhcp_enable if state
514
+ config_set('interface', 'ipv4_dhcp_smart_relay',
515
+ name: @name, state: state ? '' : 'no')
516
+ end
517
+
518
+ def default_ipv4_dhcp_smart_relay
519
+ config_get_default('interface', 'ipv4_dhcp_smart_relay')
520
+ end
521
+
394
522
  def ipv4_forwarding
395
523
  config_get('interface', 'ipv4_forwarding', name: @name)
396
524
  end
@@ -497,6 +625,49 @@ module Cisco
497
625
  config_get_default('interface', 'ipv6_acl_out')
498
626
  end
499
627
 
628
+ def ipv6_dhcp_relay_addr
629
+ config_get('interface', 'ipv6_dhcp_relay_addr', name: @name)
630
+ end
631
+
632
+ def ipv6_dhcp_relay_addr=(list)
633
+ cur_list = ipv6_dhcp_relay_addr
634
+ # remove the current addresses first
635
+ unless cur_list.empty?
636
+ cur_list.each do |addr|
637
+ config_set('interface', 'ipv6_dhcp_relay_addr',
638
+ name: @name, state: 'no', addr: addr)
639
+ end
640
+ end
641
+ Feature.dhcp_enable unless list.empty?
642
+ list.each do |addr|
643
+ config_set('interface', 'ipv6_dhcp_relay_addr',
644
+ name: @name, state: '', addr: addr)
645
+ end
646
+ end
647
+
648
+ def default_ipv6_dhcp_relay_addr
649
+ config_get_default('interface', 'ipv6_dhcp_relay_addr')
650
+ end
651
+
652
+ def ipv6_dhcp_relay_src_intf
653
+ intf = config_get('interface', 'ipv6_dhcp_relay_src_intf', name: @name)
654
+ # Normalize by downcasing and removing white space
655
+ intf = intf.downcase.delete(' ') if intf
656
+ intf
657
+ end
658
+
659
+ def ipv6_dhcp_relay_src_intf=(val)
660
+ state = val == default_ipv6_dhcp_relay_src_intf ? 'no' : ''
661
+ intf = val == default_ipv6_dhcp_relay_src_intf ? '' : val
662
+ Feature.dhcp_enable if state.empty?
663
+ config_set('interface', 'ipv6_dhcp_relay_src_intf',
664
+ name: @name, state: state, intf: intf)
665
+ end
666
+
667
+ def default_ipv6_dhcp_relay_src_intf
668
+ config_get_default('interface', 'ipv6_dhcp_relay_src_intf')
669
+ end
670
+
500
671
  def feature_lacp?
501
672
  config_get('interface', 'feature_lacp')
502
673
  end
@@ -620,6 +791,51 @@ module Cisco
620
791
  config_get_default('interface', lookup)
621
792
  end
622
793
 
794
+ def storm_control_broadcast
795
+ config_get('interface', 'storm_control_broadcast', name: @name)
796
+ end
797
+
798
+ def storm_control_broadcast=(val)
799
+ state = val == default_storm_control_broadcast ? 'no' : ''
800
+ level = val == default_storm_control_broadcast ? '' : val
801
+ config_set('interface', 'storm_control_broadcast',
802
+ name: @name, state: state, level: level)
803
+ end
804
+
805
+ def default_storm_control_broadcast
806
+ config_get_default('interface', 'storm_control_broadcast')
807
+ end
808
+
809
+ def storm_control_multicast
810
+ config_get('interface', 'storm_control_multicast', name: @name)
811
+ end
812
+
813
+ def storm_control_multicast=(val)
814
+ state = val == default_storm_control_multicast ? 'no' : ''
815
+ level = val == default_storm_control_multicast ? '' : val
816
+ config_set('interface', 'storm_control_multicast',
817
+ name: @name, state: state, level: level)
818
+ end
819
+
820
+ def default_storm_control_multicast
821
+ config_get_default('interface', 'storm_control_multicast')
822
+ end
823
+
824
+ def storm_control_unicast
825
+ config_get('interface', 'storm_control_unicast', name: @name)
826
+ end
827
+
828
+ def storm_control_unicast=(val)
829
+ state = val == default_storm_control_unicast ? 'no' : ''
830
+ level = val == default_storm_control_unicast ? '' : val
831
+ config_set('interface', 'storm_control_unicast',
832
+ name: @name, state: state, level: level)
833
+ end
834
+
835
+ def default_storm_control_unicast
836
+ config_get_default('interface', 'storm_control_unicast')
837
+ end
838
+
623
839
  def stp_bpdufilter
624
840
  config_get('interface', 'stp_bpdufilter', name: @name)
625
841
  end
@@ -882,7 +1098,7 @@ module Cisco
882
1098
  end
883
1099
 
884
1100
  def switchport_enable_and_mode(mode_set)
885
- switchport_enable unless switchport
1101
+ switchport_enable
886
1102
 
887
1103
  if :fabricpath == mode_set
888
1104
  fabricpath_feature_set(:enabled) unless :enabled == fabricpath_feature
@@ -927,7 +1143,11 @@ module Cisco
927
1143
  end
928
1144
 
929
1145
  def switchport_trunk_allowed_vlan
930
- config_get('interface', 'switchport_trunk_allowed_vlan', name: @name)
1146
+ vlans = config_get('interface', 'switchport_trunk_allowed_vlan',
1147
+ name: @name)
1148
+ vlans = vlans.join(',') if vlans.is_a?(Array)
1149
+ vlans = Utils.normalize_range_array(vlans, :string) unless vlans == 'none'
1150
+ vlans
931
1151
  end
932
1152
 
933
1153
  def switchport_trunk_allowed_vlan=(val)
@@ -958,19 +1178,14 @@ module Cisco
958
1178
  end
959
1179
  end
960
1180
 
961
- # Interface private vlan configuration properties
962
- # private vlan mode (host, promisc, trunk promisc , trunk sec)
963
- # private vlan mapping
964
- # private vlan native vlan
965
- # private vlan allow vlan
966
-
1181
+ # --------------------------
967
1182
  def cli_error_check(result)
968
- # The NXOS interface private vlan cli does not raise an exception
1183
+ # Check for messages that can be safely ignored.
1184
+ # The NXOS interface private-vlan cli does not raise an exception
969
1185
  # in some conditions and instead just displays a STDOUT error message
970
1186
  # thus NXAPI does not detect the failure.
971
- # We must catch it by inspecting the "body" hash entry
972
- # returned by NXAPI. This vlan cli behavior is unlikely to change.
973
- # Check for messages that can be safely ignored.
1187
+ # We must catch it by inspecting the "body" hash entry returned by NXAPI.
1188
+ # This vlan cli behavior is unlikely to change.
974
1189
 
975
1190
  errors = /(ERROR:|VLAN:|Eth)/
976
1191
  return unless
@@ -983,452 +1198,326 @@ module Cisco
983
1198
  end
984
1199
  end
985
1200
 
986
- def switchport_enable_and_mode_private_vlan_host(mode_set)
987
- switchport_enable unless switchport
988
- if mode_set[/(host|promiscuous)/]
989
- config_set('interface', 'switchport_mode_private_vlan_host',
990
- name: @name, state: '', mode: IF_SWITCHPORT_MODE[mode_set])
991
- else
992
- config_set('interface', 'switchport_mode_private_vlan_host',
993
- name: @name, state: 'no', mode: IF_SWITCHPORT_MODE[mode_set])
994
- end
1201
+ # --------------------------
1202
+ # <state> switchport mode private-vlan host
1203
+ def switchport_pvlan_host
1204
+ config_get('interface', 'switchport_pvlan_host', name: @name)
995
1205
  end
996
1206
 
997
- def switchport_mode_private_vlan_host
998
- mode = config_get('interface',
999
- 'switchport_mode_private_vlan_host',
1000
- name: @name)
1001
- unless mode == default_switchport_mode_private_vlan_host
1002
- mode = IF_SWITCHPORT_MODE.key(mode)
1003
- end
1004
- mode
1005
- rescue IndexError
1006
- # Assume this is an interface that doesn't support switchport.
1007
- # Do not raise exception since the providers will prefetch this property
1008
- # regardless of interface type.
1009
- # TODO: this should probably be nil instead
1010
- return default_switchport_mode_private_vlan_host
1207
+ def switchport_pvlan_host=(state)
1208
+ pvlan_enable
1209
+ config_set('interface', 'switchport_pvlan_host',
1210
+ name: @name, state: state ? '' : 'no')
1011
1211
  end
1012
1212
 
1013
- def switchport_mode_private_vlan_host=(mode_set)
1014
- fail ArgumentError unless IF_SWITCHPORT_MODE.keys.include? mode_set
1015
- Feature.private_vlan_enable
1016
- switchport_enable_and_mode_private_vlan_host(mode_set)
1213
+ def default_switchport_pvlan_host
1214
+ config_get_default('interface', 'switchport_pvlan_host')
1017
1215
  end
1018
1216
 
1019
- def default_switchport_mode_private_vlan_host
1020
- config_get_default('interface',
1021
- 'switchport_mode_private_vlan_host')
1217
+ # --------------------------
1218
+ # <state> switchport mode private-vlan promiscuous
1219
+ def switchport_pvlan_promiscuous
1220
+ config_get('interface', 'switchport_pvlan_promiscuous', name: @name)
1022
1221
  end
1023
1222
 
1024
- def switchport_mode_private_vlan_host_association
1025
- result = config_get('interface',
1026
- 'switchport_mode_private_vlan_host_association',
1027
- name: @name)
1028
- unless result == default_switchport_mode_private_vlan_host_association
1029
- result = result[0].split(' ')
1030
- end
1031
- result
1223
+ def switchport_pvlan_promiscuous=(state)
1224
+ pvlan_enable
1225
+ config_set('interface', 'switchport_pvlan_promiscuous',
1226
+ name: @name, state: state ? '' : 'no')
1032
1227
  end
1033
1228
 
1034
- def switchport_mode_private_vlan_host_association=(vlans)
1035
- fail TypeError unless vlans.is_a?(Array) || vlans.empty?
1036
- switchport_enable unless switchport
1037
- Feature.private_vlan_enable
1038
- if vlans == default_switchport_mode_private_vlan_host_association
1039
- result = config_set('interface',
1040
- 'switchport_mode_private_vlan_host_association',
1041
- name: @name, state: 'no', vlan_pr: '', vlan_sec: '')
1042
-
1043
- else
1044
- result = config_set('interface',
1045
- 'switchport_mode_private_vlan_host_association',
1046
- name: @name, state: '',
1047
- vlan_pr: vlans[0], vlan_sec: vlans[1])
1229
+ def default_switchport_pvlan_promiscuous
1230
+ config_get_default('interface', 'switchport_pvlan_promiscuous')
1231
+ end
1048
1232
 
1049
- end
1050
- cli_error_check(result)
1051
- end
1052
-
1053
- def default_switchport_mode_private_vlan_host_association
1054
- config_get_default('interface',
1055
- 'switchport_mode_private_vlan_host_association')
1056
- end
1057
-
1058
- # This api is used by private vlan to prepare the input to the setter
1059
- # method. The input can be in the following formats for vlans:
1060
- # 10-12,14. Prepare_array api is transforming this input into a flat array.
1061
- # In the example above the returned array will be 10, 11, 12, 13. Prepare
1062
- # array is first splitting the input on ',' and the than expanding the vlan
1063
- # range element like 10-12 into a flat array. The final result will
1064
- # be a flat array.
1065
- # This way we can later used the lib utility to check the delta from
1066
- # the input vlan value and the vlan configured to apply the right config.
1067
- def prepare_array(is_list)
1068
- new_list = []
1069
- is_list.each do |item|
1070
- if item.include?(',')
1071
- new_list.push(item.split(','))
1072
- else
1073
- new_list.push(item)
1074
- end
1075
- end
1076
- new_list.flatten!
1077
- new_list.sort!
1078
- new_list.each { |item| item.gsub!('-', '..') }
1079
- is_list_new = []
1080
- new_list.each do |elem|
1081
- if elem.include?('..')
1082
- elema = elem.split('..').map { |d| Integer(d) }
1083
- elema.sort!
1084
- tr = elema[0]..elema[1]
1085
- tr.to_a.each do |item|
1086
- is_list_new.push(item.to_s)
1087
- end
1088
- else
1089
- is_list_new.push(elem)
1090
- end
1091
- end
1092
- is_list_new
1233
+ # --------------------------
1234
+ # <state> switchport private-vlan host-association <pri> <sec>
1235
+ # Note this is NOT a multiple, unlike trunk association.
1236
+ def switchport_pvlan_host_association
1237
+ config_get('interface', 'switchport_pvlan_host_association', name: @name)
1093
1238
  end
1094
1239
 
1095
- def configure_private_vlan_host_property(property, should_list_new,
1096
- is_list_new, pr_vlan)
1097
- delta_hash = Utils.delta_add_remove(should_list_new, is_list_new)
1098
- [:add, :remove].each do |action|
1099
- delta_hash[action].each do |vlans|
1100
- state = (action == :add) ? '' : 'no'
1101
- oper = (action == :add) ? 'add' : 'remove'
1102
- if property[/(host_promisc|mapping_trunk)/]
1240
+ # Input: An array of primary and secondary vlans: ['44', '244']
1241
+ def switchport_pvlan_host_association=(pri_and_sec)
1242
+ pvlan_enable
1103
1243
 
1104
- result = config_set('interface', PVLAN_PROPERTY[property],
1105
- name: @name, state: state,
1106
- vlan_pr: pr_vlan, vlans: vlans)
1107
- @match_found = true
1108
- end
1109
- if property[/allow_vlan/]
1110
- result = config_set('interface',
1111
- PVLAN_PROPERTY[property],
1112
- name: @name, state: '',
1113
- oper: oper, vlans: vlans)
1114
- end
1115
- if property[/vlan_mapping/]
1116
- result = config_set('interface',
1117
- PVLAN_PROPERTY[property],
1118
- name: @name, state: state,
1119
- vlans: vlans)
1120
- end
1121
- cli_error_check(result)
1122
- end
1123
- end
1244
+ state = pri_and_sec.empty? ? 'no' : ''
1245
+ pri, sec = pri_and_sec
1246
+ cli_error_check(
1247
+ config_set('interface', 'switchport_pvlan_host_association',
1248
+ name: @name, state: state, pri: pri, sec: sec))
1124
1249
  end
1125
1250
 
1126
- def configure_private_vlan_trunk_property(property, should_list_new,
1127
- is_list, pr_vlan)
1128
- case property
1129
- when :trunk_assoc
1130
- is_list.each do |vlans|
1131
- vlans = vlans.split(' ')
1132
- if vlans[0].eql? should_list_new[0]
1133
- config_set('interface',
1134
- 'switchport_private_vlan_association_trunk',
1135
- name: @name, state: 'no',
1136
- vlan_pr: pr_vlan, vlan: vlans[1])
1137
- break
1138
- else
1139
- next
1140
- end
1141
- end
1142
- result = config_set('interface', PVLAN_PROPERTY[property], name: @name,
1143
- state: '', vlan_pr: should_list_new[0],
1144
- vlan: should_list_new[1])
1145
- when :mapping_trunk
1146
- @match_found = false
1147
- is_list.each do |vlans|
1148
- vlans = vlans.split(' ')
1149
- interf_vlan_list_delta(:mapping_trunk, vlans,
1150
- should_list_new)
1151
- if @match_found
1152
- break
1153
- else
1154
- next
1155
- end
1156
- end
1157
- result = config_set('interface', PVLAN_PROPERTY[property], name: @name,
1158
- state: '', vlan_pr: should_list_new[0],
1159
- vlans: should_list_new[1])
1160
- end
1161
- cli_error_check(result)
1251
+ def default_switchport_pvlan_host_association
1252
+ config_get_default('interface', 'switchport_pvlan_host_association')
1162
1253
  end
1163
1254
 
1164
1255
  # --------------------------
1165
- # interf_vlan_list_delta is a helper function for the private_vlan_mapping
1166
- # property. It walks the delta hash and adds/removes each target private
1167
- # vlan.
1168
-
1169
- def interf_vlan_list_delta(property, is_list, should_list)
1170
- pr_vlan = should_list[0]
1171
- if is_list[0].eql? should_list[0]
1172
- should_list = should_list[1].split(',')
1173
- is_list = is_list[1].split(',')
1174
-
1175
- should_list_new = prepare_array(should_list)
1176
- is_list_new = prepare_array(is_list)
1177
- configure_private_vlan_host_property(property, should_list_new,
1178
- is_list_new, pr_vlan)
1179
- else
1180
- case property
1181
- when :mapping_trunk
1182
- return
1183
- end
1184
- # If primary vlan are different we can simply replacing the all
1185
- # config
1186
- if should_list == default_switchport_mode_private_vlan_host_promisc
1187
- result = config_set('interface',
1188
- 'switchport_mode_private_vlan_host_promiscous',
1189
- name: @name, state: 'no',
1190
- vlan_pr: '', vlans: '')
1256
+ # <state> switchport private-vlan mapping <primary> <vlan>
1257
+ def switchport_pvlan_mapping
1258
+ config_get('interface', 'switchport_pvlan_mapping', name: @name)
1259
+ end
1191
1260
 
1192
- else
1193
- result = config_set('interface',
1194
- 'switchport_mode_private_vlan_host_promiscous',
1195
- name: @name, state: '',
1196
- vlan_pr: pr_vlan, vlans: should_list[1])
1261
+ # Input: An array of primary vlan and range of vlans: ['44', '3-4,6']
1262
+ def switchport_pvlan_mapping=(primary_and_range)
1263
+ switchport_pvlan_mapping_delta(primary_and_range)
1264
+ end
1265
+
1266
+ def default_switchport_pvlan_mapping
1267
+ config_get_default('interface', 'switchport_pvlan_mapping')
1268
+ end
1197
1269
 
1270
+ # --------------------------
1271
+ # Find the is/should delta and add/remove commands as needed.
1272
+ #
1273
+ # Inputs:
1274
+ # primary_and_range: An array of primary vlan and range of vlans
1275
+ def switchport_pvlan_mapping_delta(primary_and_range)
1276
+ # Enable switchport mode and feature private-vlan
1277
+ pvlan_enable
1278
+ primary, should_range = primary_and_range
1279
+
1280
+ # primary changes require removing the entire command first
1281
+ is_range = switchport_pvlan_mapping_remove?(primary)
1282
+
1283
+ # convert ranges to individual elements
1284
+ is = Utils.dash_range_to_elements(is_range)
1285
+ should = Utils.dash_range_to_elements(should_range)
1286
+
1287
+ # create the delta hash and apply the changes
1288
+ delta_hash = Utils.delta_add_remove(should, is)
1289
+ Cisco::Logger.debug('switchport_pvlan_mapping_delta: '\
1290
+ "#{primary}: #{delta_hash}")
1291
+ [:add, :remove].each do |action|
1292
+ delta_hash[action].each do |vlan|
1293
+ state = (action == :add) ? '' : 'no'
1294
+ cli_error_check(
1295
+ config_set('interface', 'switchport_pvlan_mapping',
1296
+ name: @name, state: state, primary: primary, vlan: vlan))
1198
1297
  end
1199
- cli_error_check(result)
1200
1298
  end
1201
1299
  end
1202
1300
 
1203
- def switchport_mode_private_vlan_host_promisc
1204
- result = config_get('interface',
1205
- 'switchport_mode_private_vlan_host_promiscous',
1206
- name: @name)
1207
- unless result == default_switchport_mode_private_vlan_host_promisc
1208
- result = result[0].split(' ')
1301
+ # --------------------------
1302
+ # switchport_pvlan_mapping_remove?
1303
+ # This is a helper to check if command needs to be removed entirely.
1304
+ #
1305
+ # should_primary: the new primary vlan value
1306
+ # Returns: the current vlan range
1307
+ def switchport_pvlan_mapping_remove?(should_primary)
1308
+ is_primary, is_range = switchport_pvlan_mapping
1309
+
1310
+ if (is_primary != should_primary) && !is_primary.nil?
1311
+ cli_error_check(
1312
+ config_set('interface', 'switchport_pvlan_mapping',
1313
+ name: @name, state: 'no', primary: '', vlan: ''))
1314
+ is_range = []
1209
1315
  end
1210
- result
1316
+ is_range
1211
1317
  end
1212
1318
 
1213
- def switchport_mode_private_vlan_host_promisc=(vlans)
1214
- fail TypeError unless vlans.is_a?(Array)
1215
- fail TypeError unless vlans.empty? || vlans.length == 2
1216
- switchport_enable unless switchport
1217
- Feature.private_vlan_enable
1218
- is_list = switchport_mode_private_vlan_host_promisc
1219
- interf_vlan_list_delta(:host_promisc, is_list, vlans)
1319
+ # --------------------------
1320
+ # <state> switchport private-vlan mapping trunk <primary> <vlan>
1321
+ def switchport_pvlan_mapping_trunk
1322
+ config_get('interface', 'switchport_pvlan_mapping_trunk', name: @name)
1220
1323
  end
1221
1324
 
1222
- def default_switchport_mode_private_vlan_host_promisc
1223
- config_get_default('interface',
1224
- 'switchport_mode_private_vlan_host_promiscous')
1325
+ # Input: A nested array of primary vlan and range of vlans:
1326
+ # [['44', '3-4,6'], ['99', '199']]
1327
+ def switchport_pvlan_mapping_trunk=(should)
1328
+ switchport_pvlan_mapping_trunk_delta(should)
1225
1329
  end
1226
1330
 
1227
- def switchport_mode_private_vlan_trunk_promiscuous
1228
- config_get('interface',
1229
- 'switchport_mode_private_vlan_trunk_promiscuous',
1230
- name: @name)
1231
- rescue IndexError
1232
- # Assume this is an interface that doesn't support switchport.
1233
- # Do not raise exception since the providers will prefetch this property
1234
- # regardless of interface type.
1235
- # TODO: this should probably be nil instead
1236
- return default_switchport_mode_private_vlan_trunk_promiscuous
1331
+ def default_switchport_pvlan_mapping_trunk
1332
+ config_get_default('interface', 'switchport_pvlan_mapping_trunk')
1237
1333
  end
1238
1334
 
1239
- def switchport_mode_private_vlan_trunk_promiscuous=(state)
1240
- Feature.private_vlan_enable
1241
- switchport_enable unless switchport
1242
- if state == default_switchport_mode_private_vlan_trunk_promiscuous
1243
- config_set('interface',
1244
- 'switchport_mode_private_vlan_trunk_promiscuous',
1245
- name: @name, state: 'no')
1246
- else
1247
- config_set('interface',
1248
- 'switchport_mode_private_vlan_trunk_promiscuous',
1249
- name: @name, state: '')
1335
+ # --------------------------
1336
+ # switchport_pvlan_mapping_trunk_delta(should)
1337
+ #
1338
+ # Find the is/should delta and add/remove commands as needed.
1339
+ # The 'should' value is a nested array of primary vlan and secondary
1340
+ # ranges; e.g.:
1341
+ # [['44', '144-145'], ['99', '199-201']
1342
+ #
1343
+ def switchport_pvlan_mapping_trunk_delta(should)
1344
+ # Enable switchport mode and feature private-vlan
1345
+ pvlan_enable
1346
+
1347
+ # Handle single-level arrays if found: [pri, range] -> [[pri,range]]
1348
+ should = [should] if !should.empty? && (Utils.depth(should) == 1)
1349
+
1350
+ is = switchport_pvlan_mapping_trunk
1351
+ delta_hash = Utils.delta_add_remove(should, is, :updates_not_allowed)
1352
+ Cisco::Logger.debug("switchport_pvlan_mapping_trunk_delta: #{delta_hash}")
1353
+ [:remove, :add].each do |action|
1354
+ delta_hash[action].each do |pri_and_range|
1355
+ pri, range = pri_and_range
1356
+ if action == :add
1357
+ state = ''
1358
+ else
1359
+ state = 'no'
1360
+ range = ''
1361
+ end
1362
+ cli_error_check(
1363
+ config_set('interface', 'switchport_pvlan_mapping_trunk',
1364
+ name: @name, state: state, primary: pri, range: range))
1365
+ end
1250
1366
  end
1251
1367
  end
1252
1368
 
1253
- def default_switchport_mode_private_vlan_trunk_promiscuous
1254
- config_get_default('interface',
1255
- 'switchport_mode_private_vlan_trunk_promiscuous')
1369
+ # --------------------------
1370
+ # <state> switchport private-vlan association trunk <pri> <sec>
1371
+ # Supports multiple.
1372
+ def switchport_pvlan_trunk_association
1373
+ config_get('interface', 'switchport_pvlan_trunk_association', name: @name)
1256
1374
  end
1257
1375
 
1258
- def switchport_mode_private_vlan_trunk_secondary
1259
- config_get('interface',
1260
- 'switchport_mode_private_vlan_trunk_secondary',
1261
- name: @name)
1262
- rescue IndexError
1263
- # Assume this is an interface that doesn't support switchport.
1264
- # Do not raise exception since the providers will prefetch this property
1265
- # regardless of interface type.
1266
- # TODO: this should probably be nil instead
1267
- return default_switchport_mode_private_vlan_trunk_secondary
1268
- end
1376
+ # Input: A nested array of primary and secondary vlans:
1377
+ # [['44', '244'], ['99', '299']]
1378
+ def switchport_pvlan_trunk_association=(should)
1379
+ pvlan_enable
1269
1380
 
1270
- def switchport_mode_private_vlan_trunk_secondary=(state)
1271
- Feature.private_vlan_enable
1272
- switchport_enable unless switchport
1273
- if state == default_switchport_mode_private_vlan_trunk_secondary
1274
- config_set('interface', 'switchport_mode_private_vlan_trunk_secondary',
1275
- name: @name, state: 'no')
1276
- else
1277
- config_set('interface', 'switchport_mode_private_vlan_trunk_secondary',
1278
- name: @name, state: '')
1279
- end
1280
- end
1381
+ # Handle single-level arrays if found: [pri, sec] -> [[pri,sec]]
1382
+ should = [should] if !should.empty? && (Utils.depth(should) == 1)
1281
1383
 
1282
- def default_switchport_mode_private_vlan_trunk_secondary
1283
- config_get_default('interface',
1284
- 'switchport_mode_private_vlan_trunk_secondary')
1384
+ is = switchport_pvlan_trunk_association
1385
+ pvlan_trunk_association_delta(is, should)
1285
1386
  end
1286
1387
 
1287
- def switchport_private_vlan_trunk_allowed_vlan
1288
- result = config_get('interface',
1289
- 'switchport_private_vlan_trunk_allowed_vlan',
1290
- name: @name)
1388
+ def pvlan_trunk_association_delta(is, should)
1389
+ delta_hash = Utils.delta_add_remove(should, is)
1390
+ Cisco::Logger.debug("pvlan_trunk_association_delta: #{delta_hash}")
1391
+ [:remove, :add].each do |action|
1392
+ delta_hash[action].each do |pri_and_sec|
1393
+ state = (action == :add) ? '' : 'no'
1394
+ pri, sec = pri_and_sec
1291
1395
 
1292
- unless result == default_switchport_private_vlan_trunk_allowed_vlan
1293
- if result[0].eql? 'none'
1294
- result = default_switchport_private_vlan_trunk_allowed_vlan
1295
- else
1296
- result = result[0].split(',')
1396
+ # Cli does not like removals that specify the secondary
1397
+ sec = '' if action[/remove/]
1398
+ cli_error_check(
1399
+ config_set('interface', 'switchport_pvlan_trunk_association',
1400
+ name: @name, state: state, pri: pri, sec: sec))
1297
1401
  end
1298
1402
  end
1299
- result
1300
1403
  end
1301
1404
 
1302
- def switchport_private_vlan_trunk_allowed_vlan=(vlans)
1303
- fail TypeError unless vlans.is_a?(Array)
1304
- Feature.private_vlan_enable
1305
- switchport_enable unless switchport
1306
- if vlans == default_switchport_private_vlan_trunk_allowed_vlan
1307
- vlans = prepare_array(switchport_private_vlan_trunk_allowed_vlan)
1308
- # If there are no vlan presently configured, we can simply return
1309
- return if vlans == default_switchport_private_vlan_trunk_allowed_vlan
1310
- configure_private_vlan_host_property(:allow_vlan, [],
1311
- vlans, '')
1312
- else
1313
- vlans = prepare_array(vlans)
1314
- is_list = prepare_array(switchport_private_vlan_trunk_allowed_vlan)
1315
- configure_private_vlan_host_property(:allow_vlan, vlans,
1316
- is_list, '')
1317
- end
1405
+ def default_switchport_pvlan_trunk_association
1406
+ config_get_default('interface', 'switchport_pvlan_trunk_association')
1318
1407
  end
1319
1408
 
1320
- def default_switchport_private_vlan_trunk_allowed_vlan
1321
- config_get_default('interface',
1322
- 'switchport_private_vlan_trunk_allowed_vlan')
1409
+ # --------------------------
1410
+ # <state> switchport mode private-vlan trunk promiscuous
1411
+ def switchport_pvlan_trunk_promiscuous
1412
+ config_get('interface', 'switchport_pvlan_trunk_promiscuous', name: @name)
1323
1413
  end
1324
1414
 
1325
- def switchport_private_vlan_trunk_native_vlan
1326
- config_get('interface',
1327
- 'switchport_private_vlan_trunk_native_vlan',
1328
- name: @name)
1415
+ def switchport_pvlan_trunk_promiscuous=(state)
1416
+ pvlan_enable
1417
+ config_set('interface', 'switchport_pvlan_trunk_promiscuous',
1418
+ name: @name, state: state ? '' : 'no')
1329
1419
  end
1330
1420
 
1331
- def switchport_private_vlan_trunk_native_vlan=(vlan)
1332
- Feature.private_vlan_enable
1333
- switchport_enable unless switchport
1334
- if vlan == default_switchport_private_vlan_trunk_native_vlan
1335
- config_set('interface',
1336
- 'switchport_private_vlan_trunk_native_vlan',
1337
- name: @name, state: 'no', vlan: '')
1421
+ def default_switchport_pvlan_trunk_promiscuous
1422
+ config_get_default('interface', 'switchport_pvlan_trunk_promiscuous')
1423
+ end
1338
1424
 
1339
- else
1340
- config_set('interface',
1341
- 'switchport_private_vlan_trunk_native_vlan',
1342
- name: @name, state: '', vlan: vlan)
1343
- end
1425
+ # --------------------------
1426
+ # <state> switchport mode private-vlan trunk secondary
1427
+ def switchport_pvlan_trunk_secondary
1428
+ config_get('interface', 'switchport_pvlan_trunk_secondary', name: @name)
1344
1429
  end
1345
1430
 
1346
- def default_switchport_private_vlan_trunk_native_vlan
1347
- config_get_default('interface',
1348
- 'switchport_private_vlan_trunk_native_vlan')
1431
+ def switchport_pvlan_trunk_secondary=(state)
1432
+ pvlan_enable
1433
+ config_set('interface', 'switchport_pvlan_trunk_secondary',
1434
+ name: @name, state: state ? '' : 'no')
1349
1435
  end
1350
1436
 
1351
- def switchport_private_vlan_association_trunk
1352
- config_get('interface',
1353
- 'switchport_private_vlan_association_trunk',
1354
- name: @name)
1437
+ def default_switchport_pvlan_trunk_secondary
1438
+ config_get_default('interface', 'switchport_pvlan_trunk_secondary')
1355
1439
  end
1356
1440
 
1357
- def switchport_private_vlan_association_trunk=(vlans)
1358
- fail TypeError unless vlans.is_a?(Array) || vlans.empty?
1359
- Feature.private_vlan_enable
1360
- switchport_enable unless switchport
1361
- if vlans == default_switchport_private_vlan_association_trunk
1362
- config_set('interface', 'switchport_private_vlan_association_trunk',
1363
- name: @name, state: 'no',
1364
- vlan_pr: '', vlan: '')
1365
- else
1366
- is_list = switchport_private_vlan_association_trunk
1367
- configure_private_vlan_trunk_property(:trunk_assoc, vlans,
1368
- is_list, vlans[0])
1369
- end
1441
+ # --------------------------
1442
+ # <state> switchport private-vlan trunk allowed vlan <range>
1443
+ # Note that range is handled as a string because the entire range is
1444
+ # replaced instead of individually adding or removing vlans from the range.
1445
+ def switchport_pvlan_trunk_allowed_vlan
1446
+ vlans = config_get('interface', 'switchport_pvlan_trunk_allowed_vlan',
1447
+ name: @name)
1448
+ vlans = vlans.join(',') if vlans.is_a?(Array)
1449
+ vlans = Utils.normalize_range_array(vlans, :string) unless vlans == 'none'
1450
+ vlans
1370
1451
  end
1371
1452
 
1372
- def default_switchport_private_vlan_association_trunk
1373
- config_get_default('interface',
1374
- 'switchport_private_vlan_association_trunk')
1453
+ def switchport_pvlan_trunk_allowed_vlan=(range)
1454
+ pvlan_enable
1455
+
1456
+ range = Utils.normalize_range_array(range, :string) unless
1457
+ range == default_switchport_pvlan_trunk_allowed_vlan
1458
+
1459
+ config_set('interface', 'switchport_pvlan_trunk_allowed_vlan',
1460
+ name: @name, range: range)
1375
1461
  end
1376
1462
 
1377
- def switchport_private_vlan_mapping_trunk
1378
- config_get('interface',
1379
- 'switchport_private_vlan_mapping_trunk',
1380
- name: @name)
1463
+ def default_switchport_pvlan_trunk_allowed_vlan
1464
+ config_get_default('interface', 'switchport_pvlan_trunk_allowed_vlan')
1381
1465
  end
1382
1466
 
1383
- def switchport_private_vlan_mapping_trunk=(vlans)
1384
- fail TypeError unless vlans.is_a?(Array) || vlans.empty?
1385
- Feature.private_vlan_enable
1386
- switchport_enable unless switchport
1387
- if vlans == default_switchport_private_vlan_mapping_trunk
1388
- config_set('interface', 'switchport_private_vlan_mapping_trunk',
1389
- name: @name, state: 'no',
1390
- vlan_pr: '', vlans: '')
1391
- else
1392
- is_list = switchport_private_vlan_mapping_trunk
1393
- configure_private_vlan_trunk_property(:mapping_trunk, vlans,
1394
- is_list, vlans[0])
1395
- end
1467
+ # --------------------------
1468
+ # <state> switchport trunk native vlan <vlan>
1469
+ def switchport_pvlan_trunk_native_vlan
1470
+ config_get('interface', 'switchport_pvlan_trunk_native_vlan', name: @name)
1396
1471
  end
1397
1472
 
1398
- def default_switchport_private_vlan_mapping_trunk
1399
- config_get_default('interface',
1400
- 'switchport_private_vlan_mapping_trunk')
1473
+ def switchport_pvlan_trunk_native_vlan=(vlan)
1474
+ pvlan_enable
1475
+ config_set('interface', 'switchport_pvlan_trunk_native_vlan',
1476
+ name: @name, vlan: vlan)
1401
1477
  end
1402
1478
 
1403
- def private_vlan_mapping
1404
- match = config_get('interface',
1405
- 'private_vlan_mapping',
1406
- name: @name)
1407
- match[0].delete!(' ') unless match == default_private_vlan_mapping
1408
- match
1479
+ def default_switchport_pvlan_trunk_native_vlan
1480
+ config_get_default('interface', 'switchport_pvlan_trunk_native_vlan')
1409
1481
  end
1410
1482
 
1411
- def private_vlan_mapping=(vlans)
1412
- fail TypeError unless vlans.is_a?(Array) || vlans.empty?
1483
+ # --------------------------
1484
+ # This is an SVI property.
1485
+ # <state> private-vlan mapping <range> # ex. range = ['2-4,9']
1486
+ # Always returns an array.
1487
+ def pvlan_mapping
1488
+ range = config_get('interface', 'pvlan_mapping', name: @name)
1489
+ return default_pvlan_mapping if range.nil?
1490
+ range.empty? ? range : [range.delete(' ')]
1491
+ end
1492
+
1493
+ def pvlan_mapping=(range)
1494
+ feature_vlan_set
1413
1495
  Feature.private_vlan_enable
1414
- feature_vlan_set(true)
1415
- if vlans == default_private_vlan_mapping
1416
- config_set('interface', 'private_vlan_mapping',
1417
- name: @name, state: 'no', vlans: '')
1418
- else
1419
- is_list = private_vlan_mapping
1420
- new_is_list = prepare_array(is_list)
1421
- new_vlans = prepare_array(vlans)
1422
- configure_private_vlan_host_property(:vlan_mapping, new_vlans,
1423
- new_is_list, '')
1496
+
1497
+ is = Utils.dash_range_to_elements(pvlan_mapping)
1498
+ should = Utils.dash_range_to_elements(range)
1499
+
1500
+ pvlan_mapping_delta(is, should)
1501
+ end
1502
+
1503
+ def pvlan_mapping_delta(is, should)
1504
+ delta_hash = Utils.delta_add_remove(should, is)
1505
+ Cisco::Logger.debug("pvlan_mapping_delta: #{delta_hash}")
1506
+ [:remove, :add].each do |action|
1507
+ delta_hash[action].each do |vlan|
1508
+ state = (action == :add) ? '' : 'no'
1509
+ cli_error_check(
1510
+ config_set('interface', 'pvlan_mapping',
1511
+ name: @name, state: state, vlan: vlan))
1512
+ end
1424
1513
  end
1425
1514
  end
1426
1515
 
1427
- def default_private_vlan_mapping
1428
- config_get_default('interface',
1429
- 'private_vlan_mapping')
1516
+ def default_pvlan_mapping
1517
+ config_get_default('interface', 'pvlan_mapping')
1430
1518
  end
1431
1519
 
1520
+ # --------------------------
1432
1521
  # vlan_mapping & vlan_mapping_enable
1433
1522
  # Hardware & Cli Dependencies:
1434
1523
  # - F3 linecards only
@@ -1568,7 +1657,9 @@ module Cisco
1568
1657
  config_get('interface', 'feature_vlan')
1569
1658
  end
1570
1659
 
1571
- def feature_vlan_set(val)
1660
+ def feature_vlan_set(val=true)
1661
+ # 'feature interface-vlan'
1662
+ # TBD: Replace this with Feature.interface_vlan_enable
1572
1663
  return if feature_vlan? == val
1573
1664
  config_set('interface', 'feature_vlan', state: val ? '' : 'no')
1574
1665
  end