英文:
Variable in text not replaced and still with braces
问题
Convert to b64 format:
$ cat json | base64 | tr -d "\n"
ewogICJuYW1lIjogInNvbWVfdmFsdWUiLAogICJlbnZsIjogIkVOWl9URVNUIHRydWUgRU5WX1RFWFQ9e3thZGRpdGlvbmFsX3ZhcmlhYmxlfX0iCn0K
Extra vars for playbook (additional_variable and json_props):
-e additional_variable=additionaltext -e json_props=ewogICJuYW1lIjogInNvbWVfdmFsdWUiLAogICJlbnZsIjogIkVOWl9URVNUIHRydWUgRU5WX1RFWFQ9e3thZGRpdGlvbmFsX3ZhcmlhYmxlfX0iCn0K
Playbook:
---
- hosts: test
gather_facts: False
vars:
props: "{{ json_props | b64decode | from_json }}"
prop:
envs: "{{ props.envs }}"
tasks:
- debug:
msg: "{{ additional_variable }}"
- debug:
msg: "{{ prop.envs }}"
Output:
TASK [debug] **********************************************************************
ok: [127.0.0.1] => {
"msg": "additionaltext"
}
TASK [debug] **********************************************************************
ok: [127.0.0.1] => {
"msg": "ENV_TEST=true ENV_TEXT={{additional_variable}}"
}
How to set variable additional_variable from extra vars to the prop.envs string?
Any ideas?
I expect that output will be "ENV_TEST=true ENV_TEXT=additionaltext"
<details>
<summary>英文:</summary>
There is a json file (this content is transferring as base64 to playbook):
$ cat json
{
"name": "some_value",
"envs": "ENV_TEST=true ENV_TEXT={{additional_variable}}"
}
Convert to b64 format:
$ cat json | base64 | tr -d "\n"
ewogICJuYW1lIjogInNvbWVfdmFsdWUiLAogICJlbnZzIjogIkVOVl9URVNUPXRydWUgRU5WX1RFWFQ9e3thZGRpdGlvbmFsX3ZhcmlhYmxlfX0iCn0K
Extra vars for playbook (additional_variable and json_props):
-e additional_variable=additionaltext -e json_props=ewogICJuYW1lIjogInNvbWVfdmFsdWUiLAogICJlbnZzIjogIkVOVl9URVNUPXRydWUgRU5WX1RFWFQ9e3thZGRpdGlvbmFsX3ZhcmlhYmxlfX0iCn0K
Playbook:
- hosts: test
gather_facts: False
vars:
props: "{{ json_props | b64decode | from_json }}"
prop:
envs: "{{ props.envs }}"
tasks:-
debug:
msg: "{{ additional_variable }}" -
debug:
msg: "{{ prop.envs }}"
-
Output:
TASK [debug] **********************************************************************
ok: [127.0.0.1] => {
"msg": "additionaltext"
}
TASK [debug] **********************************************************************
ok: [127.0.0.1] => {
"msg": "ENV_TEST=true ENV_TEXT={{additional_variable}}"
}
How to set variable additional_variable from extra vars to the prop.envs string?
Any ideas?
I expect that output will be "ENV_TEST=true ENV_TEXT=additionaltext"
</details>
# 答案1
**得分**: 1
以下是您要翻译的部分:
问题在于变量 *props* 的值已经在表达式中被 '模板化' 了
```yaml
props: "{{ json_props|b64decode|from_json }}"
你已经发现,在提供了额外的变量之后
shell> cat evars.yml
additional_variable: additionaltext
json_props: ewogICJuYW1lIjogInNvbWVfdmFsdWUiLAogICJlbnZzIjogIkVOVl9URVNUPXRydWUgRU5WX1RFWFQ9e3thZGRpdGlvbmFsX3ZhcmlhYmxlfX0iCn0K
这个Playbook
shell> cat pb.yml
- hosts: localhost
vars:
props: "{{ json_props|b64decode|from_json }}"
tasks:
- debug:
var: props
会得到
shell> ansible-playbook -e @evars.yml pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] **********************************************************************************
ok: [localhost] =>
props:
envs: ENV_TEST=true ENV_TEXT={{additional_variable}}
name: some_value
变量 additional_variable 没有被替换在属性 envs 中,属性的显式扩展也没有帮助。Ansible 不提供在 vars 中 '模板化' 变量值的工具。但是,你可以自己创建一个自定义过滤器
shell> cat plugins/filter/template.py
from jinja2 import Environment, BaseLoader
def template(my_string, my_vars):
rtemplate = Environment(loader=BaseLoader).from_string(my_string)
return(rtemplate.render(my_vars))
class FilterModule(object):
def filters(self):
return {
'template': template,
}
配置过滤器插件的路径 DEFAULT_FILTER_PLUGIN_PATH。例如,
shell> grep filter ansible.cfg
filter_plugins = $PWD/plugins/filter
然后使用过滤器 template。作为过滤器的第二个参数,你必须提供一个包含用于替换的变量的字典
prop:
envs: "{{ props.envs|template(vars) }}"
会得到你想要的结果
prop:
envs: ENV_TEST=true ENV_TEXT=additionaltext
- 一个用于测试的完整Playbook示例
shell> cat pb.yml
- hosts: localhost
vars:
props: "{{ json_props|b64decode|from_json }}"
prop:
envs: "{{ props.envs|template(vars) }}"
tasks:
- debug:
var: props
- debug:
var: additional_variable
- debug:
var: prop
- set_fact:
envs: "{{ props.envs|template(my_vars) }}"
vars:
my_vars:
additional_variable: "{{ additional_variable }}"
- debug:
var: envs
会得到
shell> ansible-playbook -e @evars.yml pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] **********************************************************************************
ok: [localhost] =>
props:
envs: ENV_TEST=true ENV_TEXT={{additional_variable}}
name: some_value
TASK [debug] **********************************************************************************
ok: [localhost] =>
additional_variable: additionaltext
TASK [debug] **********************************************************************************
ok: [localhost] =>
prop:
envs: ENV_TEST=true ENV_TEXT=additionaltext
TASK [set_fact] *******************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] =>
envs: ENV_TEST=true ENV_TEXT=additionaltext
PLAY RECAP ************************************************************************************
localhost: ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 一个更简单的选项是传递文件名而不是编码内容。例如,给定文件
shell> cat /tmp/test.json
{
"name": "some_value",
"envs": "ENV_TEST=true ENV_TEXT={{ additional_variable }}"
}
通过 include_vars 将文件中的变量包含到字典中
shell> cat pb.yml
- hosts: localhost
tasks:
- include_vars:
file: "{{ file_json_props }}"
name: props
- debug:
var: props
这样表达式会自动 '模板化'(扩展)
shell> ansible-playbook -e additional_variable=additionaltext -e file_json_props=/tmp/test.json pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] **********************************************************************************
ok: [localhost] =>
additional_variable: additionaltext
TASK [include_vars] ***************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] =>
props:
envs: ENV_TEST=true ENV_TEXT=additionaltext
name: some_value
PLAY RECAP ************************************************************************************
localhost: ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
英文:
The problem is that the value of the variable props have already been 'templated' in the expression
props: "{{ json_props|b64decode|from_json }}"
You've already found out that given the extra variables
shell> cat evars.yml
additional_variable: additionaltext
json_props: ewogICJuYW1lIjogInNvbWVfdmFsdWUiLAogICJlbnZzIjogIkVOVl9URVNUPXRydWUgRU5WX1RFWFQ9e3thZGRpdGlvbmFsX3ZhcmlhYmxlfX0iCn0K
The playbook
shell> cat pb.yml
- hosts: localhost
vars:
props: "{{ json_props|b64decode|from_json }}"
tasks:
- debug:
var: props
gives
shell> ansible-playbook -e @evars.yml pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] **********************************************************************************
ok: [localhost] =>
props:
envs: ENV_TEST=true ENV_TEXT={{additional_variable}}
name: some_value
The variable additional_variable was not substituted in the attribute envs and explicit expansion of the attribute doesn't help either. Ansible doesn't provide a tool to 'template' a value of a variable in vars. But, you can create a custom filter on your own
shell> cat plugins/filter/template.py
from jinja2 import Environment, BaseLoader
def template(my_string, my_vars):
rtemplate = Environment(loader=BaseLoader).from_string(my_string)
return(rtemplate.render(my_vars))
class FilterModule(object):
def filters(self):
return {
'template': template,
}
Configure the path to the filter plugins DEFAULT_FILTER_PLUGIN_PATH. For example,
shell> grep filter ansible.cfg
filter_plugins = $PWD/plugins/filter
and use the filter template. As a second argument of the filter you have to provide a dictionary with the variables the template needs for the substitutions
prop:
envs: "{{ props.envs|template(vars) }}"
gives what you want
prop:
envs: ENV_TEST=true ENV_TEXT=additionaltext
<hr>
<sup>
- Example of a complete playbook for testing
shell> cat pb.yml
- hosts: localhost
vars:
props: "{{ json_props|b64decode|from_json }}"
prop:
envs: "{{ props.envs|template(vars) }}"
tasks:
- debug:
var: props
- debug:
var: additional_variable
- debug:
var: prop
- set_fact:
envs: "{{ props.envs|template(my_vars) }}"
vars:
my_vars:
additional_variable: "{{ additional_variable }}"
- debug:
var: envs
gives
shell> ansible-playbook -e @evars.yml pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] **********************************************************************************
ok: [localhost] =>
props:
envs: ENV_TEST=true ENV_TEXT={{additional_variable}}
name: some_value
TASK [debug] **********************************************************************************
ok: [localhost] =>
additional_variable: additionaltext
TASK [debug] **********************************************************************************
ok: [localhost] =>
prop:
envs: ENV_TEST=true ENV_TEXT=additionaltext
TASK [set_fact] *******************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] =>
envs: ENV_TEST=true ENV_TEXT=additionaltext
PLAY RECAP ************************************************************************************
localhost: ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
<hr>
- A simpler option is passing the filename instead of the encoded content. For example, given the file
shell> cat /tmp/test.json
{
"name": "some_value",
"envs": "ENV_TEST=true ENV_TEXT={{ additional_variable }}"
}
include the variables from the file into a dictionary by include_vars
shell> cat pb.yml
- hosts: localhost
tasks:
- include_vars:
file: "{{ file_json_props }}"
name: props
- debug:
var: props
This way the expressions are 'templated' (expanded) automatically
shell> ansible-playbook -e additional_variable=additionaltext -e file_json_props=/tmp/test.json pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] **********************************************************************************
ok: [localhost] =>
additional_variable: additionaltext
TASK [include_vars] ***************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] =>
props:
envs: ENV_TEST=true ENV_TEXT=additionaltext
name: some_value
PLAY RECAP ************************************************************************************
localhost: ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论