PgSQL - 如何在数据库完全清空时导入数据库转储?

时间:2015-03-30 02:53:41

标签: postgresql ansible database-backups

用例实际上是使用ansible自动执行此操作。我想在数据库完全为空(内部没有表)时导入数据库转储 。当然,总有一种方法可以执行sql语句,但这是最后的手段,我相信应该有更优雅的解决方案。

就我看来,

pg_restore手册并未提供此选项。

以下是我计划如何使用ansible:

  - name: db_restore | Receive latest DB backup
    shell: s3cmd --skip-existing get `s3cmd ls s3://{{ aws_bucket }}/ | grep sentry | tail -1 | awk '{print $4}'` sql.latest.tgz
    args:
        chdir: /root/
        creates: sql.latest.tgz

  - name: db_restore | Check if file exists
    stat: path=/root/sql.latest.tgz
    register: sql_latest

  - name: db_restore | Restore latest DB backup if backup file found
    shell: PGPASSWORD={{ dbpassword }} tar -xzOf /root/sentry*.tgz db.sql | psql -U{{ dbuser }} -h{{ pgsql_server }} --set ON_ERROR_STOP=on {{ dbname }}
    when: sql_latest.stat.exists
    ignore_errors: True

理想情况下,这应检查DB是否为空。不存在用于此目的的ansible模块。谷歌也保持沉默..目前的解决方案实际上也有效,导入失败时会出错,我可以忽略错误,但看到误报有点痛苦。

4 个答案:

答案 0 :(得分:5)

实际上没有“空”这样的东西;它通常具有内置类型,默认的PL / PgSQL语言等,即使您是从template0创建的。如果你从另一个模板创建,那里可能会有更多。

PostgreSQL没有记录第一次写入数据库的非模板,因此您也不能说“自创建以来已更改”。

这就是--if-empty没有pg_restore选项的原因。它没有多大意义。

到目前为止,最好的选择是执行psql来查询information_schema并确定public架构中是否有任何表。或者,更好的是,查询是否存在您知道将由转储创建的特定表和类型。

e.g。

psql -qAt mydbname -c "select 1 from information_schema.tables where table_schema = 'public' and table_name = 'testtable';"

然后,您可以测试stdout上返回的零/非零行。或者将其包装在SELECT EXISTS(...)中以从psql获取布尔值。如果您需要DO的零/非零退出状态,或者如果表存在,则使用ERROR psql块。

答案 1 :(得分:3)

要将数据库视为空,我们必须知道从创建点开始没有添加任何内容。由于postgres没有跟踪这一点(正如@Craig Ringer已经提到的那样),我建议采用与ansible不同的方法。

所以,只需使用像:

这样的处理程序机制
- name: Create zabbbix postgres DB
  postgresql_db: name="{{zabbix_db_name}}"
  notify:
    - Init zabbix database

答案 2 :(得分:2)

由于很难说,如果数据库是“空的”,正如其他人所解释的那样,检查是否更容易,如果数据库存在,则一步创建和恢复。我是这样做的:

- name: Check my_database database already exists
  become: yes
  become_user: postgres
  shell: psql -l | grep my_database
  ignore_errors: true
  register: my_database_db_existence
- debug: var=my_database_db_existence

- name: Copy backup of the my-database database
  shell: your-s3-command here
  when: my_database_db_existence | failed

- name: Restore my_database database on first run
  become_user: postgres
  shell: createdb -O my_user my_database && psql -d my_database -f /path/to/my_dump.sql
  when: my_database_db_existence | failed

P.S。还写了detailed blog post解释实现中的每个ansible任务。

答案 3 :(得分:2)

在我的 Ansible 持续部署中,我更喜欢不检查空数据库或不检查。我使用默认属性运行容器并创建数据库(如果它不存在),然后我恢复数据库(创建方案、表等):

    - hosts: all
      vars:
        database_name: "maindb"
        pg_admin_name: "postgres"
        pg_admin_password: "postgres"
        pghost: "localhost"
        pg_user_name: "vr_user"
        pg_user_password: "ChanGeMe2021"
      tasks:
        - name: Check if database is exist
          community.postgresql.postgresql_info:
            login_host: "{{ pghost }}"
            login_user: "{{ pg_admin_name }}"
            login_password: "{{ pg_admin_password }}"
            filter:
              - "databases"
          register: pg_info
        - name: Create database if not exist
          block:
            - name: Say status 
              ansible.builtin.debug:
                msg: "Database is not exist!"
            - name: Copy dadabase shchema
              ansible.builtin.copy:
                src: "./files/maindb.sql" 
                dest: "/tmp/maindb.sql" 
            - name: Create database
              community.postgresql.postgresql_db:
                login_host: "{{ pghost }}"
                login_user: "{{ pg_admin_name }}"
                login_password: "{{ pg_admin_password }}"
                name: "{{ database_name }}"
                encoding: UTF-8
                # lc_collate: ru_RU.utf8
                # lc_ctype: ru_RU.utf8
            - name: Create role 
              community.postgresql.postgresql_user:
                login_host: "{{ pghost }}"
                login_user: "{{ pg_admin_name }}"
                login_password: "{{ pg_admin_password }}"
                name: "{{ pg_user_name }}"
                password: "{{ pg_user_password }}"
            - name: Restore database
              community.postgresql.postgresql_db:
                login_host: "{{ pghost }}"
                login_user: "{{ pg_admin_name }}"
                login_password: "{{ pg_admin_password }}"
                name: "{{ database_name }}"
                state: restore
                target: "/tmp/maindb.sql"
              register: pg_restore_result
              failed_when: "'ERROR' in pg_restore_result.stderr"
            - name: Print restore result  
              ansible.builtin.debug:
                msg: "{{ pg_restore_result }}"
          rescue:
            - name: Rollback database
              community.postgresql.postgresql_db:
                login_host: "{{ pghost }}"
                login_user: "{{ pg_admin_name }}"
                login_password: "{{ pg_admin_password }}"
                name: "{{ database_name }}"
                state: absent
            - name: Print when errors
              ansible.builtin.debug:
                msg: "Restore failed, because: {{ pg_restore_result.stderr_lines[1] }}"
          when: pg_info.databases[database_name] is not defined

这个代码你可以找到here