【问题标题】:Using ruamel.yaml to update yaml block in yaml file which contains multiple yamls使用 ruamel.yaml 更新包含多个 yaml 的 yaml 文件中的 yaml 块
【发布时间】:2018-11-27 18:00:33
【问题描述】:

我有一个包含多个 yaml 块的 yaml 文件。文件可见here

基本上,我正在尝试更新文件最后一个 yaml 块中一个图像键 (ctrl+f blockfreight/go-bftx:) 的值。但是,我想保留有关文件的所有内容(包括 cmets),除了我正在更新的一个值。

我有以下代码:

"""
Retrieves a truncated version of the latest git commit sha and updates 
the go-bftx container image tag in app.yaml
"""

import sys
import ruamel.yaml
from subprocess import check_output

yaml_path = 'app.yaml'
for yaml_block in ruamel.yaml.round_trip_load_all(stream=open(yaml_path)):
    pass

# parse the most recent git commit sha from command line
docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 -- pretty=format:%h'.split()).decode()

# update go-bftx image with most recent git-commit-sha tag in the StatefulSet block
yaml_block['spec']['template']['spec']['containers'][1]['image'] = docker_image

ruamel.yaml.round_trip_dump(yaml_block, sys.stdout)

这成功编辑了值,保持 cmets 完整,但只将最终的 yaml 块发送到标准输出。

我有什么方法可以只编辑 app.yaml 中的第六个(也是最后一个)yaml 块,并保持文件的其余部分完好无损(包括 cmets)?

我尝试将上述代码中的pass 替换为将前五个yaml 发送到stdout 的if 语句,然后编辑第六个值中的值,并将其发送到stdout。我的想法是使用 bash 将所有标准输出发送到文件(例如 python app_modifier.py > app1.yaml),但这仅发送了第六个 yaml 的输出。

该代码如下所示:

for i, yaml_block in enumerate(ruamel.yaml.round_trip_load_all(stream=open(yaml_path))):
    if i != 5:
        ruamel.yaml.round_trip_dump(yaml_block, sys.stdout)
    else:
        # parse the most recent git commit sha from command line
        docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 --pretty=format:%h'.split()).decode()

        # update go-bftx image with most recent git-commit-sha tag in the StatefulSet blocks
        yaml_block['spec']['template']['spec']['containers'][1]['image'] = docker_image

        ruamel.yaml.round_trip_dump(yaml_block, sys.stdout)

任何帮助将不胜感激!谢谢!

【问题讨论】:

    标签: python yaml


    【解决方案1】:

    您的文件包含多个 YAML 文档,这是您使用 round_trip_load_all 读取的内容,它为您提供了一个生成器。

    如果您使用 round_trip_dump() 将其写回,您将永远无法获得原始文件中的 --- YAML 文档分隔符。

    您可能可以使用生成器和round_trip_dump_all,因为您知道要在哪个文档中进行更改,但是创建listround_trip_load_all 生成并处理它可能更容易。我也会使用 ruamel.yaml 的新 API 来做到这一点:

    import sys
    import ruamel.yaml
    
    yaml = ruamel.yaml.YAML()
    yaml.preserve_quotes = True
    data = list(yaml.load_all(open('app.yaml')))
    
    # parse the most recent git commit sha from command line
    # docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 -- pretty=format:%h'.split()).decode()
    docker_image = 'blockfreight/go-bftx:ci-cd-' + 'check_output_output'
    
    # update go-bftx image with most recent git-commit-sha tag in the StatefulSet block
    data[-1]['spec']['template']['spec']['containers'][1]['image'] = docker_image
    
    with open('out.yaml', 'w') as ofp:
        yaml.dump_all(data, ofp)
    

    上述大部分有效。 out.yaml 差异与您想要进行的更改以及一些空白标准化(缩进,在 [ " 之间)当然是一次性的。

    这种方法有两个主要问题:

    • 文件中的第一个 YAML 文档没有内容,因此它的 cmets 不能挂在任何映射/序列中,也不会被保留
    • 第二个 YAML 文档有一个被删除的最终注释 (# // Initializes BFTX Service to interact with endpoints)。这很可能是 ruamel.yaml 中的一个错误,它只出现在多文档文件中,我必须进行调查

    要解决第一个问题,您只能将该文档作为普通行读取,而无需ruamel.yaml。当你这样做时,你也可以只做其余的,因为这也解决了(即规避)第二个问题:

    import sys
    import ruamel.yaml
    
    with open('out.yaml', 'w') as ofp:
        lines = ''
        with open('app.yaml') as ifp:
            for line in ifp:
                lines += line
                if line == '---\n':
                    ofp.write(lines)
                    lines = ''
        # process lines from the last document
        # print(lines)
        yaml = ruamel.yaml.YAML()
        yaml.preserve_quotes = True
        data = yaml.load(lines)
    
        # parse the most recent git commit sha from command line
        # docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 -- pretty=format:%h'.split()).decode()
        docker_image = 'blockfreight/go-bftx:ci-cd-' + 'check_output_output'
    
        # update go-bftx image with most recent git-commit-sha tag in the StatefulSet block
        data['spec']['template']['spec']['containers'][1]['image'] = docker_image
    
        yaml.dump(data, ofp)
    

    这应该可以满足您的需求,除非您关心流样式序列中的前导尾随空格,或者保留缩进不一致的三个位置。 diff -u app.yaml out.yaml的输出:

    --- app.yaml    2018-06-23 14:41:02.256290577 +0200
    +++ out.yaml    2018-06-23 14:58:09.933991459 +0200
    @@ -143,7 +143,7 @@
     spec:
       selector:
         matchLabels:
    -       app: bftx
    +      app: bftx
       serviceName: blockfreight
       replicas: 1
       template:
    @@ -151,7 +151,7 @@
           labels:
             app: bftx
         spec:
    -     containers:
    +      containers:
           - name: tm
             imagePullPolicy: IfNotPresent
             image: tendermint/tendermint:0.20.0
    @@ -199,7 +199,7 @@
               tendermint node --moniker="`hostname`" --p2p.seeds="aeabbf6b891435013f2a800fa9e22a1451ca90fd@bftx0.blockfreight.net:8888,6e9515c2cfed19464e6ce11ba2297ecdb411103b@bftx1.blockfreight.net:8888,b8b988370783bd0e58bf926d621a47160af2bdae@bftx2.blockfreight.net:8888,8c091f4e3dc4ac27db1efd38beee012d99967fd8@bftx3.blockfreight.net:8888" --proxy_app="tcp://localhost:46658" --consensus.create_empty_blocks=false
           - name: app
             imagePullPolicy: Always
    -        image: blockfreight/go-bftx:rc1
    +        image: blockfreight/go-bftx:ci-cd-check_output_output
             ports:
             - containerPort: 12345
             - containerPort: 46658
    @@ -247,7 +247,7 @@
             - mountPath: /etc/nginx/conf.d/pub_key.conf
               name: tmconfigdir
               subPath: pub_key_nginx.conf
    -     volumes:
    +      volumes:
           - name: tmconfigdir
             configMap:
               name: bftx-config
    @@ -262,7 +262,7 @@
           annotations:
             volume.alpha.kubernetes.io/storage-class: anything
         spec:
    -      accessModes: [ "ReadWriteOnce" ]
    +      accessModes: ["ReadWriteOnce"]
           resources:
             requests:
               storage: 2Gi
    @@ -271,7 +271,7 @@
           annotations:
             volume.alpha.kubernetes.io/storage-class: anything
         spec:
    -      accessModes: [ "ReadWriteOnce" ]
    +      accessModes: ["ReadWriteOnce"]
           resources:
             requests:
               storage: 12Mi
    

    【讨论】:

    • 感谢您非常彻底的回答!
    猜你喜欢
    • 2011-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 1970-01-01
    • 2021-12-11
    • 2021-12-24
    • 1970-01-01
    • 2021-07-07
    相关资源
    最近更新 更多