diff --git a/README.md b/README.md index 89d5105..d506cd8 100644 --- a/README.md +++ b/README.md @@ -73,12 +73,11 @@ sudo echo "experimental-features = nix-command flakes" > '/etc/nix/nix.conf' - To start the backend server, execute: ```bash - clan webui --reload --no-open --log-level debug --populate + clan webui --reload --no-open --log-level debug --populate --emulate ``` - The server will automatically restart if any Python files change. - The `--populate` flag will automatically populate the database with dummy data - - - To emulate some distributed system behavior run `python3 tests/emulate_fastapi.py` + - The `--emulate` flag will automatically run servers the database with dummy data for the fronted to communicate with (ap, dlg, c1 and c2) 8. **Build the Frontend**: diff --git a/pkgs/clan-cli/clan_cli/__init__.py b/pkgs/clan-cli/clan_cli/__init__.py index 163a47d..02a9f5a 100644 --- a/pkgs/clan-cli/clan_cli/__init__.py +++ b/pkgs/clan-cli/clan_cli/__init__.py @@ -5,7 +5,7 @@ from types import ModuleType from typing import Optional from . import webui -from .custom_logger import register +from .custom_logger import setup_logging log = logging.getLogger(__name__) @@ -30,10 +30,6 @@ def create_parser(prog: Optional[str] = None) -> argparse.ArgumentParser: parser_webui = subparsers.add_parser("webui", help="start webui") webui.register_parser(parser_webui) - # if args.debug: - register(logging.DEBUG) - log.debug("Debug log activated") - if argcomplete: argcomplete.autocomplete(parser) @@ -47,6 +43,12 @@ def main() -> None: parser = create_parser() args = parser.parse_args() + if args.debug: + setup_logging(logging.DEBUG) + log.debug("Debug log activated") + else: + setup_logging(logging.INFO) + if not hasattr(args, "func"): return diff --git a/pkgs/clan-cli/clan_cli/config.py b/pkgs/clan-cli/clan_cli/config.py new file mode 100644 index 0000000..1891573 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/config.py @@ -0,0 +1,8 @@ +host = "127.0.0.1" +port_dlg = 7000 +port_ap = 7500 +port_client_base = 8000 +dlg_url = f"http://{host}:{port_dlg}/docs" +ap_url = f"http://{host}:{port_ap}/docs" +c1_url = f"http://{host}:{port_client_base}/docs" +c2_url = f"http://{host}:{port_client_base + 1}/docs" diff --git a/pkgs/clan-cli/clan_cli/custom_logger.py b/pkgs/clan-cli/clan_cli/custom_logger.py index f9f324e..a73a95d 100644 --- a/pkgs/clan-cli/clan_cli/custom_logger.py +++ b/pkgs/clan-cli/clan_cli/custom_logger.py @@ -61,10 +61,19 @@ def get_caller() -> str: return ret -def register(level: Any) -> None: - handler = logging.StreamHandler() - handler.setLevel(level) - handler.setFormatter(CustomFormatter()) - logger = logging.getLogger("registerHandler") - logger.addHandler(handler) - # logging.basicConfig(level=level, handlers=[handler]) +def setup_logging(level: Any) -> None: + # Get the root logger and set its level + main_logger = logging.getLogger("clan_cli") + main_logger.setLevel(level) + + # Create and add the default handler + default_handler = logging.StreamHandler() + + # Create and add your custom handler + default_handler.setLevel(level) + default_handler.setFormatter(CustomFormatter()) + main_logger.addHandler(default_handler) + + # Set logging level for other modules used by this module + logging.getLogger("asyncio").setLevel(logging.INFO) + logging.getLogger("httpx").setLevel(level=logging.WARNING) diff --git a/pkgs/clan-cli/clan_cli/emulate_fastapi.py b/pkgs/clan-cli/clan_cli/emulate_fastapi.py new file mode 100644 index 0000000..982a1fb --- /dev/null +++ b/pkgs/clan-cli/clan_cli/emulate_fastapi.py @@ -0,0 +1,178 @@ +import sys +import time +import urllib +from datetime import datetime + +from fastapi import FastAPI +from fastapi.responses import HTMLResponse, JSONResponse + +import clan_cli.config as config +from clan_cli.webui.schemas import Resolution + +app_dlg = FastAPI(swagger_ui_parameters={"tryItOutEnabled": True}) +app_ap = FastAPI(swagger_ui_parameters={"tryItOutEnabled": True}) +app_c1 = FastAPI(swagger_ui_parameters={"tryItOutEnabled": True}) +app_c2 = FastAPI(swagger_ui_parameters={"tryItOutEnabled": True}) + +apps = [ + (app_dlg, config.port_dlg), + (app_ap, config.port_ap), + (app_c1, config.port_client_base), + (app_c2, config.port_client_base + 1), +] + + +#### HEALTHCHECK +@app_c1.get("/") +async def root_c1() -> str: + return "C1 is alive" + + +@app_c1.get("/health") +async def healthcheck_c1() -> str: + return "200 OK" + + +@app_c2.get("/") +async def root_c2() -> str: + return "C2 is alive" + + +@app_c2.get("/health") +async def healthcheck_c2() -> str: + return "200 OK" + + +@app_dlg.get("/") +async def root_dlg() -> str: + return "DLG is alive" + + +@app_dlg.get("/health") +async def healthcheck_dlg() -> str: + return "200 OK" + + +@app_ap.get("/") +async def root_ap() -> str: + return "AP is alive" + + +@app_ap.get("/health") +async def healthcheck_ap() -> str: + return "200 OK" + + +def get_health(*, url: str, max_retries: int = 20, delay: float = 0.2) -> str | None: + for attempt in range(max_retries): + try: + with urllib.request.urlopen(url) as response: # type: ignore + return response.read() + except urllib.error.URLError as e: # type: ignore + print(f"Attempt {attempt + 1} failed: {e.reason}", file=sys.stderr) + time.sleep(delay) + return None + + +#### CONSUME SERVICE + +# TODO send_msg??? + + +@app_c1.get("/consume_service_from_other_entity", response_class=HTMLResponse) +async def consume_service_from_other_entity_c1() -> HTMLResponse: + html_content = """ + +
+ + + + """ + time.sleep(3) + return HTMLResponse(content=html_content, status_code=200) + + +@app_c2.get("/consume_service_from_other_entity", response_class=HTMLResponse) +async def consume_service_from_other_entity_c2() -> HTMLResponse: + html_content = """ + + + + + + """ + time.sleep(3) + return HTMLResponse(content=html_content, status_code=200) + + +@app_ap.get("/ap_list_of_services", response_class=JSONResponse) +async def ap_list_of_services() -> JSONResponse: + res = [ + { + "uuid": "98ae4334-6c12-ace8-ae34-0454cac5b68c", + "service_name": "Carlos Printing46", + "service_type": "3D Printing", + "endpoint_url": "127.0.0.1:6600/v1/print_daemon46", + "status": "unknown", + "other": {"action": ["register", "deregister", "delete", "create"]}, + "entity_did": "did:sov:test:6600", + "entity": { + "did": "did:sov:test:6600", + "name": "AP", + "ip": "127.0.0.1:6600", + "network": "255.255.0.0", + "visible": True, + "other": {}, + "attached": False, + "stop_health_task": False, + "roles": ["AP"], + }, + }, + { + "uuid": "988c24c9-61b1-cd22-6280-1c4510435a10", + "service_name": "Carlos Printing47", + "service_type": "3D Printing", + "endpoint_url": "127.0.0.1:6600/v1/print_daemon47", + "status": "unknown", + "other": {"action": ["register", "deregister", "delete", "create"]}, + "entity_did": "did:sov:test:6600", + "entity": { + "did": "did:sov:test:6600", + "name": "AP", + "ip": "127.0.0.1:6600", + "network": "255.255.0.0", + "visible": True, + "other": {}, + "attached": False, + "stop_health_task": False, + "roles": ["AP"], + }, + }, + ] + # resp = json.dumps(obj=res) + return JSONResponse(content=res, status_code=200) + + +@app_dlg.get("/dlg_list_of_did_resolutions", response_model=list[Resolution]) +async def dlg_list_of_did_resolutions() -> list[Resolution]: + res = [] + + res.append( + Resolution( + timestamp=datetime.fromisoformat("2021-10-12T12:52:00.000Z"), + requester_name="C1", + requester_did="did:sov:test:1122", + resolved_did="did:sov:test:1234", + other={"test": "test"}, + ) + ) + res.append( + Resolution( + timestamp=datetime.fromisoformat("2021-10-12T12:53:00.000Z"), + requester_name="C2", + requester_did="did:sov:test:1123", + resolved_did="did:sov:test:1234", + other={"test": "test"}, + ) + ) + return res diff --git a/pkgs/clan-cli/clan_cli/webui/__init__.py b/pkgs/clan-cli/clan_cli/webui/__init__.py index 1305e78..5ba79aa 100644 --- a/pkgs/clan-cli/clan_cli/webui/__init__.py +++ b/pkgs/clan-cli/clan_cli/webui/__init__.py @@ -1,11 +1,15 @@ import argparse +import logging from typing import Callable, NoReturn, Optional +log = logging.getLogger(__name__) + start_server: Optional[Callable] = None ServerImportError: Optional[ImportError] = None try: from .server import start_server except ImportError as e: + log.exception(e) ServerImportError = e @@ -28,6 +32,12 @@ def register_parser(parser: argparse.ArgumentParser) -> None: help="Populate the database with dummy data", default=False, ) + parser.add_argument( + "--emulate", + action="store_true", + help="Emulate two entities c1 and c2 + dlg and ap", + default=False, + ) parser.add_argument( "--no-open", action="store_true", help="Don't open the browser", default=False ) diff --git a/pkgs/clan-cli/clan_cli/webui/routers/endpoints.py b/pkgs/clan-cli/clan_cli/webui/routers/endpoints.py index 6a16fda..8ce5e27 100644 --- a/pkgs/clan-cli/clan_cli/webui/routers/endpoints.py +++ b/pkgs/clan-cli/clan_cli/webui/routers/endpoints.py @@ -1,10 +1,10 @@ import logging import time -from datetime import datetime -from typing import List, Optional +from typing import Any, List, Optional import httpx -from fastapi import APIRouter, BackgroundTasks, Depends +from fastapi import APIRouter, BackgroundTasks, Depends, Query +from fastapi.responses import HTMLResponse from sqlalchemy.orm import Session from ...errors import ClanError @@ -15,6 +15,7 @@ from ..schemas import ( Eventmessage, EventmessageCreate, Resolution, + Role, Service, ServiceCreate, ) @@ -48,7 +49,7 @@ def get_all_services( @router.get("/api/v1/service", response_model=List[Service], tags=[Tags.services]) def get_service_by_did( - entity_did: str = "did:sov:test:1234", + entity_did: str = "did:sov:test:120", skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db), @@ -63,7 +64,7 @@ def get_service_by_did( tags=[Tags.services], ) def get_services_without_entity( - entity_did: str = "did:sov:test:1234", + entity_did: str = "did:sov:test:120", skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db), @@ -74,30 +75,13 @@ def get_services_without_entity( @router.delete("/api/v1/service", tags=[Tags.services]) def delete_service( - entity_did: str = "did:sov:test:1234", + entity_did: str = "did:sov:test:120", db: Session = Depends(sql_db.get_db), ) -> dict[str, str]: sql_crud.delete_service_by_entity_did(db, entity_did) return {"message": "service deleted"} -######################### -# # -# REPOSITORY # -# # -######################### -@router.get( - "/api/v1/repositories", - response_model=List[Service], - tags=[Tags.repositories], -) -def get_all_repositories( - skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db) -) -> List[sql_models.Service]: - repositories = sql_crud.get_services(db, skip=skip, limit=limit) - return repositories - - ######################### # # # Entity # @@ -106,17 +90,29 @@ def get_all_repositories( @router.post("/api/v1/entity", response_model=Entity, tags=[Tags.entities]) def create_entity( entity: EntityCreate, db: Session = Depends(sql_db.get_db) -) -> EntityCreate: +) -> sql_models.Entity: return sql_crud.create_entity(db, entity) @router.get( - "/api/v1/entity_by_name", response_model=Optional[Entity], tags=[Tags.entities] + "/api/v1/entity_by_name_or_did", + response_model=Optional[Entity], + tags=[Tags.entities], ) -def get_entity_by_name( - entity_name: str, db: Session = Depends(sql_db.get_db) +def get_entity_by_name_or_did( + entity_name_or_did: str = "C1", db: Session = Depends(sql_db.get_db) ) -> Optional[sql_models.Entity]: - entity = sql_crud.get_entity_by_name(db, name=entity_name) + entity = sql_crud.get_entity_by_name_or_did(db, name=entity_name_or_did) + return entity + + +@router.get( + "/api/v1/entity_by_roles", response_model=List[Entity], tags=[Tags.entities] +) +def get_entity_by_roles( + roles: List[Role] = Query(...), db: Session = Depends(sql_db.get_db) +) -> List[sql_models.Entity]: + entity = sql_crud.get_entity_by_role(db, roles=roles) return entity @@ -130,7 +126,7 @@ def get_all_entities( @router.get("/api/v1/entity", response_model=Optional[Entity], tags=[Tags.entities]) def get_entity_by_did( - entity_did: str = "did:sov:test:1234", + entity_did: str = "did:sov:test:120", db: Session = Depends(sql_db.get_db), ) -> Optional[sql_models.Entity]: entity = sql_crud.get_entity_by_did(db, did=entity_did) @@ -149,10 +145,10 @@ def get_attached_entities( return entities -@router.post("/api/v1/detach", tags=[Tags.entities]) +@router.put("/api/v1/detach", tags=[Tags.entities]) def detach_entity( background_tasks: BackgroundTasks, - entity_did: str = "did:sov:test:1234", + entity_did: str = "did:sov:test:120", skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db), @@ -164,10 +160,10 @@ def detach_entity( return {"message": f"Detached {entity_did} successfully"} -@router.post("/api/v1/attach", tags=[Tags.entities]) +@router.put("/api/v1/attach", tags=[Tags.entities]) def attach_entity( background_tasks: BackgroundTasks, - entity_did: str = "did:sov:test:1234", + entity_did: str = "did:sov:test:120", skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db), @@ -175,7 +171,7 @@ def attach_entity( entity = sql_crud.get_entity_by_did(db, did=entity_did) if entity is None: raise ClanError(f"Entity with did '{entity_did}' not found") - url = f"http://{entity.ip}" + url = f"http://{entity.ip}/health" sql_crud.set_stop_health_task(db, entity_did, False) print("Start health query at", url) background_tasks.add_task(attach_entity_loc, db, entity_did) @@ -184,7 +180,7 @@ def attach_entity( @router.get("/api/v1/is_attached", tags=[Tags.entities]) def is_attached( - entity_did: str = "did:sov:test:1234", db: Session = Depends(sql_db.get_db) + entity_did: str = "did:sov:test:120", db: Session = Depends(sql_db.get_db) ) -> dict[str, str]: entity = sql_crud.get_entity_by_did(db, did=entity_did) @@ -209,7 +205,7 @@ def attach_entity_loc(db: Session, entity_did: str) -> None: entity = sql_crud.get_entity_by_did(db, did=entity_did) try: assert entity is not None - url = f"http://{entity.ip}" + url = f"http://{entity.ip}/health" while entity.stop_health_task is False: response = httpx.get(url, timeout=2) @@ -233,14 +229,34 @@ def attach_entity_loc(db: Session, entity_did: str) -> None: @router.delete("/api/v1/entity", tags=[Tags.entities]) -async def delete_entity( - entity_did: str = "did:sov:test:1234", +def delete_entity( + entity_did: str = "did:sov:test:120", db: Session = Depends(sql_db.get_db), ) -> dict[str, str]: sql_crud.delete_entity_by_did_recursive(db, did=entity_did) return {"message": "Entity deleted and all relations to that entity"} +def get_rpc_by_role(db: Session, role: Role, path: str) -> Any: + matching_entities = sql_crud.get_entity_by_role(db, roles=[role]) + if matching_entities is None: + raise ClanError(f"No {role} found") + if len(matching_entities) > 1: + raise ClanError(f"More than one {role} found") + dlg = matching_entities[0] + + url = f"http://{dlg.ip}/{path}" + try: + response = httpx.get(url, timeout=2) + except httpx.HTTPError as e: + raise ClanError(f"{role} not reachable at {url}") from e + + if response.status_code != 200: + raise ClanError(f"{role} returned {response.status_code}") + + return response.json() + + ######################### # # # Resolution # @@ -249,21 +265,24 @@ async def delete_entity( @router.get( "/api/v1/resolutions", response_model=List[Resolution], tags=[Tags.resolutions] ) -async def get_all_resolutions( +def get_all_resolutions( skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db) ) -> List[Resolution]: - # TODO: Get resolutions from DLG entity + return get_rpc_by_role(db, Role("DLG"), "dlg_list_of_did_resolutions") - return [ - Resolution( - requester_name="C1", - requester_did="did:sov:test:1122", - resolved_did="did:sov:test:1234", - other={"test": "test"}, - timestamp=datetime.now(), - id=1, - ) - ] + +######################### +# # +# Repository # +# # +######################### +@router.get( + "/api/v1/repositories", tags=[Tags.repositories], response_model=List[Service] +) +def get_all_repositories( + skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db) +) -> List[Service]: + return get_rpc_by_role(db, Role("AP"), "ap_list_of_services") ######################### @@ -271,10 +290,10 @@ async def get_all_resolutions( # Eventmessage # # # ######################### - - -@router.post("/api/v1/send_msg", response_model=Eventmessage, tags=[Tags.eventmessages]) -async def create_eventmessage( +@router.post( + "/api/v1/event_message", response_model=Eventmessage, tags=[Tags.eventmessages] +) +def create_eventmessage( eventmsg: EventmessageCreate, db: Session = Depends(sql_db.get_db) ) -> EventmessageCreate: return sql_crud.create_eventmessage(db, eventmsg) @@ -285,8 +304,36 @@ async def create_eventmessage( response_model=List[Eventmessage], tags=[Tags.eventmessages], ) -async def get_all_eventmessages( +def get_all_eventmessages( skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db) ) -> List[sql_models.Eventmessage]: eventmessages = sql_crud.get_eventmessages(db, skip=skip, limit=limit) return eventmessages + + +############################## +# # +# EMULATED API ENDPOINTS # +# # +############################## +@router.get("/emulate", response_class=HTMLResponse) +@router.get("/emu", response_class=HTMLResponse) +def get_emulated_enpoints() -> HTMLResponse: + from clan_cli.config import ap_url, c1_url, c2_url, dlg_url + + html_content = f""" + + +Emulated API endpoints for testing purposes.
+DLG: {dlg_url}
+AP: {ap_url}
+C1: {c1_url}
+C2: {c2_url}
+ + + """ + return HTMLResponse(content=html_content, status_code=200) diff --git a/pkgs/clan-cli/clan_cli/webui/schemas.py b/pkgs/clan-cli/clan_cli/webui/schemas.py index b3175f0..a203d0f 100644 --- a/pkgs/clan-cli/clan_cli/webui/schemas.py +++ b/pkgs/clan-cli/clan_cli/webui/schemas.py @@ -1,8 +1,11 @@ +import logging from datetime import datetime from enum import Enum from typing import List -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, validator + +log = logging.getLogger(__name__) class Status(Enum): @@ -11,6 +14,12 @@ class Status(Enum): UNKNOWN = "unknown" +class Role(Enum): + PROSUMER = "service_prosumer" + AP = "AP" + DLG = "DLG" + + class Machine(BaseModel): name: str status: Status @@ -21,31 +30,51 @@ class Machine(BaseModel): # Entity # # # ######################### +class EntityRolesBase(BaseModel): + role: Role = Field(..., example=Role("service_prosumer")) + + +class EntityRolesCreate(EntityRolesBase): + id: int = Field(...) + entity_did: str = Field(...) + + +class EntityRoles(EntityRolesBase): + class Config: + orm_mode = True + + class EntityBase(BaseModel): - did: str = Field(..., example="did:sov:test:1234") + did: str = Field(..., example="did:sov:test:120") name: str = Field(..., example="C1") ip: str = Field(..., example="127.0.0.1") + network: str = Field(..., example="255.255.0.0") visible: bool = Field(..., example=True) other: dict = Field( ..., example={ "network": "Carlos Home Network", - "roles": ["service repository", "service prosumer"], }, ) class EntityCreate(EntityBase): - pass + roles: List[Role] = Field(..., example=[Role("service_prosumer"), Role("AP")]) -class Entity(EntityCreate): +class Entity(EntityBase): attached: bool = Field(...) stop_health_task: bool = Field(...) + roles: List[Role] class Config: orm_mode = True + # define a custom getter function for roles + @validator("roles", pre=True) + def get_roles(cls, v: List[EntityRoles]) -> List[Role]: + return [x.role for x in v] + ######################### # # @@ -64,7 +93,7 @@ class ServiceBase(BaseModel): class ServiceCreate(ServiceBase): - entity_did: str = Field(..., example="did:sov:test:1234") + entity_did: str = Field(..., example="did:sov:test:120") class Service(ServiceCreate): @@ -90,7 +119,7 @@ class ServicesByName(BaseModel): class ResolutionBase(BaseModel): requester_name: str = Field(..., example="C1") requester_did: str = Field(..., example="did:sov:test:1122") - resolved_did: str = Field(..., example="did:sov:test:1234") + resolved_did: str = Field(..., example="did:sov:test:120") other: dict = Field(..., example={"test": "test"}) @@ -100,7 +129,6 @@ class ResolutionCreate(ResolutionBase): class Resolution(ResolutionCreate): timestamp: datetime - id: int class Config: orm_mode = True @@ -112,7 +140,6 @@ class Resolution(ResolutionCreate): # # ######################### class EventmessageBase(BaseModel): - id: int = Field(..., example=123456) timestamp: int = Field(..., example=1234123413) group: int = Field(..., example=1) # event group type (for the label) group_id: int = Field( @@ -120,14 +147,15 @@ class EventmessageBase(BaseModel): ) # specific to one group needed to enable visually nested groups msg_type: int = Field(..., example=1) # message type for the label src_did: str = Field(..., example="did:sov:test:2234") - des_did: str = Field(..., example="did:sov:test:1234") + des_did: str = Field(..., example="did:sov:test:120") class EventmessageCreate(EventmessageBase): msg: dict = Field(..., example={"optinal": "values"}) # optional - pass class Eventmessage(EventmessageCreate): + id: int = Field(...) + class Config: orm_mode = True diff --git a/pkgs/clan-cli/clan_cli/webui/server.py b/pkgs/clan-cli/clan_cli/webui/server.py index b1ad401..4dce764 100644 --- a/pkgs/clan-cli/clan_cli/webui/server.py +++ b/pkgs/clan-cli/clan_cli/webui/server.py @@ -1,5 +1,6 @@ import argparse import logging +import multiprocessing as mp import shutil import subprocess import time @@ -14,6 +15,8 @@ import uvicorn from pydantic import AnyUrl, IPvAnyAddress from pydantic.tools import parse_obj_as +import clan_cli.config as config +from clan_cli.emulate_fastapi import apps, get_health from clan_cli.errors import ClanError log = logging.getLogger(__name__) @@ -126,6 +129,26 @@ def start_server(args: argparse.Namespace) -> None: cmd = ["pytest", "-s", str(test_db_api)] subprocess.run(cmd, check=True) + config.host = args.host + if args.emulate: + # start servers as processes (dlg, ap, c1 and c2 for tests) + for app, port in apps: + proc = mp.Process( + target=uvicorn.run, + args=(app,), + kwargs={ + "host": args.host, + "port": port, + "log_level": args.log_level, + }, + daemon=True, + ) + proc.start() + url = f"http://{args.host}:{port}" + res = get_health(url=url + "/health") + if res is None: + raise Exception(f"Couldn't reach {url} after starting server") + uvicorn.run( "clan_cli.webui.app:app", host=args.host, diff --git a/pkgs/clan-cli/clan_cli/webui/sql_crud.py b/pkgs/clan-cli/clan_cli/webui/sql_crud.py index 64b968c..81c81de 100644 --- a/pkgs/clan-cli/clan_cli/webui/sql_crud.py +++ b/pkgs/clan-cli/clan_cli/webui/sql_crud.py @@ -1,5 +1,6 @@ from typing import List, Optional +from sqlalchemy import func from sqlalchemy.orm import Session from sqlalchemy.sql.expression import true @@ -65,8 +66,21 @@ def get_services_without_entity_id( ######################### def create_entity(db: Session, entity: schemas.EntityCreate) -> sql_models.Entity: db_entity = sql_models.Entity( - **entity.dict(), attached=False, stop_health_task=False + did=entity.did, + name=entity.name, + ip=entity.ip, + network=entity.network, + visible=entity.visible, + other=entity.other, + attached=False, + stop_health_task=False, ) + + db_roles = [] + for role in entity.roles: + db_roles.append(sql_models.EntityRoles(role=role)) + + db_entity.roles = db_roles db.add(db_entity) db.commit() db.refresh(db_entity) @@ -83,8 +97,34 @@ def get_entity_by_did(db: Session, did: str) -> Optional[sql_models.Entity]: return db.query(sql_models.Entity).filter(sql_models.Entity.did == did).first() -def get_entity_by_name(db: Session, name: str) -> Optional[sql_models.Entity]: - return db.query(sql_models.Entity).filter(sql_models.Entity.name == name).first() +def get_entity_by_name_or_did(db: Session, name: str) -> Optional[sql_models.Entity]: + return ( + db.query(sql_models.Entity) + .filter((sql_models.Entity.name == name) | (sql_models.Entity.did == name)) + .first() + ) + + +def get_entity_by_role( + db: Session, roles: List[schemas.Role] +) -> List[sql_models.Entity]: + # create a subquery to count the matching roles for each entity + subquery = ( + db.query( + sql_models.EntityRoles.entity_did, + func.count(sql_models.EntityRoles.role).label("role_count"), + ) + .filter(sql_models.EntityRoles.role.in_(roles)) + .group_by(sql_models.EntityRoles.entity_did) + .subquery() + ) + # join the subquery with the entity table and filter by the role count + return ( + db.query(sql_models.Entity) + .join(subquery, sql_models.Entity.did == subquery.c.entity_did) + .filter(subquery.c.role_count == len(roles)) + .all() + ) # get attached @@ -107,12 +147,11 @@ def set_stop_health_task(db: Session, entity_did: str, value: bool) -> None: if db_entity is None: raise ClanError(f"Entity with did '{entity_did}' not found") - setattr(db_entity, "stop_health_task", value) + db_entity.stop_health_task = value # type: ignore # save changes in db db.add(db_entity) db.commit() - db.refresh(db_entity) def set_attached_by_entity_did(db: Session, entity_did: str, attached: bool) -> None: @@ -120,12 +159,11 @@ def set_attached_by_entity_did(db: Session, entity_did: str, attached: bool) -> if db_entity is None: raise ClanError(f"Entity with did '{entity_did}' not found") - setattr(db_entity, "attached", attached) + db_entity.attached = attached # type: ignore # save changes in db db.add(db_entity) db.commit() - db.refresh(db_entity) def delete_entity_by_did(db: Session, did: str) -> None: @@ -148,7 +186,15 @@ def delete_entity_by_did_recursive(db: Session, did: str) -> None: def create_eventmessage( db: Session, eventmsg: schemas.EventmessageCreate ) -> sql_models.Eventmessage: - db_eventmessage = sql_models.Eventmessage(**eventmsg.dict()) + db_eventmessage = sql_models.Eventmessage( + timestamp=eventmsg.timestamp, + group=eventmsg.group, + group_id=eventmsg.group_id, + msg_type=eventmsg.msg_type, + src_did=eventmsg.src_did, + des_did=eventmsg.des_did, + msg=eventmsg.msg, + ) db.add(db_eventmessage) db.commit() db.refresh(db_eventmessage) diff --git a/pkgs/clan-cli/clan_cli/webui/sql_models.py b/pkgs/clan-cli/clan_cli/webui/sql_models.py index 742b237..d83918d 100644 --- a/pkgs/clan-cli/clan_cli/webui/sql_models.py +++ b/pkgs/clan-cli/clan_cli/webui/sql_models.py @@ -1,6 +1,7 @@ -from sqlalchemy import JSON, Boolean, Column, ForeignKey, Integer, String, Text +from sqlalchemy import JSON, Boolean, Column, Enum, ForeignKey, Integer, String, Text from sqlalchemy.orm import relationship +from .schemas import Role from .sql_db import Base # Relationsship example @@ -14,16 +15,30 @@ class Entity(Base): did = Column(String, primary_key=True, index=True) name = Column(String, index=True, unique=True) ip = Column(String, index=True) + network = Column(String, index=True) attached = Column(Boolean, index=True) visible = Column(Boolean, index=True) stop_health_task = Column(Boolean) ## Non queryable body ## - # In here we deposit: Network, Roles, Visible, etc. + # In here we deposit: Not yet defined stuff other = Column(JSON) ## Relations ## services = relationship("Service", back_populates="entity") + roles = relationship("EntityRoles", back_populates="entity") + + +class EntityRoles(Base): + __tablename__ = "entity_roles" + + ## Queryable body ## + id = Column(Integer, primary_key=True, autoincrement=True) + entity_did = Column(String, ForeignKey("entities.did")) + role = Column(Enum(Role), index=True, nullable=False) # type: ignore + + ## Relations ## + entity = relationship("Entity", back_populates="roles") class ServiceAbstract(Base): @@ -54,7 +69,7 @@ class Eventmessage(Base): __tablename__ = "eventmessages" ## Queryable body ## - id = Column(Integer, primary_key=True, index=True) + id = Column(Integer, primary_key=True, autoincrement=True) timestamp = Column(Integer, unique=True, index=True) group = Column(Integer, index=True) group_id = Column(Integer, index=True) diff --git a/pkgs/clan-cli/clan_cli/webui/tags.py b/pkgs/clan-cli/clan_cli/webui/tags.py index 3d52367..941337c 100644 --- a/pkgs/clan-cli/clan_cli/webui/tags.py +++ b/pkgs/clan-cli/clan_cli/webui/tags.py @@ -18,14 +18,14 @@ tags_metadata: List[Dict[str, Any]] = [ "name": str(Tags.services), "description": "Operations on a service.", }, - { - "name": str(Tags.entities), - "description": "Operations on an entity.", - }, { "name": str(Tags.repositories), "description": "Operations on a repository.", }, + { + "name": str(Tags.entities), + "description": "Operations on an entity.", + }, { "name": str(Tags.resolutions), "description": "Operations on a resolution.", diff --git a/pkgs/clan-cli/emulate_entity.sh b/pkgs/clan-cli/emulate_entity.sh deleted file mode 100755 index 047880a..0000000 --- a/pkgs/clan-cli/emulate_entity.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -while true ; do printf 'HTTP/1.1 200 OK\r\n\r\ncool, thanks' | nc -l -N 127.0.0.1 7002; done diff --git a/pkgs/clan-cli/pyproject.toml b/pkgs/clan-cli/pyproject.toml index adbf1ca..547a4e3 100644 --- a/pkgs/clan-cli/pyproject.toml +++ b/pkgs/clan-cli/pyproject.toml @@ -68,7 +68,7 @@ ignore_missing_imports = true [tool.ruff] line-length = 88 select = [ "E", "F", "I", "N"] -ignore = [ "E501" ] +ignore = [ "E501", "N805" ] exclude = ["tests/openapi_client"] [tool.black] diff --git a/pkgs/clan-cli/tests/api.py b/pkgs/clan-cli/tests/api.py index 1c3644d..5a3f376 100644 --- a/pkgs/clan-cli/tests/api.py +++ b/pkgs/clan-cli/tests/api.py @@ -11,6 +11,7 @@ from fastapi.testclient import TestClient from openapi_client import ApiClient, Configuration from ports import PortFunction +import clan_cli.config as config from clan_cli.webui.app import app @@ -31,10 +32,11 @@ def get_health(*, url: str, max_retries: int = 20, delay: float = 0.2) -> str | # Pytest fixture to run the server in a separate process +# server @pytest.fixture(scope="session") def server_url(unused_tcp_port: PortFunction) -> Generator[str, None, None]: port = unused_tcp_port() - host = "127.0.0.1" + host = config.host proc = Process( target=uvicorn.run, args=(app,), diff --git a/pkgs/clan-cli/tests/emulate_fastapi.py b/pkgs/clan-cli/tests/emulate_fastapi.py deleted file mode 100644 index 1033a81..0000000 --- a/pkgs/clan-cli/tests/emulate_fastapi.py +++ /dev/null @@ -1,153 +0,0 @@ -import time - -import uvicorn -from fastapi import FastAPI -from fastapi.responses import HTMLResponse - -app = FastAPI() - -# bash tests: curl localhost:8000/ap_list_of_services - - -@app.get("/health") -async def healthcheck() -> str: - return "200 OK" - - -@app.get("/consume_service_from_other_entity", response_class=HTMLResponse) -async def consume_service_from_other_entity() -> HTMLResponse: - html_content = """ - - - - - - """ - time.sleep(3) - return HTMLResponse(content=html_content, status_code=200) - - -@app.get("/ap_list_of_services", response_class=HTMLResponse) -async def ap_list_of_services() -> HTMLResponse: - html_content = b"""HTTP/1.1 200 OK\r\n\r\n[[ - { - "uuid": "8e285c0c-4e40-430a-a477-26b3b81e30df", - "service_name": "Carlos Printing", - "service_type": "3D Printing", - "endpoint_url": "http://127.0.0.1:8000", - "status": "unknown", - "other": { - "action": [ - "register", - "deregister", - "delete", - "create" - ] - }, - "entity_did": "did:sov:test:1234" - }, - { - "uuid": "8e285c0c-4e40-430a-a477-26b3b81e30d1", - "service_name": "Luiss Fax", - "service_type": "Fax", - "endpoint_url": "http://127.0.0.1:8000", - "status": "unknown", - "other": { - "action": [ - "register", - "deregister", - "delete", - "create" - ] - }, - "entity_did": "did:sov:test:1235" - }, - { - "uuid": "8e285c0c-4e40-430a-a477-26b3b81e30d2", - "service_name": "Erdems VR-Stream", - "service_type": "VR-Stream", - "endpoint_url": "http://127.0.0.1:8000", - "status": "unknown", - "other": { - "action": [ - "register", - "deregister", - "delete", - "create" - ] - }, - "entity_did": "did:sov:test:1236" - }, - { - "uuid": "8e285c0c-4e40-430a-a477-26b3b81e30d3", - "service_name": "Onurs gallary", - "service_type": "gallary", - "endpoint_url": "http://127.0.0.1:8000", - "status": "unknown", - "other": { - "action": [ - "register", - "deregister", - "delete", - "create" - ] - }, - "entity_did": "did:sov:test:1237" - }, - { - "uuid": "8e285c0c-4e40-430a-a477-26b3b81e30d4", - "service_name": "Saras Game-Shop", - "service_type": "Game-Shop", - "endpoint_url": "http://127.0.0.1:8000", - "status": "unknown", - "other": { - "action": [ - "register", - "deregister", - "delete", - "create" - ] - }, - "entity_did": "did:sov:test:1238" - } -]]""" - return HTMLResponse(content=html_content, status_code=200) - - -@app.get("/dlg_list_of_did_resolutions", response_class=HTMLResponse) -async def dlg_list_of_did_resolutions() -> HTMLResponse: - html_content = b"""HTTP/1.1 200 OK\r\n\r\n -[ - { - "did": "did:sov:test:1234", - "name": "C1", - "ip": "127.0.0.1:5100", - "attached": false, - "visible": true, - "other": { - "network": "Carlo1's Home Network", - "roles": [ - "service repository", - "service consumer" - ] - } - }, - { - "did": "did:sov:test:1235", - "name": "C2", - "ip": "127.0.0.1:5100", - "attached": false, - "visible": true, - "other": { - "network": "Carlo2's Home Network", - "roles": [ - "service repository", - "service prosumer" - ] - } - } -]""" - return HTMLResponse(content=html_content, status_code=200) - - -uvicorn.run(app, host="localhost", port=8000) diff --git a/pkgs/clan-cli/tests/openapi_client/__init__.py b/pkgs/clan-cli/tests/openapi_client/__init__.py index c30337b..bf8d04e 100644 --- a/pkgs/clan-cli/tests/openapi_client/__init__.py +++ b/pkgs/clan-cli/tests/openapi_client/__init__.py @@ -20,7 +20,6 @@ __version__ = "1.0.0" from openapi_client.api.default_api import DefaultApi from openapi_client.api.entities_api import EntitiesApi from openapi_client.api.eventmessages_api import EventmessagesApi -from openapi_client.api.repositories_api import RepositoriesApi from openapi_client.api.resolution_api import ResolutionApi from openapi_client.api.services_api import ServicesApi @@ -43,6 +42,7 @@ from openapi_client.models.eventmessage_create import EventmessageCreate from openapi_client.models.http_validation_error import HTTPValidationError from openapi_client.models.machine import Machine from openapi_client.models.resolution import Resolution +from openapi_client.models.role import Role from openapi_client.models.service import Service from openapi_client.models.service_create import ServiceCreate from openapi_client.models.status import Status diff --git a/pkgs/clan-cli/tests/openapi_client/api/__init__.py b/pkgs/clan-cli/tests/openapi_client/api/__init__.py index 87b34f9..88a80e5 100644 --- a/pkgs/clan-cli/tests/openapi_client/api/__init__.py +++ b/pkgs/clan-cli/tests/openapi_client/api/__init__.py @@ -4,7 +4,6 @@ from openapi_client.api.default_api import DefaultApi from openapi_client.api.entities_api import EntitiesApi from openapi_client.api.eventmessages_api import EventmessagesApi -from openapi_client.api.repositories_api import RepositoriesApi from openapi_client.api.resolution_api import ResolutionApi from openapi_client.api.services_api import ServicesApi diff --git a/pkgs/clan-cli/tests/openapi_client/api/entities_api.py b/pkgs/clan-cli/tests/openapi_client/api/entities_api.py index 82431a5..041bafe 100644 --- a/pkgs/clan-cli/tests/openapi_client/api/entities_api.py +++ b/pkgs/clan-cli/tests/openapi_client/api/entities_api.py @@ -18,12 +18,13 @@ import warnings from pydantic import validate_arguments, ValidationError -from pydantic import StrictInt, StrictStr +from pydantic import StrictInt, StrictStr, conlist from typing import Any, List, Optional, Dict from openapi_client.models.entity import Entity from openapi_client.models.entity_create import EntityCreate +from openapi_client.models.role import Role from openapi_client.api_client import ApiClient from openapi_client.api_response import ApiResponse @@ -184,7 +185,7 @@ class EntitiesApi: } return self.api_client.call_api( - '/api/v1/attach', 'POST', + '/api/v1/attach', 'PUT', _path_params, _query_params, _header_params, @@ -624,7 +625,7 @@ class EntitiesApi: } return self.api_client.call_api( - '/api/v1/detach', 'POST', + '/api/v1/detach', 'PUT', _path_params, _query_params, _header_params, @@ -1074,17 +1075,17 @@ class EntitiesApi: _request_auth=_params.get('_request_auth')) @validate_arguments - def get_entity_by_name(self, entity_name : StrictStr, **kwargs) -> Entity: # noqa: E501 - """Get Entity By Name # noqa: E501 + def get_entity_by_name_or_did(self, entity_name_or_did : Optional[StrictStr] = None, **kwargs) -> Entity: # noqa: E501 + """Get Entity By Name Or Did # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.get_entity_by_name(entity_name, async_req=True) + >>> thread = api.get_entity_by_name_or_did(entity_name_or_did, async_req=True) >>> result = thread.get() - :param entity_name: (required) - :type entity_name: str + :param entity_name_or_did: + :type entity_name_or_did: str :param async_req: Whether to execute the request asynchronously. :type async_req: bool, optional :param _request_timeout: timeout setting for this request. @@ -1098,22 +1099,22 @@ class EntitiesApi: """ kwargs['_return_http_data_only'] = True if '_preload_content' in kwargs: - message = "Error! Please call the get_entity_by_name_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + message = "Error! Please call the get_entity_by_name_or_did_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 raise ValueError(message) - return self.get_entity_by_name_with_http_info(entity_name, **kwargs) # noqa: E501 + return self.get_entity_by_name_or_did_with_http_info(entity_name_or_did, **kwargs) # noqa: E501 @validate_arguments - def get_entity_by_name_with_http_info(self, entity_name : StrictStr, **kwargs) -> ApiResponse: # noqa: E501 - """Get Entity By Name # noqa: E501 + def get_entity_by_name_or_did_with_http_info(self, entity_name_or_did : Optional[StrictStr] = None, **kwargs) -> ApiResponse: # noqa: E501 + """Get Entity By Name Or Did # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.get_entity_by_name_with_http_info(entity_name, async_req=True) + >>> thread = api.get_entity_by_name_or_did_with_http_info(entity_name_or_did, async_req=True) >>> result = thread.get() - :param entity_name: (required) - :type entity_name: str + :param entity_name_or_did: + :type entity_name_or_did: str :param async_req: Whether to execute the request asynchronously. :type async_req: bool, optional :param _preload_content: if False, the ApiResponse.data will @@ -1142,7 +1143,7 @@ class EntitiesApi: _params = locals() _all_params = [ - 'entity_name' + 'entity_name_or_did' ] _all_params.extend( [ @@ -1161,7 +1162,7 @@ class EntitiesApi: if _key not in _all_params: raise ApiTypeError( "Got an unexpected keyword argument '%s'" - " to method get_entity_by_name" % _key + " to method get_entity_by_name_or_did" % _key ) _params[_key] = _val del _params['kwargs'] @@ -1173,8 +1174,8 @@ class EntitiesApi: # process the query parameters _query_params = [] - if _params.get('entity_name') is not None: # noqa: E501 - _query_params.append(('entity_name', _params['entity_name'])) + if _params.get('entity_name_or_did') is not None: # noqa: E501 + _query_params.append(('entity_name_or_did', _params['entity_name_or_did'])) # process the header parameters _header_params = dict(_params.get('_headers', {})) @@ -1196,7 +1197,147 @@ class EntitiesApi: } return self.api_client.call_api( - '/api/v1/entity_by_name', 'GET', + '/api/v1/entity_by_name_or_did', 'GET', + _path_params, + _query_params, + _header_params, + body=_body_params, + post_params=_form_params, + files=_files, + response_types_map=_response_types_map, + auth_settings=_auth_settings, + async_req=_params.get('async_req'), + _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 + _preload_content=_params.get('_preload_content', True), + _request_timeout=_params.get('_request_timeout'), + collection_formats=_collection_formats, + _request_auth=_params.get('_request_auth')) + + @validate_arguments + def get_entity_by_roles(self, roles : conlist(Role), **kwargs) -> List[Entity]: # noqa: E501 + """Get Entity By Roles # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_entity_by_roles(roles, async_req=True) + >>> result = thread.get() + + :param roles: (required) + :type roles: List[Role] + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _request_timeout: timeout setting for this request. + If one number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: List[Entity] + """ + kwargs['_return_http_data_only'] = True + if '_preload_content' in kwargs: + message = "Error! Please call the get_entity_by_roles_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + raise ValueError(message) + return self.get_entity_by_roles_with_http_info(roles, **kwargs) # noqa: E501 + + @validate_arguments + def get_entity_by_roles_with_http_info(self, roles : conlist(Role), **kwargs) -> ApiResponse: # noqa: E501 + """Get Entity By Roles # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_entity_by_roles_with_http_info(roles, async_req=True) + >>> result = thread.get() + + :param roles: (required) + :type roles: List[Role] + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _preload_content: if False, the ApiResponse.data will + be set to none and raw_data will store the + HTTP response body without reading/decoding. + Default is True. + :type _preload_content: bool, optional + :param _return_http_data_only: response data instead of ApiResponse + object with status code, headers, etc + :type _return_http_data_only: bool, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :type _request_auth: dict, optional + :type _content_type: string, optional: force content-type for the request + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: tuple(List[Entity], status_code(int), headers(HTTPHeaderDict)) + """ + + _params = locals() + + _all_params = [ + 'roles' + ] + _all_params.extend( + [ + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout', + '_request_auth', + '_content_type', + '_headers' + ] + ) + + # validate the arguments + for _key, _val in _params['kwargs'].items(): + if _key not in _all_params: + raise ApiTypeError( + "Got an unexpected keyword argument '%s'" + " to method get_entity_by_roles" % _key + ) + _params[_key] = _val + del _params['kwargs'] + + _collection_formats = {} + + # process the path parameters + _path_params = {} + + # process the query parameters + _query_params = [] + if _params.get('roles') is not None: # noqa: E501 + _query_params.append(('roles', _params['roles'])) + _collection_formats['roles'] = 'multi' + + # process the header parameters + _header_params = dict(_params.get('_headers', {})) + # process the form parameters + _form_params = [] + _files = {} + # process the body parameter + _body_params = None + # set the HTTP header `Accept` + _header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # authentication setting + _auth_settings = [] # noqa: E501 + + _response_types_map = { + '200': "List[Entity]", + '422': "HTTPValidationError", + } + + return self.api_client.call_api( + '/api/v1/entity_by_roles', 'GET', _path_params, _query_params, _header_params, diff --git a/pkgs/clan-cli/tests/openapi_client/api/eventmessages_api.py b/pkgs/clan-cli/tests/openapi_client/api/eventmessages_api.py index 092ef36..b509802 100644 --- a/pkgs/clan-cli/tests/openapi_client/api/eventmessages_api.py +++ b/pkgs/clan-cli/tests/openapi_client/api/eventmessages_api.py @@ -175,7 +175,7 @@ class EventmessagesApi: } return self.api_client.call_api( - '/api/v1/send_msg', 'POST', + '/api/v1/event_message', 'POST', _path_params, _query_params, _header_params, diff --git a/pkgs/clan-cli/tests/openapi_client/api/repositories_api.py b/pkgs/clan-cli/tests/openapi_client/api/repositories_api.py deleted file mode 100644 index bedb1e3..0000000 --- a/pkgs/clan-cli/tests/openapi_client/api/repositories_api.py +++ /dev/null @@ -1,192 +0,0 @@ -# coding: utf-8 - -""" - FastAPI - - No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - - The version of the OpenAPI document: 0.1.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import re # noqa: F401 -import io -import warnings - -from pydantic import validate_arguments, ValidationError - -from pydantic import StrictInt - -from typing import List, Optional - -from openapi_client.models.service import Service - -from openapi_client.api_client import ApiClient -from openapi_client.api_response import ApiResponse -from openapi_client.exceptions import ( # noqa: F401 - ApiTypeError, - ApiValueError -) - - -class RepositoriesApi: - """NOTE: This class is auto generated by OpenAPI Generator - Ref: https://openapi-generator.tech - - Do not edit the class manually. - """ - - def __init__(self, api_client=None) -> None: - if api_client is None: - api_client = ApiClient.get_default() - self.api_client = api_client - - @validate_arguments - def get_all_repositories(self, skip : Optional[StrictInt] = None, limit : Optional[StrictInt] = None, **kwargs) -> List[Service]: # noqa: E501 - """Get All Repositories # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_all_repositories(skip, limit, async_req=True) - >>> result = thread.get() - - :param skip: - :type skip: int - :param limit: - :type limit: int - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. - If one number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: List[Service] - """ - kwargs['_return_http_data_only'] = True - if '_preload_content' in kwargs: - message = "Error! Please call the get_all_repositories_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 - raise ValueError(message) - return self.get_all_repositories_with_http_info(skip, limit, **kwargs) # noqa: E501 - - @validate_arguments - def get_all_repositories_with_http_info(self, skip : Optional[StrictInt] = None, limit : Optional[StrictInt] = None, **kwargs) -> ApiResponse: # noqa: E501 - """Get All Repositories # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_all_repositories_with_http_info(skip, limit, async_req=True) - >>> result = thread.get() - - :param skip: - :type skip: int - :param limit: - :type limit: int - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(List[Service], status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = [ - 'skip', - 'limit' - ] - _all_params.extend( - [ - 'async_req', - '_return_http_data_only', - '_preload_content', - '_request_timeout', - '_request_auth', - '_content_type', - '_headers' - ] - ) - - # validate the arguments - for _key, _val in _params['kwargs'].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method get_all_repositories" % _key - ) - _params[_key] = _val - del _params['kwargs'] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - - # process the query parameters - _query_params = [] - if _params.get('skip') is not None: # noqa: E501 - _query_params.append(('skip', _params['skip'])) - - if _params.get('limit') is not None: # noqa: E501 - _query_params.append(('limit', _params['limit'])) - - # process the header parameters - _header_params = dict(_params.get('_headers', {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - ['application/json']) # noqa: E501 - - # authentication setting - _auth_settings = [] # noqa: E501 - - _response_types_map = { - '200': "List[Service]", - '422': "HTTPValidationError", - } - - return self.api_client.call_api( - '/api/v1/repositories', 'GET', - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get('async_req'), - _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 - _preload_content=_params.get('_preload_content', True), - _request_timeout=_params.get('_request_timeout'), - collection_formats=_collection_formats, - _request_auth=_params.get('_request_auth')) diff --git a/pkgs/clan-cli/tests/openapi_client/docs/EntitiesApi.md b/pkgs/clan-cli/tests/openapi_client/docs/EntitiesApi.md index dc621f8..4cc9b38 100644 --- a/pkgs/clan-cli/tests/openapi_client/docs/EntitiesApi.md +++ b/pkgs/clan-cli/tests/openapi_client/docs/EntitiesApi.md @@ -2,17 +2,18 @@ All URIs are relative to _http://localhost_ -| Method | HTTP request | Description | -| ----------------------------------------------------------------- | --------------------------------- | --------------------- | -| [**attach_entity**](EntitiesApi.md#attach_entity) | **POST** /api/v1/attach | Attach Entity | -| [**create_entity**](EntitiesApi.md#create_entity) | **POST** /api/v1/entity | Create Entity | -| [**delete_entity**](EntitiesApi.md#delete_entity) | **DELETE** /api/v1/entity | Delete Entity | -| [**detach_entity**](EntitiesApi.md#detach_entity) | **POST** /api/v1/detach | Detach Entity | -| [**get_all_entities**](EntitiesApi.md#get_all_entities) | **GET** /api/v1/entities | Get All Entities | -| [**get_attached_entities**](EntitiesApi.md#get_attached_entities) | **GET** /api/v1/attached_entities | Get Attached Entities | -| [**get_entity_by_did**](EntitiesApi.md#get_entity_by_did) | **GET** /api/v1/entity | Get Entity By Did | -| [**get_entity_by_name**](EntitiesApi.md#get_entity_by_name) | **GET** /api/v1/entity_by_name | Get Entity By Name | -| [**is_attached**](EntitiesApi.md#is_attached) | **GET** /api/v1/is_attached | Is Attached | +| Method | HTTP request | Description | +| ------------------------------------------------------------------------- | ------------------------------------- | ------------------------- | +| [**attach_entity**](EntitiesApi.md#attach_entity) | **PUT** /api/v1/attach | Attach Entity | +| [**create_entity**](EntitiesApi.md#create_entity) | **POST** /api/v1/entity | Create Entity | +| [**delete_entity**](EntitiesApi.md#delete_entity) | **DELETE** /api/v1/entity | Delete Entity | +| [**detach_entity**](EntitiesApi.md#detach_entity) | **PUT** /api/v1/detach | Detach Entity | +| [**get_all_entities**](EntitiesApi.md#get_all_entities) | **GET** /api/v1/entities | Get All Entities | +| [**get_attached_entities**](EntitiesApi.md#get_attached_entities) | **GET** /api/v1/attached_entities | Get Attached Entities | +| [**get_entity_by_did**](EntitiesApi.md#get_entity_by_did) | **GET** /api/v1/entity | Get Entity By Did | +| [**get_entity_by_name_or_did**](EntitiesApi.md#get_entity_by_name_or_did) | **GET** /api/v1/entity_by_name_or_did | Get Entity By Name Or Did | +| [**get_entity_by_roles**](EntitiesApi.md#get_entity_by_roles) | **GET** /api/v1/entity_by_roles | Get Entity By Roles | +| [**is_attached**](EntitiesApi.md#is_attached) | **GET** /api/v1/is_attached | Is Attached | # **attach_entity** @@ -486,11 +487,11 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **get_entity_by_name** +# **get_entity_by_name_or_did** -> Entity get_entity_by_name(entity_name) +> Entity get_entity_by_name_or_did(entity_name_or_did=entity_name_or_did) -Get Entity By Name +Get Entity By Name Or Did ### Example @@ -513,22 +514,22 @@ configuration = openapi_client.Configuration( with openapi_client.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = openapi_client.EntitiesApi(api_client) - entity_name = 'entity_name_example' # str | + entity_name_or_did = 'C1' # str | (optional) (default to 'C1') try: - # Get Entity By Name - api_response = api_instance.get_entity_by_name(entity_name) - print("The response of EntitiesApi->get_entity_by_name:\n") + # Get Entity By Name Or Did + api_response = api_instance.get_entity_by_name_or_did(entity_name_or_did=entity_name_or_did) + print("The response of EntitiesApi->get_entity_by_name_or_did:\n") pprint(api_response) except Exception as e: - print("Exception when calling EntitiesApi->get_entity_by_name: %s\n" % e) + print("Exception when calling EntitiesApi->get_entity_by_name_or_did: %s\n" % e) ``` ### Parameters -| Name | Type | Description | Notes | -| --------------- | ------- | ----------- | ----- | -| **entity_name** | **str** | | +| Name | Type | Description | Notes | +| ---------------------- | ------- | ----------- | ------------------------------------ | +| **entity_name_or_did** | **str** | | [optional] [default to 'C1'] | ### Return type @@ -552,6 +553,73 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **get_entity_by_roles** + +> List[Entity] get_entity_by_roles(roles) + +Get Entity By Roles + +### Example + +```python +import time +import os +import openapi_client +from openapi_client.models.entity import Entity +from openapi_client.models.role import Role +from openapi_client.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to http://localhost +# See configuration.py for a list of all supported configuration parameters. +configuration = openapi_client.Configuration( + host = "http://localhost" +) + + +# Enter a context with an instance of the API client +with openapi_client.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = openapi_client.EntitiesApi(api_client) + roles = [openapi_client.Role()] # List[Role] | + + try: + # Get Entity By Roles + api_response = api_instance.get_entity_by_roles(roles) + print("The response of EntitiesApi->get_entity_by_roles:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling EntitiesApi->get_entity_by_roles: %s\n" % e) +``` + +### Parameters + +| Name | Type | Description | Notes | +| --------- | ------------------------- | ----------- | ----- | +| **roles** | [**List[Role]**](Role.md) | | + +### Return type + +[**List[Entity]**](Entity.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | ------------------- | ---------------- | +| **200** | Successful Response | - | +| **422** | Validation Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **is_attached** > Dict[str, str] is_attached(entity_did=entity_did) diff --git a/pkgs/clan-cli/tests/openapi_client/docs/Entity.md b/pkgs/clan-cli/tests/openapi_client/docs/Entity.md index fa7efb2..83b3b80 100644 --- a/pkgs/clan-cli/tests/openapi_client/docs/Entity.md +++ b/pkgs/clan-cli/tests/openapi_client/docs/Entity.md @@ -2,15 +2,17 @@ ## Properties -| Name | Type | Description | Notes | -| -------------------- | ---------- | ----------- | ----- | -| **did** | **str** | | -| **name** | **str** | | -| **ip** | **str** | | -| **visible** | **bool** | | -| **other** | **object** | | -| **attached** | **bool** | | -| **stop_health_task** | **bool** | | +| Name | Type | Description | Notes | +| -------------------- | ------------------------- | ----------- | ----- | +| **did** | **str** | | +| **name** | **str** | | +| **ip** | **str** | | +| **network** | **str** | | +| **visible** | **bool** | | +| **other** | **object** | | +| **attached** | **bool** | | +| **stop_health_task** | **bool** | | +| **roles** | [**List[Role]**](Role.md) | | ## Example diff --git a/pkgs/clan-cli/tests/openapi_client/docs/EntityCreate.md b/pkgs/clan-cli/tests/openapi_client/docs/EntityCreate.md index 4fff16a..2b06e83 100644 --- a/pkgs/clan-cli/tests/openapi_client/docs/EntityCreate.md +++ b/pkgs/clan-cli/tests/openapi_client/docs/EntityCreate.md @@ -2,13 +2,15 @@ ## Properties -| Name | Type | Description | Notes | -| ----------- | ---------- | ----------- | ----- | -| **did** | **str** | | -| **name** | **str** | | -| **ip** | **str** | | -| **visible** | **bool** | | -| **other** | **object** | | +| Name | Type | Description | Notes | +| ----------- | ------------------------- | ----------- | ----- | +| **did** | **str** | | +| **name** | **str** | | +| **ip** | **str** | | +| **network** | **str** | | +| **visible** | **bool** | | +| **other** | **object** | | +| **roles** | [**List[Role]**](Role.md) | | ## Example diff --git a/pkgs/clan-cli/tests/openapi_client/docs/Eventmessage.md b/pkgs/clan-cli/tests/openapi_client/docs/Eventmessage.md index cbe65cb..96427cd 100644 --- a/pkgs/clan-cli/tests/openapi_client/docs/Eventmessage.md +++ b/pkgs/clan-cli/tests/openapi_client/docs/Eventmessage.md @@ -4,7 +4,6 @@ | Name | Type | Description | Notes | | ------------- | ---------- | ----------- | ----- | -| **id** | **int** | | | **timestamp** | **int** | | | **group** | **int** | | | **group_id** | **int** | | @@ -12,6 +11,7 @@ | **src_did** | **str** | | | **des_did** | **str** | | | **msg** | **object** | | +| **id** | **int** | | ## Example diff --git a/pkgs/clan-cli/tests/openapi_client/docs/EventmessageCreate.md b/pkgs/clan-cli/tests/openapi_client/docs/EventmessageCreate.md index eb6f16d..4ed2b69 100644 --- a/pkgs/clan-cli/tests/openapi_client/docs/EventmessageCreate.md +++ b/pkgs/clan-cli/tests/openapi_client/docs/EventmessageCreate.md @@ -4,7 +4,6 @@ | Name | Type | Description | Notes | | ------------- | ---------- | ----------- | ----- | -| **id** | **int** | | | **timestamp** | **int** | | | **group** | **int** | | | **group_id** | **int** | | diff --git a/pkgs/clan-cli/tests/openapi_client/docs/EventmessagesApi.md b/pkgs/clan-cli/tests/openapi_client/docs/EventmessagesApi.md index d6affb9..c8f26b1 100644 --- a/pkgs/clan-cli/tests/openapi_client/docs/EventmessagesApi.md +++ b/pkgs/clan-cli/tests/openapi_client/docs/EventmessagesApi.md @@ -4,7 +4,7 @@ All URIs are relative to _http://localhost_ | Method | HTTP request | Description | | ---------------------------------------------------------------------- | ------------------------------ | --------------------- | -| [**create_eventmessage**](EventmessagesApi.md#create_eventmessage) | **POST** /api/v1/send_msg | Create Eventmessage | +| [**create_eventmessage**](EventmessagesApi.md#create_eventmessage) | **POST** /api/v1/event_message | Create Eventmessage | | [**get_all_eventmessages**](EventmessagesApi.md#get_all_eventmessages) | **GET** /api/v1/event_messages | Get All Eventmessages | # **create_eventmessage** diff --git a/pkgs/clan-cli/tests/openapi_client/docs/RepositoriesApi.md b/pkgs/clan-cli/tests/openapi_client/docs/RepositoriesApi.md deleted file mode 100644 index ff735f0..0000000 --- a/pkgs/clan-cli/tests/openapi_client/docs/RepositoriesApi.md +++ /dev/null @@ -1,75 +0,0 @@ -# openapi_client.RepositoriesApi - -All URIs are relative to _http://localhost_ - -| Method | HTTP request | Description | -| ------------------------------------------------------------------- | ---------------------------- | -------------------- | -| [**get_all_repositories**](RepositoriesApi.md#get_all_repositories) | **GET** /api/v1/repositories | Get All Repositories | - -# **get_all_repositories** - -> List[Service] get_all_repositories(skip=skip, limit=limit) - -Get All Repositories - -### Example - -```python -import time -import os -import openapi_client -from openapi_client.models.service import Service -from openapi_client.rest import ApiException -from pprint import pprint - -# Defining the host is optional and defaults to http://localhost -# See configuration.py for a list of all supported configuration parameters. -configuration = openapi_client.Configuration( - host = "http://localhost" -) - - -# Enter a context with an instance of the API client -with openapi_client.ApiClient(configuration) as api_client: - # Create an instance of the API class - api_instance = openapi_client.RepositoriesApi(api_client) - skip = 0 # int | (optional) (default to 0) - limit = 100 # int | (optional) (default to 100) - - try: - # Get All Repositories - api_response = api_instance.get_all_repositories(skip=skip, limit=limit) - print("The response of RepositoriesApi->get_all_repositories:\n") - pprint(api_response) - except Exception as e: - print("Exception when calling RepositoriesApi->get_all_repositories: %s\n" % e) -``` - -### Parameters - -| Name | Type | Description | Notes | -| --------- | ------- | ----------- | --------------------------- | -| **skip** | **int** | | [optional] [default to 0] | -| **limit** | **int** | | [optional] [default to 100] | - -### Return type - -[**List[Service]**](Service.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: application/json - -### HTTP response details - -| Status code | Description | Response headers | -| ----------- | ------------------- | ---------------- | -| **200** | Successful Response | - | -| **422** | Validation Error | - | - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/pkgs/clan-cli/tests/openapi_client/docs/Role.md b/pkgs/clan-cli/tests/openapi_client/docs/Role.md new file mode 100644 index 0000000..a60cc52 --- /dev/null +++ b/pkgs/clan-cli/tests/openapi_client/docs/Role.md @@ -0,0 +1,10 @@ +# Role + +An enumeration. + +## Properties + +| Name | Type | Description | Notes | +| ---- | ---- | ----------- | ----- | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkgs/clan-cli/tests/openapi_client/models/__init__.py b/pkgs/clan-cli/tests/openapi_client/models/__init__.py index 4460d22..b211606 100644 --- a/pkgs/clan-cli/tests/openapi_client/models/__init__.py +++ b/pkgs/clan-cli/tests/openapi_client/models/__init__.py @@ -21,6 +21,7 @@ from openapi_client.models.eventmessage_create import EventmessageCreate from openapi_client.models.http_validation_error import HTTPValidationError from openapi_client.models.machine import Machine from openapi_client.models.resolution import Resolution +from openapi_client.models.role import Role from openapi_client.models.service import Service from openapi_client.models.service_create import ServiceCreate from openapi_client.models.status import Status diff --git a/pkgs/clan-cli/tests/openapi_client/models/entity.py b/pkgs/clan-cli/tests/openapi_client/models/entity.py index 0ff4d16..b60806c 100644 --- a/pkgs/clan-cli/tests/openapi_client/models/entity.py +++ b/pkgs/clan-cli/tests/openapi_client/models/entity.py @@ -18,8 +18,9 @@ import re # noqa: F401 import json -from typing import Any, Dict -from pydantic import BaseModel, Field, StrictBool, StrictStr +from typing import Any, Dict, List +from pydantic import BaseModel, Field, StrictBool, StrictStr, conlist +from openapi_client.models.role import Role class Entity(BaseModel): """ @@ -28,11 +29,13 @@ class Entity(BaseModel): did: StrictStr = Field(...) name: StrictStr = Field(...) ip: StrictStr = Field(...) + network: StrictStr = Field(...) visible: StrictBool = Field(...) other: Dict[str, Any] = Field(...) attached: StrictBool = Field(...) stop_health_task: StrictBool = Field(...) - __properties = ["did", "name", "ip", "visible", "other", "attached", "stop_health_task"] + roles: conlist(Role) = Field(...) + __properties = ["did", "name", "ip", "network", "visible", "other", "attached", "stop_health_task", "roles"] class Config: """Pydantic configuration""" @@ -73,10 +76,12 @@ class Entity(BaseModel): "did": obj.get("did"), "name": obj.get("name"), "ip": obj.get("ip"), + "network": obj.get("network"), "visible": obj.get("visible"), "other": obj.get("other"), "attached": obj.get("attached"), - "stop_health_task": obj.get("stop_health_task") + "stop_health_task": obj.get("stop_health_task"), + "roles": obj.get("roles") }) return _obj diff --git a/pkgs/clan-cli/tests/openapi_client/models/entity_create.py b/pkgs/clan-cli/tests/openapi_client/models/entity_create.py index f9df72b..1775ccb 100644 --- a/pkgs/clan-cli/tests/openapi_client/models/entity_create.py +++ b/pkgs/clan-cli/tests/openapi_client/models/entity_create.py @@ -18,8 +18,9 @@ import re # noqa: F401 import json -from typing import Any, Dict -from pydantic import BaseModel, Field, StrictBool, StrictStr +from typing import Any, Dict, List +from pydantic import BaseModel, Field, StrictBool, StrictStr, conlist +from openapi_client.models.role import Role class EntityCreate(BaseModel): """ @@ -28,9 +29,11 @@ class EntityCreate(BaseModel): did: StrictStr = Field(...) name: StrictStr = Field(...) ip: StrictStr = Field(...) + network: StrictStr = Field(...) visible: StrictBool = Field(...) other: Dict[str, Any] = Field(...) - __properties = ["did", "name", "ip", "visible", "other"] + roles: conlist(Role) = Field(...) + __properties = ["did", "name", "ip", "network", "visible", "other", "roles"] class Config: """Pydantic configuration""" @@ -71,8 +74,10 @@ class EntityCreate(BaseModel): "did": obj.get("did"), "name": obj.get("name"), "ip": obj.get("ip"), + "network": obj.get("network"), "visible": obj.get("visible"), - "other": obj.get("other") + "other": obj.get("other"), + "roles": obj.get("roles") }) return _obj diff --git a/pkgs/clan-cli/tests/openapi_client/models/eventmessage.py b/pkgs/clan-cli/tests/openapi_client/models/eventmessage.py index ece8617..4f0eb94 100644 --- a/pkgs/clan-cli/tests/openapi_client/models/eventmessage.py +++ b/pkgs/clan-cli/tests/openapi_client/models/eventmessage.py @@ -25,7 +25,6 @@ class Eventmessage(BaseModel): """ Eventmessage """ - id: StrictInt = Field(...) timestamp: StrictInt = Field(...) group: StrictInt = Field(...) group_id: StrictInt = Field(...) @@ -33,7 +32,8 @@ class Eventmessage(BaseModel): src_did: StrictStr = Field(...) des_did: StrictStr = Field(...) msg: Dict[str, Any] = Field(...) - __properties = ["id", "timestamp", "group", "group_id", "msg_type", "src_did", "des_did", "msg"] + id: StrictInt = Field(...) + __properties = ["timestamp", "group", "group_id", "msg_type", "src_did", "des_did", "msg", "id"] class Config: """Pydantic configuration""" @@ -71,14 +71,14 @@ class Eventmessage(BaseModel): return Eventmessage.parse_obj(obj) _obj = Eventmessage.parse_obj({ - "id": obj.get("id"), "timestamp": obj.get("timestamp"), "group": obj.get("group"), "group_id": obj.get("group_id"), "msg_type": obj.get("msg_type"), "src_did": obj.get("src_did"), "des_did": obj.get("des_did"), - "msg": obj.get("msg") + "msg": obj.get("msg"), + "id": obj.get("id") }) return _obj diff --git a/pkgs/clan-cli/tests/openapi_client/models/eventmessage_create.py b/pkgs/clan-cli/tests/openapi_client/models/eventmessage_create.py index 34915bb..cb1a740 100644 --- a/pkgs/clan-cli/tests/openapi_client/models/eventmessage_create.py +++ b/pkgs/clan-cli/tests/openapi_client/models/eventmessage_create.py @@ -25,7 +25,6 @@ class EventmessageCreate(BaseModel): """ EventmessageCreate """ - id: StrictInt = Field(...) timestamp: StrictInt = Field(...) group: StrictInt = Field(...) group_id: StrictInt = Field(...) @@ -33,7 +32,7 @@ class EventmessageCreate(BaseModel): src_did: StrictStr = Field(...) des_did: StrictStr = Field(...) msg: Dict[str, Any] = Field(...) - __properties = ["id", "timestamp", "group", "group_id", "msg_type", "src_did", "des_did", "msg"] + __properties = ["timestamp", "group", "group_id", "msg_type", "src_did", "des_did", "msg"] class Config: """Pydantic configuration""" @@ -71,7 +70,6 @@ class EventmessageCreate(BaseModel): return EventmessageCreate.parse_obj(obj) _obj = EventmessageCreate.parse_obj({ - "id": obj.get("id"), "timestamp": obj.get("timestamp"), "group": obj.get("group"), "group_id": obj.get("group_id"), diff --git a/pkgs/clan-cli/tests/openapi_client/models/role.py b/pkgs/clan-cli/tests/openapi_client/models/role.py new file mode 100644 index 0000000..1af9d78 --- /dev/null +++ b/pkgs/clan-cli/tests/openapi_client/models/role.py @@ -0,0 +1,41 @@ +# coding: utf-8 + +""" + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + The version of the OpenAPI document: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import json +import pprint +import re # noqa: F401 +from aenum import Enum, no_arg + + + + + +class Role(str, Enum): + """ + An enumeration. + """ + + """ + allowed enum values + """ + SERVICE_PROSUMER = 'service_prosumer' + AP = 'AP' + DLG = 'DLG' + + @classmethod + def from_json(cls, json_str: str) -> Role: + """Create an instance of Role from a JSON string""" + return Role(json.loads(json_str)) + + diff --git a/pkgs/clan-cli/tests/openapi_client/test/test_eventmessage.py b/pkgs/clan-cli/tests/openapi_client/test/test_eventmessage.py deleted file mode 100644 index 21852d5..0000000 --- a/pkgs/clan-cli/tests/openapi_client/test/test_eventmessage.py +++ /dev/null @@ -1,67 +0,0 @@ -# coding: utf-8 - -""" - FastAPI - - No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - - The version of the OpenAPI document: 0.1.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import unittest -import datetime - -from openapi_client.models.eventmessage import Eventmessage # noqa: E501 - -class TestEventmessage(unittest.TestCase): - """Eventmessage unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def make_instance(self, include_optional) -> Eventmessage: - """Test Eventmessage - include_option is a boolean, when False only required - params are included, when True both required and - optional params are included """ - # uncomment below to create an instance of `Eventmessage` - """ - model = Eventmessage() # noqa: E501 - if include_optional: - return Eventmessage( - id = 123456, - timestamp = 1234123413, - group = 1, - group_id = 12345, - msg_type = 1, - src_did = 'did:sov:test:2234', - des_did = 'did:sov:test:1234', - msg = {optinal=values} - ) - else: - return Eventmessage( - id = 123456, - timestamp = 1234123413, - group = 1, - group_id = 12345, - msg_type = 1, - src_did = 'did:sov:test:2234', - des_did = 'did:sov:test:1234', - msg = {optinal=values}, - ) - """ - - def testEventmessage(self): - """Test Eventmessage""" - # inst_req_only = self.make_instance(include_optional=False) - # inst_req_and_optional = self.make_instance(include_optional=True) - -if __name__ == '__main__': - unittest.main() diff --git a/pkgs/clan-cli/tests/openapi_client/test/test_eventmessage_create.py b/pkgs/clan-cli/tests/openapi_client/test/test_eventmessage_create.py deleted file mode 100644 index 8bc282d..0000000 --- a/pkgs/clan-cli/tests/openapi_client/test/test_eventmessage_create.py +++ /dev/null @@ -1,67 +0,0 @@ -# coding: utf-8 - -""" - FastAPI - - No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - - The version of the OpenAPI document: 0.1.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import unittest -import datetime - -from openapi_client.models.eventmessage_create import EventmessageCreate # noqa: E501 - -class TestEventmessageCreate(unittest.TestCase): - """EventmessageCreate unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def make_instance(self, include_optional) -> EventmessageCreate: - """Test EventmessageCreate - include_option is a boolean, when False only required - params are included, when True both required and - optional params are included """ - # uncomment below to create an instance of `EventmessageCreate` - """ - model = EventmessageCreate() # noqa: E501 - if include_optional: - return EventmessageCreate( - id = 123456, - timestamp = 1234123413, - group = 1, - group_id = 12345, - msg_type = 1, - src_did = 'did:sov:test:2234', - des_did = 'did:sov:test:1234', - msg = {optinal=values} - ) - else: - return EventmessageCreate( - id = 123456, - timestamp = 1234123413, - group = 1, - group_id = 12345, - msg_type = 1, - src_did = 'did:sov:test:2234', - des_did = 'did:sov:test:1234', - msg = {optinal=values}, - ) - """ - - def testEventmessageCreate(self): - """Test EventmessageCreate""" - # inst_req_only = self.make_instance(include_optional=False) - # inst_req_and_optional = self.make_instance(include_optional=True) - -if __name__ == '__main__': - unittest.main() diff --git a/pkgs/clan-cli/tests/openapi_client/test/test_eventmessages_api.py b/pkgs/clan-cli/tests/openapi_client/test/test_eventmessages_api.py deleted file mode 100644 index e2841ab..0000000 --- a/pkgs/clan-cli/tests/openapi_client/test/test_eventmessages_api.py +++ /dev/null @@ -1,45 +0,0 @@ -# coding: utf-8 - -""" - FastAPI - - No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - - The version of the OpenAPI document: 0.1.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import unittest - -from openapi_client.api.eventmessages_api import EventmessagesApi # noqa: E501 - - -class TestEventmessagesApi(unittest.TestCase): - """EventmessagesApi unit test stubs""" - - def setUp(self) -> None: - self.api = EventmessagesApi() # noqa: E501 - - def tearDown(self) -> None: - pass - - def test_create_eventmessage(self) -> None: - """Test case for create_eventmessage - - Create Eventmessage # noqa: E501 - """ - pass - - def test_get_all_eventmessages(self) -> None: - """Test case for get_all_eventmessages - - Get All Eventmessages # noqa: E501 - """ - pass - - -if __name__ == '__main__': - unittest.main() diff --git a/pkgs/clan-cli/tests/test_db_api.py b/pkgs/clan-cli/tests/test_db_api.py index b619729..6e2911b 100644 --- a/pkgs/clan-cli/tests/test_db_api.py +++ b/pkgs/clan-cli/tests/test_db_api.py @@ -13,13 +13,21 @@ from openapi_client.models import ( Eventmessage, EventmessageCreate, Machine, + Role, ServiceCreate, Status, ) +import clan_cli.config as config + random.seed(42) +host = config.host +port_dlg = config.port_dlg +port_ap = config.port_ap +port_client_base = config.port_client_base + num_uuids = 100 uuids = [str(uuid.UUID(int=random.getrandbits(128))) for i in range(num_uuids)] @@ -30,17 +38,39 @@ def test_health(api_client: ApiClient) -> None: assert res.status == Status.ONLINE -def create_entities(num: int = 10) -> list[EntityCreate]: +def create_entities(num: int = 10, role: str = "entity") -> list[EntityCreate]: res = [] for i in range(num): en = EntityCreate( did=f"did:sov:test:12{i}", name=f"C{i}", - ip=f"127.0.0.1:{7000+i}", + ip=f"{host}:{port_client_base+i}", + network="255.255.0.0", + roles=[Role("service_prosumer")], visible=True, other={}, ) res.append(en) + dlg = EntityCreate( + did=f"did:sov:test:{port_dlg}", + name="DLG", + ip=f"{host}:{port_dlg}", + network="255.255.0.0", + roles=[Role("DLG")], + visible=True, + other={}, + ) + res.append(dlg) + ap = EntityCreate( + did=f"did:sov:test:{port_ap}", + name="AP", + ip=f"{host}:{port_ap}", + network="255.255.0.0", + roles=[Role("AP")], + visible=True, + other={}, + ) + res.append(ap) return res @@ -60,6 +90,7 @@ def create_service(idx: int, entity: Entity) -> ServiceCreate: def test_create_entities(api_client: ApiClient) -> None: api = EntitiesApi(api_client=api_client) + for own_entity in create_entities(): res: Entity = api.create_entity(own_entity) assert res.did == own_entity.did @@ -85,7 +116,6 @@ def create_eventmessages(num: int = 2) -> list[EventmessageCreate]: for i in range(num): group_id = i % 5 + random.getrandbits(6) em_req_send = EventmessageCreate( - id=random.getrandbits(18), timestamp=starttime + i * 10, group=i % 5, group_id=group_id, @@ -96,7 +126,6 @@ def create_eventmessages(num: int = 2) -> list[EventmessageCreate]: ) res.append(em_req_send) em_req_rec = EventmessageCreate( - id=random.getrandbits(18), timestamp=starttime + (i * 10) + 2, group=i % 5, group_id=group_id, @@ -108,7 +137,6 @@ def create_eventmessages(num: int = 2) -> list[EventmessageCreate]: res.append(em_req_rec) group_id = i % 5 + random.getrandbits(6) em_res_send = EventmessageCreate( - id=random.getrandbits(18), timestamp=starttime + i * 10 + 4, group=i % 5, group_id=group_id, @@ -119,7 +147,6 @@ def create_eventmessages(num: int = 2) -> list[EventmessageCreate]: ) res.append(em_res_send) em_res_rec = EventmessageCreate( - id=random.getrandbits(6), timestamp=starttime + (i * 10) + 8, group=i % 5, group_id=group_id, @@ -135,8 +162,10 @@ def create_eventmessages(num: int = 2) -> list[EventmessageCreate]: def test_create_eventmessages(api_client: ApiClient) -> None: api = EventmessagesApi(api_client=api_client) assert [] == api.get_all_eventmessages() - for own_eventmsg in create_eventmessages(): + for idx, own_eventmsg in enumerate(create_eventmessages()): res: Eventmessage = api.create_eventmessage(own_eventmsg) - # breakpoint() - assert res.id == own_eventmsg.id + + assert res.msg == own_eventmsg.msg + assert res.src_did == own_eventmsg.src_did + assert res.des_did == own_eventmsg.des_did assert [] != api.get_all_eventmessages() diff --git a/pkgs/ui/nix/ui-assets.nix b/pkgs/ui/nix/ui-assets.nix index 1914722..2bf9756 100644 --- a/pkgs/ui/nix/ui-assets.nix +++ b/pkgs/ui/nix/ui-assets.nix @@ -1,5 +1,5 @@ { fetchzip }: fetchzip { - url = "https://gitea.gchq.icu/api/packages/IoSL/generic/IoSL-service-aware-frontend/0zz102k9sm0q9rlkrb06fkz2ap8i42gm65wr1qp4lxsg9kpgca70/assets.tar.gz"; - sha256 = "0zz102k9sm0q9rlkrb06fkz2ap8i42gm65wr1qp4lxsg9kpgca70"; + url = "https://gitea.gchq.icu/api/packages/IoSL/generic/IoSL-service-aware-frontend/04h6w20fgq1zd4qzqm1rqkyk1s3mxnra1088icdrshsdm29x81xa/assets.tar.gz"; + sha256 = "04h6w20fgq1zd4qzqm1rqkyk1s3mxnra1088icdrshsdm29x81xa"; } diff --git a/pkgs/ui/src/app/layout.tsx b/pkgs/ui/src/app/layout.tsx index 9d1eb85..c8c34c3 100644 --- a/pkgs/ui/src/app/layout.tsx +++ b/pkgs/ui/src/app/layout.tsx @@ -11,7 +11,6 @@ import { import { StyledEngineProvider } from "@mui/material/styles"; import axios from "axios"; import localFont from "next/font/local"; -import Image from "next/image"; import * as React from "react"; import { Toaster } from "react-hot-toast"; import "./globals.css"; @@ -85,25 +84,15 @@ export default function RootLayout({ className={tw`${!showSidebarDerived && translate } flex h-full w-full flex-col overflow-y-scroll transition-[margin] duration-150 ease-in-out`} > -