Eine hierarchische Konfiguration mit YAML in Python.
Die neueste Version ist: 0.15.2
Ein Python -Modul, mit dem Sie hierarchische Konfigurationsdateien mithilfe der YAML -Syntax zusammenführen können. Es bietet tiefgreifende Zusammenführungen, variable Interpolation und Geheimnisse von Secrets -Managern.
Es ist ideal, wenn Sie Ihre Hierarchie so strukturieren möchten, dass Sie eine Doppelarbeit vermeiden. Sie können eine Struktur für Ihre Konfiguration mithilfe einer Hierarchie wie Umgebung/Projekt/Cluster/App definieren. Es liegt an Ihnen, welche Ebenen Sie in dieser Hierarchie verwenden möchten. Das Tool liest alle YAML -Dateien aus dem Stamm (wobei Standardwerte) bis zum Blatt (wo die meisten spezifischen Werte vorhanden wären, die Vorrang haben).
Die Idee kam von Puppets Hiera.
pipdocker -Bilddictpip pip install himldocker -Bild docker run ghcr.io/adobe/himl:latest himl-config-merger --helpSiehe alle Docker -Tags unter: https://github.com/adobe/himl/pkgs/container/himl/versions
git clone https://github.com/adobe/himl
cd himl
sudo python install -e .
Dies wird einfach/default.yaml mit einfach/produktion/env.yaml verschmelzen
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 ) Das obige Beispiel fusioniert simple/default.yaml mit simple/production/env.yaml :
$ tree examples/simple
examples/simple
├── default.yaml
└── production
└── env.yaml
Das Beispiel zeigt auch eine tiefe Verschmelzung von Listen und Karten.
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 :
- item3Ergebnis:
env : prod
deep :
key1 : v1
key2 : v2
key3 : v3
deep_list :
- item1
- item2
- item3 Ein CLI -Tool namens himl wird automatisch über pip installiert. Sie können es verwenden, um einen Baum von YAMLS zu analysieren, und es gibt entweder die kombinierte Konfiguration bei der Standardausgabe aus oder schreiben sie in eine Datei.
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=cluster2Basierend auf der Konfigurationsstruktur aus dem Beispiel-/Komplexordner lautet die Ausgabe des obigen Befehls Folgendes:
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
Wo der Beispieleordner ungefähr so aussieht:
$ 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
Um eine Wiederholung zu vermeiden, wollten wir es ermöglichen, einen Wert einmal zu definieren und ihn in anderen Teilen der YAML -Konfiguration wiederzuverwenden. Im Gegensatz zu YAML -Ankern funktionieren diese Interpolationen über mehrere Dateien hinweg.
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 ist möglich, den gleichen Schlüssel (z. B. ein Diktat/eine Liste) in mehreren Dateien zu haben und sie mit einer tiefen Zusammenführung zu kombinieren. Sehen Sie hier ein Beispiel.
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)}} " Verwenden Sie Vault CLI, um die Fallback -Methode über LDAP zu authentifizieren.
Rufen Sie nur einen Schlüsselwert von einem Geheimnis ab. Der Pfadschwanz wird als Schlüssel verwendet:
my_value : " {{vault.key(/path/from/vault/key)}} "Abrufen Sie alle Schlüssel-/Wertpaare von einem Tresorpfad ab:
my_dict : " {{vault.path(/path/from/vault)}} "Generieren Sie ein Token für eine Richtlinie:
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)}} " Das himl-config-merger Skript enthält die Logik der Zusammenführung eines hierarchischen Konfigurationsverzeichnisses und des Erstellens der Yaml-Dateien mit Endergebnissen.
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
Eingabebeispiel:
> 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
Ausgabe:
merged_output
├── dev
│ ├── us-east-1
│ │ ├── cluster1.yaml
│ │ └── cluster2.yaml
│ └── us-west-2
│ └── cluster1.yaml
└── prod
└── eu-west-2
└── ireland1.yaml
Das Nutzung von HIML lädt das Konfigurations-Merger-Skript die Konfigurationsbaumstruktur und Deep-Merken alle Schlüssel aus allen YAML-Dateien, die von einem Root-Pfad zu einer Kante gefunden wurden. Für jedes Blattverzeichnis wird eine Datei unter --output-dir erstellt.
Unter jeder Ebene gibt es einen obligatorischen "Level-Schlüssel", der von Config-Merger zum Berechnen des Endergebnisses verwendet wird. Dieser Schlüssel sollte in einer der Dateien unter jeder Ebene vorhanden sein. (zB Env.yaml unter env).
Einige Konfigurationen, die in den höheren Ebenen des Verzeichnisbaums angegeben sind, sind möglicherweise nicht im Ergebnis (Leaf) erforderlich. Aus diesem Grund kann das Konfigurations-Merger-Skript eine Reihe von Filterregeln anwenden, die über den Parameter --filter-rules-key angegeben werden. Diese Eigenschaft muss in der Konfiguration vorhanden sein und enthält Regeln für die Entfernung der Stammebene aus der Ausgabe. Der Filter wird angewendet, wenn das Selektorobjekt mit einer Teilmenge der Ausgabetasten übereinstimmt und die in der values angegebenen Schlüssel oder die Tasten, die dem regex -Muster übereinstimmen, festgehalten.
# 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 :
- tagsErstellen Sie die Ausgabe mit Filterung:
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 Die Filterung der Regelauswahl und der Tasten funktioniert nur auf der Stammebene der Konfiguration. Es ist nicht möglich, verschachtelte Schlüssel zu filtern.
Abgesehen von den Standardfunktionen in der PyYaml Bibliothek implementiert die himl-config-merger Komponente auch ein benutzerdefiniertes YAML-Tag namens !include
Beispiel:
VA7 : !include configs/env=int/region=va7/kafka-brokers.yaml regionBrokers.VA7Dies ersetzt den Wert nach der Interpolation durch den Wert der RegionBroker.
Ein optionaler Parameter type_strategies kann an configProcessor übergeben werden, um benutzerdefiniertes Zusammenführungsverhalten zu definieren. Es können benutzerdefinierte Funktionen sein, die Ihren Anforderungen entsprechen. Ihre Funktion sollte die Argumente von (Konfiguration, Pfad, Basis, NXT) übernehmen und das zusammengeführte Ergebnis zurückgeben.
Beispiel:
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" ])] ))