Как использовать включенные переменные из файла с шаблоном jinja2 и with_items.

Вопрос или проблема

У меня возникает ошибка, при которой поля моей переменной не распознаются при попытке построить конфигурацию с использованием шаблона jinja2. Это нужно для синхронизации репозиториев Linux с системами на основе yum и apt из золотого источника с помощью ansible. Каждая конфигурация репозитория будет размещена в отдельном файле, и задача будет обновлена с именем переменной. Конфигурации основных систем должны быть помещены в один файл с использованием многократных упоминаний “-” и списка атрибутов.

Я рассмотрел:

цикл for в jinja2

https://omarkhawaja.com/accessing-ansible-variables-with-jinja2-loops/

https://stackoverflow.com/questions/25418158/templating-multiple-yum-repo-files-with-ansible-template-module

а также других, менее актуальных для того, что я делаю.

файл переменных:

---
repo:
  - name: google_chrome
    async: 1
    url: http://dl.google.com/linux/chrome/rpm/stable/x86_6
...

включение задания переменной:

- name: Включить переменные в переменную 'chrome'.
  include_vars:
    file: google_chrome_repo.yaml
    name: chrome

задание для использования модуля шаблона:

- name: сгенерировать конфигурацию для Centos
  template:
    src: yum_template.j2
    dest: "/etc/yum.repos.d/{{ item }}.repo"
    backup: yes
  with_items:
    - chrome
  when:
    - ansible_distribution == 'CentOS'

шаблон:

{% for i in item %}
[ {{ i.name }} ]
async = {{ i.async }}
baseurl = {{ i.url }}
enabled = {{ i.repo_enable }}
enablegroups = {{ i.pkggrp_enable }}
failovermethod = {{ i.ha_method }}
gpgkey = {{ i.gpgkey_url }}
http_caching = {{ i.http_caching }}
keepcache = {{ i.keepcache }}
metadata_expire = {{ i.metadata_expire }}
mirrorlist = {{ i.mirrorlist }}
mirrorlist_expire = {{ i.mirrorlist_expire }}
name = {{ i.descrip }}
protect = {{ i.protect }}
proxy = {{ i.proxy_config }}
proxy_password =  {{ i.proxy_username }}
proxy_username = {{ i.proxy_password }}
repo_gpgcheck = {{ i.repo_gpgcheck }}
retries = {{ i.repo_retry_count }}
s3_enabled = {{ i.s3_enabled }}
sslverify = {{ i.ssl_verify }}
timeout = {{ i.timeout }}
{% endfor %}

ошибка:

failed: [192.168.33.31] (item=chrome) => {"changed": false, "item": "chrome", "msg": "AnsibleUndefinedVariable: 'unicode object' has no attribute 'name'"}

любой атрибут в роли, который вызывается первым шаблоном jinja2, будет приводить к такой ошибке. Если я изменю следующий код, чтобы имя не было упомянуто, и “i.name” стало просто “chrome”, то ошибка будет на async.

Я вижу, что переменная импортирована.

ok: [192.168.33.31] => {"ansible_facts": {"chrome": {"repo": [{"async": 1, "descrip": "Google Chrome Repository", "gpgkey_url": "https://dl.google.com/linux/linux_signing_key.pub", "ha_method": "roundrobin", "http_caching": 1, "keepcache": 1, "metadata_expire": 21600, "mirrorlist": null, "mirrorlist_expire": 21600, "name": "google_chrome", "pkggrp_enable": 1, "protect": 0, "proxy_config": "__None__", "proxy_password": null, "proxy_username": null, "repo_enable": 1, "repo_gpgcheck": 1, "repo_retry_count": 10, "s3_enabled": 0, "ssl_verify": 1, "timeout": 1, "url": "http://dl.google.com/linux/chrome/rpm/stable/x86_6"}]}}, "ansible_included_var_files": ["/var/lib/awx/projects/_6__trowe/playbooks/roles/Manage_Linux_Repos/vars/google_chrome_repo.yaml"], "changed": false}

Я вижу, что указано “unicode” переменная, где я ожидал увидеть словарь. Я также пробовал with_dict, и ошибка говорит, что переменная не является словарем. Однако если я структурирую файл переменной без “repo:”, то возникает ошибка, говорящая о том, что он не был передан объект словаря…

Я нашел лучший способ достижения цели.

цель: позволить пользователям создавать файлы переменных с информацией о репозиториях. несколько репозиториев в одном файле и один к одному. (например: файл репозитория CentOS-Base имеет множество различных элементов, но elasticsearch, epel и т.д. должны быть в отдельных файлах)

  1. создайте файлы переменных, названные {repo}_{pkg_mgr}_repo.yml
  2. в файле main.yml роли найдите все файлы с {repo}_{pkg_mgr}repo.yml файлы ИЛИ *{pkg_mgr}.yml файлы, основанные на переменной, переданной из Tower/AWX и зарегистрируйте в переменной. Сделайте это для yum и apt, как передано из AWX/Tower
  3. передайте {variable}.files в задание, которое генерирует конфигурации репозиториев yum или apt.
  4. используйте модуль шаблона и файл шаблона jinja2 для создания файла репозитория и загрузите его на удаленный сервер.
  5. выполните задание, чтобы убедиться, что все gpg ключи импортированы для текущих репозиториев

** необходимо учесть, что стандартные apt репозитории размещаются в sources.list, а другие – в /etc/apt/sources.list.d/

это протестировано и работает для дистрибутивов на основе yum, сейчас работаю над APT.

Измените {% for i in item %} на {% for i in item.repo %}

Это должно решить проблему, так как ваш элемент хранит целую переменную словаря, вам нужно вызвать подсловарь под переменной chrome, который и есть repo.

Ответ или решение

Чтобы исправить вашу проблему с использованием переменных из файла и шаблоном Jinja2 с with_items, вам необходимо внести следующие изменения в ваш код.

Ваш текущий код пытается обращаться к элементам переменной item, но item на самом деле представляет собой строку "chrome", а не саму переменную. Поэтому, когда вы пытаетесь обратиться к i.name, Ansible сообщает, что переменная не определена, потому что i — это строка. Чтобы это исправить, вам нужно обращаться к содержимому переменной, которая была импортирована, в вашем случае — это chrome.repo.

Вот окончательное решение вашей проблемы:

  1. Файл переменных (google_chrome_repo.yaml):
    Убедитесь, что структура файла, который вы загружаете, выглядит так:

    ---
    repo:
     - name: google_chrome
       async: 1
       url: http://dl.google.com/linux/chrome/rpm/stable/x86_64
       repo_enable: 1
       pkggrp_enable: 1
       gpgkey_url: https://dl.google.com/linux/linux_signing_key.pub
       ha_method: roundrobin
       http_caching: 1
       keepcache: 1
       metadata_expire: 21600
       mirrorlist: null
       mirrorlist_expire: 21600
       descrip: Google Chrome Repository
       protect: 0
       proxy_config: "__None__"
       proxy_password: null
       proxy_username: null
       repo_gpgcheck: 1
       repo_retry_count: 10
       s3_enabled: 0
       ssl_verify: 1
       timeout: 1
  2. Задача для включения переменных:
    Убедитесь, что вы корректно Загружаете переменные:

    - name: Include var into the 'chrome' variable.
     include_vars:
       file: google_chrome_repo.yaml
       name: chrome
  3. Задача для использования шаблона:
    Измените использование with_items так, чтобы это соответствовало правильной структуре:

    - name: Generate config for Centos
     template:
       src: yum_template.j2
       dest: "/etc/yum.repos.d/{{ item.name }}.repo"
       backup: yes
     loop: "{{ chrome.repo }}"
     when:
       - ansible_distribution == 'CentOS'
  4. Шаблон Jinja2 (yum_template.j2):
    Измените ваш шаблон так, чтобы он корректно использовал переменные:

    {% for i in chrome.repo %}
    [{{ i.name }}]
    async = {{ i.async }}
    baseurl = {{ i.url }}
    enabled = {{ i.repo_enable }}
    enablegroups = {{ i.pkggrp_enable }}
    failovermethod = {{ i.ha_method }}
    gpgkey = {{ i.gpgkey_url }}
    http_caching = {{ i.http_caching }}
    keepcache = {{ i.keepcache }}
    metadata_expire = {{ i.metadata_expire }}
    mirrorlist = {{ i.mirrorlist }}
    mirrorlist_expire = {{ i.mirrorlist_expire }}
    name = {{ i.descrip }}
    protect = {{ i.protect }}
    proxy = {{ i.proxy_config }}
    proxy_password = {{ i.proxy_password }}
    proxy_username = {{ i.proxy_username }}
    repo_gpgcheck = {{ i.repo_gpgcheck }}
    retries = {{ i.repo_retry_count }}
    s3_enabled = {{ i.s3_enabled }}
    sslverify = {{ i.ssl_verify }}
    timeout = {{ i.timeout }}
    {% endfor %}

Теперь ваш шаблон должен корректно обрабатывать переменные, и вы не должны получать ошибки, связанные с отсутствующими атрибутами. Убедитесь, что все нужные переменные (например, repo_enable, pkggrp_enable) присутствуют в файле переменных для каждого репозитория, и тогда Ansible сможет успешно генерировать необходимые конфигурационные файлы.

Оцените материал
Добавить комментарий

Капча загружается...