cisco_node_utils 1.2.0 → 1.3.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 (255) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +13 -0
  5. data/.travis.yml +4 -1
  6. data/CHANGELOG.md +81 -2
  7. data/CONTRIBUTING.md +2 -17
  8. data/Gemfile +5 -0
  9. data/README.md +92 -47
  10. data/Rakefile +23 -1
  11. data/bin/git/hooks/hook_lib +7 -0
  12. data/bin/git/hooks/pre-commit/check_unstaged_changes +18 -0
  13. data/bin/git/hooks/pre-commit/rubocop +7 -2
  14. data/bin/git/hooks/pre-commit/validate-diffs +18 -4
  15. data/bin/git/hooks/pre-commit/validate-yaml +18 -0
  16. data/bin/git/update-hooks +64 -6
  17. data/cisco_node_utils.gemspec +9 -6
  18. data/docs/README-develop-best-practices.md +149 -50
  19. data/docs/README-develop-node-utils-APIs.md +92 -42
  20. data/docs/README-maintainers.md +7 -4
  21. data/docs/README-test-execution.md +57 -0
  22. data/docs/cisco_node_utils.yaml.example +30 -0
  23. data/docs/template-router.rb +4 -0
  24. data/ext/mkrf_conf.rb +63 -0
  25. data/lib/.rubocop.yml +2 -2
  26. data/lib/cisco_node_utils.rb +5 -0
  27. data/lib/cisco_node_utils/aaa_authentication_login.rb +5 -6
  28. data/lib/cisco_node_utils/aaa_authorization_service.rb +1 -1
  29. data/lib/cisco_node_utils/ace.rb +165 -12
  30. data/lib/cisco_node_utils/acl.rb +2 -1
  31. data/lib/cisco_node_utils/bgp.rb +184 -21
  32. data/lib/cisco_node_utils/bgp_af.rb +94 -249
  33. data/lib/cisco_node_utils/bgp_neighbor.rb +94 -14
  34. data/lib/cisco_node_utils/bgp_neighbor_af.rb +75 -8
  35. data/lib/cisco_node_utils/bridge_domain.rb +183 -0
  36. data/lib/cisco_node_utils/bridge_domain_vni.rb +206 -0
  37. data/lib/cisco_node_utils/cisco_cmn_utils.rb +85 -2
  38. data/lib/cisco_node_utils/client.rb +35 -0
  39. data/lib/cisco_node_utils/client/client.rb +234 -0
  40. data/lib/cisco_node_utils/client/grpc.rb +33 -0
  41. data/lib/cisco_node_utils/client/grpc/client.rb +311 -0
  42. data/lib/cisco_node_utils/client/grpc/ems.proto +148 -0
  43. data/lib/cisco_node_utils/client/grpc/ems.rb +111 -0
  44. data/lib/cisco_node_utils/client/grpc/ems_services.rb +49 -0
  45. data/lib/cisco_node_utils/client/nxapi.rb +31 -0
  46. data/lib/cisco_node_utils/client/nxapi/client.rb +305 -0
  47. data/lib/cisco_node_utils/client/utils.rb +164 -0
  48. data/lib/cisco_node_utils/cmd_ref/README_YAML.md +222 -254
  49. data/lib/cisco_node_utils/cmd_ref/aaa_auth_login_service.yaml +11 -8
  50. data/lib/cisco_node_utils/cmd_ref/aaa_authentication_login.yaml +22 -15
  51. data/lib/cisco_node_utils/cmd_ref/aaa_authorization_service.yaml +11 -8
  52. data/lib/cisco_node_utils/cmd_ref/acl.yaml +21 -16
  53. data/lib/cisco_node_utils/cmd_ref/bgp.yaml +239 -109
  54. data/lib/cisco_node_utils/cmd_ref/bgp_af.yaml +114 -55
  55. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor.yaml +76 -52
  56. data/lib/cisco_node_utils/cmd_ref/bgp_neighbor_af.yaml +106 -62
  57. data/lib/cisco_node_utils/cmd_ref/bridge_domain.yaml +71 -0
  58. data/lib/cisco_node_utils/cmd_ref/bridge_domain_vni.yaml +33 -0
  59. data/lib/cisco_node_utils/cmd_ref/dnsclient.yaml +35 -14
  60. data/lib/cisco_node_utils/cmd_ref/encapsulation.yaml +25 -0
  61. data/lib/cisco_node_utils/cmd_ref/evpn_vni.yaml +23 -17
  62. data/lib/cisco_node_utils/cmd_ref/fabricpath.yaml +94 -83
  63. data/lib/cisco_node_utils/cmd_ref/fabricpath_topology.yaml +22 -17
  64. data/lib/cisco_node_utils/cmd_ref/feature.yaml +76 -26
  65. data/lib/cisco_node_utils/cmd_ref/images.yaml +3 -2
  66. data/lib/cisco_node_utils/cmd_ref/interface.yaml +381 -153
  67. data/lib/cisco_node_utils/cmd_ref/interface_channel_group.yaml +21 -11
  68. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +21 -21
  69. data/lib/cisco_node_utils/cmd_ref/interface_portchannel.yaml +30 -21
  70. data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +18 -13
  71. data/lib/cisco_node_utils/cmd_ref/inventory.yaml +26 -31
  72. data/lib/cisco_node_utils/cmd_ref/itd_device_group.yaml +83 -0
  73. data/lib/cisco_node_utils/cmd_ref/itd_service.yaml +119 -0
  74. data/lib/cisco_node_utils/cmd_ref/memory.yaml +17 -6
  75. data/lib/cisco_node_utils/cmd_ref/ntp_config.yaml +10 -3
  76. data/lib/cisco_node_utils/cmd_ref/ntp_server.yaml +17 -5
  77. data/lib/cisco_node_utils/cmd_ref/ospf.yaml +33 -29
  78. data/lib/cisco_node_utils/cmd_ref/overlay_global.yaml +12 -10
  79. data/lib/cisco_node_utils/cmd_ref/pim.yaml +16 -19
  80. data/lib/cisco_node_utils/cmd_ref/portchannel_global.yaml +40 -25
  81. data/lib/cisco_node_utils/cmd_ref/radius_global.yaml +17 -12
  82. data/lib/cisco_node_utils/cmd_ref/radius_server.yaml +71 -35
  83. data/lib/cisco_node_utils/cmd_ref/radius_server_group.yaml +10 -5
  84. data/lib/cisco_node_utils/cmd_ref/show_system.yaml +6 -2
  85. data/lib/cisco_node_utils/cmd_ref/show_version.yaml +47 -43
  86. data/lib/cisco_node_utils/cmd_ref/snmp_community.yaml +13 -11
  87. data/lib/cisco_node_utils/cmd_ref/snmp_group.yaml +4 -2
  88. data/lib/cisco_node_utils/cmd_ref/snmp_notification_receiver.yaml +23 -21
  89. data/lib/cisco_node_utils/cmd_ref/snmp_server.yaml +26 -22
  90. data/lib/cisco_node_utils/cmd_ref/snmp_user.yaml +19 -17
  91. data/lib/cisco_node_utils/cmd_ref/snmpnotification.yaml +18 -6
  92. data/lib/cisco_node_utils/cmd_ref/stp_global.yaml +234 -0
  93. data/lib/cisco_node_utils/cmd_ref/syslog_server.yaml +24 -9
  94. data/lib/cisco_node_utils/cmd_ref/syslog_settings.yaml +5 -3
  95. data/lib/cisco_node_utils/cmd_ref/system.yaml +4 -3
  96. data/lib/cisco_node_utils/cmd_ref/tacacs_server.yaml +22 -20
  97. data/lib/cisco_node_utils/cmd_ref/tacacs_server_group.yaml +27 -15
  98. data/lib/cisco_node_utils/cmd_ref/tacacs_server_host.yaml +45 -16
  99. data/lib/cisco_node_utils/cmd_ref/vdc.yaml +21 -11
  100. data/lib/cisco_node_utils/cmd_ref/virtual_service.yaml +3 -2
  101. data/lib/cisco_node_utils/cmd_ref/vlan.yaml +60 -32
  102. data/lib/cisco_node_utils/cmd_ref/vpc.yaml +118 -101
  103. data/lib/cisco_node_utils/cmd_ref/vrf.yaml +54 -58
  104. data/lib/cisco_node_utils/cmd_ref/vrf_af.yaml +118 -0
  105. data/lib/cisco_node_utils/cmd_ref/vtp.yaml +19 -25
  106. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +28 -18
  107. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +34 -17
  108. data/lib/cisco_node_utils/cmd_ref/yum.yaml +6 -4
  109. data/lib/cisco_node_utils/command_reference.rb +261 -142
  110. data/lib/cisco_node_utils/constants.rb +33 -0
  111. data/lib/cisco_node_utils/encapsulation.rb +112 -0
  112. data/lib/cisco_node_utils/environment.rb +102 -0
  113. data/lib/cisco_node_utils/evpn_vni.rb +5 -3
  114. data/lib/cisco_node_utils/exceptions.rb +111 -0
  115. data/lib/cisco_node_utils/fabricpath_global.rb +52 -35
  116. data/lib/cisco_node_utils/fabricpath_topology.rb +44 -57
  117. data/lib/cisco_node_utils/feature.rb +165 -3
  118. data/lib/cisco_node_utils/interface.rb +1051 -260
  119. data/lib/cisco_node_utils/interface_channel_group.rb +11 -10
  120. data/lib/cisco_node_utils/interface_ospf.rb +1 -2
  121. data/lib/cisco_node_utils/interface_portchannel.rb +4 -12
  122. data/lib/cisco_node_utils/interface_service_vni.rb +7 -7
  123. data/lib/cisco_node_utils/itd_device_group.rb +248 -0
  124. data/lib/cisco_node_utils/itd_device_group_node.rb +144 -0
  125. data/lib/cisco_node_utils/itd_service.rb +523 -0
  126. data/lib/cisco_node_utils/logger.rb +75 -0
  127. data/lib/cisco_node_utils/node.rb +62 -192
  128. data/lib/cisco_node_utils/node_util.rb +56 -10
  129. data/lib/cisco_node_utils/overlay_global.rb +2 -2
  130. data/lib/cisco_node_utils/pim.rb +2 -13
  131. data/lib/cisco_node_utils/pim_group_list.rb +1 -1
  132. data/lib/cisco_node_utils/pim_rp_address.rb +1 -1
  133. data/lib/cisco_node_utils/platform.rb +52 -21
  134. data/lib/cisco_node_utils/portchannel_global.rb +89 -19
  135. data/lib/cisco_node_utils/radius_server.rb +168 -37
  136. data/lib/cisco_node_utils/router_ospf.rb +20 -35
  137. data/lib/cisco_node_utils/router_ospf_vrf.rb +4 -4
  138. data/lib/cisco_node_utils/snmpserver.rb +1 -6
  139. data/lib/cisco_node_utils/snmpuser.rb +6 -4
  140. data/lib/cisco_node_utils/stp_global.rb +676 -0
  141. data/lib/cisco_node_utils/syslog_server.rb +77 -18
  142. data/lib/cisco_node_utils/syslog_settings.rb +1 -1
  143. data/lib/cisco_node_utils/tacacs_server_group.rb +8 -4
  144. data/lib/cisco_node_utils/tacacs_server_host.rb +115 -25
  145. data/lib/cisco_node_utils/vdc.rb +12 -0
  146. data/lib/cisco_node_utils/version.rb +1 -1
  147. data/lib/cisco_node_utils/vlan.rb +147 -29
  148. data/lib/cisco_node_utils/vpc.rb +55 -3
  149. data/lib/cisco_node_utils/vrf.rb +72 -11
  150. data/lib/cisco_node_utils/vrf_af.rb +114 -29
  151. data/lib/cisco_node_utils/vtp.rb +34 -52
  152. data/lib/cisco_node_utils/vxlan_vtep.rb +34 -8
  153. data/lib/cisco_node_utils/vxlan_vtep_vni.rb +36 -4
  154. data/lib/minitest/environment_plugin.rb +31 -0
  155. data/lib/minitest/log_level_plugin.rb +41 -0
  156. data/spec/client_spec.rb +7 -0
  157. data/spec/environment_spec.rb +263 -0
  158. data/spec/grpc_client_spec.rb +23 -0
  159. data/spec/isolate/all_clients_spec.rb +9 -0
  160. data/spec/isolate/grpc_only_spec.rb +16 -0
  161. data/spec/isolate/no_clients_spec.rb +26 -0
  162. data/spec/isolate/nxapi_only_spec.rb +16 -0
  163. data/spec/nxapi_client_spec.rb +42 -0
  164. data/spec/schema.yaml +75 -0
  165. data/spec/shared_examples_for_clients.rb +14 -0
  166. data/spec/spec_helper.rb +91 -0
  167. data/spec/whitespace_spec.rb +10 -0
  168. data/spec/yaml_spec.rb +42 -0
  169. data/tests/.rubocop.yml +2 -2
  170. data/tests/CSCuxdublin-1.0.0-7.0.3.I3.1.lib32_n9000.rpm +0 -0
  171. data/tests/basetest.rb +96 -36
  172. data/tests/ciscotest.rb +220 -12
  173. data/tests/cmd_config.yaml +71 -49
  174. data/tests/cmd_config_invalid.yaml +1 -1
  175. data/tests/test_aaa_authentication_login.rb +1 -0
  176. data/tests/test_aaa_authentication_login_service.rb +9 -0
  177. data/tests/test_aaa_authorization_service.rb +173 -367
  178. data/tests/test_ace.rb +171 -100
  179. data/tests/test_acl.rb +10 -1
  180. data/tests/test_bgp_af.rb +395 -728
  181. data/tests/test_bgp_neighbor.rb +274 -115
  182. data/tests/test_bgp_neighbor_af.rb +178 -77
  183. data/tests/test_bridge_domain.rb +191 -0
  184. data/tests/test_bridge_domain_vni.rb +116 -0
  185. data/tests/test_client_utils.rb +111 -0
  186. data/tests/test_command_config.rb +9 -5
  187. data/tests/test_command_reference.rb +380 -102
  188. data/tests/test_dns_domain.rb +13 -3
  189. data/tests/test_domain_name.rb +13 -3
  190. data/tests/test_encapsulation.rb +77 -0
  191. data/tests/test_evpn_vni.rb +25 -7
  192. data/tests/test_fabricpath_global.rb +167 -163
  193. data/tests/test_fabricpath_topology.rb +12 -33
  194. data/tests/test_feature.rb +215 -0
  195. data/tests/test_grpc.rb +166 -0
  196. data/tests/test_interface.rb +585 -344
  197. data/tests/test_interface_bdi.rb +80 -0
  198. data/tests/test_interface_channel_group.rb +6 -3
  199. data/tests/test_interface_ospf.rb +26 -24
  200. data/tests/test_interface_portchannel.rb +1 -0
  201. data/tests/test_interface_private_vlan.rb +724 -0
  202. data/tests/test_interface_service_vni.rb +37 -66
  203. data/tests/test_interface_svi.rb +98 -101
  204. data/tests/test_interface_switchport.rb +419 -549
  205. data/tests/test_itd_device_group.rb +145 -0
  206. data/tests/test_itd_device_group_node.rb +199 -0
  207. data/tests/test_itd_service.rb +298 -0
  208. data/tests/test_logger.rb +43 -0
  209. data/tests/test_name_server.rb +11 -2
  210. data/tests/test_node.rb +16 -75
  211. data/tests/test_node_ext.rb +174 -163
  212. data/tests/test_node_util.rb +119 -0
  213. data/tests/test_ntp_config.rb +5 -1
  214. data/tests/test_ntp_server.rb +2 -2
  215. data/tests/test_nxapi.rb +221 -0
  216. data/tests/test_overlay_global.rb +47 -38
  217. data/tests/test_pim.rb +2 -0
  218. data/tests/test_pim_group_list.rb +2 -0
  219. data/tests/test_pim_rp_address.rb +2 -0
  220. data/tests/test_platform.rb +86 -39
  221. data/tests/test_portchannel_global.rb +211 -135
  222. data/tests/test_radius_global.rb +13 -5
  223. data/tests/test_radius_server.rb +256 -104
  224. data/tests/test_radius_server_group.rb +2 -0
  225. data/tests/test_router_bgp.rb +781 -485
  226. data/tests/test_router_ospf.rb +26 -103
  227. data/tests/test_router_ospf_vrf.rb +52 -57
  228. data/tests/test_snmp_notification_receiver.rb +2 -0
  229. data/tests/test_snmpcommunity.rb +2 -0
  230. data/tests/test_snmpgroup.rb +2 -0
  231. data/tests/test_snmpnotification.rb +40 -21
  232. data/tests/test_snmpserver.rb +2 -0
  233. data/tests/test_snmpuser.rb +2 -0
  234. data/tests/test_stp_global.rb +563 -0
  235. data/tests/test_syslog_server.rb +32 -8
  236. data/tests/test_syslog_settings.rb +22 -9
  237. data/tests/test_tacacs_server.rb +32 -27
  238. data/tests/test_tacacs_server_group.rb +100 -45
  239. data/tests/test_tacacs_server_host.rb +135 -43
  240. data/tests/test_vdc.rb +2 -16
  241. data/tests/test_vlan.rb +106 -54
  242. data/tests/test_vlan_mt_full.rb +11 -21
  243. data/tests/test_vlan_private.rb +669 -0
  244. data/tests/test_vpc.rb +312 -159
  245. data/tests/test_vrf.rb +122 -113
  246. data/tests/test_vrf_af.rb +238 -0
  247. data/tests/test_vtp.rb +58 -102
  248. data/tests/test_vxlan_vtep.rb +38 -17
  249. data/tests/test_vxlan_vtep_vni.rb +61 -9
  250. data/tests/test_yum.rb +49 -25
  251. metadata +122 -36
  252. data/lib/cisco_node_utils/cmd_ref/fex.yaml +0 -9
  253. data/lib/cisco_node_utils/cmd_ref/vni.yaml +0 -76
  254. data/lib/cisco_node_utils/vni.rb +0 -227
  255. data/tests/test_vni.rb +0 -106
@@ -0,0 +1,206 @@
1
+ # NXAPI implementation of BridgeDomainVNI class
2
+ #
3
+ # February 2016, Rohan Gandhi Korlepara
4
+ #
5
+ # Copyright (c) 2015-2016 Cisco and/or its affiliates.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative 'node_util'
20
+ require_relative 'feature'
21
+
22
+ module Cisco
23
+ # node_utils class for bridge_domain_vni
24
+ class BridgeDomainVNI < NodeUtil
25
+ attr_reader :bd_ids, :bd_ids_list
26
+
27
+ def initialize(bds, instantiate=true)
28
+ # Spaces are removed as bridge-domain cli doesn't accept value with
29
+ # space
30
+ @bd_ids = bds.to_s.gsub(/\s+/, '')
31
+ fail 'bridge-domain value is empty' if @bd_ids.empty? # no empty strings
32
+
33
+ @bd_ids_list = BridgeDomainVNI.string_to_array(@bd_ids)
34
+ create if instantiate
35
+ end
36
+
37
+ def to_s
38
+ "Bridge Domain #{bd_ids}"
39
+ end
40
+
41
+ def self.range_bds
42
+ hash = {}
43
+ bd_list = config_get('bridge_domain_vni', 'range_bds')
44
+ return hash if bd_list.nil?
45
+
46
+ bd_list.each do |id|
47
+ hash[id] = BridgeDomainVNI.new(id, false)
48
+ end
49
+ hash
50
+ end
51
+
52
+ # This will expand the string to a list of bds as integers
53
+ def self.string_to_array(string)
54
+ list = []
55
+ narray = string.split(',')
56
+ narray.each do |elem|
57
+ if elem.include?('-')
58
+ es = elem.gsub('-', '..')
59
+ ea = es.split('..').map { |d| Integer(d) }
60
+ er = ea[0]..ea[1]
61
+ list << er.to_a
62
+ else
63
+ list << elem.to_i
64
+ end
65
+ end
66
+ list.flatten
67
+ end
68
+
69
+ # Example clis;
70
+ # system bridge-domain 101-200
71
+ # bridge-domain 101-200
72
+ # bridge-domain 101-110,120,141-145,180
73
+ # member vni 6001-6011,5041-5044,8000,9000
74
+ #
75
+ # config_get('bridge_domain_vni', 'member_vni')
76
+ # will get the current member vni in this case
77
+ # 6001-6011,5041-5044,8000,9000
78
+ #
79
+ # config_get('bridge_domain_vni', 'member_vni_bd')
80
+ # will get the current bd's mapped to member vni in this case
81
+ # 101-110,120,141-145,180
82
+ #
83
+ # The @bd_ids_list which is created when the BridgeDomainVNI object is
84
+ # initialized which could be 101-110 bd range.
85
+ # hash_map will have 101=>6001,102=>6002...120=>6011,141=>5041...180=>9000
86
+ # And the final_bd_vni hash will be based of the initialized list
87
+ # 101=>6001,102=>6002,103=>6003....110=>6010 only.
88
+ def curr_bd_vni_hash
89
+ final_bd_vni = {}
90
+ curr_vni = config_get('bridge_domain_vni', 'member_vni')
91
+ curr_bd_vni = config_get('bridge_domain_vni', 'member_vni_bd')
92
+ return final_bd_vni if curr_vni.empty? || curr_bd_vni.empty?
93
+
94
+ curr_vni_list = BridgeDomainVNI.string_to_array(curr_vni)
95
+ curr_bd_vni_list = BridgeDomainVNI.string_to_array(curr_bd_vni)
96
+
97
+ hash_map = Hash[curr_bd_vni_list.zip(curr_vni_list.map)]
98
+ @bd_ids_list.each do |bd|
99
+ final_bd_vni[bd.to_i] = hash_map[bd.to_i] if hash_map.key?(bd.to_i)
100
+ end
101
+ final_bd_vni
102
+ end
103
+
104
+ # This function will first add bds to the system bridge-domain and then
105
+ # create the bds. If bds already existing then just create. Else add the
106
+ # non added bds to system range first then create all. This is to avoid the
107
+ # idempotency issue as system add command throws error if a bd is already
108
+ # present in the system range.
109
+ def create
110
+ sys_bds_array = BridgeDomainVNI.string_to_array(system_bridge_domain)
111
+ if (@bd_ids_list - sys_bds_array).any?
112
+ add_bds = Utils
113
+ .array_to_str((@bd_ids_list - sys_bds_array), false)
114
+ config_set('bridge_domain_vni', 'system_bridge_domain', oper: 'add',
115
+ bd: add_bds)
116
+ end
117
+ config_set('bridge_domain_vni', 'create', bd: @bd_ids)
118
+ end
119
+
120
+ def destroy
121
+ bd_vni = curr_bd_vni_hash
122
+ bd_val = bd_vni.keys.join(',')
123
+ vni_val = bd_vni.values.join(',')
124
+ return '' if vni_val.empty?
125
+ config_set('bridge_domain_vni', 'member_vni', bd: bd_val,
126
+ membstate: 'no', membvni: vni_val)
127
+ config_set('bridge_domain_vni', 'vni', state: 'no', vni: vni_val)
128
+ end
129
+
130
+ ########################################################
131
+ # PROPERTIES #
132
+ ########################################################
133
+
134
+ # Bridge-Domain member vni assigning case
135
+ # Not all the bds created or initialized in this class context can have the
136
+ # member vni's mapped. So will get the vnis of the ones which are mapped to
137
+ # the bds.
138
+ # Eg: Suppose the bd mapping is as below on the switch
139
+ # bridge-domain 100,105,107-109,150
140
+ # member vni 5000, 8000, 5007-5008, 7000, 5050
141
+ # If puppet layer tries to get values of 100,105,107 bds as defined in
142
+ # manifest then the final_bd_vni map which is returned will contain only
143
+ # these mappings as below;
144
+ # '5000,8000,5007'
145
+ # This is also to handle the idempotence case, and if any mismatch then set
146
+ # the member_vni
147
+ def member_vni
148
+ bd_vni_hash = curr_bd_vni_hash
149
+ ret_list = []
150
+ @bd_ids_list.each do |bd|
151
+ ret_list << bd_vni_hash[bd]
152
+ end
153
+ Utils.array_to_str(ret_list, false)
154
+ end
155
+
156
+ # This member_vni mapping will be executed only when the val is not empty
157
+ # else it will be treated as a 'no' cli and executed as required.
158
+ # If the mappings do not match in any fashion then cli normally returns a
159
+ # failure which will be handled.
160
+ # During set of member vni we first see if any bd is mapped to some other
161
+ # vni, if yes then remove that one and apply the new vni.
162
+ # Eg: bridge-domain 100-110
163
+ # member vni 5100-5110
164
+ # Now the manifest is changed to 5100-5105,6106-6110, so hence first
165
+ # 5106-5110 mapping is removed and then 6106-6110 is applied.
166
+ def member_vni=(val)
167
+ val = val.to_s
168
+ Feature.vni_enable
169
+ bd_vni = curr_bd_vni_hash
170
+ if val.empty?
171
+ bd_val = bd_vni.keys.join(',')
172
+ vni_val = bd_vni.values.join(',')
173
+ return '' if vni_val.empty?
174
+ config_set('bridge_domain_vni', 'member_vni', bd: bd_val,
175
+ membstate: 'no', membvni: vni_val)
176
+ config_set('bridge_domain_vni', 'vni', state: 'no', vni: vni_val)
177
+ else
178
+ unless bd_vni.empty?
179
+ inp_vni_list = BridgeDomainVNI.string_to_array(val.to_s)
180
+ inp_bd_vni_hash = Hash[@bd_ids_list.zip(inp_vni_list)]
181
+
182
+ temp_hash = bd_vni.to_a.keep_if { |k, _v| inp_bd_vni_hash.key? k }
183
+ rem_hash = (temp_hash.to_a - inp_bd_vni_hash.to_a).to_h
184
+
185
+ rm_bd = rem_hash.keys.join(',')
186
+ rm_vni = rem_hash.values.join(',')
187
+ config_set('bridge_domain_vni', 'member_vni', bd: rm_bd,
188
+ membstate: 'no', membvni: rm_vni)
189
+ config_set('bridge_domain_vni', 'vni', state: 'no', vni: rm_vni)
190
+ end
191
+ config_set('bridge_domain_vni', 'vni', state: '', vni: val)
192
+ config_set('bridge_domain_vni', 'member_vni', bd: @bd_ids,
193
+ membstate: '', membvni: val)
194
+ end
195
+ end
196
+
197
+ def default_member_vni
198
+ config_get_default('bridge_domain_vni', 'member_vni')
199
+ end
200
+
201
+ # getter for system bridge-domain
202
+ def system_bridge_domain
203
+ config_get('bridge_domain_vni', 'system_bridge_domain')
204
+ end
205
+ end # Class
206
+ end # Module
@@ -24,11 +24,11 @@ module Cisco
24
24
  # password encryption types
25
25
  def self.cli_to_symbol(cli)
26
26
  case cli
27
- when '0', 0
27
+ when '0', 0, 'clear'
28
28
  :cleartext
29
29
  when '3', 3
30
30
  :"3des" # yuck :-(
31
- when '5', 5
31
+ when '5', 5, 'encrypted'
32
32
  :md5
33
33
  when '6', 6
34
34
  :aes
@@ -96,6 +96,13 @@ module Cisco
96
96
  # General utility class
97
97
  class Utils
98
98
  require 'ipaddr'
99
+
100
+ # Helper utility to check for older Nexus I2 images
101
+ def self.nexus_i2_image
102
+ require_relative 'platform'
103
+ true if Platform.image_version[/7.0.3.I2/]
104
+ end
105
+
99
106
  # Helper utility method for ip/prefix format networks.
100
107
  # For ip/prefix format '1.1.1.1/24' or '2000:123:38::34/64',
101
108
  # we need to mask the address using the prefix length so that they
@@ -117,6 +124,9 @@ module Cisco
117
124
  end
118
125
 
119
126
  def self.delta_add_remove(should, current=[], opt=nil)
127
+ current = [] if current.nil?
128
+ should = [] if should.nil?
129
+
120
130
  # Remove nil entries from array
121
131
  should.each(&:compact!) if depth(should) > 1
122
132
  delta = { add: should - current, remove: current - should }
@@ -126,6 +136,8 @@ module Cisco
126
136
 
127
137
  # Delete entries from :remove if f1 is an update to an existing command
128
138
  delta[:add].each do |id, _|
139
+ # Differentiate between comparing nested and unnested arrays by
140
+ # checking the depth of the array.
129
141
  if depth(should) == 1
130
142
  delta[:remove].delete_if { |f1| [f1] if f1.to_s == id.to_s }
131
143
  else
@@ -135,11 +147,82 @@ module Cisco
135
147
  delta
136
148
  end # delta_add_remove
137
149
 
150
+ def self.length_to_bitmask(length)
151
+ IPAddr.new('255.255.255.255').mask(length).to_s
152
+ end
153
+
154
+ def self.bitmask_to_length(bitmask)
155
+ # Convert bitmask to a 32-bit integer,
156
+ # convert that to binary, and count the 1s
157
+ IPAddr.new(bitmask).to_i.to_s(2).count('1')
158
+ rescue IPAddr::InvalidAddressError => e
159
+ raise ArgumentError, "bitmask '#{bitmask}' is not valid: #{e}"
160
+ end
161
+
138
162
  # Helper to 0-pad a mac address.
139
163
  def self.zero_pad_macaddr(mac)
140
164
  return nil if mac.nil? || mac.empty?
141
165
  o1, o2, o3 = mac.split('.').map { |o| o.to_i(16).to_s(10) }
142
166
  sprintf('%04x.%04x.%04x', o1, o2, o3)
143
167
  end
168
+
169
+ # For spanning tree range based parameters, the range
170
+ # is very dynamic and so before the parameters are set,
171
+ # the rest of the range needs to be reset
172
+ # For ex: if the ranges 2-42 and 83-200 are getting set,
173
+ # and the total range of the given parameter is 1-4000
174
+ # then 1,43-82,201-4000 needs to be reset. This method
175
+ # takes the set ranges and gives back the range to be reset
176
+ def self.get_reset_range(total_range, remove_ranges)
177
+ fail 'invalid range' unless total_range.include?('-')
178
+ return total_range if remove_ranges.empty?
179
+
180
+ trs = total_range.gsub('-', '..')
181
+ tra = trs.split('..').map { |d| Integer(d) }
182
+ tr = tra[0]..tra[1]
183
+ tarray = tr.to_a
184
+ remove_ranges.each do |rr, _val|
185
+ rarray = rr.gsub('-', '..').split(',')
186
+ rarray.each do |elem|
187
+ if elem.include?('..')
188
+ elema = elem.split('..').map { |d| Integer(d) }
189
+ ele = elema[0]..elema[1]
190
+ tarray -= ele.to_a
191
+ else
192
+ tarray.delete(elem.to_i)
193
+ end
194
+ end
195
+ end
196
+ Utils.array_to_str(tarray)
197
+ end
198
+
199
+ # This method converts an array to string form
200
+ # for ex: if the array has 1, 2 to 10, 83 to 2014, 3022
201
+ # and the string will be "1,2-10,83-2014,3022"
202
+ def self.array_to_str(array, sort=true)
203
+ farray = sort ? array.compact.uniq.sort : array.compact
204
+ lranges = []
205
+ unless farray.empty?
206
+ l = array.first
207
+ r = nil
208
+ farray.each do |aelem|
209
+ if r && aelem != r.succ
210
+ if l == r
211
+ lranges << l
212
+ else
213
+ lranges << Range.new(l, r)
214
+ end
215
+ l = aelem
216
+ end
217
+ r = aelem
218
+ end
219
+ if l == r
220
+ lranges << l
221
+ else
222
+ lranges << Range.new(l, r)
223
+ end
224
+ end
225
+ lranges.to_s.gsub('..', '-').delete('[').delete(']').delete(' ')
226
+ end
144
227
  end # class Utils
145
228
  end # module Cisco
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2015 Cisco and/or its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Namespace for Cisco-specific code
16
+ module Cisco
17
+ # Namespace for Cisco Client shim
18
+ class Client
19
+ end
20
+ end
21
+
22
+ require_relative 'client/client'
23
+
24
+ # Try to load known extensions
25
+ extensions = ['client/nxapi',
26
+ 'client/grpc',
27
+ ]
28
+ extensions.each do |ext|
29
+ begin
30
+ require_relative ext
31
+ rescue LoadError => e
32
+ # ignore missing client-(grpc|nxapi), they're not always required
33
+ raise unless e.message =~ /#{Regexp.escape(ext)}/
34
+ end
35
+ end
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # October 2015, Glenn F. Matthews
4
+ #
5
+ # Copyright (c) 2015-2016 Cisco and/or its affiliates.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative '../environment'
20
+ require_relative '../exceptions'
21
+ require_relative 'utils'
22
+ require_relative '../constants'
23
+ require_relative '../logger'
24
+
25
+ include Cisco::Logger
26
+
27
+ # Base class for clients of various RPC formats
28
+ class Cisco::Client
29
+ @@clients = [] # rubocop:disable Style/ClassVars
30
+
31
+ def self.clients
32
+ @@clients
33
+ end
34
+
35
+ # Each subclass should call this method to register itself.
36
+ def self.register_client(client)
37
+ @@clients << client
38
+ end
39
+
40
+ attr_reader :data_formats, :platform
41
+
42
+ def initialize(data_formats: [],
43
+ platform: nil,
44
+ **kwargs)
45
+ if self.class == Cisco::Client
46
+ fail NotImplementedError, 'Cisco::Client is an abstract class. ' \
47
+ "Instantiate one of #{@@clients} or use Cisco::Client.create() instead"
48
+ end
49
+ self.class.validate_args(**kwargs)
50
+ @host = kwargs[:host]
51
+ @port = kwargs[:port]
52
+ @address = @port.nil? ? @host : "#{@host}:#{@port}"
53
+ @username = kwargs[:username]
54
+ @password = kwargs[:password]
55
+ self.data_formats = data_formats
56
+ self.platform = platform
57
+ @cache_enable = true
58
+ @cache_auto = true
59
+ cache_flush
60
+ end
61
+
62
+ def self.validate_args(**kwargs)
63
+ host = kwargs[:host]
64
+ unless host.nil?
65
+ fail TypeError, 'invalid address' unless host.is_a?(String)
66
+ fail ArgumentError, 'empty address' if host.empty?
67
+ end
68
+ username = kwargs[:username]
69
+ unless username.nil?
70
+ fail TypeError, 'invalid username' unless username.is_a?(String)
71
+ fail ArgumentError, 'empty username' if username.empty?
72
+ end
73
+ password = kwargs[:password]
74
+ unless password.nil?
75
+ fail TypeError, 'invalid password' unless password.is_a?(String)
76
+ fail ArgumentError, 'empty password' if password.empty?
77
+ end
78
+ end
79
+
80
+ def supports?(data_format)
81
+ data_formats.include?(data_format)
82
+ end
83
+
84
+ # Try to create an instance of an appropriate subclass
85
+ def self.create(environment_name=nil)
86
+ fail 'No client implementations available!' if clients.empty?
87
+ debug "Trying to establish client connection. clients = #{clients}"
88
+ environment = Cisco::Environment.environment(environment_name)
89
+ host = environment[:host]
90
+ errors = []
91
+ clients.each do |client_class|
92
+ begin
93
+ debug "Trying to connect to #{host} as #{client_class}"
94
+ client = client_class.new(**environment)
95
+ debug "#{client_class} connected successfully"
96
+ return client
97
+ rescue Cisco::ClientError, TypeError, ArgumentError => e
98
+ debug "Unable to connect to #{host} as #{client_class}: #{e.message}"
99
+ debug e.backtrace.join("\n ")
100
+ errors << e
101
+ end
102
+ end
103
+ handle_errors(errors)
104
+ end
105
+
106
+ def self.handle_errors(errors)
107
+ # ClientError means we tried to connect but failed,
108
+ # so it's 'more significant' than input validation errors.
109
+ client_errors = errors.select { |e| e.kind_of? Cisco::ClientError }
110
+ if !client_errors.empty?
111
+ # Reraise the specific error if just one
112
+ fail client_errors[0] if client_errors.length == 1
113
+ # Otherwise clump them together into a new error
114
+ e_cls = client_errors[0].class
115
+ unless client_errors.all? { |e| e.class == e_cls }
116
+ e_cls = Cisco::ClientError
117
+ end
118
+ fail e_cls, ("Unable to establish any client connection:\n" +
119
+ errors.each(&:message).join("\n"))
120
+ elsif errors.any? { |e| e.kind_of? ArgumentError }
121
+ fail ArgumentError, ("Invalid arguments:\n" +
122
+ errors.each(&:message).join("\n"))
123
+ elsif errors.any? { |e| e.kind_of? TypeError }
124
+ fail TypeError, ("Invalid arguments:\n" +
125
+ errors.each(&:message).join("\n"))
126
+ end
127
+ fail Cisco::ClientError, 'No client connected, but no errors were reported?'
128
+ end
129
+
130
+ def to_s
131
+ @address.to_s
132
+ end
133
+
134
+ def inspect
135
+ "<#{self.class} of #{@address}>"
136
+ end
137
+
138
+ def cache_enable?
139
+ @cache_enable
140
+ end
141
+
142
+ def cache_enable=(enable)
143
+ @cache_enable = enable
144
+ cache_flush unless enable
145
+ end
146
+
147
+ def cache_auto?
148
+ @cache_auto
149
+ end
150
+
151
+ attr_writer :cache_auto
152
+
153
+ # Clear the cache of CLI output results.
154
+ #
155
+ # If cache_auto is true (default) then this will be performed automatically
156
+ # whenever a set() is called, but providers may also call this
157
+ # to explicitly force the cache to be cleared.
158
+ def cache_flush
159
+ # to be implemented by subclasses
160
+ end
161
+
162
+ # Configure the given state on the device.
163
+ #
164
+ # @raise [RequestNotSupported] if this client doesn't support the given
165
+ # data_format
166
+ #
167
+ # @param data_format one of Cisco::DATA_FORMATS. Default is :cli
168
+ # @param context [String, Array<String>] Context for the configuration
169
+ # @param values [String, Array<String>] Actual configuration to set
170
+ def set(data_format: :cli,
171
+ context: nil,
172
+ values: nil)
173
+ # subclasses will generally want to call Client.munge_to_array()
174
+ # on context and/or values before calling super()
175
+ fail Cisco::RequestNotSupported unless self.supports?(data_format)
176
+ cache_flush if cache_auto?
177
+ Cisco::Logger.debug("Set state using data format '#{data_format}'")
178
+ Cisco::Logger.debug(" with context:\n #{context.join("\n ")}") \
179
+ unless context.nil? || context.empty?
180
+ Cisco::Logger.debug(" to value(s):\n #{values.join("\n ")}") \
181
+ unless values.nil? || values.empty?
182
+ # to be implemented by subclasses
183
+ end
184
+
185
+ # Get the given state from the device.
186
+ #
187
+ # Unlike set() this will not clear the CLI cache;
188
+ # multiple calls with the same parameters may return cached data
189
+ # rather than querying the device repeatedly.
190
+ #
191
+ # @raise [RequestNotSupported] if the client doesn't support the data_format
192
+ # @raise [RequestFailed] if the command is rejected by the device
193
+ #
194
+ # @param data_format one of Cisco::DATA_FORMATS. Default is :cli
195
+ # @param command [String] the get command to execute
196
+ # @param context [String, Array<String>] Context to refine/filter the results
197
+ # @param value [String, Regexp] Specific key or regexp to look up
198
+ # @return [String, Hash, nil] The state found, or nil if not found.
199
+ def get(data_format: :cli,
200
+ command: nil,
201
+ context: nil,
202
+ value: nil)
203
+ # subclasses will generally want to call Client.munge_to_array()
204
+ # on context and/or value before calling super()
205
+ fail Cisco::RequestNotSupported unless self.supports?(data_format)
206
+ Cisco::Logger.debug("Get state using data format '#{data_format}'")
207
+ Cisco::Logger.debug(" executing command:\n #{command}") \
208
+ unless command.nil? || command.empty?
209
+ Cisco::Logger.debug(" with context:\n #{context.join("\n ")}") \
210
+ unless context.nil? || context.empty?
211
+ Cisco::Logger.debug(" to get value: #{value}") \
212
+ unless value.nil?
213
+ # to be implemented by subclasses
214
+ end
215
+
216
+ private
217
+
218
+ # Set the list of data formats supported by this client.
219
+ # If the client supports multiple formats, and a given feature or property
220
+ # can be managed by multiple formats, the list order indicates preference.
221
+ def data_formats=(data_formats)
222
+ data_formats = [data_formats] unless data_formats.is_a?(Array)
223
+ unknown = data_formats - Cisco::DATA_FORMATS
224
+ fail ArgumentError, "unknown data formats: #{unknown}" unless unknown.empty?
225
+ @data_formats = data_formats
226
+ end
227
+
228
+ # Set the platform of the node managed by this client.
229
+ def platform=(platform)
230
+ fail ArgumentError, "unknown platform #{platform}" \
231
+ unless Cisco::PLATFORMS.include?(platform)
232
+ @platform = platform
233
+ end
234
+ end