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"
}
Другие вопросы по тегам