使用变量

时间:2017-08-22 21:07:04

标签: python ansible yaml

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

我有什么:

  1. YAML格式的ansible主机文件。此主机文件始终不是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
    
  3. 我试图找到一种方法从#1加载YAML,读取密钥hostfile.images。[variable]来替换并用新值写回原始的ansible文件。我一直在变量方面绊倒,因为今天它可以是image1.version,下一个配置它的image2.path或两者同时。

1 个答案:

答案 0 :(得分:0)

我认为您的问题主要来自将键值对与点分表示法混合。即。

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 - 代码看起来像(未经测试):

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