【问题标题】:How do I add a pipe the vertical bar (|) into a yaml file from Python如何从 Python 将竖线 (|) 添加到 yaml 文件中
【发布时间】:2021-07-08 19:52:59
【问题描述】:

我有一个任务。我需要编写 python 代码来为 kubernetes 生成一个 yaml 文件。到目前为止,我一直在使用 pyyaml,它工作正常。这是我生成的 yaml 文件:

apiVersion: v1
kind: ConfigMap
data:
  info: 
    name: hostname.com
    aio-max-nr: 262144
    cpu:
      cpuLogicalCores: 4
    memory:
      memTotal: 33567170560
    net.core.somaxconn: 1024
    ...

但是,当我尝试创建此 configMap 时,错误是 info 需要一个 string() 而不是一个地图。所以我探索了一下,似乎解决这个问题的最简单方法是在这样的信息之后添加一个管道:

apiVersion: v1
kind: ConfigMap
data:
  info: | # this will translate everything in data into a string but still keep the format in yaml file for readability
    name: hostname.com
    aio-max-nr: 262144
    cpu:
      cpuLogicalCores: 4
    memory:
      memTotal: 33567170560
    net.core.somaxconn: 1024
    ...

这样,我的configmap就创建成功了。我的挣扎是我不知道如何从 python 代码中添加那个管道栏。这里我是手动添加的,但我想自动化整个过程。

我写的部分python代码是,假装数据是一个dict():

content = dict()
content["apiVersion"] = "v1"
content["kind"] = "ConfigMap"
data = {...}
info = {"info": data}
content["data"] = info

# Get all contents ready. Now write into a yaml file
fileName = "out.yaml"
with open(fileName, 'w') as outfile:
    yaml.dump(content, outfile, default_flow_style=False)   

我在网上搜索了很多案例,但没有一个符合我的需求。提前致谢。

【问题讨论】:

  • 请注意: | 只是语法上的精巧; yaml 表示的实际数据始终相同,因此除非您生成该 yaml 文件以供 human 消费,否则 kubernetes 并不关心管道标量。此外,在您的代码中,您有 data = {,但在生成的 yaml 中,您将其作为字符串。这听起来是您没有得到预期结果的一个很好的理由。
  • @mdaniel 感谢您的回复。解决此问题的一种方法是将 data={...} 转换为类似 res = json.dumps(data, indent=2) 的字符串。这样,yaml 文件看起来很难看,并且 kubernetes 确实成功地创建了这个 configmap,但是如果我在 kubernetes 中执行 kubectl describe configmap,结果看起来与我添加 bar 时的结果非常不同。是的,数据都在 kubernetes 的 configmap 中,但是它们以丑陋的方式呈现。哈哈

标签: python kubernetes yaml pyyaml configmap


【解决方案1】:

管道使包含的值成为字符串。 YAML 不会处理该字符串,即使它包含具有 YAML 语法的数据。因此,您需要提供一个字符串作为值。

由于字符串包含 YAML 语法中的数据,您可以通过在上一步中使用 YAML 处理包含的数据来创建字符串。要使 PyYAML 以文字块样式(即使用 |)转储标量,您需要一个自定义表示器:

import yaml, sys
from yaml.resolver import BaseResolver

class AsLiteral(str):
  pass

def represent_literal(dumper, data):
  return dumper.represent_scalar(BaseResolver.DEFAULT_SCALAR_TAG,
      data, style="|")

yaml.add_representer(AsLiteral, represent_literal)

info = {
  "name": "hostname.com",
  "aio-max-nr": 262144,
  "cpu": {
    "cpuLogicalCores": 4
  }
}

info_str = AsLiteral(yaml.dump(info))

data = {
  "apiVersion": "v1",
  "kind": "ConfigMap",
  "data": {
    "info": info_str
  }
}

yaml.dump(data, sys.stdout)

通过将渲染的 YAML 数据放入 AsLiteral 类型中,将调用注册的自定义表示器,它将所需的样式设置为 |

【讨论】:

  • 非常感谢。但是为什么类 AsLiteral(str) 是通过的?如果这个类什么都不做,那我们为什么需要它呢?
  • @LividFont info 的值应通过represent_literal 表示的指令通过使用AsLiteral 类传递给PyYAML。会不会像其他所有东西一样是str,我们将无法告诉 PyYAML 以不同的方式对待它。
猜你喜欢
  • 2023-03-03
  • 2012-02-28
  • 2021-10-15
  • 2023-03-29
  • 2015-09-08
  • 2021-11-11
  • 2018-09-20
  • 2019-07-04
  • 2023-02-02
相关资源
最近更新 更多