Вопрос или проблема
У меня возникает ошибка, при которой поля моей переменной не распознаются при попытке построить конфигурацию с использованием шаблона jinja2. Это нужно для синхронизации репозиториев Linux с системами на основе yum и apt из золотого источника с помощью ansible. Каждая конфигурация репозитория будет размещена в отдельном файле, и задача будет обновлена с именем переменной. Конфигурации основных систем должны быть помещены в один файл с использованием многократных упоминаний “-” и списка атрибутов.
Я рассмотрел:
https://omarkhawaja.com/accessing-ansible-variables-with-jinja2-loops/
а также других, менее актуальных для того, что я делаю.
файл переменных:
---
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 и т.д. должны быть в отдельных файлах)
- создайте файлы переменных, названные {repo}_{pkg_mgr}_repo.yml
- в файле main.yml роли найдите все файлы с {repo}_{pkg_mgr}repo.yml файлы ИЛИ *{pkg_mgr}.yml файлы, основанные на переменной, переданной из Tower/AWX и зарегистрируйте в переменной. Сделайте это для yum и apt, как передано из AWX/Tower
- передайте {variable}.files в задание, которое генерирует конфигурации репозиториев yum или apt.
- используйте модуль шаблона и файл шаблона jinja2 для создания файла репозитория и загрузите его на удаленный сервер.
- выполните задание, чтобы убедиться, что все 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
.
Вот окончательное решение вашей проблемы:
-
Файл переменных (
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
-
Задача для включения переменных:
Убедитесь, что вы корректно Загружаете переменные:- name: Include var into the 'chrome' variable. include_vars: file: google_chrome_repo.yaml name: chrome
-
Задача для использования шаблона:
Измените использование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'
-
Шаблон 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 сможет успешно генерировать необходимые конфигурационные файлы.