Использование ruamel.yaml для обновления блока yaml в файле yaml, который содержит несколько yaml

1

У меня есть файл yaml, который содержит несколько блоков yaml. Файл можно увидеть здесь.

В основном, я пытаюсь обновить значение для одного из ключей изображения (ctrl+f blockfreight/go-bftx: в последнем блоке yaml файла. Тем не менее, я хочу сохранить все о файле (включая комментарии), за исключением одного значения, которое я обновляю.

У меня есть следующий код:

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

Это успешно редактирует значение, сохраняет комментарии нетронутыми, но отправляет только последний блок yaml в stdout.

Есть ли способ изменить только шестой (и последний) блок yaml в app.yaml и сохранить остальную часть файла в целости (комментарии включены)?

Я попробовал заменить pass в приведенном выше коде инструкцией if, которая отправила первые пять yamls в stdout, а затем отредактировала значение в шестом значении, отправив его также в stdout. Мое мышление состояло в том, чтобы использовать bash для отправки всех файлов stdout в файл (например, 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)

Будем очень благодарны любой помощи! Спасибо!

Теги:
yaml

1 ответ

0
Лучший ответ

Ваш файл состоит из нескольких документов YAML, это то, что вы читаете при использовании round_trip_load_all, который дает вам генератор.

Если вы пишете, что обратно с помощью round_trip_dump(), вы никогда не собираетесь, чтобы получить --- разделителей документов YAML, которые находятся в исходном файле.

Вероятно, вы можете использовать генератор и round_trip_dump_all поскольку вы знаете, в каком документе внести изменения, но, вероятно, проще составить list того, что round_trip_load_all генерирует и работает над этим. Я также использовал ruamel.yaml API ruamel.yaml для этого:

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 diff с изменением, которое вы хотите сделать, и некоторыми стандартными стандартами (отступы, между [ "), которые, конечно, одно.

При таком подходе есть две основные проблемы:

  • Первый документ YAML в файле не имеет содержимого, поэтому его комментарии нельзя подвешивать из любого сопоставления/последовательности и не сохраняются
  • Второй документ 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="[email protected]:8888,[email protected]:8888,[email protected]:8888,[email protected]: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
  • 0
    Спасибо за предельно тщательный ответ!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню