Иерархическая конфигурация с использованием YAML в Python.
Последняя версия: 0.15.2
Модуль Python, который позволяет объединять иерархические файлы конфигурации с использованием синтаксиса YAML. Он предлагает глубокое слияние, переменную интерполяцию и поиск секретов от менеджеров Secrets.
Это идеально, если вы хотите структурировать свою иерархию таким образом, чтобы избежать дублирования. Вы можете определить структуру для вашей конфигурации, используя иерархию такую среду/проект/кластер/приложение. Вам решать, какие слои вы хотите использовать в этой иерархии. Инструмент будет считывать все файлы YAML, начиная с корня (где будут значения по умолчанию) вплоть до листа (где будут наиболее конкретные значения, что будет иметь приоритет).
Идея пришла из Иеры.
pipdockerdictpip pip install himldocker docker run ghcr.io/adobe/himl:latest himl-config-merger --helpСмотрите все теги Docker по адресу: https://github.com/adobe/himl/pkgs/container/himl/versions
git clone https://github.com/adobe/himl
cd himl
sudo python install -e .
Это объединит Simple/default.yaml с 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 ) Приведенный выше пример будет объединять simple/default.yaml с simple/production/env.yaml :
$ tree examples/simple
examples/simple
├── default.yaml
└── production
└── env.yaml
Пример также демонстрирует глубокое слияние списков и карт.
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 :
- item3Результат:
env : prod
deep :
key1 : v1
key2 : v2
key3 : v3
deep_list :
- item1
- item2
- item3 Инструмент CLI, называемый himl , автоматически установлен через pip . Вы можете использовать его для анализа дерева yamls, и оно будет выводить комбинированную конфигурацию на стандартном выходе, либо записать его в файл.
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=cluster2На основе дерева конфигурации из примеров/комплексной папки, выход команды выше будет следующим:
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
Где папка примеров выглядит примерно так:
$ 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
Чтобы избежать повторения, мы хотели сделать возможным определить значение один раз и повторно использовать его в других частях конфигурации YAML. В отличие от якорей YAML, эти интерполяции работают в нескольких файлах.
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}} "Можно иметь один и тот же ключ (например, DICT/List) в нескольких файлах и объединить их с помощью глубокого слияния. Смотрите пример здесь.
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)}} " Используйте CLI Vault для аутентификации, метод отступления через LDAP.
Получите только одно значение ключа из секрета, хвост пути используется в качестве ключа:
my_value : " {{vault.key(/path/from/vault/key)}} "Получить все пары ключей/значения с пути хранилища:
my_dict : " {{vault.path(/path/from/vault)}} "Создайте токен для политики:
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)}} " Сценарий himl-config-merger , содержит логику слияния иерархического каталога конфигурации и создания конечных файлов YAML.
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
Пример ввода:
> 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
Выход:
merged_output
├── dev
│ ├── us-east-1
│ │ ├── cluster1.yaml
│ │ └── cluster2.yaml
│ └── us-west-2
│ └── cluster1.yaml
└── prod
└── eu-west-2
└── ireland1.yaml
Используя HIML, сценарий конфигурации загружает структуру дерева конфигураций и глубоко перемет всех клавиш из всех файлов YAML, найденных из корневого пути к краю. Для каждого каталога листьев будет создан файл под --output-dir .
Под каждым уровнем существует обязательный «клавиш уровня», который используется Config-Merger для вычисления конечного результата. Этот ключ должен присутствовать в одном из файлов под каждым уровнем. (например, Env.yaml под Env).
Некоторые конфигурации, которые указаны на более высоких уровнях дерева каталогов, могут не понадобиться в результате конца (листьев). По этой причине сценарий конфигурации может применять набор правил фильтра, которые указаны через параметр --filter-rules-key . Это свойство должно присутствовать в конфигурации и содержит правила для удаления клавиш корневого уровня из вывода. Фильтр применяется, если объект селектора соответствует подмножеству выходных клавиш и будет хранить клавиши, указанные в списке values , или клавиши, которые соответствуют шаблону 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 :
- tagsСоздайте выход с фильтрацией:
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 Селекторы правил и фильтрация клавиш работает только на корневом уровне конфигурации. Невозможно отфильтровать вложенные ключи.
Помимо стандартных функций, найденных в библиотеке PyYaml , компонент himl-config-merger также реализует пользовательский тег YAML, который называется !include .
Пример:
VA7 : !include configs/env=int/region=va7/kafka-brokers.yaml regionBrokers.VA7Это заменит значение после интерполяции со значением региона.
Необязательный параметр type_strategies может быть передана в конфигурацию, чтобы определить пользовательское поведение слияния. Это могут быть пользовательские функции, которые соответствуют вашим потребностям. Ваша функция должна принимать аргументы (config, path, base, nxt) и вернуть объединенный результат.
Пример:
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" ])] ))