Ansible - with_dict: dictionary - Как использовать переменные, определенные в каждом словаре, которые зависят от других
Среда: Ansible 1.9.2, CentOS 6.5
Я создал роль для загрузки файлов артефактов JAVA (.tar.gz) для 3 разных версий JAVA из Artifactory. Я пытаюсь использовать функцию with_dict от Ansible (вместо использования with_items).
Созданы следующие файлы:
$ cat role /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, которые зависят от других переменных, определенных в том же ключе (скажем, в ключе java7_60)?
Прямо сейчас, когда я пытаюсь использовать текущие переменные dist_file или dist_url ИЛИ закомментированные строки, как их установить (т. Е. С помощью item.value.), Это не устанавливает значение этих 2-х переменных как желаемое, т.е. зависит от версии других переменных ., group_path, classifier, ext и artifactory_url (который определен в файле defaults / main.yml другой распространенной роли).
Я видел, что для использования with_dict: в playbook/task, я должен использовать {{ item.value. имя_переменной }} но как я могу определить переменную, которая зависит от других в том же разделе KEY словаря.
Сообщение об ошибке, которое я получаю при использовании вышеуказанного словаря в следующей задаче:
$ cat role / 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 (с текущей настройкой в role /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 (со строками, которые в данный момент закомментированы в role /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"]}
3 ответа
Я считаю, что лучший способ сделать то, что вы хотите (так как я не верю, что переменные цикла могут ссылаться на себя), состоит в том, чтобы ваша задача была:
- 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 есть блоки, с помощью которых вы сможете циклически выполнять несколько задач по определению и определять переменные для всех задач в этом блоке.
Мне было любопытно по этому поводу, поэтому я немного покопался и при этом натолкнулся на этот похожий ответ. Это только часть решения в вашем случае.
Похоже, что 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"
}
}
}
}
Благодаря Брюсу П и Сеперу Н. я сделал следующее после того, как принял решения / подсказки из их ответа. Теперь моя задача - работать с несколькими инструментами (jdk, mvn, gradle, maven и т. Д.) С несколькими версиями с минимальными изменениями в файлах и без необходимости (определение 2-го словаря).
Что я сделал:
На верхнем уровне / по умолчанию для некоторых общих ролей / main.yml у меня будет следующее:
Роли $ cat /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 }}"
В ролях $ cat /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 файл для записей поиска / сервера имен) и если все выглядит хорошо, то решения, опубликованные здесь, будут РАБОТАТЬ!
Мне лично понравилось решение для передачи уровня переменной инструмента (на уровне роли / задачи) (таким образом, отказ от использования инструмента определения: на уровне словаря) и отсутствие необходимости определять индивидуальные переменные уровня _dist_file/dist_url.