PythonでYAMLを使用した階層構成。
最新バージョンは0.15.2です
YAML構文を使用して階層構成ファイルをマージできるPythonモジュール。秘密マネージャーからの深いマージ、可変補間、および秘密の検索を提供します。
重複を避けるように階層を構成したい場合は理想的です。環境/プロジェクト/クラスター/アプリなどの階層を使用して、構成の構造を定義できます。この階層で使用したいレイヤーはあなた次第です。このツールは、ルート(デフォルト値がある)から葉まで始まるすべてのYAMLファイルを読み取ります(ほとんどの特定の値が優先される場合)。
アイデアは人形のhieraから来ました。
pipを使用しますdocker画像を使用しますdictを補間しますpipを使用しますpip install himldocker画像を使用しますdocker run ghcr.io/adobe/himl:latest himl-config-merger --helphttps://github.com/adobe/himl/pkgs/container/himl/versionsですべてのDockerタグを参照してください
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
- item3himlと呼ばれるCLIツールがpipを介して自動的にインストールされます。それを使用してヤムルのツリーを解析すると、標準出力で結合された構成を出力するか、ファイルに書き込みます。
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)}} " Vault CLIを使用して、LDAPを介してフォールバックメソッドを認証します。
秘密から1つのキー値のみを取得すると、パステールはキーとして使用されます。
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の下に作成されます。
各レベルでは、最終結果を計算するために構成合併によって使用される必須の「レベルキー」があります。このキーは、各レベルの下のファイルの1つに存在する必要があります。 (例:envの下のenv.yaml)。
ディレクトリツリーのより高いレベルで指定された一部の構成は、最終(葉)結果では必要ない場合があります。このため、Config-Merger Scriptは--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コンポーネントは、 !include呼ばれるカスタムYAMLタグも実装しています。
例:
VA7 : !include configs/env=int/region=va7/kafka-brokers.yaml regionBrokers.VA7これにより、補間後の値は、configs/env = int/region = va7/kafka-brokers.yamlパスの下にあるRegionBrokers.va7の値に置き換えられます。
オプションのパラメーターtype_strategies configprocessorに渡して、カスタムマージの動作を定義できます。ニーズに合ったカスタム関数である可能性があります。関数は、(構成、パス、ベース、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" ])] ))