Ansible-with_dict:dictionary-如何使用每个字典中定义的依赖于其他字典的变量

Ansible-with_dict:dictionary-如何使用每个字典中定义的依赖于其他字典的变量,ansible,roles,ansible-playbook,ordereddictionary,Ansible,Roles,Ansible Playbook,Ordereddictionary,环境为:Ansible 1.9.2,CentOS 6.5 我创建了一个角色,用于从Artifactory下载3个不同JAVA版本的JAVA(.tar.gz)工件文件。我正在尝试使用Ansible的with_dict特性(而不是with_items) 创建了以下文件: $cat roles/java/defaults/main.yml --- java_versions: java7_60: version: 1.7.60 group_path: com/oracle/jdk

环境为:Ansible 1.9.2,CentOS 6.5

我创建了一个角色,用于从Artifactory下载3个不同JAVA版本的JAVA(.tar.gz)工件文件。我正在尝试使用Ansible的with_dict特性(而不是with_items)

创建了以下文件:

$cat 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 }}"
---
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 }}"
---
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
如何设置或使用dist_filedist_url变量,这些变量取决于在同一个键中定义的其他变量(比如在键java7_60中)

现在,当我尝试当前dist_文件或dist_url变量注释掉的行设置它们的方式(即使用item.value.)时,它并没有根据需要设置这两个变量的值,即根据其他变量版本、组路径、分类器、ext和artifactory_url(在另一个常用角色的defaults/main.yml文件中定义)

我看到,对于与_dict一起使用:在playbook/task中,我必须使用{{item.value.variable_name}},但是如何定义一个依赖于字典同一关键部分中其他变量的变量呢

在以下任务中使用上述词典时收到的错误消息是:

$cat 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_文件/dist_url(当前设置为roles/java/defaults/main.yml):

错误消息使用dist_文件/dist_url(其中包含当前在roles/java/defaults/main.yml中注释掉的行):


我相信做你想做的最好的方法(因为我不相信循环变量可以引用它们自己)是让你的任务是:

- 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有一些块,通过这些块,您可以通过dict将多个任务循环在一起,并且您可以为该块中的所有任务定义要使用的变量。

我对此很好奇,所以我做了一些挖掘,在这样做的过程中,我遇到了一些问题。不过,这只是你的解决方案的一部分

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_下载时,您将获得所需的完整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。在从他们的回复中获得解决方案/提示后,我做了以下工作。现在,我的任务是为多个工具(jdk、mvn、gradle、maven等)工作,这些工具具有多个版本,对文件所做的更改最少,并且不需要(第二个字典定义)

我所做的:

在顶级/some common role的默认/main.yml中,我将有以下内容:

$cat角色/some_common_global_角色/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 }}"
---
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 }}"
---
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
$cat 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 }}"
---
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 }}"
---
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
在单个工具的roles/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 }}"
如果使用上述方法,我可以在给定的roles//defaults/main.yml任务级别定义“tool”变量,它将可用于dist_文件/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条目),如果一切正常,那么这里发布的解决方案将起作用


我个人喜欢传递工具变量(在角色/任务级别)的解决方案(因此,否定了定义工具:在字典级别)并且不需要定义单个级别的dist\u文件/dist\u url变量。

而不是将所有变量组合在变量
dict\u url
中并在任务中引用它,让任务本身执行
wget-q{{{artifactory\u url}}/{{item.value.group\u path}/{{item.value.version}/{{dist\u file}}}
不是更容易吗?谢谢你的评论。我试过了,但这让任务看起来有点难看。即使我这样做了,我认为问题在于是否可以使用同一个键中的另一个字典变量设置一个字典变量。不管怎样,问题似乎是字典变量中的变量没有被替换。我在试你说的话,看看是否行得通!想知道是否有一种方法可以在字典的关键部分组合/重用变量。我认为最简单(也许是最好)的方法是在角色中创建dist_文件和dist_url字符串,而不是在字典中定义它。@sephernazari我喜欢这个主意!,你能告诉我怎么做吗?你的意思是,我仍然可以使用dict:只使用4个字典变量(version、group\u path、classifier和ext)并创建2个变量:dist\u file和roles/java/tasks/main.yml中的dist\u url?Bruce P的答案最适合于没有不同java的情况