最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ansible - How to combine dictionaries directly in var file - Stack Overflow

programmeradmin3浏览0评论

I would like to use variable servers.server1 in task without additional steps like step_var. How to substitute variables and add dictionaries to another dictionary outside of tasks in var file?

#var/main.yaml

common_parts_1:
  storage:
    type: nfs
    value: 10GB
common_parts_2:
  cpu:
    cores: 2
  memory:
    value: 2GB
  
servers:
  server1:
    name: superPC
    owner: John 
    "{{ common_parts_1 }}"
    "{{ common_parts_2 }}"

Expected result:

servers:
  server1:
    name: superPC
    owner: John
    storage:
      type: nfs
      value: 10GB
    cpu:
      cores: 2
    memory:
      value: 2GB

I would like to use variable servers.server1 in task without additional steps like step_var. How to substitute variables and add dictionaries to another dictionary outside of tasks in var file?

#var/main.yaml

common_parts_1:
  storage:
    type: nfs
    value: 10GB
common_parts_2:
  cpu:
    cores: 2
  memory:
    value: 2GB
  
servers:
  server1:
    name: superPC
    owner: John 
    "{{ common_parts_1 }}"
    "{{ common_parts_2 }}"

Expected result:

servers:
  server1:
    name: superPC
    owner: John
    storage:
      type: nfs
      value: 10GB
    cpu:
      cores: 2
    memory:
      value: 2GB

Share Improve this question edited Feb 17 at 8:11 phanaz 1,58111 silver badges22 bronze badges asked Feb 16 at 19:29 KucharskyKucharsky 2651 gold badge5 silver badges21 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 2

I see two simple ways to implement this

  • Ansible's combine filter
  • YAML anchors and aliases

Ansible's combine filter

# vars/vars1.yml
---
common_parts_1:
  storage:
    type: nfs
    value: 10GB
common_parts_2:
  cpu:
    cores: 2
  memory:
    value: 2GB

servers_pre:
  server1:
    name: superPC
    owner: John

servers:
  server1: "{{ servers_pre.server1 | combine(common_parts_1) | combine(common_parts_2) }}"

First you do not define servers but e.g. servers_pre. Then you can define servers by combining the data from the other variables, for this you can use the combine filter of Ansible.

YAML anchors and aliases

# vars/vars2.yml
---
common_parts_1: &common_parts_1
  storage:
    type: nfs
    value: 10GB
common_parts_2: &common_parts_2
  cpu:
    cores: 2
  memory:
    value: 2GB

servers:
  server1:
    name: superPC
    owner: John
    <<: [*common_parts_1, *common_parts_2]
  server2:
    name: nanoPC
    owner: James
    <<: *common_parts_2

This variant is based purely on YAML and uses YAML anchors and aliases. You do not only define the key common_parts_1, but also define the data structure as an anchor using &common_parts_1. You can then insert this data structure elsewhere using the alias *common_parts_1.

To insert a data structures with an alias in a level on which you have already defined data, use <<: followed by the alias (see server2). If you want to insert several anchored data structures, define the aliases as a list (see server1).

Difference between the two variants

Attention, the two variants are not identical.

If you have the same key in common_parts_1 and common_parts_2: combine (in the default configuration list_merge=replace) overwrites the last occurrence of the key. Therefore, the order of the combine variant should be chosen from the most general (left) to the most specific (right). The YAML variant acts slightly differently here.

Make your own tests to ensure that the result is as desired.

Put the dictionaries you want to combine into a list

servers:
  server1: "{{ [common_parts_1, common_parts_2, server1] | combine }}"

gives what you want

servers:
    server1:
        cpu:
            cores: 2
        memory:
            value: 2GB
        name: superPC
        owner: John
        storage:
            type: nfs
            value: 10GB

As a side note: Combine all server_* with all common_parts_.*. For example, given the file var/main.yml

shell> cat var/main.yml
common_parts_1:
  storage:
    type: nfs
    value: 10GB
common_parts_2:
  cpu:
    cores: 2
  memory:
    value: 2GB
  
server_1:
  name: superPC
  owner: John
  
server_2:
  name: trashPC
  owner: Jack
  cpu:
    cores: 1
  memory:
    value: 512MB

declare the below variables in the same file

common_parts: "{{ q('vars', *q('varnames', '^common_parts_.*$')) | combine }}"
servers_values: "{{ [common_parts] | product(q('vars', *q('varnames', '^server_.*$')))
                                   | map('combine') }}"
servers_names: "{{ q('varnames', '^server_.*$') }}"
servers: "{{ dict(servers_names | zip(servers_values)) }}"

Then, the below play

- hosts: all

  vars_files:
    - var/main.yml

  tasks:

    - debug:
        var: common_parts

    - debug:
        var: servers_names

    - debug:
        var: servers_values

    - debug:
        var: servers

gives

    servers:
        server_1:
            cpu:
                cores: 2
            memory:
                value: 2GB
            name: superPC
            owner: John
            storage:
                type: nfs
                value: 10GB
        server_2:
            cpu:
                cores: 1
            memory:
                value: 512MB
            name: trashPC
            owner: Jack
            storage:
                type: nfs
                value: 10GB
发布评论

评论列表(0)

  1. 暂无评论