1 # Copyright (c) 2018 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Keywords to manipulate bridge domain configuration using Honeycomb REST API.
16 The keywords make possible to put and get configuration data and to get
20 from resources.libraries.python.HTTPRequest import HTTPCodes
21 from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError
22 from resources.libraries.python.honeycomb.HoneycombUtil \
23 import DataRepresentation
24 from resources.libraries.python.honeycomb.HoneycombUtil \
25 import HoneycombUtil as HcUtil
28 class BridgeDomainKeywords(object):
29 """Keywords to manipulate bridge domain configuration.
31 Implements keywords which get configuration and operational data about
32 bridge domains and put the bridge domains' parameters using Honeycomb REST
36 PARAMS = ("flood", "forward", "learn", "unknown-unicast-flood",
43 def _configure_bd(node, bd_name, data,
44 data_representation=DataRepresentation.JSON):
45 """Send bridge domain configuration data and check the response.
47 :param node: Honeycomb node.
48 :param bd_name: The name of bridge domain.
49 :param data: Configuration data to be sent in PUT request.
50 :param data_representation: How the data is represented.
54 :type data_representation: DataRepresentation
55 :returns: Content of response.
57 :raises HoneycombError: If the status code in response on PUT is not
61 status_code, resp = HcUtil.\
62 put_honeycomb_data(node, "config_bridge_domain", data,
63 data_representation=data_representation)
64 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
66 "The configuration of bridge domain '{0}' was not successful. "
67 "Status code: {1}.".format(bd_name, status_code))
71 def _set_bd_properties(node, bd_name, path, new_value=None):
72 """Set bridge domain properties.
74 This method reads bridge domain configuration data, creates, changes or
75 removes the requested data and puts it back to Honeycomb.
77 :param node: Honeycomb node.
78 :param bd_name: The name of bridge domain.
79 :param path: Path to data we want to change, create or remove.
80 :param new_value: The new value to be set. If None, the item will be
85 :type new_value: str, dict or list
86 :returns: Content of response.
88 :raises HoneycombError: If it is not possible to get or set the data.
91 status_code, resp = HcUtil.\
92 get_honeycomb_data(node, "config_bridge_domain")
93 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
95 "Not possible to get configuration information about the "
96 "bridge domains. Status code: {0}.".format(status_code))
99 new_data = HcUtil.set_item_value(resp, path, new_value)
101 new_data = HcUtil.remove_item(resp, path)
103 return BridgeDomainKeywords._configure_bd(node, bd_name, new_data)
106 def _create_bd_structure(bd_name, **kwargs):
107 """Create the bridge domain data structure as it is expected by
110 :param bd_name: Bridge domain name.
111 :param kwargs: Parameters and their values. The accepted parameters are
112 defined in BridgeDomainKeywords.PARAMS.
115 :returns: Bridge domain data structure.
119 bd_structure = {"name": bd_name}
121 for param, value in kwargs.items():
122 if param not in BridgeDomainKeywords.PARAMS:
123 raise HoneycombError("The parameter {0} is invalid.".
125 bd_structure[param] = str(value)
130 def get_all_bds_cfg_data(node):
131 """Get configuration data about all bridge domains from Honeycomb.
133 :param node: Honeycomb node.
135 :returns: Configuration data about all bridge domains from Honeycomb.
137 :raises HoneycombError: If it is not possible to get configuration data.
140 status_code, resp = HcUtil.\
141 get_honeycomb_data(node, "config_bridge_domain")
142 if status_code != HTTPCodes.OK:
143 raise HoneycombError(
144 "Not possible to get configuration information about the "
145 "bridge domains. Status code: {0}.".format(status_code))
147 return resp["bridge-domains"]["bridge-domain"]
149 except (KeyError, TypeError):
153 def get_bd_cfg_data(node, bd_name):
154 """Get configuration data about the given bridge domain from Honeycomb.
156 :param node: Honeycomb node.
157 :param bd_name: The name of bridge domain.
160 :returns: Configuration data about the given bridge domain from
165 intfs = BridgeDomainKeywords.get_all_bds_cfg_data(node)
167 if intf["name"] == bd_name:
172 def get_all_bds_oper_data(node):
173 """Get operational data about all bridge domains from Honeycomb.
175 :param node: Honeycomb node.
177 :returns: Operational data about all bridge domains from Honeycomb.
179 :raises HoneycombError: If it is not possible to get operational data.
182 status_code, resp = HcUtil.\
183 get_honeycomb_data(node, "oper_bridge_domains")
184 if status_code != HTTPCodes.OK:
185 raise HoneycombError(
186 "Not possible to get operational information about the "
187 "bridge domains. Status code: {0}.".format(status_code))
189 return resp["bridge-domains-state"]["bridge-domain"]
191 except (KeyError, TypeError):
195 def get_bd_oper_data(node, bd_name):
196 """Get operational data about the given bridge domain from Honeycomb.
198 :param node: Honeycomb node.
199 :param bd_name: The name of bridge domain.
202 :returns: Operational data about the given bridge domain from Honeycomb.
206 intfs = BridgeDomainKeywords.get_all_bds_oper_data(node)
208 if intf["name"] == bd_name:
213 def add_first_bd(node, bd_name, **kwargs):
214 """Add the first bridge domain.
216 If there are any other bridge domains configured, they will be removed.
218 :param node: Honeycomb node.
219 :param bd_name: Bridge domain name.
220 :param kwargs: Parameters and their values. The accepted parameters are
221 defined in BridgeDomainKeywords.PARAMS
225 :returns: Bridge domain data structure.
229 new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs)
230 bridge_domain = {"bridge-domains": {"bridge-domain": [new_bd, ]}}
231 return BridgeDomainKeywords._configure_bd(node, bd_name, bridge_domain)
234 def add_bd(node, bd_name, **kwargs):
235 """Add a bridge domain.
237 :param node: Honeycomb node.
238 :param bd_name: Bridge domain name.
239 :param kwargs: Parameters and their values. The accepted parameters are
240 defined in BridgeDomainKeywords.PARAMS
244 :returns: Bridge domain data structure.
248 path = ("bridge-domains", "bridge-domain")
249 new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs)
250 bridge_domain = [new_bd, ]
251 return BridgeDomainKeywords._set_bd_properties(node, bd_name, path,
255 def remove_all_bridge_domains(node):
256 """Remove all bridge domains.
258 :param node: Honeycomb node.
260 :returns: Content of response.
262 :raises HoneycombError: If it is not possible to remove all bridge
266 data = {"bridge-domains": {"bridge-domain": []}}
268 status_code, resp = HcUtil.\
269 put_honeycomb_data(node, "config_bridge_domain", data)
271 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
272 raise HoneycombError("Not possible to remove all bridge domains. "
273 "Status code: {0}.".format(status_code))
277 def remove_bridge_domain(node, bd_name):
278 """Remove a bridge domain.
280 :param node: Honeycomb node.
281 :param bd_name: The name of bridge domain to be removed.
284 :returns: Content of response.
286 :raises HoneycombError: If it is not possible to remove the bridge
290 path = ("bridge-domains", ("bridge-domain", "name", bd_name))
292 status_code, resp = HcUtil.\
293 get_honeycomb_data(node, "config_bridge_domain")
294 if status_code != HTTPCodes.OK:
295 raise HoneycombError(
296 "Not possible to get configuration information about the "
297 "bridge domains. Status code: {0}.".format(status_code))
299 new_data = HcUtil.remove_item(resp, path)
300 status_code, resp = HcUtil.\
301 put_honeycomb_data(node, "config_bridge_domain", new_data)
302 if status_code != HTTPCodes.OK:
303 raise HoneycombError("Not possible to remove bridge domain {0}. "
305 format(bd_name, status_code))
309 def configure_bridge_domain(node, bd_name, param, value):
310 """Configure a bridge domain.
312 :param node: Honeycomb node.
313 :param bd_name: Bridge domain name.
314 :param param: Parameter to set, change or remove. The accepted
315 parameters are defined in BridgeDomainKeywords.PARAMS
316 :param value: The new value to be set, change or remove. If None, the
317 item will be removed.
322 :returns: Content of response.
326 if param not in BridgeDomainKeywords.PARAMS:
327 raise HoneycombError("The parameter {0} is invalid.".format(param))
329 path = ("bridge-domains", ("bridge-domain", "name", bd_name), param)
330 return BridgeDomainKeywords.\
331 _set_bd_properties(node, bd_name, path, value)
334 def add_l2_fib_entry(node, bd_name, l2_fib_entry):
335 """Add an L2 FIB entry to the bridge domain's list of L2 FIB entries.
337 :param node: Honeycomb node.
338 :param bd_name: Bridge domain's name.
339 :param l2_fib_entry: L2 FIB entry to be added to the L2 FIB table.
342 :type l2_fib_entry: dict
343 :returns: Content of response.
347 path = ("bridge-domains",
348 ("bridge-domain", "name", bd_name),
352 new_l2_fib_entry = [l2_fib_entry, ]
353 return BridgeDomainKeywords._set_bd_properties(
354 node, bd_name, path, new_l2_fib_entry)
357 def modify_l2_fib_entry(node, bd_name, mac, param, value):
358 """Modify an existing L2 FIB entry in the bridge domain's L2 FIB table.
359 The L2 FIB entry is specified by MAC address.
361 :param node: Honeycomb node.
362 :param bd_name: Bridge domain's name.
363 :param mac: MAC address used as the key in L2 FIB data structure.
364 :param param: The parameter to be modified.
365 :param value: The new value of the parameter.
370 :type value: str or int
371 :returns: Content of response.
375 path = ("bridge-domains",
376 ("bridge-domain", "name", bd_name),
378 ("l2-fib-entry", "phys-address", mac),
381 return BridgeDomainKeywords._set_bd_properties(
382 node, bd_name, path, value)
385 def remove_l2_fib_entry(node, bd_name, mac):
386 """Remove an L2 FIB entry from bridge domain's L2 FIB table. The
387 entry is specified by MAC address.
389 :param node: Honeycomb node.
390 :param bd_name: Bridge domain's name.
391 :param mac: MAC address used as the key in L2 FIB data structure.
395 :returns: Content of response.
397 :raises HoneycombError: If it is not possible to remove the specified
401 path = ("bridge-domains",
402 ("bridge-domain", "name", bd_name),
404 ("l2-fib-entry", "phys-address", str(mac)))
406 status_code, resp = HcUtil.\
407 get_honeycomb_data(node, "config_bridge_domain")
408 if status_code != HTTPCodes.OK:
409 raise HoneycombError("Not possible to get configuration information"
410 " about the L2 FIB entry {0} from bridge "
411 "domain {1}. Status code: {2}.".
412 format(mac, bd_name, status_code))
414 new_data = HcUtil.remove_item(resp, path)
415 status_code, resp = HcUtil.\
416 put_honeycomb_data(node, "config_bridge_domain", new_data)
417 if status_code != HTTPCodes.OK:
418 raise HoneycombError("Not possible to remove L2 FIB entry {0} from "
419 "bridge domain {1}. Status code: {2}.".
420 format(mac, bd_name, status_code))
425 def remove_all_l2_fib_entries(node, bd_name):
426 """Remove all entries from the bridge domain's L2 FIB table.
428 :param node: Honeycomb node.
429 :param bd_name: Bridge domain's name.
432 :returns: Content of response.
436 path = ("bridge-domains",
437 ("bridge-domain", "name", bd_name),
440 return BridgeDomainKeywords._set_bd_properties(
441 node, bd_name, path, None)
444 def get_all_l2_fib_entries(node, bd_name):
445 """Retrieves all entries from the bridge domain's L2 FIB table.
447 :param node: Honeycomb node.
448 :param bd_name: Bridge domain's name.
451 :returns: Bridge domain's L2 FIB table or empty list if the table does
452 not exist or it is empty.
456 bd_data = BridgeDomainKeywords.get_bd_oper_data(node, bd_name)
458 return bd_data["l2-fib-table"]["l2-fib-entry"]
463 def get_l2_fib_entry(node, bd_name, mac):
464 """Retrieves an entry from bridge domain's L2 FIB table. The entry is
465 specified by MAC address.
467 :param node: Honeycomb node.
468 :param bd_name: Bridge domain's name.
469 :param mac: MAC address used as the key in L2 FIB data structure.
473 :returns: The requested entry from bridge domain's L2 FIB table or empty
474 dictionary if it does not exist in the L2 FIB table.
478 l2_fib = BridgeDomainKeywords.get_all_l2_fib_entries(node, bd_name)
480 if entry["phys-address"] == mac: