使用Ansible运行PostgreSQL脚本

时间:2015-08-19 18:33:22

标签: postgresql ansible

我正在寻找一种使用Ansible运行Postgres脚本的方法。虽然我找到了一个相当不错的例子Here,但我需要:

  • 以用户postgres
  • 运行脚本
  • 我不一定需要在服务器上保留脚本的副本,所以如果我需要副本,它只能用于临时用途。

任何人都可以告诉我这是否可行,如果是这样的话,可以运行它。这是我到目前为止使用Ansible尝试的内容,它只是挂在这些点上:

 - name: Testing DB to make sure it is available
   command: psql -U bob image
   register: b
 - debug: b

 - name: Verifying Tables exist in Image
   shell: \d image
   register: c
 - debug: c

 - name: Exiting Image DB
   shell: \q
   register: d
 - debug: d

 - name: Going to Agent DB
   command: psql -U bob agent
   register: e
 - debug: e

登录图像数据库时,它始终挂在它的第一部分。

3 个答案:

答案 0 :(得分:23)

为什么它不起作用

此:

 - name: Testing DB to make sure it is available
   command: psql -U bob image
   register: b
 - debug: b

 - name: Verifying Tables exist in Image
   shell: \d image
   register: c
 - debug: c

没有做你认为的事情。

第一个命令运行psql -U bob image。这将启动psql会话。 psql等待stdin的输入。 Ansible永远不会发送任何内容,只是等待你指定的命令退出,所以它可以检查退出代码。

所以Ansible等待psql退出,psql等待Ansible发送一些输入。

Ansible的每项任务都是独立的。 shellcommand模块不会更改后续命令运行的shell。您根本无法按照预期的方式执行此操作。

即使在第一项任务之后退出psql(或转到后台),您也会从第二项任务中收到错误,例如:

bash: d: command not found

因此,您尝试这样做的方式并不适用。

怎么做

您需要将每个任务作为单独的psql命令运行,并使用命令字符串:

 - name: Testing DB to make sure it is available
   command: psql -U bob image -c 'SELECT 1;'

 - name: Verifying Tables exist in Image
   command: psql -U bob image -c '\d image'

...或标准输入,但Ansible似乎不支持将变量作为stdin提供给命令。

...或者(可能是模板化的)SQL脚本:

- name: Template sql script
  template:  src="my.sql.j2" dest="{{sometemplocation}}/my.sql"

- name: Execute sql script
  shell: "psql {{sometemplocation}}/my.sql"

- name: Delete sql script
  file: path="{{sometemplocation}}/my.sql" state=absent

或者,您可以使用Ansible的内置支持来查询PostgreSQL,但在这种情况下,您无法使用psql客户端的反斜杠命令,如\d,你只需要使用SQL。查询information_schema表信息等

这是我的一些代码看起来如何

这是我编写的自动化模块的一个例子,它对PostgreSQL做了很多。

真的,我应该把它搞砸并编写一个psql Ansible任务,通过psql运行命令,而不是使用shell,这是非常糟糕和笨拙的。但就目前而言,它确实有效。我使用从变量中分配的连接字符串或使用set_fact生成的连接字符串来减少混乱并使连接更加灵活。

- name: Wait for the target node to be ready to be joined
  shell: "{{postgres_install_dir}}/bin/psql '{{bdr_join_target_dsn}}' -qAtw 'SELECT bdr.bdr_node_join_wait_for_ready();'"

- name: Template pre-BDR-join SQL script
  template:  src="{{bdr_pre_join_sql_template}}" dest="{{postgres_install_dir}}/bdr_pre_join_{{inventory_hostname}}.sql"

- name: Execute pre-BDR-join SQL script
  shell: "{{postgres_install_dir}}/bin/psql '{{bdr_node_dsn}}' -qAtw -f {{postgres_install_dir}}/bdr_pre_join_{{inventory_hostname}}.sql"

- name: Delete pre-BDR-join SQL script
  file: path="{{postgres_install_dir}}/bdr_pre_join_{{inventory_hostname}}.sql" state=absent

- name: bdr_group_join
  shell: "{{postgres_install_dir}}/bin/psql '{{bdr_node_dsn}}' -qAtw -c \"SELECT bdr.bdr_group_join(local_node_name := '{{inventory_hostname}}', node_external_dsn := '{{bdr_node_dsn}}', join_using_dsn := '{{bdr_join_target_dsn}}');\""

- name: Template post-BDR-join SQL script
  template:  src="{{bdr_post_join_sql_template}}" dest="{{postgres_install_dir}}/bdr_post_join_{{inventory_hostname}}.sql"

- name: Execute post-BDR-join SQL script
  shell: "{{postgres_install_dir}}/bin/psql '{{bdr_node_dsn}}' -qAtw -f {{postgres_install_dir}}/bdr_post_join_{{inventory_hostname}}.sql"

- name: Delete post-BDR-join SQL script
  file: path="{{postgres_install_dir}}/bdr_post_join_{{inventory_hostname}}.sql" state=absent

答案 1 :(得分:8)

Craig给出的答案很好,但未能解决以特定用户身份运行命令的问题。这可以通过添加他的代码来完成:

- name: Testing DB to make sure it is available
  become: true
  become_user: postgres
  command: psql -U bob image -c 'SELECT 1;'

- name: Verifying Tables exist in Image
  become: true
  become_user: postgres
  command: psql -U bob image -c '\d image'

注意“成为”和“成为_用户”参数。这些将告诉Ansible在运行命令之前更改为正确的用户。

重要提示:Ansible 1.9及更早版本使用sudo: yessudo_user: postgres代替become: truebecome_user: postgres

答案 2 :(得分:4)

基于上面的优秀响应,您还可以在Ansible任务中指定环境变量,如下所示。请注意,这假设您已使用目标数据库的密码设置.pgpass文件。

-   name: Execute some sql via psql
    command: psql -f /path/to/your/sql
    environment:
        PGUSER: "{{ db_user }}"
        PGDATABASE: "{{ db_name }}"
        PGHOST: "{{ db_host }}"
        PGPASS: "{{ pgpass_filepath }}"