Compare commits
3 Commits
4b5b9cfe6a
...
a4c9bf8e6f
| Author | SHA1 | Date | |
|---|---|---|---|
| a4c9bf8e6f | |||
| c7b7e8f6f8 | |||
| 8f8baeabe4 |
@ -13,7 +13,7 @@ def get_pillar_name_sequence(name: str) -> list[str]:
|
|||||||
|
|
||||||
def decode_pillar_value(pillar: Pillar) -> str | int | float | bool | list | dict:
|
def decode_pillar_value(pillar: Pillar) -> str | int | float | bool | list | dict:
|
||||||
match pillar.parameter_type:
|
match pillar.parameter_type:
|
||||||
case 'string': return pillar.value
|
case 'string': return str(pillar.value)
|
||||||
case 'integer': return int(pillar.value)
|
case 'integer': return int(pillar.value)
|
||||||
case 'float': return float(pillar.value)
|
case 'float': return float(pillar.value)
|
||||||
case 'boolean': return bool(pillar.value)
|
case 'boolean': return bool(pillar.value)
|
||||||
@ -32,10 +32,17 @@ def get_pillar_for_target(db: Session, target: UUID) -> dict:
|
|||||||
name = row.pillar_name
|
name = row.pillar_name
|
||||||
value = decode_pillar_value(row)
|
value = decode_pillar_value(row)
|
||||||
labels = get_pillar_name_sequence(name)
|
labels = get_pillar_name_sequence(name)
|
||||||
|
print(f"Labels: {labels}, Value: {value}")
|
||||||
current = out
|
current = out
|
||||||
l = len(labels)
|
l = len(labels)
|
||||||
for i, label in enumerate(labels):
|
for i, label in enumerate(labels):
|
||||||
if label not in current:
|
if i < l-1:
|
||||||
current[label] = {} if i < l-1 else value
|
if label not in current:
|
||||||
|
current[label] = {}
|
||||||
|
elif type(current[label]) is not dict:
|
||||||
|
current[label] = {}
|
||||||
|
current = current[label]
|
||||||
|
else:
|
||||||
|
current[label] = json.loads(str(value))
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
from .host import host
|
from .host import host
|
||||||
from .hostgroup import hostgroup
|
from .hostgroup import hostgroup
|
||||||
from .query import query
|
|
||||||
from .state import state
|
from .state import state
|
||||||
from .pillar import pillar
|
from .pillar import pillar
|
||||||
from .environment import environment
|
from .environment import environment
|
||||||
|
|||||||
@ -22,7 +22,7 @@ def environment_list():
|
|||||||
for env in response.json():
|
for env in response.json():
|
||||||
click.echo(f" - {env}")
|
click.echo(f" - {env}")
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to list environments:\n{e}")
|
click.echo(f"Failed to list environments:\n{e.response.text}")
|
||||||
|
|
||||||
|
|
||||||
@environment.command("show")
|
@environment.command("show")
|
||||||
@ -33,10 +33,9 @@ def environment_show(name: str):
|
|||||||
try:
|
try:
|
||||||
# Validate name format before making request
|
# Validate name format before making request
|
||||||
if not split_and_validate_path.__module__ or True: # Using environment-specific validation
|
if not split_and_validate_path.__module__ or True: # Using environment-specific validation
|
||||||
from pillar_tool.util.validation import validate_environment_name
|
|
||||||
if not validate_environment_name(name):
|
if not validate_environment_name(name):
|
||||||
raise click.ClickException(
|
click.echo("Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
||||||
"Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
return
|
||||||
|
|
||||||
response = requests.get(f'{base_url()}/environment/{name}', headers=auth_header())
|
response = requests.get(f'{base_url()}/environment/{name}', headers=auth_header())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -45,7 +44,7 @@ def environment_show(name: str):
|
|||||||
click.echo(f"Environment: {env_data['environment']}")
|
click.echo(f"Environment: {env_data['environment']}")
|
||||||
click.echo(f"Hosts assigned: {env_data['host_count']}")
|
click.echo(f"Hosts assigned: {env_data['host_count']}")
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to show environment:\n{e}")
|
click.echo(f"Failed to show environment:\n{e.response.text}")
|
||||||
|
|
||||||
|
|
||||||
@environment.command("create")
|
@environment.command("create")
|
||||||
@ -55,8 +54,8 @@ def environment_create(name: str):
|
|||||||
click.echo(f"Creating environment '{name}'...")
|
click.echo(f"Creating environment '{name}'...")
|
||||||
try:
|
try:
|
||||||
if not validate_environment_name(name):
|
if not validate_environment_name(name):
|
||||||
raise click.ClickException(
|
click.echo("Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
||||||
"Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
return
|
||||||
|
|
||||||
# No body data needed for environment creation
|
# No body data needed for environment creation
|
||||||
response = requests.post(f'{base_url()}/environment/{name}', headers=auth_header())
|
response = requests.post(f'{base_url()}/environment/{name}', headers=auth_header())
|
||||||
@ -64,7 +63,7 @@ def environment_create(name: str):
|
|||||||
|
|
||||||
click.echo(f"Environment '{name}' created successfully.")
|
click.echo(f"Environment '{name}' created successfully.")
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to create environment:\n{e}")
|
click.echo(f"Failed to create environment:\n{e.response.text}")
|
||||||
|
|
||||||
|
|
||||||
@environment.command("delete")
|
@environment.command("delete")
|
||||||
@ -74,8 +73,8 @@ def environment_delete(name: str):
|
|||||||
click.echo(f"Deleting environment '{name}'...")
|
click.echo(f"Deleting environment '{name}'...")
|
||||||
try:
|
try:
|
||||||
if not validate_environment_name(name):
|
if not validate_environment_name(name):
|
||||||
raise click.ClickException(
|
click.echo("Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
||||||
"Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
return
|
||||||
|
|
||||||
response = requests.delete(f'{base_url()}/environment/{name}', headers=auth_header())
|
response = requests.delete(f'{base_url()}/environment/{name}', headers=auth_header())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -85,13 +84,13 @@ def environment_delete(name: str):
|
|||||||
if e.response is not None and e.response.status_code == 409:
|
if e.response is not None and e.response.status_code == 409:
|
||||||
conflict_data = e.response.json() if e.response.content else {}
|
conflict_data = e.response.json() if e.response.content else {}
|
||||||
hosts_list = conflict_data.get('assigned_hosts', [])
|
hosts_list = conflict_data.get('assigned_hosts', [])
|
||||||
raise click.ClickException(
|
click.echo(
|
||||||
f"Failed to delete environment:\n"
|
f"Failed to delete environment:\n"
|
||||||
f"{conflict_data.get('message', 'Environment has assigned hosts')}\n"
|
f"{conflict_data.get('message', 'Environment has assigned hosts')}\n"
|
||||||
f"Assigned hosts: {', '.join(hosts_list) if hosts_list else 'none'}"
|
f"Assigned hosts: {', '.join(hosts_list) if hosts_list else 'none'}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise click.ClickException(f"Failed to delete environment:\n{e}")
|
click.echo(f"Failed to delete environment:\n{e.response.text}")
|
||||||
|
|
||||||
@environment.command("import")
|
@environment.command("import")
|
||||||
@click.argument("name")
|
@click.argument("name")
|
||||||
@ -101,8 +100,8 @@ def environment_import(name: str):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if not validate_environment_name(name):
|
if not validate_environment_name(name):
|
||||||
raise click.ClickException(
|
click.echo("Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
||||||
"Invalid environment name. Use only alphanumeric, underscore or dash characters.")
|
return
|
||||||
|
|
||||||
response = requests.patch(f'{base_url()}/environment/{name}', headers=auth_header())
|
response = requests.patch(f'{base_url()}/environment/{name}', headers=auth_header())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -110,7 +109,7 @@ def environment_import(name: str):
|
|||||||
click.echo(f"Environment '{name}' imported successfully.")
|
click.echo(f"Environment '{name}' imported successfully.")
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
if e.response is not None:
|
if e.response is not None:
|
||||||
raise click.ClickException(f"Failed to import environment:\n{e}")
|
raise click.ClickException(f"Failed to import environment:\n{e.response.text}")
|
||||||
else:
|
else:
|
||||||
raise click.ClickException(f"Failed to import environment:\n{e}")
|
raise click.ClickException(f"Failed to import environment:\n{e}")
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ def host_list():
|
|||||||
for h in response.json():
|
for h in response.json():
|
||||||
click.echo(f" - {h}")
|
click.echo(f" - {h}")
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to list hosts:\n{e}")
|
raise click.ClickException(f"Failed to list hosts:\n{e.response.text}")
|
||||||
|
|
||||||
@host.command("create")
|
@host.command("create")
|
||||||
@click.argument("fqdn")
|
@click.argument("fqdn")
|
||||||
@ -35,7 +35,7 @@ def host_create(fqdn: str, parent: str | None):
|
|||||||
response = requests.post(f"{base_url()}/host/{fqdn}", json=params.model_dump(), headers=auth_header())
|
response = requests.post(f"{base_url()}/host/{fqdn}", json=params.model_dump(), headers=auth_header())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to create host:\n{e}")
|
raise click.ClickException(f"Failed to create host:\n{e.response.text}")
|
||||||
|
|
||||||
click.echo(f"Host '{fqdn}' created!")
|
click.echo(f"Host '{fqdn}' created!")
|
||||||
|
|
||||||
@ -51,7 +51,9 @@ def host_delete(fqdn: str):
|
|||||||
click.echo("Deleting host...")
|
click.echo("Deleting host...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.delete(f'{base_url}/host/{fqdn}', headers=auth_header())
|
response = requests.delete(f'{base_url()}/host/{fqdn}', headers=auth_header())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
|
click.echo(f"Host '{fqdn}' deleted!")
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to delete host:\n{e}")
|
raise click.ClickException(f"Failed to delete host:\n{e.response.text}")
|
||||||
|
|||||||
@ -39,7 +39,7 @@ def hostgroup_show(path: str):
|
|||||||
response = requests.get(f'{base_url()}/hostgroup/{name}', headers=auth_header(), params=data.model_dump())
|
response = requests.get(f'{base_url()}/hostgroup/{name}', headers=auth_header(), params=data.model_dump())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to show hostgroup:\n{e}")
|
raise click.ClickException(f"Failed to show hostgroup:\n{e.response.text}")
|
||||||
|
|
||||||
|
|
||||||
@hostgroup.command("create")
|
@hostgroup.command("create")
|
||||||
@ -56,7 +56,7 @@ def hostgroup_create(path: str):
|
|||||||
response = requests.post(f'{base_url()}/hostgroup/{name}', headers=auth_header(), json=data.model_dump())
|
response = requests.post(f'{base_url()}/hostgroup/{name}', headers=auth_header(), json=data.model_dump())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to create hostgroup:\n{e}")
|
raise click.ClickException(f"Failed to create hostgroup:\n{e.response.text}")
|
||||||
|
|
||||||
|
|
||||||
@hostgroup.command("delete")
|
@hostgroup.command("delete")
|
||||||
@ -71,4 +71,4 @@ def hostgroup_delete(path: str):
|
|||||||
response = requests.delete(f'{base_url()}/hostgroup/{name}{query_params}', headers=auth_header())
|
response = requests.delete(f'{base_url()}/hostgroup/{name}{query_params}', headers=auth_header())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise click.ClickException(f"Failed to delete hostgroup:\n{e}")
|
raise click.ClickException(f"Failed to delete hostgroup:\n{e.response.text}")
|
||||||
|
|||||||
@ -14,19 +14,20 @@ def pillar():
|
|||||||
|
|
||||||
|
|
||||||
@pillar.command("get")
|
@pillar.command("get")
|
||||||
@click.argument("fqdn")
|
@click.argument("target")
|
||||||
def pillar_get(fqdn):
|
def pillar_get(target: str):
|
||||||
"""Get pillar data for a given FQDN."""
|
"""Get pillar data for a given host or hostgroup."""
|
||||||
try:
|
try:
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
f"{base_url()}/pillar/{fqdn}",
|
f"{base_url()}/pillar/{target.replace('/', "%%2f")}",
|
||||||
headers=auth_header(),
|
headers=auth_header()
|
||||||
)
|
)
|
||||||
|
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
pillar_data = response.json()
|
pillar_data = response.json()
|
||||||
click.echo(yaml.dump({fqdn: pillar_data}))
|
click.echo(json.dumps(pillar_data, indent=2))
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
click.echo(f"Error: {e}")
|
click.echo(f"Error: {e.response.json()}")
|
||||||
|
|
||||||
@pillar.command("set")
|
@pillar.command("set")
|
||||||
@click.argument("name")
|
@click.argument("name")
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
import click
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from .cli_main import main, auth_header, base_url
|
|
||||||
|
|
||||||
|
|
||||||
@main.group("query")
|
|
||||||
def query():
|
|
||||||
pass
|
|
||||||
@ -45,7 +45,7 @@ def top_assign(host: str, state: str):
|
|||||||
click.echo("Assigning state to host...")
|
click.echo("Assigning state to host...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.post(f'{base_url()}/top/assign/{host}/{state}', headers=auth_header())
|
response = requests.post(f'{base_url()}/top/assign/{host.replace('/', "%%2f")}/{state}', headers=auth_header())
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
click.echo("Assigned state")
|
click.echo("Assigned state")
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy import select, insert, bindparam, and_
|
from sqlalchemy import select, insert, bindparam, and_, 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
|
||||||
@ -153,12 +153,17 @@ async def host_add(request: Request, fqdn: str, params: HostCreateParams):
|
|||||||
is_hostgroup=False
|
is_hostgroup=False
|
||||||
)
|
)
|
||||||
stmt_create_host_with_parent = insert(Host).values(id=new_host.id, name=new_host.name, parent_id=new_host.parent_id, is_hostgroup=new_host.is_hostgroup)
|
stmt_create_host_with_parent = insert(Host).values(id=new_host.id, name=new_host.name, parent_id=new_host.parent_id, is_hostgroup=new_host.is_hostgroup)
|
||||||
db.execute(stmt_create_host_with_parent).fetchall()
|
db.execute(stmt_create_host_with_parent)
|
||||||
|
|
||||||
# Prepare response with creation details
|
# Prepare response with creation details
|
||||||
output = {
|
output = {
|
||||||
"message": "Host created",
|
"message": "Host created",
|
||||||
"host": new_host, # return the final host in the hierarchy
|
"host": {
|
||||||
|
'id': str(new_host.id),
|
||||||
|
'name': new_host.name,
|
||||||
|
'parent': str(new_host.parent_id),
|
||||||
|
'is_hostgroup': new_host.is_hostgroup
|
||||||
|
}, # return the final host in the hierarchy
|
||||||
}
|
}
|
||||||
|
|
||||||
# include the full path to the new host if it exists
|
# include the full path to the new host if it exists
|
||||||
@ -189,6 +194,21 @@ async def host_delete(request: Request, fqdn: str):
|
|||||||
Raises:
|
Raises:
|
||||||
HTTPException: If FQDN format is invalid or host is not found
|
HTTPException: If FQDN format is invalid or host is not found
|
||||||
"""
|
"""
|
||||||
pass
|
|
||||||
|
db: Session = request.state.db
|
||||||
|
|
||||||
|
if not validate_fqdn(fqdn):
|
||||||
|
raise HTTPException(status_code=400, detail="Provided host is not an FQDN")
|
||||||
|
|
||||||
|
host_stmt = select(Host).where(and_(Host.name == fqdn, Host.is_hostgroup == False))
|
||||||
|
host_res = db.execute(host_stmt).fetchall()
|
||||||
|
if len(host_res) != 1:
|
||||||
|
raise HTTPException(status_code=400, detail="Host not found")
|
||||||
|
host: Host = host_res[0][0]
|
||||||
|
|
||||||
|
db.execute(delete(Host).where(Host.id == host.id))
|
||||||
|
|
||||||
|
return JSONResponse(status_code=204, content={"message": "Host deleted"})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
from sqlalchemy import select, insert, bindparam, delete, and_
|
from sqlalchemy import select, insert, bindparam, delete, and_
|
||||||
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, Depends
|
||||||
from starlette.responses import JSONResponse
|
from starlette.responses import JSONResponse
|
||||||
|
|
||||||
from pillar_tool.db import Host
|
from pillar_tool.db import Host
|
||||||
@ -45,7 +45,7 @@ def hostgroups_get(req: Request):
|
|||||||
return JSONResponse(status_code=200, content=all_hostgroup_names)
|
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, params: HostgroupParams):
|
||||||
"""
|
"""
|
||||||
Retrieve a specific host group by name with additional details
|
Retrieve a specific host group by name with additional details
|
||||||
|
|
||||||
@ -66,7 +66,11 @@ 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 []
|
path = []
|
||||||
|
if params:
|
||||||
|
path = split_and_validate_path(params.path) if params.path else []
|
||||||
|
|
||||||
|
print("test")
|
||||||
|
|
||||||
# get the path from the db
|
# get the path from the db
|
||||||
path_stmt = select(Host).where(and_(Host.name == bindparam('name') and Host.parent_id == bindparam('parent_id')))
|
path_stmt = select(Host).where(and_(Host.name == bindparam('name') and Host.parent_id == bindparam('parent_id')))
|
||||||
@ -117,7 +121,7 @@ def hostgroup_create(req: Request, name: str, params: HostgroupParams):
|
|||||||
"""
|
"""
|
||||||
db = req.state.db
|
db = req.state.db
|
||||||
path = params.path
|
path = params.path
|
||||||
labels = split_and_validate_path(path) if path is not None else []
|
labels = ( split_and_validate_path(path) if path is not None else [] ) or []
|
||||||
labels += [ name ]
|
labels += [ name ]
|
||||||
|
|
||||||
stmt = select(Host).where(and_(Host.name == bindparam('name'), Host.is_hostgroup == True, Host.parent_id == bindparam('last')))
|
stmt = select(Host).where(and_(Host.name == bindparam('name'), Host.is_hostgroup == True, Host.parent_id == bindparam('last')))
|
||||||
|
|||||||
@ -26,8 +26,8 @@ router = APIRouter(
|
|||||||
|
|
||||||
# Note: there is no list of all pillars, as this would not be helpful
|
# Note: there is no list of all pillars, as this would not be helpful
|
||||||
|
|
||||||
@router.get("/{fqdn}")
|
@router.get("/{target}")
|
||||||
def pillar_get(req: Request, fqdn: str):
|
def pillar_get(req: Request, target: str) -> JSONResponse:
|
||||||
# TODO: implement
|
# TODO: implement
|
||||||
# this function should:
|
# this function should:
|
||||||
# - get the affected host hierarchy
|
# - get the affected host hierarchy
|
||||||
@ -37,27 +37,54 @@ def pillar_get(req: Request, fqdn: str):
|
|||||||
# if any error happens, return non-200 status and an empty dictionary so that salt does not shit itself
|
# if any error happens, return non-200 status and an empty dictionary so that salt does not shit itself
|
||||||
db: Session = req.state.db
|
db: Session = req.state.db
|
||||||
|
|
||||||
# get the host hierarchy
|
# if the target is a hostgroup with path, then split the path and get to the target host this way
|
||||||
host_stmt = select(Host).where(and_(Host.name == fqdn, Host.is_hostgroup == False))
|
target = target.replace("%%2F", "%%2f")
|
||||||
result = db.execute(host_stmt).fetchall()
|
if "%%2f" in target:
|
||||||
if len(result) == 0:
|
path_labels = target.split("%%2f")
|
||||||
return JSONResponse(status=404, content={})
|
|
||||||
# NOTE: should be enforced by the database
|
|
||||||
assert len(result) == 1
|
|
||||||
|
|
||||||
host: Host = result[0][0]
|
|
||||||
path: list[Host] = [host]
|
host_stmt_remain = select(Host).where(and_(Host.name == bindparam('frag'), Host.parent_id == bindparam('parent_id')))
|
||||||
parent_stmt = select(Host).where(Host.id == bindparam('parent'))
|
host_stmt_first = select(Host).where(and_(Host.name == bindparam('frag'), Host.parent_id == None))
|
||||||
while path[-1].parent_id is not None:
|
host_stmt = host_stmt_first
|
||||||
result = db.execute(parent_stmt, {'parent': path[-1].parent_id}).fetchall()
|
|
||||||
|
parent_id = None
|
||||||
|
path: list[Host] = []
|
||||||
|
for fragment in path_labels:
|
||||||
|
result = db.execute(host_stmt, {"frag": fragment, "parent_id": parent_id}).fetchall()
|
||||||
|
host_stmt = host_stmt_remain
|
||||||
|
if len(result) == 0:
|
||||||
|
return JSONResponse(status_code=404, content={"message": f"No such path fragment: {fragment} with parent_id {parent_id}"})
|
||||||
|
assert len(result) == 1 # Note: that the db should enforce this
|
||||||
|
|
||||||
|
current: Host = result[0][0]
|
||||||
|
parent_id = current.id
|
||||||
|
path.append(current)
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
# get the host hierarchy from a fqdn or unique hostgroup name
|
||||||
|
host_stmt = select(Host).where(Host.name == target)
|
||||||
|
result = db.execute(host_stmt).fetchall()
|
||||||
|
if len(result) == 0:
|
||||||
|
return JSONResponse(status_code=404, content={'message': f'No such target: {target}'})
|
||||||
# NOTE: should be enforced by the database
|
# NOTE: should be enforced by the database
|
||||||
assert len(result) == 1
|
if len(result) > 1:
|
||||||
tmp: Host = result[0][0]
|
return JSONResponse(status_code=400, content={'message': f'Multiple targets: {target}'})
|
||||||
path.append(tmp)
|
|
||||||
|
host: Host = result[0][0]
|
||||||
|
path: list[Host] = [host]
|
||||||
|
parent_stmt = select(Host).where(Host.id == bindparam('parent'))
|
||||||
|
while path[-1].parent_id is not None:
|
||||||
|
result = db.execute(parent_stmt, {'parent': path[-1].parent_id}).fetchall()
|
||||||
|
# NOTE: should be enforced by the database
|
||||||
|
assert len(result) == 1
|
||||||
|
tmp: Host = result[0][0]
|
||||||
|
path.append(tmp)
|
||||||
|
|
||||||
|
path.reverse()
|
||||||
|
|
||||||
|
|
||||||
path.reverse()
|
|
||||||
out = merge([get_pillar_for_target(db, host.id) for host in path])
|
out = merge([get_pillar_for_target(db, host.id) for host in path])
|
||||||
|
|
||||||
return JSONResponse(status_code=200, content=out)
|
return JSONResponse(status_code=200, content=out)
|
||||||
|
|
||||||
|
|
||||||
@ -126,11 +153,10 @@ def pillar_create(req: Request, name: str, params: PillarParams):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
# build the pillar package
|
# build the pillar package
|
||||||
pillars_to_store= [
|
pillars_to_store = [
|
||||||
{ 'name': name, 'value': params.value, 'type': params.type }
|
{ 'name': name, 'value': params.value, 'type': params.type }
|
||||||
]
|
]
|
||||||
|
|
||||||
print(f"Pillars to store: {pillars_to_store}")
|
|
||||||
# store pillar data
|
# store pillar data
|
||||||
insert_stmt = insert(Pillar).values(id=bindparam('new_id'), host_id=target.id, pillar_name=bindparam('name'), parameter_type=bindparam('type'), value=bindparam('value'))
|
insert_stmt = insert(Pillar).values(id=bindparam('new_id'), host_id=target.id, pillar_name=bindparam('name'), parameter_type=bindparam('type'), value=bindparam('value'))
|
||||||
upsert_stmt = insert_stmt.on_conflict_do_update(constraint='pillar_unique_pillar_name', set_={'parameter_type': bindparam('type'), 'value': bindparam('value')} )
|
upsert_stmt = insert_stmt.on_conflict_do_update(constraint='pillar_unique_pillar_name', set_={'parameter_type': bindparam('type'), 'value': bindparam('value')} )
|
||||||
|
|||||||
@ -112,12 +112,19 @@ def top_state_assign(req: Request, host_name: str, state_name: str):
|
|||||||
db: Session = req.state.db
|
db: Session = req.state.db
|
||||||
|
|
||||||
# get the host in question
|
# get the host in question
|
||||||
host_stmt = select(Host).where(Host.name == host_name)
|
path_labels = host_name.replace("%%2F", "%%2f").split("%%2f")
|
||||||
host_res = db.execute(host_stmt).fetchall()
|
parent_id = None
|
||||||
if len(host_res) != 1:
|
for path in path_labels:
|
||||||
return JSONResponse(status_code=404, content={"error": f"Host '{host_name} not found"})
|
host_stmt = select(Host).where(and_(Host.name == path, Host.parent_id == parent_id))
|
||||||
|
host_res = db.execute(host_stmt).fetchall()
|
||||||
|
|
||||||
host: Host = host_res[0][0]
|
if len(host_res) != 1:
|
||||||
|
return JSONResponse(status_code=404, content={"error": f"Host '{host_name} not found"})
|
||||||
|
|
||||||
|
current: Host = host_res[0][0]
|
||||||
|
parent_id = current.id
|
||||||
|
|
||||||
|
host: Host = current
|
||||||
|
|
||||||
parent_stmt = select(Host).where(Host.id == bindparam("parent_id"))
|
parent_stmt = select(Host).where(Host.id == bindparam("parent_id"))
|
||||||
parents: list[Host] = []
|
parents: list[Host] = []
|
||||||
|
|||||||
@ -53,10 +53,10 @@ class StateParams(BaseModel):
|
|||||||
|
|
||||||
# Pillar operations
|
# Pillar operations
|
||||||
class PillarParams(BaseModel):
|
class PillarParams(BaseModel):
|
||||||
host: str | None
|
host: str | None = None
|
||||||
hostgroup: str | None
|
hostgroup: str | None = None
|
||||||
value: str | None # value if the pillar should be set
|
value: str | None = None # value if the pillar should be set
|
||||||
type: str | None # type of pillar if pillar should be set
|
type: str | None = None # type of pillar if pillar should be set
|
||||||
|
|
||||||
|
|
||||||
def get_model_from_query[T](model: T) -> Callable[[Request], T]:
|
def get_model_from_query[T](model: T) -> Callable[[Request], T]:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user