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

ansible - How to convert complex YAML dictionary to another format? - Stack Overflow

programmeradmin5浏览0评论

I have an Ansible role that uses a rather complex configuration in form of a dictionary. The old config format wasn't beneficial in many ways so I rewrote the role to be a lot easier to configure.

As the role is already in broad use I'd like to stay compatible with existing inventories and playbooks that use the old config format. In order to achieve this I thought I could migrate the old config into the new format (all data is there and migratable, so technically it's possible) before running the role.

Sample data

  • NOTE: content makes no sense, but it shows the structural differences between formats
  • NOTE2: this question is about a general approach to this problem (use set_facts? use templates? use custom Python script?) and not about the actual migration of the sample data

Old config format:

petshop_old:
  petshop_data:
    name: awesome_petshop
  employee_data:
    - name_of_employee: sara
      date_of_birth: 2000
    - name_of_employee: john
      date_of_birth: 1995
  task_data:
    - name: clean_dogs
      time: morning
      by: john
    - name: clean_cats
      time: evening
      by: john
    - name: feed_birds
      time: evening
      by: sara

New config format:

petshop_new:
  name: awesome_petshop
  employees:
    - name: sara
      birth_year: 2000
      tasks:
        - name: feed_birds
          time: evening
    - name: john
      birth_year: 1995
      tasks:
        - name: clean_dogs
          time: morning
        - name: clean_cats
          time: evening

tasks/main.yml:

- name: Migrate the old config data into the new format
  when: (petshop_old is defined) and (petshop_new is not defined)
  block:
    [...] Here come the migration tasks [...]

- name: This tasks prints the config, even when originally petshop_old was given to the role
  ansible.builtin.debug:
    var: petshop_new
[...] do more stuff with the data [...]

What would be the best approach to migrate the old config into the new format before running the actual tasks that perform the role?

I have an Ansible role that uses a rather complex configuration in form of a dictionary. The old config format wasn't beneficial in many ways so I rewrote the role to be a lot easier to configure.

As the role is already in broad use I'd like to stay compatible with existing inventories and playbooks that use the old config format. In order to achieve this I thought I could migrate the old config into the new format (all data is there and migratable, so technically it's possible) before running the role.

Sample data

  • NOTE: content makes no sense, but it shows the structural differences between formats
  • NOTE2: this question is about a general approach to this problem (use set_facts? use templates? use custom Python script?) and not about the actual migration of the sample data

Old config format:

petshop_old:
  petshop_data:
    name: awesome_petshop
  employee_data:
    - name_of_employee: sara
      date_of_birth: 2000
    - name_of_employee: john
      date_of_birth: 1995
  task_data:
    - name: clean_dogs
      time: morning
      by: john
    - name: clean_cats
      time: evening
      by: john
    - name: feed_birds
      time: evening
      by: sara

New config format:

petshop_new:
  name: awesome_petshop
  employees:
    - name: sara
      birth_year: 2000
      tasks:
        - name: feed_birds
          time: evening
    - name: john
      birth_year: 1995
      tasks:
        - name: clean_dogs
          time: morning
        - name: clean_cats
          time: evening

tasks/main.yml:

- name: Migrate the old config data into the new format
  when: (petshop_old is defined) and (petshop_new is not defined)
  block:
    [...] Here come the migration tasks [...]

- name: This tasks prints the config, even when originally petshop_old was given to the role
  ansible.builtin.debug:
    var: petshop_new
[...] do more stuff with the data [...]

What would be the best approach to migrate the old config into the new format before running the actual tasks that perform the role?

Share Improve this question edited Feb 5 at 12:42 β.εηοιτ.βε 39.1k14 gold badges77 silver badges98 bronze badges asked Jan 23 at 7:07 MOnsDaRMOnsDaR 8,6648 gold badges55 silver badges72 bronze badges 6
  • Read old Yaml with some programming language, convert to new format using ordinarry array/object functions, write new Yaml config file – Justinas Commented Jan 23 at 7:21
  • I thought there would be a good way to do this in Ansible as part of the role instead of doing this on the side... Looks like I approached this from the wrong angle :/ – MOnsDaR Commented Jan 23 at 7:33
  • Why to convert it every time, if you can do it only once? – Justinas Commented Jan 23 at 7:50
  • 1 Because I do not have control over all the old inventories and playbooks using the role. – MOnsDaR Commented Jan 23 at 8:55
  • 1 Please refrain from adding an answer to the question itself. – β.εηοιτ.βε Commented Feb 5 at 12:43
 |  Show 1 more comment

2 Answers 2

Reset to default 1

For the given old.conf YAML file, using a quick and lazy loop approach with Jinja2 Templating, a minimal example playbook

---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

    - include_vars:
        file: old.conf
        name: old

    - debug:
        var: old

    - debug:
        msg: |
          petshop_new:
            name: {{ old.petshop_old.petshop_data.name }}
            employees:
          {% for employee in old.petshop_old.employee_data %}
              - name: {{ employee.name_of_employee }}
                birth_year: {{ employee.date_of_birth }}
                tasks:
          {% for task in old.petshop_old.task_data %}
          {% if employee.name_of_employee == task.by %}
                  - name: {{ task.name }}
                    time: {{ task.time }}
          {% endif %}
          {% endfor %}
          {% endfor %}

will result into an output of

TASK [debug] *****************
ok: [localhost] =>
  old:
    petshop_old:
      employee_data:
      - date_of_birth: 2000
        name_of_employee: sara
      - date_of_birth: 1995
        name_of_employee: john
      petshop_data:
        name: awesome_petshop
      task_data:
      - by: john
        name: clean_dogs
        time: morning
      - by: john
        name: clean_cats
        time: evening
      - by: sara
        name: feed_birds
        time: evening

TASK [debug] *****************
ok: [localhost] =>
  msg: |-
    petshop_new:
      name: awesome_petshop
      employees:
        - name: sara
          birth_year: 2000
          tasks:
            - name: feed_birds
              time: evening
        - name: john
          birth_year: 1995
          tasks:
            - name: clean_dogs
              time: morning
            - name: clean_cats
              time: evening

It can become easily written out via

    - copy:
        dest: new.conf
        content: |
          pet...

I solved it using a template and the ansible.builtin.template filter.

config_migration.j2:

petshop_new:
  name: {{ petshop_old['petshop_data']['name'] }}
  [...] further jinja-templating to create a YAML with the new cfg format [...]

Migration tasks:

- name: Migrate the old config data into the new format
  when: (petshop_old is defined) and (petshop_new is not defined)
  ansible.builtin.set_fact:
    petshop_new: '{{ lookup("ansible.builtin.template", "./config_migration.j2") | from_yaml }}'

- name: This tasks prints the config, even when originally petshop_old was given to the role
  ansible.builtin.debug:
    var: petshop_new
[...] do more stuff with the data [...]
发布评论

评论列表(0)

  1. 暂无评论