仅通过过滤器更改所有dict键值

时间:2019-05-31 07:48:19

标签: ansible jinja2

我有一个烦人的字典

ports:
  webui: 7200
  webadmin: 7209
  core_api: 7201
  stock_api: 7204
  import_export: 7207

我想转换其中的所有键,例如

ports:
  staging-webui: 7200
  staging-webadmin: 7209
  staging-core_api: 7201
  staging-stock_api: 7204
  staging-import_export: 7207

我在“ vars”部分这样做,所以我不能将“ set_fact”和“ with_items”一起使用来迭代字典。只能通过过滤器吗?

我找到了可行的答案,

env: staging # comes from outside

regex_env: "\"key\": \"{{ env }}-\\1\""
app_upstreams: "{{ ports | dict2items | map('to_json') | map('regex_replace', '\"key\":\\s\"(.*)\"', lookup('vars', 'regex_env')) | map('from_json') }}"

但它看起来确实很丑,还有其他好看的解决方案吗?

3 个答案:

答案 0 :(得分:1)

我只是想为自己解决这个问题。我想出了一个不需要使用过滤器插件或 jinja 模板的解决方案。只是纯粹的 ansible playbook 任务。我是在最新版本的 Ansible 上执行此操作的,因此我无法确认它是否适用于旧版本。

它的工作原理是创建具有重命名键的第二个字典,然后用重命名的字典覆盖原始字典。这是一个完整的剧本,您可以将其用作概念证明。

---
- hosts: localhost
  connection: local
  vars:
    prefix: staging
    ports:
      webui: 7200
      webadmin: 7209
      core_api: 7201
      stock_api: 7204
      import_export: 7207
    renamed_ports: {}

  tasks:
  - name: set renamed ports
    ansible.builtin.set_fact:
      renamed_ports: "{{ renamed_ports | combine({ prefix + '-' + item.key: item.value }) }}"
    with_dict: "{{ ports }}"

  - name: rewrite original ports
    ansible.builtin.set_fact:
      ports: "{{ renamed_ports }}"

  - name: erase renamed ports if you want to
    ansible.builtin.set_fact:
      renamed_ports:

  - name: print ports
    ansible.builtin.debug:
      var: ports
...

这是打印端口任务的输出:

TASK [print ports] ****************************************************************************
ok: [localhost] => {
    "ports": {
        "staging-core_api": 7201,
        "staging-import_export": 7207,
        "staging-stock_api": 7204,
        "staging-webadmin": 7209,
        "staging-webui": 7200
    }
}

答案 1 :(得分:0)

您可以使用jinja2模板模块来实现此目的,并使用所有变量创建一个yml文件。

剧本->

---
- hosts: localhost
  vars:
    ports:
      webui: 7200
      webadmin: 7209
      core_api: 7201
      stock_api: 7204
      import_export: 7207
  tasks:
    - name: debug module
      debug:
        var: "{{ item }}"
      with_items:
        - ports

    - name: template
      template:
        src: templates/template.yml
        dest: templates/dest.yml

jinja2模板->

ports:
{% for key, value in ports.iteritems() %}
  staging-{{ key }}: {{ value }}
{% endfor %}

输出->

ports:
  staging-core_api: 7201
  staging-import_export: 7207
  staging-stock_api: 7204
  staging-webui: 7200
  staging-webadmin: 7209

答案 2 :(得分:0)

使用简单的过滤器

$ cat filter_plugins/dict_utils.py
def prefix_key(d, prefix='prefix'):
    for key in d.keys():
        d[prefix + key] = d.pop(key)
    return d
class FilterModule(object):
    ''' utility filters for operating on dictionary '''
    def filters(self):
        return {
            'prefix_key' : prefix_key
        }

下面的任务

- debug:
    var: staging_ports
  vars:
    staging_ports: "{{ ports|prefix_key(prefix='staging_') }}"

给予:

"staging_ports": {
    "staging_core_api": 7201, 
    "staging_import_export": 7207, 
    "staging_stock_api": 7204, 
    "staging_webadmin": 7209, 
    "staging_webui": 7200
}