it-swarm.com.ru

Ansible - with_dict: dictionary - Как использовать переменные, определенные в каждом словаре, которые зависят от других

Среда: Ansible 1.9.2, CentOS 6.5

Я создал роль для загрузки файлов артефактов Java (.tar.gz) для 3 различных версий Java из Artifactory. Я пытаюсь использовать функцию with_dict от Ansible (вместо использования with_items).

Созданы следующие файлы:

Роли $ cat/Java/defaults/main.yml

---
Java_versions:
  Java7_60:
    version: 1.7.60
    group_path: com/Oracle/jdk
    classifier: linux-x64
    ext: tar.gz
    dist_file: "jdk-{{ version }}-{{ classifier }}-{{ ext }}"
#    dist_file: "jdk-{{item.value.version }}-{{ item.value.classifier }}-{{ item.value.ext }}"
    dist_url: "{{ artifactory_url }}/{{ group_path }}/{{ version }}/{{ dist_file }}"
#    dist_url: "{{ artifactory_url }}/{{ item.value.group_path }}/{{ item.value.version }}/{{ dist_file }}"

  Java7_67:
    version: 1.7.67
    group_path: com/Oracle/jdk
    classifier: linux-x64
    ext: tar.gz
    dist_file: "jdk-{{item.value.version }}-{{ item.value.classifier }}-{{ item.value.ext }}"
    dist_url: "{{ artifactory_url }}/{{ item.value.group_path }}/{{ item.value.version }}/{{ dist_file }}"
  Java8_45:
    version: 1.8.45
    group_path: com/Oracle/jdk
    classifier: linux-x64
    ext: tar.gz
    dist_file: "jdk-{{item.value.version }}-{{ item.value.classifier }}-{{ item.value.ext }}"
    dist_url: "{{ artifactory_url }}/{{ item.value.group_path }}/{{ item.value.version }}/{{ dist_file }}"

Как я могу установить или использовать dist_file или dist_url переменные, которые зависят от других переменных, определенных в том же ключе (скажем, в KEY Java7_60)?

Прямо сейчас, когда я пытаюсь использовать текущие переменные dist_file или dist_urlИЛИзакомментированные строки способом их установки (т. Е. С помощью item.value.), Это не устанавливает значение этих 2 переменных по желанию то есть в зависимости от других переменных version, group_path, classifier, ext и artifactory_url (которые определены в файле defaults/main.yml другой распространенной роли).

Я видел, что для использования with_dict: в playbook/task я должен использовать {{item.value .variable_name}}, но как определить переменную, которая зависит от других в том же разделе KEY словаря ,.

Сообщение об ошибке, которое я получаю при использовании вышеуказанного словаря в следующей задаче:

Роли $ cat/Java/tasks/main.yml :

- name: Download Java/JDK Versions
  command: wget -q "{{ item.value.dist_url }}"
    chdir="{{ common_download_dir }}"
    creates="{{ common_download_dir }}/{{ item.value.dist_file }}"
  with_dict: "{{ Java_versions }}"
  become_user: "{{ build_user }}"

Сообщение об ошибке с использованием dist_file/dist_url (с текущей настройкой в ​​ролях/Java/defaults/main.yml):

TASK: [Java | Download Java/JDK Versions] *************************************
failed: [server01.poc.jenkins] => (item={'key': 'Java7_60', 'value': {'dist_file': u'jdk-{# version #}-{# classifier #}-{# ext #}', 'ext': 'tar.gz', 'version': '1.7.60', 'dist_url': u'{# artifactory_ur #}/{# group_path #}/{# version #}/{# dist_file #}', 'group_path': 'com/Oracle/jdk', 'classifier': 'linux-x64'}}) => {"changed": true, "cmd": ["wget", "-q", "{# artifactory_url #}/{# group_path #}/{# version }/{# dist_file #}"], "delta": "0:00:00.006081", "end": "2015-11-23 12:50:18.383728", "item": {"key": "Java7_60", "value": {"classifier": "linux-x64", "dist_file": "jdk-{# version #}-{# classifier #}-{# ext #}, "dist_url": "{# artifactory_url #}/{# group_path #}/{# version #}/{# dist_file #}", "ext": "tar.gz", "group_path": "com/Oracle/jdk", "version": "1.7.60"}}, "rc": 4, "start": "2015-11-23 12:50:18.377647", "wrnings": ["Consider using get_url module rather than running wget"]}

Сообщение об ошибке с использованием dist_file/dist_url (со строками которые в настоящее время закомментированы в ролях/Java/defaults/main.yml):

TASK: [Java | Download Java/JDK Versions] *************************************
failed: [server01.poc.jenkins] => (item={'key': 'Java7_60', 'value': {'dist_file': u'jdk-{#item.value.version #}-{# item.value.classifier #}-{# item.value.ext #}', 'ext': 'tar.gz', 'version': '1.7.60' , 'dist_url': u'{# artifactory_url #}/{# item.value.group_path #}/{# item.value.version #}/{# dist_file #}', 'group_path': 'com/Oracle/jdk', 'classifier': 'linux-x64'}}) => {"changed": true, "cmd": ["wget",  "-q", "{# artifactory_url #}/{# item.value.group_path #}/{# item.value.version #}/{# dist_file #}"], "delta": "0:00:00.005900", "end": "2015-11-23 12:36:24.131327", "item": {"key": "Java7_60", "value": {"cla ssifier": "linux-x64", "dist_file": "jdk-{#item.value.version #}-{# item.value.classifier #}-{# item.value.ext #}", "dist_url": "{# artifactory_url #}/{# item.value.group_path #}/{# item.value.version #}/{#  dist_file #}", "ext": "tar.gz", "group_path": "com/Oracle/jdk", "version": "1.7.60"}}, "rc": 4, "start": "2015-11-23 12:36:24.125427", "warnings": ["Consider using get_url module rather than running wget"]}
5
Arun Sangal

Я считаю, что лучший способ сделать то, что вы хотите (так как я не верю, что переменные цикла могут ссылаться на себя), состоит в том, чтобы ваша задача была:

- name: Download Java/JDK Versions
  command: wget -q "{{ artifactory_url }}/{{ item.value.group_path }}/{{ item.value.version }}/jdk-{{item.value.version }}-{{ item.value.classifier }}-{{ item.value.ext }}"
    chdir="{{ common_download_dir }}"
    creates="{{ common_download_dir }}/jdk-{{item.value.version }}-{{ item.value.classifier }}-{{ item.value.ext }}"
  with_dict: "{{ Java_versions }}"
  become_user: "{{ build_user }}"

по сути, вручную вставляя переменные в вашу задачу.

Это не красиво, если вам нужно использовать переменные для нескольких задач, но в ansible 1.x я не думаю, что есть способ сделать это красиво. В Ansible 2.0 есть блоки, с помощью которых вы сможете циклически выполнять несколько задач по определению и определять переменные для всех задач в этом блоке.

2
Sepehr Nazari

Мне было любопытно об этом, поэтому я немного покопался, и при этом я наткнулся этот похожий ответ . Это только часть решения в вашем случае. 

Похоже, что Ansible не позволит вам ссылаться на переменную из ее собственного определения, что, я думаю, имеет смысл, поскольку оно не полностью определено. Таким образом, что-то вроде этого не будет работать, и на самом деле вызовет несколько запутанную ошибку, когда на переменную ссылаются:

---
myvar:
    param1: foo
    param2: "{{ myvar['foo'] }} bar"

Из вашего собственного примера также видно, что Ansible не позволит вам использовать конструкции item в переменных для ссылки на другие сложные переменные. Этот вид имеет смысл для меня, так как кажется, что Ansible разрешает конструкции jinja2 в переменных во время определения переменной, а не во время выполнения, когда на нее ссылаются. 

Так что, хотя это не совсем то, что вы искали, я думаю, что если вы разделите свою переменную на две части, вы можете заставить это работать, выполняя что-то вроде этого:

---
artifactory_url: "http://path.to.jarfile"
Java_versions:
  Java7_60:
    version: 1.7.60
    group_path: com/Oracle/jdk
    classifier: linux-x64
    ext: tar.gz

Java_downloads:
  Java7_60:
    dist_url: "{{ artifactory_url }}/{{ Java_versions['Java7_60']['group_path'] }}/{{ Java_versions['Java7_60']['version'] }}/jdk-{{ Java_versions['Java7_60']['version'] }}-{{ Java_versions['Java7_60']['classifier'] }}.{{ Java_versions['Java7_60']['ext'] }}"

Когда вы отлаживаете Java_downloads таким образом, вы получаете полный URL, который вы ищете:

TASK: [debug var=item] ********************************************************
ok: [localhost] => (item={'key': 'Java7_60', 'value': {'dist_url': u'http://path.to.jarfile/com/Oracle/jdk/1.7.60/jdk-1.7.60-linux-x64.tar.gz'}}) => {
    "item": {
        "key": "Java7_60",
        "value": {
            "dist_url": "http://path.to.jarfile/com/Oracle/jdk/1.7.60/jdk-1.7.60-linux-x64.tar.gz"
        }
    },
    "var": {
        "item": {
            "key": "Java7_60",
            "value": {
                "dist_url": "http://path.to.jarfile/com/Oracle/jdk/1.7.60/jdk-1.7.60-linux-x64.tar.gz"
            }
        }
    }
} 
3
Bruce P

Благодаря Брюсу П и Сеперу Н. я сделал следующее после получения решений/подсказок из их ответа. Теперь моя задача - работать с несколькими инструментами (jdk, mvn, gradle, maven и т.д.) С несколькими версиями с минимальными изменениями в файлах и без необходимости (определение 2-го словаря).

Что я сделал:

На верхнем уровне/по умолчанию для некоторых общих ролей/main.yml у меня будет следующее:

роли кота/some_common_global_role/defaults/main.yml

---
a_var: giga
other_var: fifa

dist_file: "{{ item.value.tool }}-{{item.value.version }}-{{ item.value.classifier }}.{{ item.value.ext }}"
dist_url: "{{ artifactory_url }}/{{ item.value.group_path }}/{{ item.value.version }}/{{ dist_file }}"

В $ роли ролей/Java/defaults/main.yml

---
tool: jdk

Java_versions:
  Java7_60:
    version: 1.7.60
    group_path: com/Oracle/jdk
    classifier: linux-x64
    ext: tar.gz
  Java7_67:
    version: 1.7.67
    group_path: com/Oracle/jdk
    classifier: linux-x64
    ext: tar.gz
  Java8_45:
    version: 1.8.45
    group_path: com/Oracle/jdk
    classifier: linux-x64
    ext: tar.gz

В ролях отдельных инструментов/default/main.yml я установлю один и тот же словарь и переменную инструмента, и он загрузит несколько инструментов/версий. В этом случае default/main.yml вашей общей роли уровня будет выглядеть так:

---
dist_file: "{{ tool }}-{{item.value.version }}-{{ item.value.classifier }}.{{ item.value.ext }}"
dist_url: "{{ artifactory_url }}/{{ item.value.group_path }}/{{ item.value.version }}/{{ dist_file }}"

Если я использую описанный выше подход, я могу определить переменную «tool» на заданных ролях // defaults/main.yml, и она будет доступна dist_file/dist_url. 

Также вместо использования команды: wget -q "...", я могу использовать get_url (модуль) в Ansible.

- name: Download Java/JDK Versions
#  command: wget -q "{{ dist_url }}"
#    chdir="{{ common_download_dir }}"
#    creates="{{ common_download_dir }}/{{ dist_file }}"
  get_url: url="{{ dist_url }}" dest="{{ common_download_dir }}"
  become_user: "{{ build_user }}"
  with_dict: "{{ Java_versions }}"

и убедитесь, что с удаленного компьютера вы можете пропинговать сервер Artifactory (проверьте ping .... или /etc/resolv.conf файл для записей поиска/сервера имен), и если все выглядит хорошо, то решения, опубликованные здесь, будут РАБОТАТЬ!

Мне лично понравилось решение для передачи уровня переменной tool (на уровне роли/задачи) (таким образом, отказ от использования инструмента определения: на уровне словаря) и отсутствие необходимости определять переменные отдельного уровня _dist_file/dist_url.

1
Arun Sangal