Uma configuração hierárquica usando YAML em Python.
A versão mais recente é: 0.15.2
Um módulo Python que permite mesclar arquivos de configuração hierárquica usando a sintaxe YAML. Oferece mesclagem profunda, interpolação variável e recuperação de segredos dos gerentes de segredos.
É ideal se você deseja estruturar sua hierarquia de tal maneira que você evite a duplicação. Você pode definir uma estrutura para sua configuração usando uma hierarquia como ambiente/projeto/cluster/app. Cabe a você quais camadas você deseja usar nesta hierarquia. A ferramenta lerá todos os arquivos YAML a partir da raiz (onde os valores padrão seriam) até a folha (onde seria a maioria dos valores específicos, o que terá precedência).
A ideia veio da Hiera de Puppet.
pipdockerdict inteiropip pip install himldocker docker run ghcr.io/adobe/himl:latest himl-config-merger --helpVeja todas as tags do Docker em: https://github.com/adobe/himl/pkgs/container/himl/versions
git clone https://github.com/adobe/himl
cd himl
sudo python install -e .
Isso mesclará simples/default.yaml com simples/produção/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 ) O exemplo acima se fundirá simple/default.yaml com simple/production/env.yaml :
$ tree examples/simple
examples/simple
├── default.yaml
└── production
└── env.yaml
O exemplo também mostra a fusão profunda de listas e 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 Uma ferramenta CLI chamada himl é instalada automaticamente via pip . Você pode usá -lo para analisar uma árvore de iamls e ele produzirá a configuração combinada na saída padrão ou a gravará em um arquivo.
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=cluster2Com base na árvore de configuração da pasta exemplos/complexos, a saída do comando acima será o seguinte:
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
Onde a pasta Exemplos se parece com o seguinte:
$ 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 a repetição, queríamos possibilitar definir um valor uma vez e reutilizá -lo em outras partes da configuração da YAML. Ao contrário das âncoras da YAML, essas interpolações funcionam em vários arquivos.
data/default.yaml :
allowed_roles :
- " arn:aws:iam::{{account.id}}:role/myrole " data/dev/env.yaml :
account:
id: "123456"
dict inteiro 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}} "É possível ter a mesma chave (por exemplo, um ditado/lista) em vários arquivos e combiná -los usando uma mesclagem profunda. Veja um exemplo aqui.
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 CLI do Vault para autenticar o método de fallback via LDAP.
Recuperar apenas um valor -chave de um segredo, a cauda do caminho é usada como chave:
my_value : " {{vault.key(/path/from/vault/key)}} "Recuperar todos os pares de chave/valor de um caminho do cofre:
my_dict : " {{vault.path(/path/from/vault)}} "Gerar um token para uma 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)}} " O script himl-config-merger , contém lógica de mesclar um diretório de configuração hierárquica e criar os arquivos YAML do resultado 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
Exemplo 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
Saída:
merged_output
├── dev
│ ├── us-east-1
│ │ ├── cluster1.yaml
│ │ └── cluster2.yaml
│ └── us-west-2
│ └── cluster1.yaml
└── prod
└── eu-west-2
└── ireland1.yaml
Aproveitando o HIML, o script de configuração carrega a estrutura da árvore das configurações e erra profundamente todas as teclas de todos os arquivos YAML encontrados de um caminho raiz para uma borda. Para cada diretório de folhas, um arquivo será criado em --output-dir .
Em cada nível, existe uma "chave de nível" obrigatória usada pela Config-Merger para calcular o resultado final. Essa chave deve estar presente em um dos arquivos em cada nível. (por exemplo, Env.yaml sob Env).
Algumas configurações especificadas nos níveis mais altos da árvore do diretório podem não ser necessários no final do final (folha). Por esse motivo, o script Config-Merger pode aplicar um conjunto de regras de filtro que são especificadas através do parâmetro --filter-rules-key . Esta propriedade deve estar presente na configuração e contém regras para remover as teclas de nível raiz da saída. O filtro é aplicado se o objeto seletor corresponder a um subconjunto das teclas de saída e manterá as chaves especificadas na lista values ou nas teclas que correspondem ao padrão 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 :
- tagsCrie a saída com a filtragem:
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 Seletores de regras e filtragem de teclas funciona apenas no nível raiz da configuração. Não é possível filtrar as teclas aninhadas.
Além dos recursos padrão encontrados na biblioteca PyYaml , o componente himl-config-merger também implementa uma tag YAML personalizada chamada !include .
Exemplo:
VA7 : !include configs/env=int/region=va7/kafka-brokers.yaml regionBrokers.VA7Isso substituirá o valor após a interpolação pelo valor dos brokers da região.VA7 encontrado no caminho das configurações/env = int/região = va7/kafka-corkers.yaml.
Um parâmetro opcional type_strategies pode ser transmitido para o ConfigProcessor para definir o comportamento de fusão personalizado. Podem ser funções personalizadas que atendam às suas necessidades. Sua função deve assumir os argumentos de (Config, Path, Base, NXT) e retornar o resultado mesclado.
Exemplo:
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" ])] ))