【问题标题】:Accessing / Replacing Yaml values via python using variables使用变量通过python访问/替换Yaml值
【发布时间】:2018-01-31 07:00:16
【问题描述】:

我一直在尝试解决我认为很简单但无法根据变量更新 yaml 文件的问题

我有什么:

  1. YAML 格式的 ansible hosts 文件。该主机文件并非始终 100% 相同。它可以有一个包含多个图像值的字典(作为一个例子),我只想改变一个。

    namespace: demo1
    images:
      image1:
        path: "path1"
        version: "v1"
      image2:
        path: "path2"
        version: "1.2.3"
        user: "root"
    
  2. 一个 YAML 文件,其中包含我要替换的内容的键/值。我们已经在这个 YAML 中为我们系统的其他部分进行了很多配置,所以如果我能提供帮助(ini、JSON 等),我不想拆分为其他类型的配置类型,我真的很想要这个是点符号。

    schema: v1.0
    hostfile:
    - path: path/to/ansible_hosts_file
      images:
        image1.version: v1.1
    

我正在尝试找到一种从 #1 加载 YAML 的方法,读取密钥 hostfile.images.[variable] 以用新值替换并写回原始 ansible 文件。我一直被变量方面绊倒,因为今天它可以是 image1.version 和下一个配置它的 image2.path 或同时两者。

【问题讨论】:

  • 你能发布你想要的yaml文件吗?

标签: python ansible yaml


【解决方案1】:

我认为您的问题主要来自将键值对与点符号混合。即

images:
  image1.version: v1.1 

而不是做

images.image1.version: v1.1

已解决 Python 和任意分隔符(不一定是“.”)in this answer 的点分表示法检索问题。设置只涉及提供两个额外的函数,它们接受第二个参数,这是设置并将它们移植到CommentedMap resp 的值。 CommentesSeq)

基于此,您需要根据您的密钥进行预选:

upd = ruamel.yaml.round_trip_load(open('update.yaml')
# schema check here
for hostfile in upd['hostfile']:
   data = ruamel.yaml.round_trip_load(open(hostfile['path']))
   images = data['images']
   for dotted in hostfile['images']:
       val = hostfile['images'][dotted]  
       images.string_set(dotted, val)

实际的string_set-ting 代码可能看起来像(未经测试):

def mapping_string_set(self, s, val, delimiter=None, key_delim=None):
    def p(v):
        try:
            v = int(v)
        except:
            pass
        return v
       # possible extend for primitives like float, datetime, booleans, etc.

    if delimiter is None:
        delimiter = '.'
    if key_delim is None:
        key_delim = ','
    try:
        key, rest = s.split(delimiter, 1)
    except ValueError:
        key, rest = s, None
    if key_delim in key:
        key = tuple((p(key) for key in key.split(key_delim)))
    else:
        key = p(key)
    if rest is None:
        self[key] = val
        return 
    self[key].string_set(rest, val, delimiter, key_delim)

ruamel.yaml.comments.CommentedMap.string_set = mapping_string_set

def sequence_string_set(self, s, delimiter=None, key_delim=None):
    if delimiter is None:
        delimiter = '.'
    try:
        key, rest = s.split(delimiter, 1)
    except ValueError:
        key, rest = s, None
    key = int(key)
    if rest is None:
        self[key] = val
        return
    self[key].string_set(rest, val, delimiter, key_delim)

ruamel.yaml.comments.CommentedSeq.string_set = sequence_string_set

【讨论】:

  • 安东,感谢您的帮助。我被拖走了,现在又回到了它,我们修改模板的设计已经改变,所以我无法测试到我可以投票的地方。
猜你喜欢
  • 2011-11-28
  • 1970-01-01
  • 2022-06-15
  • 1970-01-01
  • 2013-06-04
  • 2017-01-20
  • 2011-07-14
  • 1970-01-01
  • 2021-03-16
相关资源
最近更新 更多