Compare commits
No commits in common. "9216c95f10b4b3c11de196402e3e0d7c39d58917" and "bfb568b456b5a414f3c3527f2d23980eb3bb8abf" have entirely different histories.
9216c95f10
...
bfb568b456
@ -3,9 +3,8 @@ import base64
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from urllib.parse import quote
|
|
||||||
|
|
||||||
from pillar_tool.schemas import HostCreateParams, HostgroupParams
|
from pillar_tool.schemas import HostCreateParams
|
||||||
from pillar_tool.util import config, load_config, Config
|
from pillar_tool.util import config, load_config, Config
|
||||||
from pillar_tool.util.validation import split_and_validate_path, validate_fqdn
|
from pillar_tool.util.validation import split_and_validate_path, validate_fqdn
|
||||||
|
|
||||||
@ -121,51 +120,14 @@ def hostgroup_list():
|
|||||||
raise click.ClickException(f"Failed to list hostgroups:\n{e}")
|
raise click.ClickException(f"Failed to list hostgroups:\n{e}")
|
||||||
|
|
||||||
|
|
||||||
@hostgroup.command("show")
|
|
||||||
@click.argument("path")
|
|
||||||
def hostgroup_show(path: str):
|
|
||||||
click.echo(f"Showing hostgroup '{path}'...")
|
|
||||||
try:
|
|
||||||
labels = split_and_validate_path(path)
|
|
||||||
name = labels[-1]
|
|
||||||
path = '/'.join(labels[:-1]) if len(labels) > 1 else None
|
|
||||||
data = HostgroupParams(
|
|
||||||
path=path
|
|
||||||
)
|
|
||||||
response = requests.get(f'{base_url}/hostgroup/{name}', headers=auth_header, params=data.model_dump())
|
|
||||||
response.raise_for_status()
|
|
||||||
except requests.exceptions.HTTPError as e:
|
|
||||||
raise click.ClickException(f"Failed to show hostgroup:\n{e}")
|
|
||||||
|
|
||||||
|
|
||||||
@hostgroup.command("create")
|
@hostgroup.command("create")
|
||||||
@click.argument("path")
|
@click.argument("path")
|
||||||
def hostgroup_create(path: str):
|
def hostgroup_create(path: str):
|
||||||
click.echo(f"Creating hostgroup '{path}'...")
|
click.echo("TODO: implement")
|
||||||
try:
|
|
||||||
labels = split_and_validate_path(path)
|
|
||||||
path = "/".join(labels[:-1]) if len(labels) > 1 else ''
|
|
||||||
name = labels[-1]
|
|
||||||
data = HostgroupParams(
|
|
||||||
path=path
|
|
||||||
)
|
|
||||||
response = requests.post(f'{base_url}/hostgroup/{name}', headers=auth_header, json=data.model_dump())
|
|
||||||
response.raise_for_status()
|
|
||||||
except requests.exceptions.HTTPError as e:
|
|
||||||
raise click.ClickException(f"Failed to create hostgroup:\n{e}")
|
|
||||||
|
|
||||||
|
|
||||||
@hostgroup.command("delete")
|
@hostgroup.command("delete")
|
||||||
@click.argument("path")
|
@click.argument("path")
|
||||||
def hostgroup_delete(path: str):
|
def hostgroup_delete(path: str):
|
||||||
click.echo(f"Deleting hostgroup {path}...")
|
click.echo("TODO: implement")
|
||||||
try:
|
|
||||||
labels = split_and_validate_path(path)
|
|
||||||
name = labels[-1]
|
|
||||||
prefix = "/".join(labels[:-1]) if len(labels) > 1 else None
|
|
||||||
query_params = f"?path={prefix}" if prefix is not None else ''
|
|
||||||
response = requests.delete(f'{base_url}/hostgroup/{name}{query_params}', headers=auth_header)
|
|
||||||
response.raise_for_status()
|
|
||||||
except requests.exceptions.HTTPError as e:
|
|
||||||
raise click.ClickException(f"Failed to delete hostgroup:\n{e}")
|
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import uuid
|
from http.client import HTTPResponse
|
||||||
|
|
||||||
|
from sqlalchemy import select, insert, bindparam
|
||||||
from sqlalchemy import select, insert, bindparam, delete
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from fastapi import APIRouter, Query, Depends
|
from fastapi import APIRouter
|
||||||
from starlette.responses import JSONResponse
|
from starlette.responses import JSONResponse
|
||||||
|
|
||||||
from pillar_tool.db import Host
|
from pillar_tool.db import Host
|
||||||
from pillar_tool.schemas import HostgroupParams, get_hostgroup_params_from_query, get_model_from_query
|
from pillar_tool.schemas import HostgroupCreateParams
|
||||||
from pillar_tool.util.validation import split_and_validate_path
|
from pillar_tool.util.validation import split_and_validate_path
|
||||||
|
|
||||||
router = APIRouter(
|
router = APIRouter(
|
||||||
@ -34,20 +33,13 @@ def hostgroups_get(req: Request):
|
|||||||
result = db.execute(select(Host).where(Host.is_hostgroup == True)).fetchall()
|
result = db.execute(select(Host).where(Host.is_hostgroup == True)).fetchall()
|
||||||
hosts: list[Host] = list(map(lambda x: x[0], result))
|
hosts: list[Host] = list(map(lambda x: x[0], result))
|
||||||
|
|
||||||
all_hostgroups = { x.id: x for x in hosts }
|
return JSONResponse(status_code=200, content=list(map(lambda x: x.name, hosts)))
|
||||||
all_hostgroup_names = []
|
|
||||||
for host in hosts:
|
|
||||||
ancestors = [host]
|
|
||||||
while ancestors[-1].parent_id is not None:
|
|
||||||
ancestors.append(all_hostgroups[ancestors[-1].parent_id])
|
|
||||||
all_hostgroup_names.append('/'.join(map(lambda x: x.name, reversed(ancestors))))
|
|
||||||
|
|
||||||
return JSONResponse(status_code=200, content=all_hostgroup_names)
|
|
||||||
|
|
||||||
@router.get("/{name}")
|
@router.get("/{name}")
|
||||||
def hostgroup_get(req: Request, name: str, params: HostgroupParams = Depends(get_model_from_query(HostgroupParams))):
|
def hostgroup_get(req: Request, name: str, path_input: str | None = None):
|
||||||
"""
|
"""
|
||||||
Retrieve a specific host group by name with additional details
|
Retrieve a specific host group by name.
|
||||||
|
|
||||||
Fetches and returns details of the specified host group.
|
Fetches and returns details of the specified host group.
|
||||||
Returns 404 if no such host group exists.
|
Returns 404 if no such host group exists.
|
||||||
@ -55,7 +47,7 @@ def hostgroup_get(req: Request, name: str, params: HostgroupParams = Depends(get
|
|||||||
Args:
|
Args:
|
||||||
req (Request): The incoming request object.
|
req (Request): The incoming request object.
|
||||||
name (str): The name of the host group to retrieve.
|
name (str): The name of the host group to retrieve.
|
||||||
params (HostgroupCreateParams): the path of the group if desired
|
path_input (str): the path of the group if desired
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSONResponse: A JSON response with status code 200 and the host group details on success,
|
JSONResponse: A JSON response with status code 200 and the host group details on success,
|
||||||
@ -66,7 +58,8 @@ def hostgroup_get(req: Request, name: str, params: HostgroupParams = Depends(get
|
|||||||
# decode the path
|
# decode the path
|
||||||
last = None
|
last = None
|
||||||
ancestors = []
|
ancestors = []
|
||||||
path = split_and_validate_path(params.path) if params.path else []
|
if path_input is not None:
|
||||||
|
path = split_and_validate_path(path_input)
|
||||||
|
|
||||||
# get the path from the db
|
# get the path from the db
|
||||||
path_stmt = select(Host).where(Host.name == bindparam('name') and Host.parent_id == bindparam('parent_id'))
|
path_stmt = select(Host).where(Host.name == bindparam('name') and Host.parent_id == bindparam('parent_id'))
|
||||||
@ -90,6 +83,7 @@ def hostgroup_get(req: Request, name: str, params: HostgroupParams = Depends(get
|
|||||||
|
|
||||||
# Note: this should be enforced by the database
|
# Note: this should be enforced by the database
|
||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
|
print("check 1")
|
||||||
|
|
||||||
hg: Host = result[0][0]
|
hg: Host = result[0][0]
|
||||||
|
|
||||||
@ -100,7 +94,7 @@ def hostgroup_get(req: Request, name: str, params: HostgroupParams = Depends(get
|
|||||||
|
|
||||||
|
|
||||||
@router.post("/{name}")
|
@router.post("/{name}")
|
||||||
def hostgroup_create(req: Request, name: str, params: HostgroupParams):
|
def hostgroup_create(req: Request, name: str, params: HostgroupCreateParams):
|
||||||
"""
|
"""
|
||||||
Create a new host group.
|
Create a new host group.
|
||||||
|
|
||||||
@ -109,40 +103,37 @@ def hostgroup_create(req: Request, name: str, params: HostgroupParams):
|
|||||||
Args:
|
Args:
|
||||||
req (Request): The incoming request object.
|
req (Request): The incoming request object.
|
||||||
name (str): The name of the host group (used as identifier).
|
name (str): The name of the host group (used as identifier).
|
||||||
params (HostgroupCreateParams): Additional Parameters
|
params (HostgroupCreateParams): The creation parameters (e.g., description, associated hosts).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSONResponse: A JSON response with status code 201 on success,
|
JSONResponse: A JSON response with status code 201 on success,
|
||||||
or appropriate error codes (e.g., 409 if already exists).
|
or appropriate error codes (e.g., 409 if already exists).
|
||||||
"""
|
"""
|
||||||
db = req.state.db
|
pass
|
||||||
path = params.path
|
|
||||||
labels = split_and_validate_path(path) if path is not None else []
|
|
||||||
labels += [ name ]
|
|
||||||
|
|
||||||
stmt = select(Host).where(Host.name == bindparam('name') and Host.is_hostgroup == True and Host.parent_id == bindparam('last'))
|
|
||||||
last = None
|
|
||||||
for label in labels:
|
|
||||||
result = db.execute(stmt, {'name': label, 'last': last}).fetchall()
|
|
||||||
|
|
||||||
if len(result) == 1:
|
@router.patch("/{name}")
|
||||||
# simply step down through the hierarchy
|
def hostgroup_update(req: Request, name: str, params: HostgroupCreateParams):
|
||||||
host = result[0][0]
|
"""
|
||||||
last = host.id
|
Update an existing host group by name.
|
||||||
elif len(result) == 0:
|
|
||||||
new_id = uuid.uuid4()
|
|
||||||
db.execute(insert(Host).values(id=new_id, name=label, is_hostgroup=True, parent_id=last))
|
|
||||||
last = new_id
|
|
||||||
else:
|
|
||||||
# this should not be possible
|
|
||||||
assert False
|
|
||||||
|
|
||||||
# TODO: return the newly created hostgroups
|
Updates the specified host group with new parameters.
|
||||||
return JSONResponse(status_code=201, content={})
|
Returns 404 if no such host group exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
req (Request): The incoming request object.
|
||||||
|
name (str): The current name of the host group to update.
|
||||||
|
params (HostgroupCreateParams): The updated parameters.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
JSONResponse: A JSON response with status code 200 on success,
|
||||||
|
or 404 if not found.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{name}")
|
@router.delete("/{name}")
|
||||||
def hostgroup_delete(req: Request, name: str, params: HostgroupParams = Depends(get_model_from_query(HostgroupParams))):
|
def hostgroup_delete(req: Request, name: str, params: HostgroupCreateParams):
|
||||||
"""
|
"""
|
||||||
Delete a host group by name.
|
Delete a host group by name.
|
||||||
|
|
||||||
@ -158,32 +149,4 @@ def hostgroup_delete(req: Request, name: str, params: HostgroupParams = Depends(
|
|||||||
JSONResponse: A JSON response with status code 204 on successful deletion,
|
JSONResponse: A JSON response with status code 204 on successful deletion,
|
||||||
or 404 if not found.
|
or 404 if not found.
|
||||||
"""
|
"""
|
||||||
db = req.state.db
|
pass
|
||||||
|
|
||||||
labels = split_and_validate_path(params.path) or []
|
|
||||||
labels.append(name)
|
|
||||||
last = None
|
|
||||||
|
|
||||||
stmt_step = select(Host).where(Host.name == bindparam('name') and Host.parent_id == bindparam('last') and Host.is_hostgroup == True)
|
|
||||||
for label in labels:
|
|
||||||
result = db.execute(stmt_step, {'name': label, 'last': last}).fetchall()
|
|
||||||
|
|
||||||
if len(result) == 0:
|
|
||||||
return JSONResponse(status_code=404, content={}) # TODO: truly define a error format
|
|
||||||
|
|
||||||
# this should be enforced by the database
|
|
||||||
assert len(result) == 1
|
|
||||||
|
|
||||||
host: Host = result[0][0]
|
|
||||||
last = host.id
|
|
||||||
|
|
||||||
children_stmt = select(Host).where(Host.parent_id == last)
|
|
||||||
children: list[Host] = list(map(lambda x: x[0], db.execute(children_stmt).fetchall()))
|
|
||||||
if len(children) != 0:
|
|
||||||
return JSONResponse(status_code=400, content={
|
|
||||||
'message': "Cannot delete a hostgroup that still has children",
|
|
||||||
'children': [ '/'.join(labels + [x.name]) for x in children ]
|
|
||||||
})
|
|
||||||
|
|
||||||
db.execute(delete(Host).where(Host.id == last))
|
|
||||||
return JSONResponse(status_code=204, content={})
|
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
from typing import Type, Callable
|
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from starlette.requests import Request
|
|
||||||
from starlette.responses import JSONResponse
|
from starlette.responses import JSONResponse
|
||||||
|
|
||||||
|
|
||||||
@ -43,14 +40,6 @@ class HostCreateParams(BaseModel):
|
|||||||
parent: str | None
|
parent: str | None
|
||||||
|
|
||||||
# Hostgroup operations
|
# Hostgroup operations
|
||||||
class HostgroupParams(BaseModel):
|
class HostgroupCreateParams(BaseModel):
|
||||||
path: str | None
|
parent: str | None
|
||||||
|
|
||||||
|
|
||||||
def get_hostgroup_params_from_query(req: Request):
|
|
||||||
return HostgroupParams(**dict(req.query_params))
|
|
||||||
|
|
||||||
def get_model_from_query[T](model: T) -> Callable[[Request], T]:
|
|
||||||
def aux(req: Request) -> T:
|
|
||||||
return model.model_validate(dict(req.query_params or {}))
|
|
||||||
return aux
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user