Source code for resource.agent.handler.lcp

from resource.base.handler.lcp import LCP as Base_LCP

from requests import post as post_req
from requests.auth import HTTPBasicAuth as HTTP_Basic_Auth
from toolz import valmap

from document.agent.catalog import Agent_Catalog_Document
from document.exec_env import Exec_Env_Document
from lib.response import Unprocessable_Entity_Response
from utils.log import Log
from utils.sequence import expand, extract, is_dict, wrap

__all__ = [
    'LCP'
]

# TODO add resource to instance
# TODO check if work everything


[docs]class LCP(Base_LCP): 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 = dict(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) @classmethod def handler(cls, instance, req, resp): agent_catalog = cls.from_doc(document=Agent_Catalog_Document, id=instance.agent_catalog_id, label='Agent Catalog', resp=resp) exec_env = cls.from_doc(document=Exec_Env_Document, id=instance.exec_env_id, label='Execution Environment', resp=resp) if all([agent_catalog, exec_env]): return LCP(catalog=agent_catalog, req=req, resp=resp).__apply(instance=instance, exec_env=exec_env) return False def __apply(self, instance, exec_env): if self.num > 0: username, password = exec_env.lcp.username, exec_env.lcp.password schema = 'https' if exec_env.lcp.https else 'http' resp_lcp = post_req(f'{schema}://{exec_env.hostname}:{exec_env.lcp.port}/config', auth=HTTP_Basic_Auth(username, password), 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 __frmt(self, x, data): if isinstance(x, (list, tuple)): return [self.__frmt(i, data) for i in x] else: try: return x.format(**data) except Exception as e: self.log.exception(f'Not possible to format {x}', e) return x def __transform_action(self, action, data): return valmap(lambda x: self.__frmt(x, data), action) def __transform_parameter(self, parameter, data): p = expand(parameter, value=data.get('value', None)) return valmap(lambda x: self.__frmt(x, data), p) def __transform_resource(self, resource, data): r = expand(resource, content=data.get('content', None)) return valmap(lambda x: self.__frmt(x, data), r) def __save(self, instance, data, type, catalogs, handler): results = filter(lambda r: r.get('type', None) == type, data) save = False for result in results: id = result.get('id', None) doc = catalogs.get(id, None) error = result.get('error', False) if handler(instance, doc, result, error): save = True return save def __save_action(self, instance, doc, result, error): save = False if doc.status is not None: instance.status = doc.status if not error else 'unknown' save = True if not error: instance.edit_action(result) save = True return save def __save_parameter(self, instance, doc, result, error): if not error: instance.edit_parameter(result) return True return False def __save_resource(self, instance, doc, result, error): if not error: instance.edit_resource(result) return True return False