英文:
How can I define a variable in a SQL query saved in a jinja2 template and have it substituted with a value when the query is run by ansible?
问题
在我的Ansible playbook中,有一个任务在我的数据库上运行一个保存在Jinja2模板中的SQL查询。以下是如何编辑我的playbook和Jinja2模板以将该变量传递给查询的步骤:
在Ansible playbook中,确保你已经定义了一个名为input_date
的变量,如下所示:
input_date: "2023-05-03"
此变量应该保存在文件playbooks/my_playbook/vars/target_date.yml
中。
然后,在你的Ansible playbook中,在community.postgresql.postgresql_copy
任务中,你可以使用extra_vars
来传递这个变量到Jinja2模板中,如下所示:
- name: generate report
community.postgresql.postgresql_copy:
login_host: '{{ db_host }}'
login_user: '{{ db_username }}'
login_password: '{{ db_password }}'
db: '{{ db_database }}'
port: '{{ db_database_port }}'
src: "{{ lookup('template', 'my_report_query.sql.j2', variables={'input_date': input_date}) }}"
copy_to: /tmp/my_report.csv
options:
format: csv
delimiter: ';'
header: yes
这里,我们使用了variables
参数来传递input_date
变量到Jinja2模板中。在Jinja2模板中,你可以使用input_date
变量来替换SQL查询中的日期值。
这样,你的SQL查询将使用input_date
变量中的日期值,而不是硬编码的日期值。这样,你可以轻松地在Ansible playbook中更改日期值而不必修改查询本身。
英文:
In my Ansible playbook, there is a task which runs a SQL query saved in a Jinja2 template on my database.
- hosts: "{{ hosts_list }}"
gather_facts: no
vars_files:
- vars/main.yml
- vars/my_hosts.yml
- vars/target_date.yml
tasks:
- name: generate report
community.postgresql.postgresql_copy:
login_host: '{{ db_host }}'
login_user: '{{ db_username }}'
login_password: '{{ db_password }}'
db: '{{ db_database }}'
port: '{{ db_database_port }}'
src: "{{ lookup('template', 'my_report_query.sql.j2') }}"
copy_to: /tmp/my_report.csv
options:
format: csv
delimiter: ';'
header: yes
The query is something like:
select * from mytable where date='2023-02-03';
Now, I would like to pass to the query a value of the date which is defined in my Ansible playbook.
So, in the case there would be a variable defined in my Ansible playbook as
input_date: "2023-05-03"
saved in file playbooks/my_playbook/vars/target_date.yml
How can I edit my playbook and Jinja2 template in order to pass that variable to the query?
答案1
得分: 3
在Ansible中,你不需要将变量传递给你的模板 - 模板可以访问当前范围内的所有变量。换句话说,你只需要确保已经引用了target_date.yml
文件。例如,我们可以使用include_vars
模块来实现这一点:
- hosts: localhost
gather_facts: false
vars:
db_host: localhost
db_username: example_user
db_password: example_pass
db_database: example_db
tasks:
- name: 读取变量文件
include_vars:
file: vars/target_date.yml
- name: 生成报告
community.postgresql.postgresql_copy:
login_host: '{{ db_host }}'
login_user: '{{ db_username }}'
login_password: '{{ db_password }}'
db: '{{ db_database }}'
port: '{{ db_database_port|default(5432) }}'
src: "{{ lookup('template', 'my_report_query.j2.sql') }}"
copy_to: /tmp/my_report.csv
options:
format: csv
delimiter: ';'
header: yes
我们还可以通过以下方式读取变量文件:
-
通过在
ansible-playbook
命令行上使用-e
选项:ansible-playbook playbook.yaml -e @vars/target_date.yaml
-
通过在播放中使用
vars_files
选项:- hosts: localhost vars_files: - vars/target_date.yml
-
通过在
group_vars
或host_vars
目录中的适当文件中设置input_date
变量。
等等。
请注意,为了使你的playbook正常工作,你需要在查询模板中删除分号;
。带有终端分号的复制任务将会失败,如下所示:
Cannot execute SQL 'COPY (select * from mytable where date='2023-05-03';
) TO '/tmp/my_report.csv' (format csv, delimiter ';', header True)': syntax error at or near ";"
LINE 1: COPY (select * from mytable where date='2023-05-03';
^
英文:
In Ansible, you don't pass variables to your templates -- a template has access to all variables that are currently in scope. In other words, you just need to make sure that you've sourced that target_date.yml
file. For example, here we're doing that with the include_vars
module:
- hosts: localhost
gather_facts: false
vars:
db_host: localhost
db_username: example_user
db_password: example_pass
db_database: example_db
tasks:
- name: read vars file
include_vars:
file: vars/target_date.yml
- name: generate report
community.postgresql.postgresql_copy:
login_host: '{{ db_host }}'
login_user: '{{ db_username }}'
login_password: '{{ db_password }}'
db: '{{ db_database }}'
port: '{{ db_database_port|default(5432) }}'
src: "{{ lookup('template', 'my_report_query.j2.sql') }}"
copy_to: /tmp/my_report.csv
options:
format: csv
delimiter: ';'
header: yes
We could also read in the vars file:
-
By using the
-e
option on theansible-playbook
command line:ansible-playbook playbook.yaml -e @vars/target_date.yaml
-
By using the
vars_files
option in the play:- hosts: localhost vars_files: - vars/target_date.yml
-
By setting the
input_date
variable in an appropriate file in thegroup_vars
orhost_vars
directories.
Etc.
Note that for your playbook to work, you'll need to drop the ;
in your query template. With the terminal semicolon your copy task will fail with:
Cannot execute SQL 'COPY (select * from mytable where date='2023-05-03';
) TO '/tmp/my_report.csv' (format csv, delimiter ';', header True)': syntax error at or near ";"
LINE 1: COPY (select * from mytable where date='2023-05-03';
^
答案2
得分: 0
根据 @β.εηοιτ.βε 的建议,只需使用 jinja2 中的表达式标签 {{ ... }}
来替换 jinja2 模板中日期的硬编码值。
select * from mytable where date='{{ input_date }}'
另外,正如 @larsks 指出的,jinja2 模板中的查询语句不能以分号 (;
) 结尾。
英文:
As suggested by @β.εηοιτ.βε , it was sufficient to replace the hardcoded value of the date in jinja2 templates with the jinja2 "expression tags" {{ ... }}
select * from mytable where date='{{ input_date }}'
also, as indicated by @larsks, the query in the jinja2 template must not end with column ( ;
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论