简体   繁体   English

使用ruamel.yaml更新包含多个Yaml的Yaml文件中的Yaml块

[英]Using ruamel.yaml to update yaml block in yaml file which contains multiple yamls

I've got a yaml file which contains several yaml blocks. 我有一个包含几个yaml块的yaml文件。 The file can be seen here . 该文件可以在这里看到。

Basically, I am trying to update the value for one of the image keys ( ctrl+f blockfreight/go-bftx: ) in the last yaml block of the file. 基本上,我正在尝试更新文件最后一个Yaml块中图像键之一( ctrl+f blockfreight/go-bftx:的值。 However, I want to preserve everything about the file (including comments) except for the one value that I am updating. 但是,我要保留有关文件的所有内容(包括注释),但我要更新的值除外。

I've got the following code: 我有以下代码:

"""
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)

This successfully edits the value, keeps comments intact, but only sends the final yaml block to stdout. 这样可以成功编辑值,保持注释完整,但只会将最终的yaml块发送到stdout。

Is there any way for me to edit only the sixth (and final) yaml block in app.yaml, and keep the rest of the file intact (comments included)? 我有什么办法可以只编辑app.yaml中的第六个(也是最后一个)yaml块,并保持文件的其余部分不变(包括注释)?

I tried replacing pass in the above code with an if statement that sent the first five yamls to stdout, and then edited the value in the sixth value, sending that to stdout as well. 我尝试用pass前五个Yaml发送到stdout的if语句替换上述代码中的pass,然后编辑第六个值中的值,并将其也发送到stdout。 My thinking was to use bash to send all of the stdout to a file (eg python app_modifier.py > app1.yaml ), but this only sent the output from the sixth yaml. 我的想法是使用bash将所有stdout发送到文件(例如python app_modifier.py > app1.yaml ),但这仅发送了第六个python app_modifier.py > app1.yaml的输出。

That code looked like this: 该代码如下所示:

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)

Any assistance would be greatly appreciated! 任何帮助将不胜感激! Thank you! 谢谢!

Your file consists of multiple YAML documents, this is what you read in using round_trip_load_all , which gives you a generator. 您的文件包含多个YAML文档,这是您使用round_trip_load_all所阅读的round_trip_load_all ,它为您提供了一个生成器。

If you write that back using round_trip_dump() , you are never going to get the --- YAML document separators that are in the original file. 如果使用round_trip_dump()写回该round_trip_dump() ,则永远不会获得原始文件中的--- YAML文档分隔符。

You can probably use a generator and round_trip_dump_all since you know in which document to make changes, but it is probably easier to make a list of what round_trip_load_all generates and work on that. 您可能可以使用一个generator和round_trip_dump_all因为您知道在哪个文档中进行更改,但是list round_trip_load_all生成的内容并进行处理可能更容易。 I would also use ruamel.yaml 's new API to do so: 我还将使用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)

The above mostly works. 以上大部分有效。 The out.yaml diff's with the change you want to make, and some whitespace standardisations (indents, between [ " ) which are of course one off. out.yaml diff包含您要进行的更改,以及一些空白标准化(缩进, [ "之间),这当然是一次性的。

There are two major issues with this approach: 这种方法有两个主要问题:

  • The first YAML document in the file has no content, so its comments cannot be hung from any mapping/sequence and are not preserved 该文件中的第一个YAML文档没有内容,因此其注释不能从任何映射/序列中挂起并且也不会保留
  • The second YAML document has a final comment ( # // Initializes BFTX Service to interact with endpoints ) that gets dropped. 第二个YAML文档具有最后的注释( # // Initializes BFTX Service to interact with endpoints )。 That is most likely a bug in ruamel.yaml that shows up in multi-document files only and that I have to investigate 这很可能是ruamel.yaml中的错误,该错误仅显示在多文档文件中,我必须进行调查

To solve the first issue, you can only read that document as normal lines without ruamel.yaml . 要解决第一个问题,您只能将该文档阅读为常规行,而没有ruamel.yaml When you do so, you might as well do all but the rest, as this solves (ie circumvents) the second issue as well: 当您这样做时,除了其余步骤之外,您也可以做所有其他事情,因为这也可以解决(即规避)第二个问题:

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)

This should do what you want unless you care about the leading trailing space in a flow style sequence, or preserve the three places with inconsistent indentation. 除非您关心流程样式序列中的前尾空格,否则这应该做您想做的事情,或者保留三个缩进不一致的位置。 The output of diff -u app.yaml out.yaml : 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM