def on_post(self, req, resp): req_data = req.media or {} resp_data, valid = Config_Request_Schema( many=is_list(req_data), method=HTTP_Method.POST).validate(data=req_data) if valid: req_data_wrap = wrap(req_data) if len(req_data_wrap) > 0: for config in req_data_wrap: for cfg, cfg_list in config.items(): for data in wrap(cfg_list): if cfg == 'actions': output = self.__actions(data) schema = Config_Action_Response_Schema elif cfg == 'parameters': output = self.__parameters(data) schema = Config_Parameter_Response_Schema elif cfg == 'resources': output = self.__resources(data) schema = Config_Resource_Response_Schema output.update(id=data.get('id', None), timestamp=datetime_to_str()) resp_data, valid = schema( many=False, method=HTTP_Method.POST).validate(data=output) if valid: Content_Response(output).add(resp) else: resp_data.add(resp) else: msg = f'No content to apply configurations with the {{request}}' No_Content_Response(msg, request=req_data).apply(resp) else: resp_data.apply(resp)
def on_put(self, req, resp, id=None): req_data = req.media or {} resp_data, valid = Code_Request_Schema(many=is_list(req_data), partial=True, method=HTTP_Method.PUT).validate(data=req.media, id=id) if valid: req_data_wrap = wrap(req_data) if len(req_data_wrap) > 0: for data in req_data_wrap: id, code, interface, metrics = item_getter('id', 'code', 'interface', 'metrics')(data) if all([id, code, interface]): pc = self.polycube.update(cube=id, code='\n'.join(code), interface=interface, metrics=metrics) if not pc.get('error', False): msg = f'Code with the id={id} correctly updated' resp_data = Ok_Response(msg) else: msg = f'Not possible to update code with the id={id}' resp_data = Unprocessable_Entity_Response(msg) resp_data.update(**pc) else: msg = f'Not possible to update code with the id={id}' resp_data = Unprocessable_Entity_Response(msg) resp_data.apply(resp) else: msg = f'No content to update code with the {{request}}' No_Content_Response(msg, request=req_data).apply(resp) else: resp_data.apply(resp)
def on_delete(self, req, resp, id=None): req_data = req.media or {} resp_data, valid = Code_Request_Schema(many=is_list(req_data), partial=True, method=HTTP_Method.DELETE).validate(data=req.media, id=id) if valid: req_data_wrap = wrap(req_data) if len(req_data_wrap) > 0: for data in req_data_wrap: id = data.get('id', None) if id is not None: pc = self.polycube.delete(cube=id) if not pc.get('error', False): msg = f'Code with the id={id} correctly deleted' resp_data = Reset_Content_Response(msg) else: msg = f'Not possible to delete code with the id={id}' resp_data = Unprocessable_Entity_Response(msg) resp_data.update(**pc) else: msg = f'Not possible to update code with the id={id}' resp_data = Unprocessable_Entity_Response(msg) resp_data.apply(resp) else: msg = f'No content to delete code with the {{request}}' No_Content_Response(msg, request=req_data).apply(resp) else: resp_data.apply(resp)
def __init__(self, catalog, req, resp): self.log = Log.get('agent-instance-lcp') self.req = req self.resp = resp self.req_lcp = [] self.actions = [] self.parameters = [] self.resources = [] self.catalogs = {'actions': {}, 'parameters': {}, 'resources': {}} operations = wrap(self.req.get('operations', [])) for req_op in operations: req_lcp_op = {} self.req_lcp.append(req_lcp_op) self.__prepare(req_lcp_op, 'actions', catalog=catalog.actions, data=req_op.get('actions', []), transform_handler=self.__transform_action) self.__prepare(req_lcp_op, 'parameters', catalog=catalog.parameters, data=req_op.get('parameters', []), transform_handler=self.__transform_parameter) self.__prepare(req_lcp_op, 'resources', catalog=catalog.resources, data=req_op.get('resources', []), transform_handler=self.__transform_resource) self.num = len(operations)
def on_base_put(self, req, resp, id=None): so = self.doc.Status_Operation req_data = req.media or {} resp_data, valid = self.schema(many=is_list(req_data), unknown='INCLUDE', partial=True, method=HTTP_Method.PUT).validate( data=req_data, id=id) if valid: req_data_wrap = wrap(req_data) if len(req_data_wrap) > 0: for req_data in req_data_wrap: req_data_lcp = deepcopy(req_data) req_data_id = req_data.pop('id', id) try: if len(req_data) == 0: msg = f'Update for {self.name} with id={req_data_id} not necessary' Not_Modified_Response(msg).add(resp) else: self.rm_ignore_fields(req_data) obj = self.doc.get(id=req_data_id) resp_data_lcp = [] hndl = self.get_lcp_handler(HTTP_Method.PUT) modified = hndl(instance=obj, req=req_data_lcp, resp=resp_data_lcp) resp_data = Ok_Response( f'{self.name.capitalize()} with the id={req_data_id} correctly updated' ) if len(resp_data_lcp) > 0: for rdl in resp_data_lcp: if rdl['error']: msg = f'Not possible to update a {self.name} with the id={req_data_id}' resp_data = Unprocessable_Entity_Response( msg) break resp_data.update(lcp_response=resp_data_lcp) force = req_data.get('force', False) if (not resp_data.error or force) and len(req_data) > 0: res = obj.update(**req_data) if res == so.UPDATED: modified = True if force: msg = f'Some errors occur but the {self.name} with the id={req_data_id} forcedly updated' resp_data = Unprocessable_Entity_Response( msg) if not resp_data.error and not modified: msg = f'{self.name.capitalize()} with the id={req_data_id} no need to update' resp_data = Not_Modified_Response(msg) resp_data.add(resp) except Exception as e: msg = f'Not possible to update a {self.name} with the id={req_data_id}' Unprocessable_Entity_Response(msg, exception=e).add(resp) else: msg = f'No content to update {self.name} based on the {{request}}' No_Content_Response(msg, request=req_data).apply(resp) else: resp_data.apply(resp)
def _deserialize(self, value, attr, data, **kwargs): if value: if isinstance(value, str): value = value.replace('\r', '').splitlines() else: value = wrap(value) return super(List_or_One, self)._deserialize(value, attr, data, **kwargs)
def routes(api, spec): log = Log.get('resource') for res_class in db: res = res_class() for route in wrap(res_class.routes): api.add_route(route, res) spec.path(resource=res) log.success(f'{route} endpoint configured')
def __apply(self, instance, exec_env): if self.num > 0: schema = 'https' if exec_env.lcp.https else 'http' resp_lcp = post_req( f'{schema}://{exec_env.hostname}:{exec_env.lcp.port}/config', headers={'Authorization': create_token()}, json=self.req_lcp) if resp_lcp.content: try: resp_lcp_data = resp_lcp.json() if resp_lcp.status_code >= 300 or (is_dict(resp_lcp) and resp_lcp_data.get( 'error', False)): Unprocessable_Entity_Response(resp_lcp_data) \ .add(self.resp) return False else: save_actions = self.__save( instance=instance, data=resp_lcp_data, type='action', catalogs=self.catalogs['actions'], handler=self.__save_action) save_parameters = self.__save( instance=instance, data=resp_lcp_data, type='parameter', catalogs=self.catalogs['parameters'], handler=self.__save_parameter) save_resources = self.__save( instance=instance, data=resp_lcp_data, type='resource', catalogs=self.catalogs['resources'], handler=self.__save_resource) if save_actions or save_parameters or save_resources: instance.save() self.resp.extend(wrap(resp_lcp_data)) return True except Exception as e: msg = f'Response from LCP({exec_env.meta.id}@{exec_env.hostname}:{exec_env.lcp.port}) not valid' self.log.exception(msg, e) uer = Unprocessable_Entity_Response(msg, exception=e) uer.add(self.resp) return False else: msg = f'Request to LCP({exec_env.meta.id}@{exec_env.hostname}:{exec_env.lcp.port}) not executed' Unprocessable_Entity_Response(msg).add(self.resp) return False return False
def __prepare(self, req_op, type, catalog, data, transform_handler): catalog_docs = [] req_op[type] = [] for data_item in wrap(data): id = data_item.get('id', None) catalog_doc = self.catalogs[type].get(id, None) or LCP.from_catalog(catalog=catalog, id=id, label=type.title(), resp=self.resp) if catalog_doc: self.catalogs[type][id] = catalog_doc d = catalog_doc.config.to_dict() config = transform_handler(d, data_item) config.update(**data_item) self.log.info(f'Prepare {type}: {config}') req_op[type].append(config) return catalog_docs
def on_base_post(self, req, resp, id=None): req_data = req.media or {} resp_data, valid = self.schema(many=is_list(req_data), unknown='INCLUDE', method=HTTP_Method.POST).validate( data=req_data, id=id) if valid: req_data_wrap = wrap(req_data) if len(req_data_wrap) > 0: for req_data in req_data_wrap: req_data_lcp = deepcopy(req_data) req_data_id = req_data.pop('id', id) try: self.rm_ignore_fields(req_data) obj = self.doc(meta={'id': req_data_id}, **req_data) resp_data_lcp = [] resp_data = Created_Response( f'{self.name.capitalize()} with the id={req_data_id} correctly created' ) hndl = self.get_lcp_handler(HTTP_Method.POST) hndl(instance=obj, req=req_data_lcp, resp=resp_data_lcp) if len(resp_data_lcp) > 0: for rdl in resp_data_lcp: if rdl['error']: msg = f'Not possible to create a {self.name} with the id={req_data_id}' resp_data = Unprocessable_Entity_Response( msg) break resp_data.update(lcp_response=resp_data_lcp) force = req_data.get('force', False) if not resp_data.error or force: obj.save() if force: msg = f'Some errors occur but the {self.name} with the id={req_data_id} forcedly created' resp_data = Unprocessable_Entity_Response(msg) resp_data.add(resp) except Exception as e: msg = f'Not possible to create a {self.name} with the id={req_data_id}' Unprocessable_Entity_Response(msg, exception=e).add(resp) else: msg = f'No content to create {self.names} based the {{request}}' No_Content_Response(msg, request=req_data).apply(resp) else: resp_data.apply(resp)
def __actions(self, data): cmd = data.get('cmd', None) daemon = data.get('daemon', False) output = dict(type='action') run = ' '.join([cmd] + wrap(data.get('args', []))) start = time.time() proc = self.__run_cmd(cmd=run, daemon=daemon, output=output) if daemon: output.update(error=False, executed=run, return_code=0) else: output.update(error=proc.returncode != 0, executed=run, return_code=proc.returncode, duration=time.time() - start) self.__set_std(proc.stdout, output, 'stdout') self.__set_std(proc.stderr, output, 'stderr') return output
def __apply(self, instance, exec_env, caller, data): h, p = exec_env.hostname, exec_env.lcp.port schema = 'https' if exec_env.lcp.https else 'http' resp_caller = caller(f'{schema}://{h}:{p}/code', headers={'Authorization': create_token()}, json=data(self.catalog)) if resp_caller.content: try: self.resp.extend(wrap(resp_caller.json())) except Exception as e: msg = f'Response from LCP({exec_env.meta.id}@{exec_env.hostname}:{exec_env.lcp.port}) not valid' self.log.exception(msg, e) uer = Unprocessable_Entity_Response(msg, exception=e) uer.add(self.resp) else: msg = f'Request to LCP({exec_env.meta.id}@{exec_env.hostname}:{exec_env.lcp.port}) not executed' Unprocessable_Entity_Response(msg).add(self.resp)
def __actions(self, data): cmd = data.get('cmd', None) daemon = data.get('daemon', False) output_format = data.get('output_format', 'plain') output = {'type': 'action'} run = ' '.join([cmd] + wrap(data.get('args', []))) start = time.time() proc = self.__run_cmd(cmd=run, daemon=daemon, output=output) if daemon: output.update(error=False, return_code=0) else: output.update(error=proc.returncode != 0, return_code=proc.returncode, duration=time.time() - start) self.__set_std(proc.stdout, output, 'stdout', output_format) self.__set_std(proc.stderr, output, 'stderr', output_format) return output
def __actions(self, data): cmd = data.get('cmd', None) daemon = data.get('daemon', None) output = dict(type='action') # TODO validate daemon if cmd @stop, @restart if cmd.startswith('@') and cmd in ('@stop', '@restart'): output.update(self.__run_daemon(cmd=cmd, daemon=daemon)) else: run = ' '.join([cmd] + wrap(data.get('args', []))) start = time.time() proc = self.__run_cmd(cmd=run, daemon=daemon, output=output) output.update(error=proc.returncode != 0, executed=run, return_code=proc.returncode, duration=time.time() - start) self.__set_std(proc.stdout, output, 'stdout') self.__set_std(proc.stderr, output, 'stderr') return output
def decorator(self): if self.__name__.endswith('Selected_Resource'): mode = 'selected' else: mode = 'base' for method in wrap(methods): base_mth = getattr(self, f'on_base_{method}') setattr(self, f'on_{method}', copy_func(base_mth, f'on_{method}')) mth = getattr(self, f'on_{method}', None) path = Path( __file__).parent / f'../docstring/{mode}/{method}.{ext}' with path.open('r') as file: mth.__doc__ = format(file.read(), self=self) if self.schema.__doc__ is not None: self.tag = { 'name': self.doc.Index.name, 'description': self.schema.__doc__.strip(' \n') } return self
def __parameters(self, data): schema = data.get('schema', None) source = data.get('source', None) path = wrap(data.get('path', [])) value = data.get('value', None) output = {'type': 'parameter'} try: source = expand_user(source) output.update( self.parsers.get(schema)(schema, source, path, value)) return output except File_Not_Found_Error as e: msg = f'Source {source} not found' self.log.exception(msg, e) return Not_Found_Response(msg, e, type='parameter', data=data) except Exception as e: msg = f'Source {source} not accessible' self.log.exception(msg, e) return Bad_Request_Response(e, message=msg, type='parameter', data=data)
def __parameters(self, data): schema = data.get('schema', None) source = data.get('source', None) path = wrap(data.get('path', None)) value = data.get('value', None) output = dict(type='parameter') try: source = expand_user(source) output.update( self.parsers.get(schema)(schema, source, path, value)) except File_Not_Found_Error as e: self.log.exception(e) output.update(error=True, data=data, description=f'Source {source} not found', exception=extract_info(e)) except Exception as e: self.log.exception(e) output.update(error=True, data=data, description=f'Source {source} not accessible', exception=extract_info(e)) return output