def from_json(json: Json, _: type = object, **__: object) -> Trigger: if "cron_expression" in json: return from_js(json, TimeTrigger) elif "message_type" in json: return from_js(json, EventTrigger) else: raise AttributeError( f"Can not deserialize {json} into StepAction!")
def from_json(json: Json, _: type = object, **__: object) -> TaskCommand: if "message" in json: return from_js(json, SendMessage) elif "command" in json: return from_js(json, ExecuteOnCLI) else: raise AttributeError( f"Can not deserialize {json} into TaskCommand!")
def from_json(json: Json, _: type = object, **__: object) -> Workflow: return Workflow( json["id"], json["name"], from_js(json["steps"], List[Step]), from_js(json["triggers"], List[Trigger]), from_js(json["on_surpass"], TaskSurpassBehaviour), )
def parse_selector(js: Json) -> NodeSelector: if "node_id" in js: return from_js(js["node_id"], str) elif "search_criterea" in js: return from_js(js["search_criteria"], str) else: raise AttributeError( f"can't parse edge selector! Got {json.dumps(js)}")
def test_json_marshalling_subscription() -> None: roundtrip(Subscription("test")) roundtrip(Subscription("test", False, timedelta(days=1))) assert from_js({"message_type": "foo"}, Subscription) == Subscription("foo") assert from_js({"message_type": "foo"}, Subscription) == Subscription("foo") assert from_js({ "message_type": "a", "timeout": 86400 }, Subscription) == Subscription("a", True, timedelta(days=1))
def from_json(json: Json, _: type = object, **__: object) -> StepAction: if "wait_for_message_type" in json: return from_js(json, WaitForEvent) elif "message_type" in json: return from_js(json, PerformAction) elif "command" in json: return from_js(json, ExecuteCommand) elif "event" in json: return from_js(json, EmitEvent) else: raise AttributeError( f"Can not deserialize {json} into StepAction!")
def from_json(json: Json, _: type = object, **__: object) -> Job: maybe_wait = ((from_js(json["wait_trigger"], EventTrigger), from_js(json["wait_timeout"], timedelta)) if "wait_trigger" in json else None) trigger = json.get("trigger") return Job( json["id"], from_js(json["command"], ExecuteCommand), from_js(json["timeout"], timedelta), from_js(trigger, Trigger) if trigger is not None else None, maybe_wait, json.get("environment"), active=json.get( "active", True), # backward compatibility: in case the prop is missing )
async def subscriber(self, uid: str) -> Optional[Subscriber]: async with self.session.get(self.base_path + f"/subscriber/{uid}") as r: if r.status == 200: return from_js(await r.json(), Subscriber) else: return None
async def subscribers_for_event(self, event_type: str) -> List[Subscriber]: async with self.session.get(self.base_path + f"/subscribers/for/{event_type}") as r: if r.status == 200: return from_js(await r.json(), List[Subscriber]) else: raise AttributeError(await r.text())
async def put_config_validation(self, request: Request) -> StreamResponse: config_id = request.match_info["config_id"] js = await self.json_from_request(request) js["id"] = config_id config_model = from_js(js, ConfigValidation) model = await self.config_handler.put_config_validation(config_model) return await single_result(request, to_js(model))
async def update_subscriber(self, request: Request) -> StreamResponse: subscriber_id = request.match_info["subscriber_id"] body = await self.json_from_request(request) subscriptions = from_js(body, List[Subscription]) sub = await self.subscription_handler.update_subscriptions( subscriber_id, subscriptions) return await single_result(request, to_json(sub))
async def model(self) -> Model: async with self.session.get(self.base_path + "/model") as response: model_json = await response.json() model = Model.from_kinds([ from_js(kind, Kind) for kind in model_json["kinds"].values() ]) # type: ignore return model
async def receive() -> None: try: async for msg in ws: if isinstance( msg, WSMessage) and msg.type == WSMsgType.TEXT and len( msg.data.strip()) > 0: log.info( f"Incoming message: type={msg.type} data={msg.data} extra={msg.extra}" ) js = json.loads(msg.data) if "data" in js: js["data"]["subscriber_id"] = listener_id message: Message = from_js(js, Message) if isinstance(message, Action): raise AttributeError( "Actors should not emit action messages. ") elif isinstance(message, ActionDone): await self.workflow_handler.handle_action_done( message) elif isinstance(message, ActionError): await self.workflow_handler.handle_action_error( message) else: await self.message_bus.emit(message) except Exception as ex: # do not allow any exception - it will destroy the async fiber and cleanup log.info( f"Receive: message listener {listener_id}: {ex}. Hang up.") finally: await self.clean_ws_handler(wsid)
async def receive() -> None: try: async for msg in ws: if isinstance( msg, WSMessage) and msg.type == WSMsgType.TEXT and len( msg.data.strip()) > 0: log.info( f"Incoming message: type={msg.type} data={msg.data} extra={msg.extra}" ) tr = from_js(json.loads(msg.data), WorkerTaskResult) if tr.result == "error": error = tr.error if tr.error else "worker signalled error without detailed error message" await self.worker_task_queue.error_task( worker_id, tr.task_id, error) elif tr.result == "done": await self.worker_task_queue.acknowledge_task( worker_id, tr.task_id, tr.data) else: log.info( f"Do not understand this message: {msg.data}") except Exception as ex: # do not allow any exception - it will destroy the async fiber and cleanup log.info(f"Receive: worker:{worker_id}: {ex}. Hang up.") finally: await self.clean_ws_handler(worker_id)
async def update_configs_model(self, update: List[Kind]) -> Model: async with self.session.patch(self.base_path + "/configs/model", json=to_js(update)) as response: model_json = await response.json() model = Model.from_kinds([ from_js(kind, Kind) for kind in model_json["kinds"].values() ]) # type: ignore return model
async def test_query_not(filled_graph_db: ArangoGraphDB, foo_model: Model) -> None: # select everything that is not foo --> should be blas blas = Query.by(Query.mk_term("foo").not_term()) async with await filled_graph_db.search_list( QueryModel(blas.on_section("reported"), foo_model)) as gen: result = [from_js(x["reported"], Bla) async for x in gen] assert len(result) == 102
def validate_core_config() -> Optional[Json]: config = value_in_path(task_data, ["config", ResotoCoreRoot]) if isinstance(config, dict): # try to read editable config, throws if there are errors read = from_js(config, EditableConfig) return read.validate() else: return {"error": "Expected a json object"}
def test_json_marshalling_works() -> None: m = ModelFoo(1, "some foo", 23) js = to_js(m) js["identity"] = 1 js["a"] = "some foo" js["b"] = 23 again = from_js(js, ModelFoo) d = DeepDiff(m, again, truncate_datetime="second") assert len(d) == 0
async def all(self) -> AsyncGenerator[T, None]: with await self.db.all(self.collection_name) as cursor: for element in cursor: try: yield from_js(element, self.t_type) except JsonsError: log.warning( f"Not able to parse {element} into {type_fqn(self.t_type)}. Ignore." )
async def search_graph_explain(self, graph: str, search: str) -> EstimatedSearchCost: async with self.session.post(self.base_path + f"/graph/{graph}/search/explain", data=search) as r: if r.status == 200: return from_js(await r.json(), EstimatedSearchCost) else: raise AttributeError(await r.text())
async def merge_graph(self, graph: str, update: MultiDiGraph) -> GraphUpdate: js = self.graph_to_json(update) async with self.session.post(self.base_path + f"/graph/{graph}/merge", json=js) as r: if r.status == 200: return from_js(await r.json(), GraphUpdate) else: raise AttributeError(await r.text())
async def update_subscriber( self, uid: str, subscriptions: List[Subscription]) -> Optional[Subscriber]: async with self.session.put(self.base_path + f"/subscriber/{uid}", json=to_js(subscriptions)) as r: if r.status == 200: return from_js(await r.json(), Subscriber) else: raise AttributeError(await r.text())
async def delete_subscription(self, uid: str, subscription: Subscription) -> Subscriber: async with self.session.delete( self.base_path + f"/subscriber/{uid}/{subscription.message_type}") as r: if r.status == 200: return from_js(await r.json(), Subscriber) else: raise AttributeError(await r.text())
async def handle_message(msg: str) -> None: tr = from_js(json.loads(msg), WorkerTaskResult) if tr.result == "error": error = tr.error if tr.error else "worker signalled error without detailed error message" await self.worker_task_queue.error_task( worker_id, tr.task_id, error) elif tr.result == "done": await self.worker_task_queue.acknowledge_task( worker_id, tr.task_id, tr.data) else: log.info(f"Do not understand this message: {msg}")
async def get_configs_model(self) -> Model: async with self.session.get(self.base_path + f"/configs/model") as r: if r.status == 200: model_json = await r.json() model = Model.from_kinds([ from_js(kind, Kind) for kind in model_json["kinds"].values() ]) # type: ignore return model else: raise AttributeError(await r.text())
async def __update_model(self) -> None: try: kinds = from_js(config_model(), List[Kind]) await self.config_handler.update_configs_model(kinds) await self.config_handler.put_config_validation( ConfigValidation(ResotoCoreConfigId, external_validation=True)) await self.config_handler.put_config_validation( ConfigValidation(ResotoCoreCommandsConfigId, external_validation=True)) log.debug("Resoto core config model updated.") except Exception as ex: log.error(f"Could not update resoto core config model: {ex}", exc_info=ex)
async def handle_message(msg: str) -> None: js = json.loads(msg) if "data" in js: js["data"]["subscriber_id"] = listener_id message: Message = from_js(js, Message) if isinstance(message, Action): raise AttributeError( "Actors should not emit action messages. ") elif isinstance(message, ActionDone): await self.workflow_handler.handle_action_done(message) elif isinstance(message, ActionError): await self.workflow_handler.handle_action_error(message) else: await self.message_bus.emit(message)
async def add_subscription(self, uid: str, subscription: Subscription) -> Subscriber: props = { "timeout": str(int(subscription.timeout.total_seconds())), "wait_for_completion": str(subscription.wait_for_completion), } async with self.session.post( self.base_path + f"/subscriber/{uid}/{subscription.message_type}", params=props) as r: if r.status == 200: return from_js(await r.json(), Subscriber) else: raise AttributeError(await r.text())
async def test_query_list(filled_graph_db: ArangoGraphDB, foo_model: Model) -> None: blas = Query.by("foo", P("identifier") == "9").traverse_out().filter( "bla", P("f") == 23) async with await filled_graph_db.search_list( QueryModel(blas.on_section("reported"), foo_model)) as gen: result = [from_js(x["reported"], Bla) async for x in gen] assert len(result) == 10 foos_or_blas = parse_query("is([foo, bla])") async with await filled_graph_db.search_list( QueryModel(foos_or_blas.on_section("reported"), foo_model)) as gen: result = [x async for x in gen] assert len(result) == 111 # 113 minus 1 graph_root, minus one cloud
async def cli_evaluate( self, graph: str, command: str, **env: str) -> List[Tuple[ParsedCommands, List[AccessJson]]]: props = {"graph": graph, "section": "reported", **env} async with self.session.post(self.base_path + f"/cli/evaluate", data=command, params=props) as r: if r.status == 200: return [( ParsedCommands( from_js(json["parsed"], List[ParsedCommand]), json["env"]), AccessJson.wrap(json["execute"]), ) for json in await r.json()] else: raise AttributeError(await r.text())