cisco_node_utils 1.3.0 → 1.4.0

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