【问题标题】:Generating dynamic YAML file from a for loop in Python从 Python 中的 for 循环生成动态 YAML 文件
【发布时间】:2021-05-20 05:00:47
【问题描述】:

我有一个template.yml,内容如下:

hostname:
   image: my_image:latest
   script:
    - ansible -m command -a "echo Hi"  hostname

使用python,我需要读取一个.txt文件,内容如下:

server1.example.com
server2.example.com
server3.example.com
...

并使用一些循环并替换上面template.yml 中两个位置的主机名变量。所有配置都需要在一个 output.yml 文件中。

我一直在尝试使用 python yaml 库及其 yaml.update 和 yaml.dump 功能,但无法将所有生成的配置存储在同一个输出文件中。对此的任何帮助表示赞赏。

更新:

我已经添加了我在下面尝试过的代码:

import yaml

def generate_yml(host):
    with open('template.yml') as f:
        config = yaml.safe_load(f)
        config['hostname']['script'] = "ansible -m command -a 'echo Hi' " + host
    return config

    with open('output.yml', 'w') as f:
        yaml.dump(config, f, default_flow_style=False)

hostfile = open("test.txt", "r")
for host in hostfile:
    host = host.rstrip("\n")
    generate_yml(host)
myfile.close()

对于yaml_update,我试过了:

    with open('output.yml','r') as f:
        config = yaml.load(yamlfile)
        config['hostname']['script'] = "ansible -m command -a 'echo Hi' " + host  
        config['hostname'].update(config)
        
    with open('output.yml', 'w') as yamlfile:
        yaml.dump(config, yamlfile, default_flow_style=False)

这两种方法都只为.txt文件中的最后一个条目编写配置,并且不考虑template.yml中的第一个主机名变量。

【问题讨论】:

  • 提供示例输入文件和示例输出文件以及您尝试过但不起作用的代码会很有帮助
  • @KrishnaChaurasia 添加了详细信息。
  • @KrishnaChaurasia 我正在寻找这样的东西:pastebin.com/e6JLwVMN

标签: python yaml pyyaml


【解决方案1】:

试试这个。 它将模板加载为字典,并为每个主机使用适当的hostname 替换形成一个新字典,并将整个内容转储到output.yml 文件中。请注意,这需要 PyYaml - pip insatll pyyaml

import yaml


with open("./template.yml") as f:
    template = yaml.load(f)

HOSTS = [
    "host_a",
    "host_b",
    "host_c"
]

output = {host: template["hostname"] for host in HOSTS}


with open("./output.yml", "w") as f:
    yaml.dump(output, f)

【讨论】:

  • 这失败了output = {host: template["hostname"]) for host in HOSTS} ^ SyntaxError: invalid syntax
  • @slal,对不起,我添加了一个额外的)。我编辑了答案,请重试
【解决方案2】:

当前代码存在一些问题:

  1. 使用return config,您只是退出函数而不写入文件。
  2. 您每次都以写入模式w 打开文件,因此内容会被覆盖。
  3. 您正在将script 部分添加为字符串对象,但它应该是右侧yamllist

正确的实现应该是:

import yaml
def generate_yml(host):
    with open('template.yml') as f:
        config = yaml.safe_load(f)
        config[host] = config['hostname'].copy()
        config[host]['script'] = ["ansible -m command -a 'echo Hi' " + host] # add the command as a list for the correct yaml
        del config['hostname']   # del the 'hostname' key from config

    with open('output.yml', 'a') as f: # open the file in append mode
        yaml.dump(config, f, default_flow_style=False)

hostfile = open("test.txt", "r")
for host in hostfile:
    host = host.rstrip("\n")
    generate_yml(host)

hostfile.close()

输出:

server1.example.com:
  image: my_image:latest
  script:
  - ansible -m command -a 'echo Hi' server1.example.com
server2.example.com:
  image: my_image:latest
  script:
  - ansible -m command -a 'echo Hi' server2.example.com
server3.example.com:
  image: my_image:latest
  script:
  - ansible -m command -a 'echo Hi' server3.example.com

【讨论】:

  • 非常感谢。这样就完成了。
【解决方案3】:

YAML 不是模板引擎。您是否考虑过使用模板引擎?

这就是使用 pystache 的方法:

import pystache, yaml

input = """
{{#hostnames}}
{{.}}:
   image: my_image:latest
   script:
    - ansible -m command -a "echo Hi"  {{.}}
{{/hostnames}}
"""

vars = """
server1.example.com
server2.example.com
server3.example.com
"""

print(pystache.render(input, {"hostnames": [h for h in vars.splitlines() if h]}))

输出:

server1.example.com:
   image: my_image:latest
   script:
    - ansible -m command -a "echo Hi"  server1.example.com
server2.example.com:
   image: my_image:latest
   script:
    - ansible -m command -a "echo Hi"  server2.example.com
server3.example.com:
   image: my_image:latest
   script:
    - ansible -m command -a "echo Hi"  server3.example.com

与将输入实际解析为 YAML 相比,您可以在使用模板引擎时保持格式(例如 cmets 和原始缩进)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 2015-03-26
    相关资源
    最近更新 更多