Ansible "template error" 在格式化字符串中使用变量
Ansible "template error" using variable in formatted string
这个 ansible 任务应该检查是否安装了特定版本的 npm 包,如果没有,则安装它。我正在使用的 when
条件涉及带有已定义变量 pm2_version
的格式化字符串,但由于某种原因,我在测试中尝试使用该变量导致了错误。
我希望表达式 f'pm2@{pm2_version}'
应该创建一个格式化的字符串,但显然这种期望是不正确的。在这里使用变量的正确方法是什么?
相关任务如下:
- name: List installed packages
shell: 'npm list -g --depth=0'
args:
executable: /bin/bash
environment:
PATH: "{{ ansible_env.HOME }}/.nvm/versions/node/{{node_version}}/bin:{{ ansible_env.PATH }}"
register: npm_package_list
- name: Install pm2
shell: 'npm i -g pm2@{{pm2_version}}'
args:
executable: /bin/bash
environment:
PATH: '{{ ansible_env.HOME }}/.nvm/versions/node/{{node_version}}/bin:{{ ansible_env.PATH }}'
when: npm_package_list.stdout.find(f'pm2@{pm2_version}') == -1
但是 运行 剧本,我收到以下错误:
FAILED! => {"msg": "The conditional check 'npm_package_list.stdout.find(f'pm2@{pm2_version}') == -1' failed. The error was: template error while templating string: expected token ',', got 'string'.
你想要做的是 Ansible 中的 anti-pattern。
Ansible是基于idempotency,也就是说,在你的情况下,如果npm包已经安装在请求的版本,Ansible什么都不做,return你一个ok
status 而它会 return 你一个 changed
status 以防它必须安装它。
但是为此,您必须使用专用 npm
module:
- npm:
name: "{{ 'pm2@%s' | format(pm2_version) }}"
global: yes
executable: >-
{{ ansible_env.HOME }}/.nvm/versions/node/{{ node_version }}/bin/npm
不过,您的两个(也许三个)问题是:
- Jinja 没有实现 Python 的所有功能,因此有些功能无法使用,例如
find
字符串
- 同理,不支持f-strings
- (可能是问题中的拼写错误)您的
when
关闭错误缩进。
为了在字符串中找到子字符串,您可以使用 in
,或者在您的情况下 not in
测试。
为了获得 f-string 格式,您可以使用 format
filter,或者只使用字符串连接 ~
.
所以,你的情况应该是这样的:
when: "'pm2@%s' | format(pm2_version) not in npm_package_list.stdout"
或
when: "'pm2@' ~ pm2_version not in npm_package_list.stdout"
给定任务:
- debug:
var: "'pm2@%s' | format(pm2_version) not in npm_package_list.stdout"
vars:
pm2_version: 1.2.4
npm_package_list:
stdout: pm2@1.2.3
产生:
ok: [localhost] =>
'''pm2@%s'' | format(pm2_version) not in npm_package_list.stdout': true
这个 ansible 任务应该检查是否安装了特定版本的 npm 包,如果没有,则安装它。我正在使用的 when
条件涉及带有已定义变量 pm2_version
的格式化字符串,但由于某种原因,我在测试中尝试使用该变量导致了错误。
我希望表达式 f'pm2@{pm2_version}'
应该创建一个格式化的字符串,但显然这种期望是不正确的。在这里使用变量的正确方法是什么?
相关任务如下:
- name: List installed packages
shell: 'npm list -g --depth=0'
args:
executable: /bin/bash
environment:
PATH: "{{ ansible_env.HOME }}/.nvm/versions/node/{{node_version}}/bin:{{ ansible_env.PATH }}"
register: npm_package_list
- name: Install pm2
shell: 'npm i -g pm2@{{pm2_version}}'
args:
executable: /bin/bash
environment:
PATH: '{{ ansible_env.HOME }}/.nvm/versions/node/{{node_version}}/bin:{{ ansible_env.PATH }}'
when: npm_package_list.stdout.find(f'pm2@{pm2_version}') == -1
但是 运行 剧本,我收到以下错误:
FAILED! => {"msg": "The conditional check 'npm_package_list.stdout.find(f'pm2@{pm2_version}') == -1' failed. The error was: template error while templating string: expected token ',', got 'string'.
你想要做的是 Ansible 中的 anti-pattern。
Ansible是基于idempotency,也就是说,在你的情况下,如果npm包已经安装在请求的版本,Ansible什么都不做,return你一个ok
status 而它会 return 你一个 changed
status 以防它必须安装它。
但是为此,您必须使用专用 npm
module:
- npm:
name: "{{ 'pm2@%s' | format(pm2_version) }}"
global: yes
executable: >-
{{ ansible_env.HOME }}/.nvm/versions/node/{{ node_version }}/bin/npm
不过,您的两个(也许三个)问题是:
- Jinja 没有实现 Python 的所有功能,因此有些功能无法使用,例如
find
字符串 - 同理,不支持f-strings
- (可能是问题中的拼写错误)您的
when
关闭错误缩进。
为了在字符串中找到子字符串,您可以使用 in
,或者在您的情况下 not in
测试。
为了获得 f-string 格式,您可以使用 format
filter,或者只使用字符串连接 ~
.
所以,你的情况应该是这样的:
when: "'pm2@%s' | format(pm2_version) not in npm_package_list.stdout"
或
when: "'pm2@' ~ pm2_version not in npm_package_list.stdout"
给定任务:
- debug:
var: "'pm2@%s' | format(pm2_version) not in npm_package_list.stdout"
vars:
pm2_version: 1.2.4
npm_package_list:
stdout: pm2@1.2.3
产生:
ok: [localhost] =>
'''pm2@%s'' | format(pm2_version) not in npm_package_list.stdout': true