Une configuration hiérarchique utilisant YAML dans Python.
La dernière version est: 0.15.2
Un module Python qui vous permet de fusionner les fichiers de configuration hiérarchiques à l'aide de la syntaxe YAML. Il offre une fusion profonde, une interpolation variable et une récupération des secrets des gestionnaires de secrets.
Il est idéal si vous souhaitez structurer votre hiérarchie de telle manière que vous évitez la duplication. Vous pouvez définir une structure pour votre configuration à l'aide d'une hiérarchie telle environnement / projet / cluster / application. C'est à vous de vos couches que vous souhaitez utiliser dans cette hiérarchie. L'outil lira tous les fichiers YAML à partir de la racine (où les valeurs par défaut seraient) jusqu'à la feuille (où la plupart des valeurs spécifiques seraient, ce qui aurait priorité).
L'idée est venue de Hiera de Puppet.
pipdockerdict entierpip pip install himldocker docker run ghcr.io/adobe/himl:latest himl-config-merger --helpVoir toutes les balises Docker sur: https://github.com/adobe/himl/pkgs/container/himl/versions
git clone https://github.com/adobe/himl
cd himl
sudo python install -e .
Cela fusionnera simple / par défaut.yaml avec simple / production / 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 ) L'exemple ci-dessus fusionnera simple/default.yaml avec simple/production/env.yaml :
$ tree examples/simple
examples/simple
├── default.yaml
└── production
└── env.yaml
L'exemple présente également une fusion profonde des listes et des cartes.
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 :
- item3Résultat:
env : prod
deep :
key1 : v1
key2 : v2
key3 : v3
deep_list :
- item1
- item2
- item3 Un outil CLI appelé himl est automatiquement installé via pip . Vous pouvez l'utiliser pour analyser une arborescence de YAMLS et il sortira la configuration combinée à la sortie standard ou l'écrira dans un fichier.
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=cluster2Sur la base de l'arborescence de configuration à partir du dossier Exemples / complexe, la sortie de la commande ci-dessus sera la suivante:
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
Où le dossier Exemples ressemble à ceci:
$ 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
Afin d'éviter la répétition, nous voulions permettre de définir une valeur une fois et de la réutiliser dans d'autres parties de la configuration YAML. Contrairement aux ancres YAML, ces interpolations fonctionnent sur plusieurs fichiers.
data/default.yaml :
allowed_roles :
- " arn:aws:iam::{{account.id}}:role/myrole " data/dev/env.yaml :
account:
id: "123456"
dict entier 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}} "Il est possible d'avoir la même clé (par exemple, un dict / liste) dans plusieurs fichiers et de les combiner à l'aide d'une fusion profonde. Voir un exemple ici.
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)}} " Utilisez Vault CLI pour authentifier la méthode de secours via LDAP.
Récupérez une seule valeur de clé à partir d'un secret, la queue de chemin est utilisée comme clé:
my_value : " {{vault.key(/path/from/vault/key)}} "Récupérez toutes les paires de clés / valeur à partir d'un chemin de coffre-fort:
my_dict : " {{vault.path(/path/from/vault)}} "Générer un jeton pour une politique:
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)}} " Le script himl-config-merger , contient une logique de fusion d'un répertoire de configuration hiérarchique et de création des fichiers YAML Résultat final.
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
Exemple d'entrée:
> 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
Sortir:
merged_output
├── dev
│ ├── us-east-1
│ │ ├── cluster1.yaml
│ │ └── cluster2.yaml
│ └── us-west-2
│ └── cluster1.yaml
└── prod
└── eu-west-2
└── ireland1.yaml
Tirant en tirant le HIML, le script Config-Merger charge la structure des arborescences configs et les touches profondes de tous les fichiers YAML trouvés d'un chemin racine à un bord. Pour chaque répertoire des feuilles, un fichier sera créé sous --output-dir .
Sous chaque niveau, il existe une "clé de niveau" obligatoire qui est utilisée par Config-Merger pour calculer le résultat final. Cette clé doit être présente dans l'un des fichiers sous chaque niveau. (par exemple, Env.yaml sous Env).
Certaines configurations spécifiées dans les niveaux supérieurs de l'arborescence de répertoire peuvent ne pas être nécessaires dans le résultat final (feuille). Pour cette raison, le script Config-Merger peut appliquer un ensemble de règles de filtre spécifiées via le paramètre --filter-rules-key . Cette propriété doit être présente dans la configuration et contient des règles pour supprimer les touches de niveau racine de la sortie. Le filtre est appliqué si l'objet sélecteur correspond à un sous-ensemble des touches de sortie et conservera les touches spécifiées dans la liste values ou les touches qui correspondent au modèle 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 :
- tagsConstruisez la sortie avec filtrage:
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 Les sélecteurs de règles et les touches Le filtrage ne fonctionne qu'au niveau racine de la configuration. Il n'est pas possible de filtrer les clés imbriquées.
Outre les fonctionnalités standard trouvées dans la bibliothèque PyYaml , le composant himl-config-merger implémente également une étiquette YAML personnalisée appelée !include .
Exemple:
VA7 : !include configs/env=int/region=va7/kafka-brokers.yaml regionBrokers.VA7Cela remplacera la valeur après l'interpolation par la valeur de RegionBrokers.va7 trouvée sous les configs / env = int / région = VA7 / Kafka-Brokers.yaml Path.
Un paramètre de type_strategies facultatif peut être transmis dans ConfigProcessor pour définir le comportement de fusion personnalisé. Il peut s'agir de fonctions personnalisées qui répondent à vos besoins. Votre fonction doit prendre les arguments de (config, path, base, nxt) et renvoyer le résultat fusionné.
Exemple:
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" ])] ))