diff --git a/pillar_tool/ptcli/cli/pillar.py b/pillar_tool/ptcli/cli/pillar.py index ba51cb3..1f634dd 100644 --- a/pillar_tool/ptcli/cli/pillar.py +++ b/pillar_tool/ptcli/cli/pillar.py @@ -5,6 +5,7 @@ import click import requests from .cli_main import main, auth_header, base_url +from ...schemas import PillarParams @main.group("pillar") @@ -52,11 +53,27 @@ def pillar_set(name: str, host: str | None, hostgroup: str | None, parameter_typ except ValueError as e: print(f"Failed to validate value: {e}") else: - data = { - 'host': host, - 'hostgroup': hostgroup, - 'type': parameter_type, - 'value': json.dumps(value) - } + data = PillarParams( + host=host, + hostgroup=hostgroup, + type=parameter_type, + value=json.dumps(value) + ) - requests.post(f"{base_url()}/pillar/{name}", headers=auth_header(), json=data) \ No newline at end of file + requests.post(f"{base_url()}/pillar/{name}", headers=auth_header(), json=data.model_dump()) + +@pillar.command("delete") +@click.argument("name") +@click.option("--host") +@click.option("--hostgroup") +def pillar_delete(name: str, host: str | None, hostgroup: str | None): + try: + data = PillarParams( + host=host, + hostgroup=hostgroup, + type=None, + value=None, + ) + requests.delete(f"{base_url()}/pillar/{name}", headers=auth_header(), json=data.model_dump()) + except Exception as e: + print(f"ERROR: {e}") diff --git a/pillar_tool/routers/pillar.py b/pillar_tool/routers/pillar.py index e582a70..27b1b7a 100644 --- a/pillar_tool/routers/pillar.py +++ b/pillar_tool/routers/pillar.py @@ -147,5 +147,45 @@ def pillar_create(req: Request, name: str, params: PillarParams): @router.delete("/{name}") def pillar_delete(req: Request, name: str, params: PillarParams): - # TODO: implement db = req.state.db + + if params.host is not None: + # delete a pillar at the host level + target_stmt = select(Host).where(and_(Host.name == params.host, Host.is_hostgroup == False)) + result = db.execute(target_stmt).fetchall() + + if len(result) == 0: + return JSONResponse(status_code=404, content={}) + + # this should be enforced by the database + assert len(result) == 1 + target: Host = result[0][0] + elif params.hostgroup is not None: + # delete a pillar at the hostgroup level + path = split_and_validate_path(params.hostgroup) + if not path: + return JSONResponse(status_code=400, content={'message': "No target specified"}) + last = None + current = None + # Note: both statements need to be present, since '==' will not work for None and 'is' will not work for a UUID + group_stmt = select(Host).where(and_(Host.is_hostgroup == True, Host.parent_id == bindparam('parent'), Host.name == bindparam('name'))) + group_stmt_none = select(Host).where(and_(Host.is_hostgroup == True, Host.parent_id.is_(None), Host.name == bindparam('name'))) + for label in path: + result = db.execute(group_stmt if last is not None else group_stmt_none, {'name': label, 'parent': last}).fetchall() + if len(result) == 0: + return JSONResponse(status_code=404, content={'message': f"No hostgroup named: {params.hostgroup}"}) + # Note: this should be enforced by the database + assert len(result) == 1, f"Result: {[x[0].name for x in result]}" + current: Host = result[0][0] + last = current.id + target: Host = current + else: + return JSONResponse(status_code=400, content={ + 'message': "Either Host or Hostgroup needs to be set!" + }) + + # TODO: make this delete recursive + delete_stmt = delete(Pillar).where(and_(Pillar.host_id == target.id, Pillar.pillar_name == name)) + result = db.execute(delete_stmt) + + return JSONResponse(status_code=200, content={'message': 'ok'})