Merge branch 'main' into frontend
Some checks failed
checks-impure / test (pull_request) Successful in 29s
checks / test (pull_request) Has been cancelled

This commit is contained in:
2023-12-09 19:15:13 +01:00
10 changed files with 109 additions and 63 deletions

View File

@@ -1,6 +1,6 @@
# 1Service Aware Network Project Repo # Service Aware Network Project Repo
Welcome to our website repository! This repo is designed to help you and your team build high-quality websites efficiently. We've carefully chosen the technologies to make development smooth and enjoyable. Here's what you can expect from this template: Welcome to our website repository! This repo is designed to build high-quality websites efficiently. We've carefully chosen the technologies to make development smooth and enjoyable.
**Frontend**: Our frontend is powered by [React NextJS](https://nextjs.org/), a popular and versatile framework for building web applications. **Frontend**: Our frontend is powered by [React NextJS](https://nextjs.org/), a popular and versatile framework for building web applications.
@@ -26,6 +26,12 @@ Let's get your development environment up and running:
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
``` ```
On Windows Subsystem for Linux (WSL) the installer will fail and tell you what to do. Execute the command from the error message and then afterwards execute:
```bash
sudo echo "experimental-features = nix-command flakes" > '/etc/nix/nix.conf'
```
2. **Install direnv**: 2. **Install direnv**:
- Download the direnv package from [here](https://direnv.net/docs/installation.html) or run the following command: - Download the direnv package from [here](https://direnv.net/docs/installation.html) or run the following command:
@@ -45,6 +51,7 @@ Let's get your development environment up and running:
4. **Clone the Repository and Navigate**: 4. **Clone the Repository and Navigate**:
- Clone this repository and navigate to it. - Clone this repository and navigate to it.
- If you are under Windows Subystem For Linux (WSL) please clone the repository to the home folder of your Linux. Do NOT clone it onto your Windows machine!
5. **Allow .envrc**: 5. **Allow .envrc**:
@@ -66,9 +73,10 @@ Let's get your development environment up and running:
- To start the backend server, execute: - To start the backend server, execute:
```bash ```bash
clan webui --reload --no-open --log-level debug clan webui --reload --no-open --log-level debug --populate
``` ```
- The server will automatically restart if any Python files change. - The server will automatically restart if any Python files change.
- The `--populate` flag will automatically populate the database with dummy data
8. **Build the Frontend**: 8. **Build the Frontend**:
@@ -95,19 +103,19 @@ Let's set up your Git workflow to collaborate effectively:
```bash ```bash
tea login add tea login add
``` ```
- Go to https://gitea.gchq.icu/user/settings/applications and create token with all privileges
- Fill out the prompt as follows: - Fill out the prompt as follows:
- URL of Gitea instance: `https://gitea.gchq.icu` - URL of Gitea instance: `https://gitea.gchq.icu`
- Name of new Login [gitea.gchq.icu]: `gitea.gchq.icu:7171` - Name of new Login [gitea.gchq.icu]: `gitea.gchq.icu:7171`
- Do you have an access token? No - Do you have an access token? Yes
- Username: YourUsername - Token: \***\*\*\*\***
- Password: YourPassword
- Set Optional settings: No - Set Optional settings: No
2. **Git Workflow**: 2. **Git Workflow**:
1. Add your changes to Git using `git add <file1> <file2>`. 1. Add your changes to Git using `git add <file1> <file2>`.
2. Run `nix fmt` to lint your files. 2. Run `nix fmt` to lint your files. This will format your files and make changes!
3. Commit your changes with a descriptive message: `git commit -a -m "My descriptive commit message"`. 3. Commit your changes and those of nix fmt with a descriptive message: `git commit -a -m "My descriptive commit message"`.
4. Make sure your branch has the latest changes from upstream by executing: 4. Make sure your branch has the latest changes from upstream by executing:
```bash ```bash
git fetch && git rebase origin/main --autostash git fetch && git rebase origin/main --autostash
@@ -188,8 +196,8 @@ If you need to inspect the Nix sandbox while running tests, follow these steps:
2. Use `cntr` and `psgrep` to attach to the Nix sandbox. This allows you to interactively debug your code while it's paused. For example: 2. Use `cntr` and `psgrep` to attach to the Nix sandbox. This allows you to interactively debug your code while it's paused. For example:
```bash ```bash
cntr exec -w your_sandbox_name
psgrep -a -x your_python_process_name psgrep -a -x your_python_process_name
cntr attach <pid>
``` ```
These debugging and testing methods will help you identify and fix issues in your backend code efficiently, ensuring the reliability and robustness of your application. These debugging and testing methods will help you identify and fix issues in your backend code efficiently, ensuring the reliability and robustness of your application.

View File

@@ -22,6 +22,12 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
parser.add_argument( parser.add_argument(
"--host", type=str, default="localhost", help="Host to listen on" "--host", type=str, default="localhost", help="Host to listen on"
) )
parser.add_argument(
"--populate",
action="store_true",
help="Populate the database with dummy data",
default=False,
)
parser.add_argument( parser.add_argument(
"--no-open", action="store_true", help="Don't open the browser", default=False "--no-open", action="store_true", help="Don't open the browser", default=False
) )

View File

@@ -35,10 +35,11 @@ def setup_app() -> FastAPI:
# bind sql engine # bind sql engine
# TODO comment aut and add flag to run with pupulated data rm *.sql run pytest with marked then start clan webui # TODO comment aut and add flag to run with pupulated data rm *.sql run pytest with marked then start clan webui
# https://docs.pytest.org/en/7.1.x/example/markers.html # https://docs.pytest.org/en/7.1.x/example/markers.html
sql_models.Base.metadata.drop_all(engine) # sql_models.Base.metadata.drop_all(engine)
sql_models.Base.metadata.create_all(bind=engine) sql_models.Base.metadata.create_all(bind=engine)
app = FastAPI(lifespan=lifespan) app = FastAPI(lifespan=lifespan, swagger_ui_parameters={"tryItOutEnabled": True})
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=origins, allow_origins=origins,

View File

@@ -25,7 +25,7 @@ def sql_error_handler(request: Request, exc: SQLAlchemyError) -> JSONResponse:
def clan_error_handler(request: Request, exc: ClanError) -> JSONResponse: def clan_error_handler(request: Request, exc: ClanError) -> JSONResponse:
log.error("ClanError: %s", exc) log.exception(exc)
detail = [ detail = [
{ {
"loc": [], "loc": [],

View File

@@ -1,3 +1,4 @@
import logging
import time import time
from typing import List, Optional from typing import List, Optional
@@ -5,6 +6,7 @@ import httpx
from fastapi import APIRouter, BackgroundTasks, Depends from fastapi import APIRouter, BackgroundTasks, Depends
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from ...errors import ClanError
from .. import sql_crud, sql_db, sql_models from .. import sql_crud, sql_db, sql_models
from ..schemas import ( from ..schemas import (
Consumer, Consumer,
@@ -20,6 +22,8 @@ from ..tags import Tags
router = APIRouter() router = APIRouter()
log = logging.getLogger(__name__)
######################### #########################
# # # #
@@ -141,11 +145,7 @@ def get_repository(
@router.post("/api/v1/create_entity", response_model=Entity, tags=[Tags.entities]) @router.post("/api/v1/create_entity", response_model=Entity, tags=[Tags.entities])
def create_entity( def create_entity(
entity: EntityCreate, db: Session = Depends(sql_db.get_db) entity: EntityCreate, db: Session = Depends(sql_db.get_db)
) -> EntityCreate | str: ) -> EntityCreate:
# todo checken ob schon da ...
if sql_crud.get_entity_by_did(db, did=entity.did):
print("did already exsists")
return "Error did already exsists in db"
return sql_crud.create_entity(db, entity) return sql_crud.create_entity(db, entity)
@@ -178,7 +178,7 @@ def get_attached_entities(
return entities return entities
@router.post("/api/v1/detach") @router.post("/api/v1/detach", response_model=Entity, tags=[Tags.entities])
async def detach( async def detach(
background_tasks: BackgroundTasks, background_tasks: BackgroundTasks,
entity_did: str = "did:sov:test:1234", entity_did: str = "did:sov:test:1234",
@@ -186,13 +186,11 @@ async def detach(
limit: int = 100, limit: int = 100,
db: Session = Depends(sql_db.get_db), db: Session = Depends(sql_db.get_db),
) -> dict[str, str]: ) -> dict[str, str]:
background_tasks.add_task( entity = sql_crud.set_attached_by_entity_did(db, entity_did, False)
sql_crud.set_attached_by_entity_did, db, entity_did, False return entity
)
return {"message": "Detaching in the background"}
@router.post("/api/v1/attach") @router.post("/api/v1/attach", tags=[Tags.entities])
async def attach( async def attach(
background_tasks: BackgroundTasks, background_tasks: BackgroundTasks,
entity_did: str = "did:sov:test:1234", entity_did: str = "did:sov:test:1234",
@@ -200,27 +198,28 @@ async def attach(
limit: int = 100, limit: int = 100,
db: Session = Depends(sql_db.get_db), db: Session = Depends(sql_db.get_db),
) -> dict[str, str]: ) -> dict[str, str]:
if sql_crud.get_entity_by_did(db, entity_did) is None:
raise ClanError(f"Entity with did '{entity_did}' not found")
background_tasks.add_task(attach_entity, db, entity_did) background_tasks.add_task(attach_entity, db, entity_did)
return {"message": "Attaching in the background"} return {"message": "Attaching in the background"}
# TODO
def attach_entity(db: Session, entity_did: str) -> None: def attach_entity(db: Session, entity_did: str) -> None:
db_entity = sql_crud.set_attached_by_entity_did(db, entity_did, True) db_entity = sql_crud.set_attached_by_entity_did(db, entity_did, True)
try: try:
if db_entity is not None: while db_entity.attached:
while db_entity.attached: # query status endpoint
# query status endpoint # https://www.python-httpx.org/
# https://www.python-httpx.org/ response = httpx.get(f"http://{db_entity.ip}", timeout=2)
response = httpx.get(f"http://{db_entity.ip}", timeout=2) print(response)
print(response) # test with:
# test with: # while true ; do printf 'HTTP/1.1 200 OK\r\n\r\ncool, thanks' | nc -l -N localhost 5555 ; done
# while true ; do printf 'HTTP/1.1 200 OK\r\n\r\ncool, thanks' | nc -l -N localhost 5555 ; done # client test (apt install python3-httpx):
# client test (apt install python3-httpx): # httpx http://localhost:5555
# httpx http://localhost:5555 # except not reached set false
# except not reached set false time.sleep(1)
time.sleep(1) except Exception:
except Exception as e: log.warning(f"Entity {entity_did} not reachable. Setting attached to false")
print(e)
if db_entity is not None: db_entity = sql_crud.set_attached_by_entity_did(db, entity_did, False)
db_entity = sql_crud.set_attached_by_entity_did(db, entity_did, False)

View File

@@ -27,7 +27,7 @@ class ProducerBase(BaseModel):
service_type: str = "3D Printing" service_type: str = "3D Printing"
endpoint_url: str = "http://127.0.0.1:8000" endpoint_url: str = "http://127.0.0.1:8000"
status: str = "unknown" status: str = "unknown"
other: dict = {"test": "test"} other: dict = {"action": ["register", "deregister", "delete", "create"]}
class ProducerCreate(ProducerBase): class ProducerCreate(ProducerBase):
@@ -91,7 +91,11 @@ class EntityBase(BaseModel):
name: str = "C1" name: str = "C1"
ip: str = "127.0.0.1" ip: str = "127.0.0.1"
attached: bool = False attached: bool = False
other: dict = {"test": "test"} visible: bool = True
other: dict = {
"network": "Carlo's Home Network",
"roles": ["service repository", "service prosumer"],
}
class EntityCreate(EntityBase): class EntityCreate(EntityBase):

View File

@@ -105,6 +105,27 @@ def start_server(args: argparse.Namespace) -> None:
if not args.no_open: if not args.no_open:
Thread(target=open_browser, args=(base_url, args.sub_url)).start() Thread(target=open_browser, args=(base_url, args.sub_url)).start()
# DELETE all data from the database
from . import sql_models
from .sql_db import engine
sql_models.Base.metadata.drop_all(engine)
if args.populate:
test_dir = Path(__file__).parent.parent.parent / "tests"
if not test_dir.is_dir():
raise ClanError(f"Could not find test dir: {test_dir}")
test_db_api = test_dir / "test_db_api.py"
if not test_db_api.is_file():
raise ClanError(f"Could not find test db api: {test_db_api}")
import subprocess
cmd = ["pytest", "-s", "-n0", str(test_db_api)]
subprocess.run(cmd, check=True)
uvicorn.run( uvicorn.run(
"clan_cli.webui.app:app", "clan_cli.webui.app:app",
host=args.host, host=args.host,

View File

@@ -3,6 +3,7 @@ from typing import List, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from sqlalchemy.sql.expression import true from sqlalchemy.sql.expression import true
from ..errors import ClanError
from . import schemas, sql_models from . import schemas, sql_models
######################### #########################
@@ -153,21 +154,18 @@ def get_attached_entities(
) )
# set attached
# None if did not found
# Returns same entity if setting didnt changed something # Returns same entity if setting didnt changed something
def set_attached_by_entity_did( def set_attached_by_entity_did(
db: Session, entity_did: str, value: bool db: Session, entity_did: str, value: bool
) -> Optional[sql_models.Entity]: ) -> sql_models.Entity:
# ste attached to true
db_entity = get_entity_by_did(db, entity_did) db_entity = get_entity_by_did(db, entity_did)
if db_entity is not None: if db_entity is None:
# db_entity.attached = Column(True) raise ClanError(f"Entity with did '{entity_did}' not found")
setattr(db_entity, "attached", value)
# save changes in db setattr(db_entity, "attached", value)
db.add(db_entity)
db.commit() # save changes in db
db.refresh(db_entity) db.add(db_entity)
return db_entity db.commit()
else: db.refresh(db_entity)
return db_entity return db_entity

View File

@@ -26,6 +26,7 @@ class Entity(Base):
name = Column(String, index=True) name = Column(String, index=True)
ip = Column(String, index=True) ip = Column(String, index=True)
attached = Column(Boolean, index=True) attached = Column(Boolean, index=True)
visible = Column(Boolean, index=True)
## Non queryable body ## ## Non queryable body ##
# In here we deposit: Network, Roles, Visible, etc. # In here we deposit: Network, Roles, Visible, etc.

View File

@@ -77,7 +77,7 @@ def test_producer(api: TestClient) -> None:
"service_type": "3D Printing", "service_type": "3D Printing",
"endpoint_url": "http://127.0.0.1:8000", "endpoint_url": "http://127.0.0.1:8000",
"status": "unknown", "status": "unknown",
"other": {"test": "test"}, "other": {"action": ["register", "deregister", "delete", "create"]},
"entity_did": default_entity_did, "entity_did": default_entity_did,
} }
paramter = "producer" paramter = "producer"
@@ -92,7 +92,7 @@ def test_producer2(api: TestClient) -> None:
"service_type": "Fax", "service_type": "Fax",
"endpoint_url": "http://127.0.0.1:8001", "endpoint_url": "http://127.0.0.1:8001",
"status": "unknown", "status": "unknown",
"other": {"faxen": "dicke"}, "other": {"action": ["register", "deregister", "delete", "create"]},
"entity_did": default_entity_did2, "entity_did": default_entity_did2,
} }
paramter = "producer" paramter = "producer"
@@ -107,7 +107,7 @@ def test_producer3(api: TestClient) -> None:
"service_type": "VR-Stream", "service_type": "VR-Stream",
"endpoint_url": "http://127.0.0.1:8002", "endpoint_url": "http://127.0.0.1:8002",
"status": "unknown", "status": "unknown",
"other": {"oculos": "rift"}, "other": {"action": ["register", "deregister", "delete", "create"]},
"entity_did": default_entity_did3, "entity_did": default_entity_did3,
} }
paramter = "producer" paramter = "producer"
@@ -122,7 +122,7 @@ def test_producer4(api: TestClient) -> None:
"service_type": "gallary", "service_type": "gallary",
"endpoint_url": "http://127.0.0.1:8003", "endpoint_url": "http://127.0.0.1:8003",
"status": "unknown", "status": "unknown",
"other": {"nice": "pics"}, "other": {"action": ["register", "deregister", "delete", "create"]},
"entity_did": default_entity_did4, "entity_did": default_entity_did4,
} }
paramter = "producer" paramter = "producer"
@@ -137,7 +137,7 @@ def test_producer5(api: TestClient) -> None:
"service_type": "Game-Shop", "service_type": "Game-Shop",
"endpoint_url": "http://127.0.0.1:8004", "endpoint_url": "http://127.0.0.1:8004",
"status": "unknown", "status": "unknown",
"other": {"war": "games"}, "other": {"action": ["register", "deregister", "delete", "create"]},
"entity_did": default_entity_did5, "entity_did": default_entity_did5,
} }
paramter = "producer" paramter = "producer"
@@ -263,7 +263,11 @@ def test_entity(api: TestClient) -> None:
"name": "C1", "name": "C1",
"ip": "127.0.0.1", "ip": "127.0.0.1",
"attached": False, "attached": False,
"other": {"test": "test"}, "visible": True,
"other": {
"network": "Carlo1's Home Network",
"roles": ["service repository", "service consumer"],
},
} }
paramter = "entity" paramter = "entity"
# get_request = "entity_did=did%3Asov%3Atest%3A1234" # get_request = "entity_did=did%3Asov%3Atest%3A1234"
@@ -276,7 +280,11 @@ def test_entity2(api: TestClient) -> None:
"name": "C2", "name": "C2",
"ip": "127.0.0.2", "ip": "127.0.0.2",
"attached": False, "attached": False,
"other": {"test": "test"}, "visible": True,
"other": {
"network": "Carlo2's Home Network",
"roles": ["service repository", "service prosumer"],
},
} }
paramter = "entity" paramter = "entity"
get_request = "entity_did=" + url.quote(default_entity_did2) get_request = "entity_did=" + url.quote(default_entity_did2)