Ansible:如何从另一个变量构造一个变量然后获取它的值
Ansible: how to construct a variable from another variable and then fetch it's value
我的问题是我需要使用一个变量 '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}}"
}
您需要在其周围加上引号:
- hosts: local
vars: [ target_host: smtp ]
tasks:
debug: msg="{{ target_host }}_host"
-- 编辑--
Kashyap I need to go one more level than this. Imagine there is
another variable 'smtp_host' and I want to construct that variable at
runtime using another variable(target_host) and attaching a string
'_host' to it. = {{ {{ target_host }}_host }} – Max
我的错。看得不够仔细
这(据我所知)是不可能的。阻止我们这样做的主要限制(无论你如何旋转它)是 'variable expansion' 在 ansible 中是单次通过过程,而你想要的需要多次通过。
我能想到的[严重hacky]方法是:
- 使用
template
从您的剧本动态创建剧本并执行它。
- 我听说 Jinja2 引擎进行多通道评估。如果您将这些字符串放入模板中,然后使用
lookup('template', ...)
过滤器,则可能是这样。不幸的是,我没有使用 Jinja2 模板的经验,所以不太确定这是否是一个选项。
您可以像这样嵌套查找:
---
- 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 }}"
您可以使用"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 }}
output:
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 loop,它为每个项目运行任务并相应地使 {{ 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] }}
请注意,变量的配置略有不同,因为它的结构是分层的。
如果你有一个像
这样的变量
vars:
myvar: xxx
xxx_var: anothervalue
工作的 Ansible 语法:
- debug: msg={{ vars[myvar + '_var'] }}
会给你类似的:
- debug: msg={{ xxx_var }}
您有两种选择方式:
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。使用 fact
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
选项而不是 msg
:
debug: var="{{ target_host }}_host"
给出:
TASK [testing] ********************************************************************************************************************************
ok: [localhost] => {
"smtp_host": "smtp.max.com"
}
上面有很多答案。这对我帮助很大。但我还没有找到如何将这些变量保存在 vars-> main.yml 文件中的单一答案。
所以你必须在 vars-> main.yml 文件中创建一个字典。
变量 -> 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
现在你必须在任务中调用这个 -> main.yml 文件:
---
- name: Down load Cassandra Binaries
get_url:
url: "file_url"
dest: "{{ base_directory }}"
checksum: "{{ cassandra[file_sha_cassandra] }}"
timeout: 800
您可以试试全局数组 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}}"
从使用 vars
lookup plugin 的 Ansible 2.5 开始,这是可能的,我认为与此处发布的其他一些方法相比,它不太可能在没有警告的情况下中断。例如:
---
- 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"
}
我的问题是我需要使用一个变量 '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}}"
}
您需要在其周围加上引号:
- hosts: local
vars: [ target_host: smtp ]
tasks:
debug: msg="{{ target_host }}_host"
-- 编辑--
Kashyap I need to go one more level than this. Imagine there is another variable 'smtp_host' and I want to construct that variable at runtime using another variable(target_host) and attaching a string '_host' to it. = {{ {{ target_host }}_host }} – Max
我的错。看得不够仔细
这(据我所知)是不可能的。阻止我们这样做的主要限制(无论你如何旋转它)是 'variable expansion' 在 ansible 中是单次通过过程,而你想要的需要多次通过。
我能想到的[严重hacky]方法是:
- 使用
template
从您的剧本动态创建剧本并执行它。 - 我听说 Jinja2 引擎进行多通道评估。如果您将这些字符串放入模板中,然后使用
lookup('template', ...)
过滤器,则可能是这样。不幸的是,我没有使用 Jinja2 模板的经验,所以不太确定这是否是一个选项。
您可以像这样嵌套查找:
---
- 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 }}"
您可以使用"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 }}
output:
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 loop,它为每个项目运行任务并相应地使 {{ 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] }}
请注意,变量的配置略有不同,因为它的结构是分层的。
如果你有一个像
这样的变量vars:
myvar: xxx
xxx_var: anothervalue
工作的 Ansible 语法:
- debug: msg={{ vars[myvar + '_var'] }}
会给你类似的:
- debug: msg={{ xxx_var }}
您有两种选择方式:
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。使用 fact
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
选项而不是 msg
:
debug: var="{{ target_host }}_host"
给出:
TASK [testing] ********************************************************************************************************************************
ok: [localhost] => {
"smtp_host": "smtp.max.com"
}
上面有很多答案。这对我帮助很大。但我还没有找到如何将这些变量保存在 vars-> main.yml 文件中的单一答案。 所以你必须在 vars-> main.yml 文件中创建一个字典。
变量 -> 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
现在你必须在任务中调用这个 -> main.yml 文件:
---
- name: Down load Cassandra Binaries
get_url:
url: "file_url"
dest: "{{ base_directory }}"
checksum: "{{ cassandra[file_sha_cassandra] }}"
timeout: 800
您可以试试全局数组 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}}"
从使用 vars
lookup plugin 的 Ansible 2.5 开始,这是可能的,我认为与此处发布的其他一些方法相比,它不太可能在没有警告的情况下中断。例如:
---
- 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"
}