implemented utility function for merging dictionaries
This commit is contained in:
parent
f47d3eb0a8
commit
9a0e34b856
@ -0,0 +1,44 @@
|
||||
import uuid
|
||||
|
||||
from fastapi.params import Depends
|
||||
from sqlalchemy import select, insert, delete
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.requests import Request
|
||||
from fastapi import APIRouter
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
from pillar_tool.db.models.top_data import State, StateAssignment
|
||||
from pillar_tool.schemas import PillarParams, get_model_from_query
|
||||
from pillar_tool.util.validation import validate_state_name
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/pillar",
|
||||
tags=["pillar"],
|
||||
)
|
||||
|
||||
# Note: there is no list of all pillars, as this would not be helpful
|
||||
|
||||
@router.get("/{name}")
|
||||
def state_get(req: Request, name: str, params: Depends(get_model_from_query(PillarParams))):
|
||||
# TODO: implement
|
||||
# this function should_
|
||||
# - get the affected host hierarchy
|
||||
# - get all the relevant pillar dictionaries
|
||||
# - merge the pillar directories
|
||||
# - return the merged pillar directory
|
||||
# if any error happens, return non-200 status and an empty dictionary so that salt does not shit itself
|
||||
db: Session = req.state.db
|
||||
|
||||
|
||||
@router.post("/{name}")
|
||||
def state_create(req: Request, name: str):
|
||||
# TODO: implement
|
||||
|
||||
db = req.state.db
|
||||
|
||||
|
||||
@router.delete("/{name}")
|
||||
def state_delete(req: Request, name: str):
|
||||
# TODO: implement
|
||||
db = req.state.db
|
||||
@ -50,7 +50,11 @@ class HostgroupParams(BaseModel):
|
||||
class StateParams(BaseModel):
|
||||
pass # No parameters needed for state operations currently
|
||||
|
||||
|
||||
# Pillar operations
|
||||
class PillarParams(BaseModel):
|
||||
target: str # must be host or hostgroup
|
||||
value: str | None # value if the pillar should be set
|
||||
type: str | None # type of pillar if pillar should be set
|
||||
|
||||
|
||||
def get_model_from_query[T](model: T) -> Callable[[Request], T]:
|
||||
|
||||
52
pillar_tool/util/pillar_utilities.py
Normal file
52
pillar_tool/util/pillar_utilities.py
Normal file
@ -0,0 +1,52 @@
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
def apply_layer(base: dict, layer: dict):
|
||||
"""
|
||||
Recursively applies key-value pairs from `layer` onto `base`.
|
||||
|
||||
For each key in `layer`:
|
||||
- If both `base[key]` and `layer[key]` are dictionaries, recursively merge them.
|
||||
- Otherwise, `base[key]` is overwritten (or newly inserted) with `layer[key]`.
|
||||
|
||||
Note: This function mutates the `base` dictionary in-place.
|
||||
|
||||
:param base: The target dictionary to be updated. Will be modified directly.
|
||||
:param layer: The source dictionary whose values will be applied to `base`.
|
||||
"""
|
||||
for key, value in layer.items():
|
||||
# if base and layer value are dicts, apply recursively
|
||||
if type(value) is dict and key in base and type(base[key]) is dict:
|
||||
apply_layer(base[key], value)
|
||||
# else replace the base value with the layer value
|
||||
# or insert the base value
|
||||
else:
|
||||
base[key] = value
|
||||
|
||||
|
||||
def merge(*pillar_data, deep_copy=True) -> dict:
|
||||
"""
|
||||
Merges multiple pillar data dictionaries into one.
|
||||
|
||||
The merging is done left-to-right: keys from later dictionaries override
|
||||
those in earlier ones. Nested dictionaries are merged recursively using
|
||||
`apply_layer`.
|
||||
|
||||
:param pillar_data: Two or more dictionaries to merge. Must contain at least one item.
|
||||
:param deep_copy: If True (default), the first dictionary is deep-copied before merging,
|
||||
preserving the original input data. If False, the first dictionary
|
||||
is modified in-place.
|
||||
:return: A new merged dictionary (if `deep_copy=True`) or the mutated first dictionary (if `deep_copy=False`).
|
||||
|
||||
Example:
|
||||
merge({'a': 1}, {'b': 2}) → {'a': 1, 'b': 2}
|
||||
merge({'a': {'x': 1}}, {'a': {'y': 2}}) → {'a': {'x': 1, 'y': 2}}
|
||||
"""
|
||||
assert len(pillar_data) > 0, "At least one pillar data is required"
|
||||
merged_pillar = deepcopy(pillar_data[0]) if deep_copy else pillar_data[0]
|
||||
|
||||
for pillar in pillar_data[1:]:
|
||||
apply_layer(merged_pillar, pillar)
|
||||
|
||||
|
||||
return merged_pillar
|
||||
Loading…
x
Reference in New Issue
Block a user