Ansible - with_dict: 字典 - 如何使用依赖于其他字典的每个字典中定义的变量
Ansible - with_dict: dictionary - How to use variables defined in each dictionary which depends upon others
环境为:Ansible 1.9.2、CentOS 6.5
我创建了一个角色,用于从 Artifactory 下载 JAVA (.tar.gz) 3 个不同 JAVA 版本的工件文件。我正在尝试使用 Ansible 的 with_dict 功能(而不是使用 with_items)。
创建了以下文件:
$猫roles/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(假设 KEY java7_60)?
现在,当我尝试使用当前 dist_file 或 dist_url 变量时 或 注释掉的行设置它们的方式(即使用item.value.),它没有根据需要设置这两个变量的值,即取决于其他变量 version、group_path、分类器、ext 和 artifactory_url(定义在另一个普通角色的defaults/main.yml文件中))。
我看到要使用 with_dict: 在 playbook/task 中,我必须使用 {{ item.value.variable_name }} 但是我如何定义一个依赖于字典同一 KEY 部分中的其他变量的变量。
我在以下任务中使用上述词典时收到的错误消息是:
$猫roles/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(当前设置在 roles/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(行 当前被注释掉 roles/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"]}
我相信做你想做的事情的最好方法(因为我不相信循环变量可以引用它们自己)是让你的任务是:
- 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 有块,你可以通过一个字典将多个任务一起循环,并且你可以为该块中的所有任务定义变量以供使用。
我对此很好奇,所以我做了一些挖掘,在这样做的过程中我遇到了 this similar answer。不过,这只是您的解决方案的一部分。
看来 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"
}
}
}
}
感谢 Bruce P 和 Sepehr N。在从他们的回复中获取 solutions/hints 后,我做了以下工作。现在,我的任务是为多个工具(jdk、mvn、gradle、maven 等)工作,这些工具具有多个版本,对文件进行的更改最少,并且不需要(第二个字典定义)。
我做了什么:
在顶层/一些常见角色的 default/main.yml 我将有以下内容:
$猫roles/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 }}"
在
$猫roles/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 中,我将设置相同的字典和工具变量,它会下载多个 tools/versions。在这种情况下,您的一些普通级别角色的 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 }}"
如果我使用上述方法,我可以在给定的角色//defaults/main.yml 任务级别定义 "tool" 变量,并且它可用于 dist_file / dist_url。
我还可以在 Ansible 中使用 get_url(模块)而不是使用命令:wget -q "..."。
- 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 }}"
并确保从远程机器上您能够 ping 到 Artifactory 服务器(检查 ping .... 或 /etc/resolv.conf 文件中的 search/nameserver 条目),如果一切正常,那么此处发布的解决方案将起作用!
我个人喜欢传递 tool 变量(在 role/task)级别的解决方案(因此,否定定义 tool: 在字典级别的使用)并且不需要定义个人级别 _dist_file/dist_url 变量。
环境为:Ansible 1.9.2、CentOS 6.5
我创建了一个角色,用于从 Artifactory 下载 JAVA (.tar.gz) 3 个不同 JAVA 版本的工件文件。我正在尝试使用 Ansible 的 with_dict 功能(而不是使用 with_items)。
创建了以下文件:
$猫roles/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(假设 KEY java7_60)?
现在,当我尝试使用当前 dist_file 或 dist_url 变量时 或 注释掉的行设置它们的方式(即使用item.value.),它没有根据需要设置这两个变量的值,即取决于其他变量 version、group_path、分类器、ext 和 artifactory_url(定义在另一个普通角色的defaults/main.yml文件中))。
我看到要使用 with_dict: 在 playbook/task 中,我必须使用 {{ item.value.variable_name }} 但是我如何定义一个依赖于字典同一 KEY 部分中的其他变量的变量。
我在以下任务中使用上述词典时收到的错误消息是:
$猫roles/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(当前设置在 roles/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(行 当前被注释掉 roles/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"]}
我相信做你想做的事情的最好方法(因为我不相信循环变量可以引用它们自己)是让你的任务是:
- 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 有块,你可以通过一个字典将多个任务一起循环,并且你可以为该块中的所有任务定义变量以供使用。
我对此很好奇,所以我做了一些挖掘,在这样做的过程中我遇到了 this similar answer。不过,这只是您的解决方案的一部分。
看来 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"
}
}
}
}
感谢 Bruce P 和 Sepehr N。在从他们的回复中获取 solutions/hints 后,我做了以下工作。现在,我的任务是为多个工具(jdk、mvn、gradle、maven 等)工作,这些工具具有多个版本,对文件进行的更改最少,并且不需要(第二个字典定义)。
我做了什么:
在顶层/一些常见角色的 default/main.yml 我将有以下内容:
$猫roles/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 }}"
在 $猫roles/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 中,我将设置相同的字典和工具变量,它会下载多个 tools/versions。在这种情况下,您的一些普通级别角色的 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 }}"
如果我使用上述方法,我可以在给定的角色//defaults/main.yml 任务级别定义 "tool" 变量,并且它可用于 dist_file / dist_url。
我还可以在 Ansible 中使用 get_url(模块)而不是使用命令:wget -q "..."。
- 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 }}"
并确保从远程机器上您能够 ping 到 Artifactory 服务器(检查 ping .... 或 /etc/resolv.conf 文件中的 search/nameserver 条目),如果一切正常,那么此处发布的解决方案将起作用!
我个人喜欢传递 tool 变量(在 role/task)级别的解决方案(因此,否定定义 tool: 在字典级别的使用)并且不需要定义个人级别 _dist_file/dist_url 变量。