From 4709e114f2d0321c94fddc3aad09456d4dcaca30 Mon Sep 17 00:00:00 2001 From: Gabin L Date: Thu, 13 Mar 2025 12:19:14 +0100 Subject: [PATCH 1/3] chore: drop dev container Signed-off-by: Gabin L --- .devcontainer/Dockerfile | 45 --------------------------------- .devcontainer/devcontainer.json | 12 --------- 2 files changed, 57 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index c4b2cb4..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM mcr.microsoft.com/devcontainers/base:jammy -# FROM mcr.microsoft.com/devcontainers/base:jammy - -ARG DEBIAN_FRONTEND=noninteractive -ARG USER=vscode - -RUN DEBIAN_FRONTEND=noninteractive \ - && apt-get update \ - && apt-get install -y build-essential --no-install-recommends make \ - ca-certificates \ - git \ - libssl-dev \ - zlib1g-dev \ - libbz2-dev \ - libreadline-dev \ - libsqlite3-dev \ - wget \ - curl \ - llvm \ - libncurses5-dev \ - xz-utils \ - tk-dev \ - libxml2-dev \ - libxmlsec1-dev \ - libffi-dev \ - liblzma-dev - -# Python and poetry installation -USER $USER -ARG HOME="/home/$USER" -ARG PYTHON_VERSION=3.12 -# ARG PYTHON_VERSION=3.10 - -ENV PYENV_ROOT="${HOME}/.pyenv" -ENV PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${HOME}/.local/bin:$PATH" - -RUN echo "done 0" \ - && curl https://pyenv.run | bash \ - && echo "done 1" \ - && pyenv install ${PYTHON_VERSION} \ - && echo "done 2" \ - && pyenv global ${PYTHON_VERSION} \ - && echo "done 3" \ - && curl -sSL https://install.python-poetry.org | python3 - \ - && poetry config virtualenvs.in-project true \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 00cd7cf..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "poetry3-poetry-pyenv", - "build": { - "dockerfile": "Dockerfile" - }, - "postCreateCommand": "poetry install", - "customizations": { - "vscode": { - "extensions":["ms-python.python", "njpwerner.autodocstring"] - } - } -} From 11ce304b088e2e9149799358866cc2863ac3cb62 Mon Sep 17 00:00:00 2001 From: Gabin L Date: Thu, 13 Mar 2025 12:19:30 +0100 Subject: [PATCH 2/3] feat: add unset quota command Signed-off-by: Gabin L --- labctl/commands/quota.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/labctl/commands/quota.py b/labctl/commands/quota.py index 06abda7..3c7be1a 100644 --- a/labctl/commands/quota.py +++ b/labctl/commands/quota.py @@ -30,7 +30,7 @@ def show_project_quota(project: str): @cli_ready @app.command(name="set") -def add_quota(project: str, quota_type: str, quantity: int, comment: Optional[str] = None): +def set_quota(project: str, quota_type: str, quantity: int, comment: Optional[str] = None): """ Add quota to OpenStack project """ @@ -48,3 +48,24 @@ def add_quota(project: str, quota_type: str, quantity: int, comment: Optional[st console.print(f"[red]Error: {call.text}[/red]") return console.print(f"[green]Quota {quota_type}={quantity} set to project {project}[/green]") + +@cli_ready +@app.command(name="unset") +def unset_quota(project: str, quota_type: str): + """ + Add quota to OpenStack project + """ + config = Config() + console.print(f"[cyan]Unsetting {quota_type} to OpenStack project {project}[/cyan]") + payload = { + "username": config.username, + "project_name": project, + "type": quota_type, + "quantity": 0, + "comment": "" + } + call = APIDriver().put(f"/quota/adjust-project", json=payload) + if call.status_code >= 400: + console.print(f"[red]Error: {call.text}[/red]") + return + console.print(f"[green]Quota {quota_type} unset from project {project}[/green]") From 3a1e95576a34dc26c5e7db858a6681dd0a9bee99 Mon Sep 17 00:00:00 2001 From: Gabin L Date: Thu, 13 Mar 2025 12:19:46 +0100 Subject: [PATCH 3/3] feat: display quota info for project on me command Signed-off-by: Gabin L --- .gitignore | 2 +- labctl/main.py | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f8f4793..8c8e658 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *.pyc dist/ - +.ruff_cache/ .DS_Store diff --git a/labctl/main.py b/labctl/main.py index 79aed61..218313e 100644 --- a/labctl/main.py +++ b/labctl/main.py @@ -69,16 +69,39 @@ def me( tree.add("[bold]Username:[/bold] " + data.get("username")) tree.add("[bold]Email:[/bold] " + data.get("email")) + # show projects info project_list = api_driver.get("/openstack/projects/" + config.username).json() project_tree = tree.add(":open_file_folder: Projects") for project in project_list: project_tree_item = project_tree.add(":computer: " + project.get('name')) project_tree_item.add("[bold]Owner:[/bold] " + project.get('owner', '')) project_tree_item.add("Members: " + " ".join(project.get('members', []))) + + # show quotas for project + project_quota_list = api_driver.get(f"/quota/project/{project.get('name')}/adjustements") + if project_quota_list.status_code >= 400: + project_tree_item.add(f":warning: Error fetching quotas for project {project.get('name')}") + continue + + project_quota_tree = project_tree_item.add(":open_file_folder: Quotas for project") + quota_types = set([quota.get('type') for quota in project_quota_list.json()]) + total_quotas = {quota_type: 0 for quota_type in quota_types} + self_quotas = {quota_type: 0 for quota_type in quota_types} + for quota in project_quota_list.json(): + total_quotas[quota.get('type')] += quota.get('quantity') + if quota.get('username') == config.username: + self_quotas[quota.get('type')] += quota.get('quantity') + + for quota_type, quantity in total_quotas.items(): + if quantity == 0: + continue + project_quota_tree.add(f"{quota_type} Total: {quantity}") + project_quota_tree.add(f"{quota_type} You give: {self_quotas[quota_type]}") + if not project_list: project_tree.add(":warning: No projects found") - quota_tree = tree.add(":open_file_folder: Quotas") + quota_tree = tree.add(":open_file_folder: Quotas owned") quota_list = api_driver.get(f"/quota/user/{config.username}/total").json() for quota in quota_list: quota_tree.add(f"Type: {quota.get('type')} / {quota.get('quantity')}")