Source code for lib.polycube

from json import loads

from falcon.errors import HTTPGatewayTimeout as HTTP_Gateway_Timeout
from falcon.errors import HTTPServiceUnavailable as HTTP_Service_Unavailable
from requests import HTTPError as HTTP_Error
from requests import delete as delete_req
from requests import get as get_req
from requests import post as post_req
from requests import put as put_req
from requests.exceptions import ConnectionError as Connection_Error
from requests.exceptions import Timeout as Timeout_Error

from reader.arg import Arg_Reader
from utils.log import Log


[docs]class Polycube: def __init__(self): self.host = Arg_Reader.db.polycube_host self.port = Arg_Reader.db.polycube_port self.timeout = Arg_Reader.db.polycube_timeout self.endpoint = f'http://{self.host}:{self.port}/polycube/v1' self.log = Log.get('polycube') self.log.info(f'Check connection to {self.endpoint}') try: resp_req = get_req(self.endpoint, timeout=Arg_Reader.db.polycube_timeout) self.__manager(resp_req) except (Connection_Error, HTTP_Error) as e: self.log.exception(f'Connection with polycube at {self.host}:{self.port} not possible', e) def get(self, cube): self.log.info(f'Get info of cube {cube}') try: resp_req = get_req(f'{self.endpoint}/dynmon/{cube}', timeout=self.timeout) self.__manager(resp_req) return loads(resp_req.content) except HTTP_Error: return None def create(self, cube, code, interface, metrics): data = {'name': cube, 'code': code, 'interface': interface, 'metrics': metrics} if self.get(cube) is None: self.log.info(f'Create cube {cube}.') attached_info = {} try: resp_req = put_req(f'{self.endpoint}/dynmon/{cube}', json={'dataplane-config': self.__dataplane_config(cube, code, metrics)}, timeout=self.timeout) attached_info = self.__attach(cube, interface) return dict(status='created', attached_info=attached_info, detached_info={}, data=data, **self.__from_resp(resp_req)) except Exception as e: self.log.exception(f'Cube {cube} not created', e) return dict(status='error', interface=attached_info, detached_info={}, data=data, **self.__from_resp(resp_req, error=True)) else: return {'error': True, 'description': f'Cube {cube} found.', 'data': data} def delete(self, cube): data = {'cube': cube} if self.get(cube) is not None: self.log.info(f'Delete cube {cube}.') try: resp_req = delete_req(f'{self.endpoint}/dynmon/{cube}', timeout=self.timeout) self.__manager(resp_req) return dict(status='deleted', data=data, **self.__from_resp(resp_req)) except Exception as e: self.log.exception(f'Cube {cube} not deleted', e) return dict(error=True, data=data, **self.__from_resp(resp_req, error=True)) else: return {'error': True, 'description': f'Cube {cube} not found.', 'data': data} def update(self, cube, code, interface, metrics): data = {'name': cube, 'code': code, 'interface': interface, 'metrics': metrics} service = self.get(cube) if service is not None: self.log.info(f'Update cube {cube}.') try: attached_iface = service.get('parent', None) attached_info = {} detached_info = {} if attached_iface is None: attached_info = self.__attach(cube, cube) elif attached_iface != interface: attached_info = self.__detach(cube, attached_iface) detached_info = self.__attach(cube, interface) resp_req = put_req(f'{self.endpoint}/dynmon/{cube}/dataplane-config', json=self.__dataplane_config(cube, code, metrics), timeout=self.timeout) self.__manager(resp_req) return dict(status='updated', attached_info=attached_info, detached_info=detached_info, data=data, **self.__from_resp(resp_req)) except Exception as e: self.log.exception(f'Cube {cube} not updated', e) return dict(status='error', attached_info=attached_info, detached_info=detached_info, data=data, **self.__from_resp(resp_req, error=True)) else: return {'error': True, 'description': f'Cube {cube} not found.', 'data': data} @staticmethod def __dataplane_config(cube, code, metrics): return { 'ingress-path': {'name': cube, 'code': code, 'metric-configs': metrics}, 'egress-path': {} } def __from_resp(self, resp, error=None): if resp.content: try: return loads(resp.content) except Exception: return {'error': error if error is not None else resp.status_code >= 400, 'message': resp.content.decode("utf-8")} else: return {'error': error if error is not None else resp.status_code >= 400} def __detach(self, cube, interface): data = {'cube': cube, 'port': interface} resp_req = post_req(f'{self.endpoint}/detach', json=data, timeout=self.timeout) self.__manager(resp_req) return dict(status='detached', data=data, **self.__from_resp(resp_req)) def __attach(self, cube, interface): data = {'cube': cube, 'port': interface} resp_req = post_req(f'{self.endpoint}/attach', json=data, timeout=self.timeout) self.__manager(resp_req) return dict(status='attached', data=data, **self.__from_resp(resp_req)) def __manager(self, resp_req): try: resp_req.raise_for_status() except Connection_Error as e: msg = f'Connection to Polycube at {self.endpoint} not possible' self.log.exception(msg, e) if resp_req.content: self.log.error(f'Response: {resp_req.content}') raise HTTP_Service_Unavailable(title='Connection error', description=msg) except Timeout_Error as e: to = Arg_Reader.db.polycube_timeout msg = f'Timely response not received from polycube at {self.endpoint} in {to} seconds.' self.log.exception(msg, e) if resp_req.content: self.log.error(f'Response: {resp_req.content}') raise HTTP_Gateway_Timeout(title='Polycube Unavailable', description=msg)