изменение вложенного dict - PullRequest
       3

изменение вложенного dict

0 голосов
/ 26 августа 2018

После развертывания виртуальной машины с IP-адресом DHCP я хотел бы получить IP-адрес и добавить его в словарь гостей.

Для первой виртуальной машины (testvm2) код выполняется должным образом и обновляет переменную tempipдля ВМ testvm2.

Но со второй виртуальной машиной (testvm1) она обновляет переменную tempip первой виртуальной машины (testvm2) с помощью IP-адреса второй виртуальной машины (testvm1) и обновляет переменную tempip второй виртуальной машины (testvm1)с кодом переменной '{{tempip_reg.stdout_lines}}'

Может кто-нибудь объяснить мне, почему это происходит?Буду признателен за помощь.

Я скопировал весь соответствующий код и вывод ниже:

словарь гостей:

---
guests:
  testvm1:
    mem: 512
    cpus: 1
    clone: template-centos
    vmid: 102
    tempip:

  testvm2:
    mem: 1536
    cpus: 2
    clone: template-centos
    vmid: 102
    tempip:

Ansible Playbook, который запускает задачу:

---
- name: Provision VMs
  hosts: infra
  become: true
  vars_files:
    - group_vars/vms.yml
    - group_vars/vars.yml
  tasks:
    - include_tasks: roles/tasks/provision-tasks.yml
      with_dict: "{{ guests }}"

Ansible Tasks:

- name: Run proxmox-get-ip-linux.sh script to register DHCP IP of VM
  script: proxmox-get-ip-linux.sh "{{ item.key }}"
  register: tempip_reg

- name: temporary IP of VM "{{ item.key }}"
  debug:
    var: tempip_reg

- name: current host in item.key
  set_fact:
    current_host: "{{ item.key }}"

- name: current_host variable set to
  debug:
    var: current_host

- name: append item.value.tempip with the DHCP IP of the VM registered in 
 last task
  set_fact:
    guests: "{{ guests|combine({ current_host: {'tempip': '{{ tempip_reg.stdout_lines }}' }}, recursive=True) }}"

- name: temporary IP of "{{ item.key }}"
  debug: var=guests

Результат первой виртуальной машины:

"tempip_reg": {
    "stdout": "192.168.1.21\r\n",
    "stdout_lines": [
        "192.168.1.21"
    }

"current_host": "testvm2"

"guests": {
    "testvm1": {
        "clone": "template-centos",
        "cpus": 1,
        "ip": "192.168.1.60",
        "mem": 512,
        "tempip": null,
        "vmid": 102
    },
    "testvm2": {
        "clone": "template-centos",
        "cpus": 2,
        "ip": "192.168.1.61",
        "mem": 1536,
        "tempip": [
            "192.168.1.21"
        ],
        "vmid": 102
    }
}

Результат второй виртуальной машины:

"tempip_reg": {
    "stdout": "192.168.1.22\r\n",
    "stdout_lines": [
        "192.168.1.22"
    }

    "current_host": "testvm1"

"guests": {
    "testvm1": {
        "clone": "template-centos",
        "cpus": 1,
        "ip": "192.168.1.60",
        "mem": 512,
        "tempip": "{{ tempip_reg.stdout_lines }}",
        "vmid": 102
    },
    "testvm2": {
        "clone": "template-centos",
        "cpus": 2,
        "ip": "192.168.1.61",
        "mem": 1536,
        "tempip": [
            "192.168.1.22"
        ],
        "vmid": 102
    }
}

1 Ответ

0 голосов
/ 27 августа 2018

TL; DR

Используя код Ansible, вы пытаетесь реализовать то, что Ansible уже делает для вас.

Ваши попытки совмещаются со встроенной функциональностью, и выполучить результаты, которые выглядят недетерминированными.


Объяснение:

  • Основная проблема в вашем коде - это совершенно ненужный цикл, объявленный с with_dict: "{{ guests }}", который вызывает включениеподать 4 раза.

    Он запускается 4 раза, потому что вы изменяете словарь guests, который зацикливается внутри включенного файла задач.

    Фактически вы получаете нечто, похожее на недетерминированный результат.

  • Вторая проблема является тривиальной: вы всегда заменяете значение tempip на строку {{ tempip_reg.stdout_lines }}.

  • Теперь из-заненужный цикл with_dict над словарем, который вы динамически изменяете, и поскольку Jinja2 использует отложенную оценку переменных, строки из предыдущих итераций интерпретируются как шаблоны и оцениваются с неверными значениями в последующих итерациях.

    Последняя итерация оставляетстрока {{ tempip_reg.stdout_lines }} не повреждена.

  • Вы также определяете и печатаете два разных факта.


Что вы должны сделать:

  • Вы не должны объявлять произвольные итерации вообще.Ansible реализует цикл для всех хостов.То есть, если вы объявите задачу:

    - include_tasks: roles/tasks/provision-tasks.yml
    

    , файл будет включен для каждого из хостов в группе infra (дважды в вашем примере).

  • Кажется, вы хотите иметь одну копию вашей структуры данных с обновленными значениями для каждой виртуальной машины.

    В то же время вы создаете факт, который представляет собой отдельный объект данных, поддерживаемый для каждого хоста отдельно.

    Таким образом, вы должны ссылаться и изменять (combine) один факт - вы можете сделать это, например, на localhost.


Вы должныструктурируйте ваш код следующим образом:

---
- name: Provision VMs
  hosts: infra
  become: true
  vars_files:
    - group_vars/vms.yml
    - group_vars/vars.yml
  tasks:
    - include_tasks: roles/tasks/provision-tasks.yml
    - debug:
        var: hostvars['localhost'].guests

и provision-tasks.yml:

- set_fact:
    guests: "{{ guests|combine({ current_host: {'tempip': tempip_reg.stdout_lines }}, recursive=True) }}"
  delegate_to: localhost

Это даст вам следующий результат:

"hostvars['localhost'].guests": {
    "testvm1": {
        "clone": "template-centos",
        "cpus": 1,
        "ip": "192.168.1.60",
        "mem": 512,
        "tempip": [
            "192.168.1.21"
        ],
        "vmid": 102
    },
    "testvm2": {
        "clone": "template-centos",
        "cpus": 2,
        "ip": "192.168.1.61",
        "mem": 1536,
        "tempip": [
            "192.168.1.22"
        ],
        "vmid": 102
    }
}

Наконец, в вышеприведенной игре вы использовали каталоги group_vars и roles/tasks в неверном контексте.Я оставил пути нетронутыми, и они будут работать для приведенного выше кода, но в основном вы никогда не должны использовать их таким образом, потому что, опять же, они имеют особое значение и обработку в Ansible.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...