Ansible: как создать переменную из другой переменной, а затем извлечь ее значение
Вот моя проблема: мне нужно использовать одну переменную "target_host", а затем добавить "_host" к ее значению, чтобы получить другое имя переменной, значение которой мне нужно. Если вы посмотрите на мою пьесу. Задача nbr 1,2,3 извлекает значение переменной, однако nbr 4 не может сделать то, что я ожидаю. Есть ли другой способ добиться того же в ANSIBLE?
---
- name: "Play to for dynamic groups"
hosts: local
vars:
- target_host: smtp
- smtp_host: smtp.max.com
tasks:
- name: testing
debug: msg={{ target_host }}
- name: testing
debug: msg={{ smtp_host }}
- name: testing
debug: msg={{ target_host }}_host
- name: testing
debug: msg={{ {{ target_host }}_host }}
Output:
TASK: [testing] ***************************************************************
ok: [127.0.0.1] => {
"msg": "smtp"
}
TASK: [testing] ***************************************************************
ok: [127.0.0.1] => {
"msg": "smtp.max.com"
}
TASK: [testing] ***************************************************************
ok: [127.0.0.1] => {
"msg": "smtp_host"
}
TASK: [testing] ***************************************************************
ok: [127.0.0.1] => {
"msg": "{{{{target_host}}_host}}"
}
7 ответов
Вы должны поместить цитаты вокруг этого:
- hosts: local
vars: [ target_host: smtp ]
tasks:
debug: msg="{{ target_host }}_host"
-- редактировать --
Кашьяп мне нужно пройти еще один уровень, чем этот. Представьте, что есть другая переменная 'smtp_host', и я хочу создать эту переменную во время выполнения, используя другую переменную (target_host) и присоединяя к ней строку '_host'. = {{ {{ target_host }}_host }} - Макс
Виноват. Не читал достаточно внимательно.
Это (AFAIK) невозможно. Основное ограничение, которое мешает нам сделать это (независимо от того, как вы его раскручиваете), заключается в том, что "расширение переменной" в ansible- это однопроходный процесс, а для того, что вы хотите, требуется многократный проход.
Я могу придумать только [серьезно хакерские] способы:
- Динамически создавайте книгу из своей книги, используя
template
и выполнить его. - Я слышал, что двигатель Jinja2 выполняет многоходовую оценку. Может быть, если вы поместите эти строки в шаблон, а затем использовать
lookup('template', ...)
фильтр. К сожалению, у меня нет опыта работы с шаблонами Jinja2, поэтому я не совсем уверен, если это вообще вариант.
Если у вас есть переменная, как
vars:
myvar: xxx
xxx_var: anothervalue
рабочий синтаксис Ansible:
- debug: msg={{ vars[myvar + '_var'] }}
даст вам аналог:
- debug: msg={{ xxx_var }}
Это возможно в Ansible 2.5 с vars
плагин поиска, который, я думаю, с меньшей вероятностью сломается без предупреждения, чем некоторые другие методы, опубликованные здесь. Например:
---
- name: "Example of dynamic groups"
hosts: localhost
vars:
- target_host: smtp
- smtp_host: smtp.max.com
tasks:
- name: testing
debug: msg={{ lookup('vars', target_host + '_host') }}
Выход:
PLAY [Example of dynamic groups] **************************************************
TASK [Gathering Facts] **************************************************
ok: [localhost]
TASK [testing] **************************************************
ok: [localhost] => {
"msg": "smtp.max.com"
}
Вы можете использовать "hostvars" для передачи переменной, факты о хосте могут быть загружены из групповых или хост-переменных
YML
---
- name: "Play to for dynamic groups"
hosts: x0
vars:
- target_host: smtp
tasks:
- set_fact: smtp_host="smtp.max.com"
- set_fact: host_var_name={{target_host}}_host
- set_fact: dym_target_host={{hostvars[inventory_hostname][host_var_name]}}
- name: testing
debug: msg={{ target_host }}
- name: testing
debug: msg={{ smtp_host }}
- name: testing
debug: msg={{ target_host }}_host
- name: testing
debug: msg={{ dym_target_host }}
выход:
PLAY [Play to for dynamic groups] *********************************************
GATHERING FACTS ***************************************************************
ok: [x0]
TASK: [set_fact smtp_host="smtp.max.com"] *************************************
ok: [x0]
TASK: [set_fact host_var_name=smtp_host] **************************************
ok: [x0]
TASK: [set_fact dym_target_host={{hostvars[inventory_hostname][host_var_name]}}] ***
ok: [x0]
TASK: [testing] ***************************************************************
ok: [x0] => {
"msg": "smtp"
}
TASK: [testing] ***************************************************************
ok: [x0] => {
"msg": "smtp.max.com"
}
TASK: [testing] ***************************************************************
ok: [x0] => {
"msg": "smtp_host"
}
TASK: [testing] ***************************************************************
ok: [x0] => {
"msg": "smtp.max.com"
}
PLAY RECAP ********************************************************************
x0 : ok=8 changed=0 unreachable=0 failed=0
В настоящее время я использую массивоподобный синтаксис Jinja 2. Я не думаю, что это отличное решение, но мне еще предстоит найти что-то лучшее.
Позвольте мне привести пример с одной из моих абстрактных задач. Посмотрите мою переменную конфигурацию и пример задачи ниже:
# Variables file, available in the task context
containers:
app:
image: mynamespace/myappcontainer:snapshot
web:
image: nginx:latest
db:
image: mariadb:latest
# Example task
- name: Start containers
docker_container:
name: "{{ item }}"
image: "{{ containers[item].image }}"
with_items:
- app
- web
- db
В приведенном выше примере я использую with_items
Ansible цикл, который запускает задачу для каждого элемента и делает {{ item }}
переменная доступна соответственно.
Это приводит к созданию 3 контейнеров Docker, каждый из которых имеет правильное имя контейнера на основе списка элементов и правильное изображение, полученное из внешних переменных, которые я настроил.
Хотя этот пример использует with_items
Это, конечно, адаптируется к вашей проблеме с использованием ваших собственных переменных.
Хотя в этой ситуации это прекрасно работает, я боюсь, что для этого требуется, чтобы переменные, к которым вы хотели бы получить доступ, были частью некоторой родительской переменной (containers
в этом примере). Поэтому я бы рекомендовал разделить переменные .
построить иерархию, а не с _
,
Переменная как a.b.c
где b
является динамическим, будет доступен с помощью a[b].c
,
Переменная как a.b
где b
является динамическим, будет доступен с помощью a[b]
,
Решение, которое вы бы использовали, может выглядеть (не проверено):
- name: "Play to for dynamic groups"
hosts: local
vars:
- target: smtp
- hosts:
smtp: smtp.max.com
imap: imap.max.com
tasks:
- name: testing
debug: msg={{ hosts[target] }}
Обратите внимание, что переменные настроены немного по-другому, потому что их структура является иерархической.
У вас есть два способа выбора:
1. Общее использование.
vars:
- target_host: smtp
- smtp: smtp.max.com
tasks:
- name: testing
debug: msg={{ target_host }}
- name: testing
debug: msg={{ smtp }}
- name: testing
debug: msg={{ vars[target_host] }}
2. Используя факт
tasks:
- set_fact: target_host=smtp
- set_fact: smtp=smtp.max.com
- name: testing
debug: msg={{ target_host }}
- name: testing
debug: msg={{ smtp }}
- name: testing
debug: msg={{hostvars[inventory_hostname][target_host]}}
Вы можете попробовать глобальный массив var:
regions:
us-east-1:
endpoint: rds.us-east-1.amazonaws.com
cn-north-1:
endpoint: rds.cn-north-1.amazonaws.com.cn
cn-northwest-1:
endpoint: rds.cn-northwest-1.amazonaws.com.cn
И используйте его, чтобы получить значение в зависимости от другого:
region_endpoint: "{{ regions[region].endpoint}}"
В твоем случае:
target_host:
imap:
host: imap.max.com
smtp:
host: smtp.max.com
тогда:
region_endpoint: "{{ target_host[service].host}}"
Вы можете вкладывать свои поиски так:
---
- hosts: local
connection: local
gather_facts: no
vars:
target_host: smtp
lookup_host: "{{ target_host }}_host"
smtp_host: smtp.max.com
tasks:
- debug: var="{{ lookup_host }}"
Выше есть много ответов. Это мне очень помогло. Но я не нашел ни одного ответа, как сохранить эту переменную в файле vars-> main.yml. Поэтому вам нужно создать словарь в файле vars-> main.yml.
vars -> файл main.yml
cassandra_version: 2.1.16
file_sha_cassandra: "apache-cassandra-{{ cassandra_version }}_sha256"
# Create Dictionary here
cassandra:
apache-cassandra-2.1.16_sha256: "sha256: checksum_of_file"
##Add more variable
Теперь вам нужно вызвать это в файле task -> main.yml:
---
- name: Down load Cassandra Binaries
get_url:
url: "file_url"
dest: "{{ base_directory }}"
checksum: "{{ cassandra[file_sha_cassandra] }}"
timeout: 800
Мне кажется, вы можете просто использовать var
вариант вместо msg
:
debug: var="{{ target_host }}_host"
дает:
TASK [testing] ********************************************************************************************************************************
ok: [localhost] => {
"smtp_host": "smtp.max.com"
}