Una configuración jerárquica que usa Yaml en Python.
La última versión es: 0.15.2
Un módulo Python que le permite fusionar archivos de configuración jerárquicos utilizando la sintaxis Yaml. Ofrece una fusión profunda, interpolación variable y recuperación de secretos de los gerentes de secretos.
Es ideal si desea estructurar su jerarquía de tal manera que evite la duplicación. Puede definir una estructura para su configuración utilizando una jerarquía como entorno/proyecto/clúster/aplicación. Depende de usted las capas que desea usar en esta jerarquía. La herramienta leerá todos los archivos YAML que comienzan desde la raíz (donde los valores predeterminados estarían) hasta la hoja (donde estarían la mayoría de los valores específicos, lo que tendrá prioridad).
La idea vino de la jera de Puppet.
pipdockerdictpip pip install himldocker docker run ghcr.io/adobe/himl:latest himl-config-merger --helpVea todas las etiquetas Docker en: https://github.com/adobe/himl/pkgs/container/himl/versions
git clone https://github.com/adobe/himl
cd himl
sudo python install -e .
Esto fusionará simple/default.yaml con simple/producción/env.yaml
from himl import ConfigProcessor
config_processor = ConfigProcessor ()
path = "examples/simple/production"
filters = () # can choose to output only specific keys
exclude_keys = () # can choose to remove specific keys
output_format = "yaml" # yaml/json
config_processor . process ( path = path , filters = filters , exclude_keys = exclude_keys ,
output_format = output_format , print_data = True ) El ejemplo anterior fusionará simple/default.yaml con simple/production/env.yaml :
$ tree examples/simple
examples/simple
├── default.yaml
└── production
└── env.yaml
El ejemplo también muestra una fusión profunda de listas y mapas.
examples/simple/default.yaml
---
env : default
deep :
key1 : v1
key2 : v2
deep_list :
- item1
- item2 examples/simple/production/env.yaml
---
env : prod
deep :
key3 : v3
deep_list :
- item3Resultado:
env : prod
deep :
key1 : v1
key2 : v2
key3 : v3
deep_list :
- item1
- item2
- item3 Una herramienta CLI llamada himl se instala automáticamente a través de pip . Puede usarlo para analizar un árbol de yamls y emitirá la configuración combinada en la salida estándar o lo escribirá en un archivo.
usage: himl [-h] [--output-file OUTPUT_FILE] [--format OUTPUT_FORMAT]
[--filter FILTER] [--exclude EXCLUDE]
[--skip-interpolation-validation]
[--skip-interpolation-resolving] [--enclosing-key ENCLOSING_KEY]
[--cwd CWD]
[--list-merge-strategy {append,override,prepend,append_unique}]
pathhiml examples/complex/env=dev/region=us-east-1/cluster=cluster2Según el árbol de configuración de la carpeta Ejemplos/Complejo, la salida del comando anterior será lo siguiente:
cluster:
description: 'This is cluster: cluster2. It is using c3.2xlarge instance type.'
name: cluster2
node_type: c3.2xlarge
region:
location: us-east-1
env: dev
Donde la carpeta de ejemplos se parece a esto:
$ tree examples/complex
examples/complex
├── default.yaml
├── env=dev
│ ├── env.yaml
│ ├── region=us-east-1
│ │ ├── cluster=cluster1
│ │ │ └── cluster.yaml
│ │ ├── cluster=cluster2
│ │ │ └── cluster.yaml
│ │ └── region.yaml
│ └── region=us-west-2
│ ├── cluster=cluster1
│ │ └── cluster.yaml
│ └── region.yaml
└── env=prod
├── env.yaml
└── region=eu-west-2
├── cluster=ireland1
│ └── cluster.yaml
└── region.yaml
Para evitar la repetición, queríamos hacer posible definir un valor una vez y reutilizarlo en otras partes de la configuración YAML. A diferencia de los anclajes de YAML, estas interpolaciones funcionan en múltiples archivos.
data/default.yaml :
allowed_roles :
- " arn:aws:iam::{{account.id}}:role/myrole " data/dev/env.yaml :
account:
id: "123456"
dict projects :
webapp1 :
tagging :
Owner : " Web Service Team "
Environment : " dev "
CostCenter : " 123 "
data-store :
Owner : " Backend Team "
Environment : " dev "
CostCenter : " 455 "
# this will copy the whole projects.webapp1.tagging dict to this key
tagging : " {{projects.webapp1.tagging}} "
# or even a double interpolation
tagging : " {{projects.{{project.name}}.tagging}} "Es posible tener la misma clave (por ejemplo, una lista/lista) en múltiples archivos y combinarlos usando una fusión profunda. Vea un ejemplo aquí.
passphrase : " {{ssm.path(/key/coming/from/aws/secrets/store/manager).aws_profile(myprofile)}} " my_value : " {{s3.bucket(my-bucket).path(path/to/file.txt).base64encode(true).aws_profile(myprofile)}} " Use Vault CLI para autenticar, método de retroceso a través de LDAP.
Recuperar solo un valor clave de un secreto, la cola de ruta se usa como clave:
my_value : " {{vault.key(/path/from/vault/key)}} "Recupere todos los pares de clave/valor de una ruta de bóveda:
my_dict : " {{vault.path(/path/from/vault)}} "Generar un token para una política:
my_token : " {{vault.token_policy(my_vault_policy)}} " # ## Terraform remote states ###
remote_states :
- name : cluster_composition
type : terraform
aws_profile : " my_aws_profile "
s3_bucket : " my_terraform_bucket "
s3_key : " mycluster.tfstate "
endpoint : " {{outputs.cluster_composition.output.value.redis_endpoint}} " kubeconfig_location : " {{env(KUBECONFIG)}} " El script himl-config-merger contiene la lógica de fusionar un directorio de configuración jerárquico y crear los archivos YAML de resultados finales.
himl-config-merger examples/complex --output-dir merged_output --levels env region cluster --leaf-directories cluster INFO:__main__:Found input config directory: examples/complex/env=prod/region=eu-west-2/cluster=ireland1
INFO:__main__:Storing generated config to: merged_output/prod/eu-west-2/ireland1.yaml
INFO:__main__:Found input config directory: examples/complex/env=dev/region=us-west-2/cluster=cluster1
INFO:__main__:Storing generated config to: merged_output/dev/us-west-2/cluster1.yaml
INFO:__main__:Found input config directory: examples/complex/env=dev/region=us-east-1/cluster=cluster1
INFO:__main__:Storing generated config to: merged_output/dev/us-east-1/cluster1.yaml
INFO:__main__:Found input config directory: examples/complex/env=dev/region=us-east-1/cluster=cluster2
INFO:__main__:Storing generated config to: merged_output/dev/us-east-1/cluster2.yaml
Ejemplo de entrada:
> tree examples/complex
examples/complex
├── default.yaml
├── env=dev
│ ├── env.yaml
│ ├── region=us-east-1
│ │ ├── cluster=cluster1
│ │ │ └── cluster.yaml
│ │ ├── cluster=cluster2
│ │ │ └── cluster.yaml
│ │ └── region.yaml
│ └── region=us-west-2
│ ├── cluster=cluster1
│ │ └── cluster.yaml
│ └── region.yaml
└── env=prod
├── env.yaml
└── region=eu-west-2
├── cluster=ireland1
│ └── cluster.yaml
└── region.yaml
Producción:
merged_output
├── dev
│ ├── us-east-1
│ │ ├── cluster1.yaml
│ │ └── cluster2.yaml
│ └── us-west-2
│ └── cluster1.yaml
└── prod
└── eu-west-2
└── ireland1.yaml
Aprovechando el himl, el script de configuración-ferina carga la estructura del árbol de configuración y los mergas profundas todas las claves de todos los archivos YAML que se encuentran desde una ruta raíz hasta un borde. Para cada directorio de Leaf, se creará un archivo en --output-dir .
Bajo cada nivel, hay una "clave de nivel" obligatoria que utiliza la ferina de configuración para calcular el resultado final. Esta clave debe estar presente en uno de los archivos en cada nivel. (por ejemplo, env.yaml bajo env).
Algunas configuraciones que se especifican en los niveles más altos del árbol de directorio podrían no ser necesarios al final (hoja). Por este motivo, el script de configuración-ferina puede aplicar un conjunto de reglas de filtro que se especifican a través del parámetro --filter-rules-key . Esta propiedad debe estar presente en la configuración y contiene reglas para eliminar las claves de nivel raíz de la salida. El filtro se aplica si el objeto selector coincide con un subconjunto de las teclas de salida y mantendrá las claves especificadas en la lista values o las teclas que coinciden con el patrón regex .
# intermediate config after hierarchical merge
env : dev
cluster : cluster1
region : us-east-1
key1 : persisted
key2 : dropped
keep_1 : persisted
tags :
cost_center : 123
_filters :
- selector :
env : " dev "
keys :
values :
- key1
regex : " keep_.* "
- selector :
cluster :
regex : " cluster1 "
keys :
values :
- tagsConstruya la salida con filtrado:
himl-config-merger examples/filters --output-dir merged_output --levels env region cluster --leaf-directories cluster --filter-rules-key _filters # output after filtering
env : dev
cluster : cluster1
region : us-east-1
key1 : persisted
keep_1 : persisted
tags :
cost_center : 123 Los selectores de reglas y las teclas El filtrado solo funciona en el nivel raíz de la configuración. No es posible filtrar las teclas anidadas.
Además de las características estándar que se encuentran en la Biblioteca PyYaml , el componente himl-config-merger también implementa una etiqueta YAML personalizada llamada !include
Ejemplo:
VA7 : !include configs/env=int/region=va7/kafka-brokers.yaml regionBrokers.VA7Esto reemplazará el valor después de la interpolación con el valor de Regionbrokers.VA7 encontrado en la ruta config/env = int/region = VA7/Kafka-Brokers.yaml.
Se pueden pasar un parámetro opcional type_strategies a configprocessor para definir el comportamiento de fusión personalizado. Podrían ser funciones personalizadas que se ajustan a sus necesidades. Su función debe tomar los argumentos de (config, ruta, base, nxt) y devolver el resultado fusionado.
Ejemplo:
from himl import ConfigProcessor
def strategy_merge_override ( config , path , base , nxt ):
"""merge list of dicts. if objects have same id, nxt replaces base."""
"""if remove flag is present in nxt item, remove base and not add nxt"""
result = deepcopy ( base )
for nxto in nxt :
for baseo in result :
# if list is not a list of dicts, bail out and let the next strategy to execute
if not isinstance ( baseo , dict ) or not isinstance ( nxto , dict ):
return STRATEGY_END
if 'id' in baseo and 'id' in nxto and baseo [ 'id' ] == nxto [ 'id' ]:
result . remove ( baseo ) #same id, remove previous item
if 'remove' not in nxto :
result . append ( nxto )
return result
config_processor = ConfigProcessor ()
path = "examples/simple/production"
filters = () # can choose to output only specific keys
exclude_keys = () # can choose to remove specific keys
output_format = "yaml" # yaml/json
config_processor . process ( path = path , filters = filters , exclude_keys = exclude_keys ,
output_format = output_format , print_data = True ,
type_strategies = [( list , [ strategy_merge_override , 'append' ]), ( dict , [ "merge" ])] ))