diff --git a/defaults/main.yml b/defaults/main.yml index d553cd0b..02313b40 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -13,7 +13,11 @@ postgresql_ctype_parts: postgresql_ctype: "{{ postgresql_ctype_parts | join('.') }}" postgresql_admin_user: "postgres" +# Pwd only needed in docker mode, which uses md5 authentication +postgresql_admin_pwd: "" postgresql_default_auth_method: "trust" +postgresql_login_host: "localhost" +postgresql_login_port: 5432 # The user/group that will run postgresql process or service postgresql_service_user: "{{ postgresql_admin_user }}" @@ -59,6 +63,7 @@ postgresql_pg_hba_passwd_hosts: [] postgresql_pg_hba_trust_hosts: [] postgresql_pg_hba_custom: [] +postgresql_docker_mode: no # postgresql.conf @@ -79,6 +84,9 @@ postgresql_pid_directory: "/var/run/postgresql" # If external_pid_file is not explicitly set, on extra PID file is written postgresql_external_pid_file: "{{ postgresql_pid_directory }}/{{postgresql_version}}-{{postgresql_cluster_name}}.pid" +# Path on the host where the docker data directory is mounted (only for docker mode) +postgresql_data_directory_docker_mount: "" + #------------------------------------------------------------------------------ # CONNECTIONS AND AUTHENTICATION #------------------------------------------------------------------------------ @@ -671,6 +679,12 @@ postgresql_exit_on_error: off # Reinitialize after backend crash? postgresql_restart_after_crash: on +#------------------------------------------------------------------------------ +# OTHER OPTIONS +#------------------------------------------------------------------------------ + +# Additional options in the form of list of dictionaries (key, value) +postgresql_custom_options: [] #------------------------------------------------------------------------------ # PGTUNE diff --git a/tasks/configure-docker.yml b/tasks/configure-docker.yml new file mode 100644 index 00000000..c34db4a9 --- /dev/null +++ b/tasks/configure-docker.yml @@ -0,0 +1,22 @@ +# file: postgresql/tasks/configure-docker.yml + +- name: PostgreSQL | Update configuration - pt. 1 (pg_hba.conf) + template: + src: pg_hba.conf.j2 + dest: "{{postgresql_data_directory_docker_mount}}/pg_hba.conf" + mode: 0640 + register: postgresql_configuration_pt1 + +- name: PostgreSQL | Update configuration - pt. 2 (postgresql.conf) + template: + src: "postgresql.conf-{{ postgresql_version }}.j2" + # if using pgtune, save the template to ".untuned" + dest: "{{postgresql_data_directory_docker_mount}}/postgresql.conf{% if postgresql_pgtune %}.untuned{% endif %}" + mode: 0640 + register: postgresql_configuration_pt2 + +- name: PostgreSQL | Create folder for additional configuration files + file: + name: "{{postgresql_data_directory_docker_mount}}/conf.d" + state: directory + mode: 0755 diff --git a/tasks/databases-common.yml b/tasks/databases-common.yml new file mode 100644 index 00000000..dadb755a --- /dev/null +++ b/tasks/databases-common.yml @@ -0,0 +1,95 @@ +--- + +- name: PostgreSQL | Make sure the PostgreSQL databases are present + postgresql_db: + name: "{{item.name}}" + owner: "{{ item.owner | default(postgresql_database_owner) }}" + encoding: "{{ item.encoding | default(postgresql_encoding) }}" + lc_collate: "{{ item.lc_collate | default(postgresql_locale) }}" + lc_ctype: "{{ item.lc_ctype | default(postgresql_ctype) }}" + port: "{{ (postgresql_docker_mode) | ternary(postgresql_login_port, postgresql_port) }}" + template: "template0" + state: present + login_user: "{{postgresql_admin_user}}" + login_password: "{{ (postgresql_docker_mode) | ternary(postgresql_admin_pwd, omit) }}" + login_host: "{{ (postgresql_docker_mode) | ternary(postgresql_login_host, omit) }}" + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_admin_user) }}" + with_items: "{{postgresql_databases}}" + when: postgresql_databases|length > 0 + +- name: PostgreSQL | Add extensions to the databases + shell: "psql {{item.0.db}} --username {{postgresql_admin_user}} {{ postgres_login_host_switch }} -c 'CREATE EXTENSION IF NOT EXISTS {{ item.1 }};'" + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + with_subelements: + - "{{postgresql_database_extensions}}" + - extensions + register: result + changed_when: "'NOTICE' not in result.stderr" + environment: "{{ postgres_env_switch }}" + +- name: PostgreSQL | Add hstore to the databases with the requirement + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} {{ postgres_login_host_switch }} -c 'CREATE EXTENSION IF NOT EXISTS hstore;'" + with_items: "{{postgresql_databases}}" + register: hstore_ext_result + failed_when: hstore_ext_result.rc != 0 and ("already exists, skipping" not in hstore_ext_result.stderr) + changed_when: hstore_ext_result.rc == 0 and ("already exists, skipping" not in hstore_ext_result.stderr) + when: item.hstore is defined and item.hstore + environment: "{{ postgres_env_switch }}" + +- name: PostgreSQL | Add uuid-ossp to the database with the requirement + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} {{ postgres_login_host_switch }} -c 'CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";'" + with_items: "{{postgresql_databases}}" + register: uuid_ext_result + failed_when: uuid_ext_result.rc != 0 and ("already exists, skipping" not in uuid_ext_result.stderr) + changed_when: uuid_ext_result.rc == 0 and ("already exists, skipping" not in uuid_ext_result.stderr) + when: item.uuid_ossp is defined and item.uuid_ossp + environment: "{{ postgres_env_switch }}" + +- name: PostgreSQL | Add postgis to the databases with the requirement + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} {{ postgres_login_host_switch }} -c 'CREATE EXTENSION IF NOT EXISTS postgis;'&&psql {{item.name}} --username {{postgresql_admin_user}} {{ postgres_login_host_switch }} -c 'CREATE EXTENSION IF NOT EXISTS postgis_topology;'" + with_items: "{{postgresql_databases}}" + when: item.gis is defined and item.gis + environment: "{{ postgres_env_switch }}" + +- name: PostgreSQL | add cube to the database with the requirement + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{ postgresql_admin_user }} {{ postgres_login_host_switch }} -c 'create extension if not exists cube;'" + with_items: "{{postgresql_databases}}" + when: item.cube is defined and item.cube + environment: "{{ postgres_env_switch }}" + +- name: PostgreSQL | Add plpgsql to the database with the requirement + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{ postgresql_admin_user }} {{ postgres_login_host_switch }} -c 'CREATE EXTENSION IF NOT EXISTS plpgsql;'" + with_items: "{{postgresql_databases}}" + when: item.plpgsql is defined and item.plpgsql + environment: "{{ postgres_env_switch }}" + +- name: PostgreSQL | add earthdistance to the database with the requirement + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{ postgresql_admin_user }} {{ postgres_login_host_switch }} -c 'create extension if not exists earthdistance;'" + with_items: "{{postgresql_databases}}" + when: item.earthdistance is defined and item.earthdistance + environment: "{{ postgres_env_switch }}" + +- name: PostgreSQL | Add citext to the database with the requirement + become: yes + become_user: "{{ (postgresql_docker_mode) | ternary('root', postgresql_service_user) }}" + shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} {{ postgres_login_host_switch }} -c 'CREATE EXTENSION IF NOT EXISTS citext;'" + with_items: "{{postgresql_databases}}" + register: citext_ext_result + failed_when: citext_ext_result.rc != 0 and ("already exists, skipping" not in citext_ext_result.stderr) + changed_when: citext_ext_result.rc == 0 and ("already exists, skipping" not in citext_ext_result.stderr) + when: item.citext is defined and item.citext + environment: "{{ postgres_env_switch }}" diff --git a/tasks/databases-docker.yml b/tasks/databases-docker.yml new file mode 100644 index 00000000..3a08f4cb --- /dev/null +++ b/tasks/databases-docker.yml @@ -0,0 +1,9 @@ +# file: postgresql/tasks/databases-docker.yml + +# Prepare facts for the docker configuration +- set_fact: + postgres_login_host_switch: "--host {{postgresql_login_host}} --port {{postgresql_login_port}}" + postgres_env_switch: + PGPASSWORD: "{{postgresql_admin_pwd}}" + +- include: databases-common.yml diff --git a/tasks/databases.yml b/tasks/databases.yml index e73de3d3..26c593ea 100644 --- a/tasks/databases.yml +++ b/tasks/databases.yml @@ -5,86 +5,9 @@ name: "{{ postgresql_service_name }}" state: started -- name: PostgreSQL | Make sure the PostgreSQL databases are present - postgresql_db: - name: "{{item.name}}" - owner: "{{ item.owner | default(postgresql_database_owner) }}" - encoding: "{{ item.encoding | default(postgresql_encoding) }}" - lc_collate: "{{ item.lc_collate | default(postgresql_locale) }}" - lc_ctype: "{{ item.lc_ctype | default(postgresql_ctype) }}" - port: "{{postgresql_port}}" - template: "template0" - state: present - login_user: "{{postgresql_admin_user}}" - become: yes - become_user: "{{postgresql_admin_user}}" - with_items: "{{postgresql_databases}}" - when: postgresql_databases|length > 0 +# Prepare facts for the non-docker configuration +- set_fact: + postgres_login_host_switch: "--port {{postgresql_port}}" + postgres_env_switch: {} -- name: PostgreSQL | Add extensions to the databases - shell: "psql {{item.0.db}} --username {{postgresql_admin_user}} -c 'CREATE EXTENSION IF NOT EXISTS {{ item.1 }};'" - become: yes - become_user: "{{postgresql_service_user}}" - with_subelements: - - "{{postgresql_database_extensions}}" - - extensions - register: result - changed_when: "'NOTICE' not in result.stderr" - -- name: PostgreSQL | Add hstore to the databases with the requirement - become: yes - become_user: "{{postgresql_service_user}}" - shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} -c 'CREATE EXTENSION IF NOT EXISTS hstore;'" - with_items: "{{postgresql_databases}}" - register: hstore_ext_result - failed_when: hstore_ext_result.rc != 0 and ("already exists, skipping" not in hstore_ext_result.stderr) - changed_when: hstore_ext_result.rc == 0 and ("already exists, skipping" not in hstore_ext_result.stderr) - when: item.hstore is defined and item.hstore - -- name: PostgreSQL | Add uuid-ossp to the database with the requirement - become: yes - become_user: "{{postgresql_service_user}}" - shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} -c 'CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";'" - with_items: "{{postgresql_databases}}" - register: uuid_ext_result - failed_when: uuid_ext_result.rc != 0 and ("already exists, skipping" not in uuid_ext_result.stderr) - changed_when: uuid_ext_result.rc == 0 and ("already exists, skipping" not in uuid_ext_result.stderr) - when: item.uuid_ossp is defined and item.uuid_ossp - -- name: PostgreSQL | Add postgis to the databases with the requirement - become: yes - become_user: "{{postgresql_service_user}}" - shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} -c 'CREATE EXTENSION IF NOT EXISTS postgis;'&&psql {{item.name}} -c 'CREATE EXTENSION IF NOT EXISTS postgis_topology;'" - with_items: "{{postgresql_databases}}" - when: item.gis is defined and item.gis - -- name: PostgreSQL | add cube to the database with the requirement - become: yes - become_user: "{{postgresql_service_user}}" - shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{ postgresql_admin_user }} -c 'create extension if not exists cube;'" - with_items: "{{postgresql_databases}}" - when: item.cube is defined and item.cube - -- name: PostgreSQL | Add plpgsql to the database with the requirement - become: yes - become_user: "{{postgresql_service_user}}" - shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{ postgresql_admin_user }} -c 'CREATE EXTENSION IF NOT EXISTS plpgsql;'" - with_items: "{{postgresql_databases}}" - when: item.plpgsql is defined and item.plpgsql - -- name: PostgreSQL | add earthdistance to the database with the requirement - become: yes - become_user: "{{postgresql_service_user}}" - shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{ postgresql_admin_user }} -c 'create extension if not exists earthdistance;'" - with_items: "{{postgresql_databases}}" - when: item.earthdistance is defined and item.earthdistance - -- name: PostgreSQL | Add citext to the database with the requirement - become: yes - become_user: "{{postgresql_service_user}}" - shell: "{{ postgresql_bin_directory}}/psql {{item.name}} --username {{postgresql_admin_user}} -c 'CREATE EXTENSION IF NOT EXISTS citext;'" - with_items: "{{postgresql_databases}}" - register: citext_ext_result - failed_when: citext_ext_result.rc != 0 and ("already exists, skipping" not in citext_ext_result.stderr) - changed_when: citext_ext_result.rc == 0 and ("already exists, skipping" not in citext_ext_result.stderr) - when: item.citext is defined and item.citext +- include: databases-common.yml diff --git a/tasks/install.yml b/tasks/install.yml index cd8741ec..1d286d57 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -1,5 +1,19 @@ # file: postgresql/tasks/install.yml +- name: Define packages to be installed + set_fact: + postgres_packages: + - "postgresql-{{postgresql_version}}" + - "postgresql-client-{{postgresql_version}}" + - "postgresql-contrib-{{postgresql_version}}" + when: not postgresql_docker_mode + +- name: Define packages to be installed (docker mode) + set_fact: + postgres_packages: + - "postgresql-client-{{postgresql_version}}" + when: postgresql_docker_mode + # The standard ca-certs are needed because without them apt_key will fail to # validate www.postgresql.org (or probably any other source). - name: PostgreSQL | Make sure the CA certificates are available @@ -43,9 +57,7 @@ cache_valid_time: "{{apt_cache_valid_time | default (3600)}}" environment: "{{postgresql_env}}" with_items: - - "postgresql-{{postgresql_version}}" - - "postgresql-client-{{postgresql_version}}" - - "postgresql-contrib-{{postgresql_version}}" + - "{{ postgres_packages }}" - name: PostgreSQL | PGTune apt: diff --git a/tasks/install_yum.yml b/tasks/install_yum.yml index 6637030d..9d778802 100644 --- a/tasks/install_yum.yml +++ b/tasks/install_yum.yml @@ -1,5 +1,19 @@ # file: postgresql/tasks/install_yum.yml +- name: Define packages to be installed + set_fact: + postgres_packages: + - "postgresql{{ postgresql_version_terse }}-server" + - "postgresql{{ postgresql_version_terse }}" + - "postgresql{{ postgresql_version_terse }}-contrib" + when: not postgresql_docker_mode + +- name: Define packages to be installed (docker mode) + set_fact: + postgres_packages: + - "postgresql{{ postgresql_version_terse }}" + when: postgresql_docker_mode + # The standard ca-certs are needed because without them apt_key will fail to # validate www.postgresql.org (or probably any other source). - name: PostgreSQL | Make sure the CA certificates are available @@ -25,9 +39,7 @@ state: present environment: "{{ postgresql_env }}" with_items: - - "postgresql{{ postgresql_version_terse }}-server" - - "postgresql{{ postgresql_version_terse }}" - - "postgresql{{ postgresql_version_terse }}-contrib" + - "{{ postgres_packages }}" - name: PostgreSQL | PGTune yum: diff --git a/tasks/main.yml b/tasks/main.yml index 58e3e3d8..2928f63c 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -15,20 +15,41 @@ tags: [postgresql, postgresql-install] - include: extensions.yml + when: not postgresql_docker_mode tags: [postgresql, postgresql-extensions] - include: configure.yml + when: not postgresql_docker_mode + tags: [postgresql, postgresql-configure] + +- include: configure-docker.yml + when: postgresql_docker_mode tags: [postgresql, postgresql-configure] - include: users.yml + when: not postgresql_docker_mode + tags: [postgresql, postgresql-users] + +- include: users-docker.yml + when: postgresql_docker_mode tags: [postgresql, postgresql-users] - include: databases.yml + when: not postgresql_docker_mode + tags: [postgresql, postgresql-databases] + +- include: databases-docker.yml + when: postgresql_docker_mode tags: [postgresql, postgresql-databases] - include: users_privileges.yml + when: not postgresql_docker_mode + tags: [postgresql, postgresql-users] + +- include: users_privileges-docker.yml + when: postgresql_docker_mode tags: [postgresql, postgresql-users] - include: monit.yml - when: monit_protection is defined and monit_protection == true + when: monit_protection is defined and monit_protection == true and not postgresql_docker_mode tags: [postgresql, postgresql-monit] diff --git a/tasks/users-docker.yml b/tasks/users-docker.yml new file mode 100644 index 00000000..32189913 --- /dev/null +++ b/tasks/users-docker.yml @@ -0,0 +1,14 @@ +# file: postgresql/tasks/users-docker.yml + +- name: PostgreSQL | Make sure the PostgreSQL users are present + postgresql_user: + name: "{{item.name}}" + password: "{{ item.pass | default(omit) }}" + encrypted: "{{ item.encrypted | default(omit) }}" + port: "{{postgresql_login_port}}" + state: present + login_user: "{{postgresql_admin_user}}" + login_password: "{{postgresql_admin_pwd}}" + login_host: "{{postgresql_login_host}}" + with_items: "{{postgresql_users}}" + when: postgresql_docker_mode and postgresql_users|length > 0 diff --git a/tasks/users_privileges-docker.yml b/tasks/users_privileges-docker.yml new file mode 100644 index 00000000..a5c41407 --- /dev/null +++ b/tasks/users_privileges-docker.yml @@ -0,0 +1,15 @@ +# file: postgresql/tasks/users_privileges.yml + +- name: PostgreSQL | Update the user privileges + postgresql_user: + name: "{{item.name}}" + db: "{{item.db | default(omit)}}" + port: "{{postgresql_login_port}}" + priv: "{{item.priv | default(omit)}}" + state: present + role_attr_flags: "{{item.role_attr_flags | default(omit)}}" + login_user: "{{postgresql_admin_user}}" + login_host: "{{postgresql_login_host}}" + login_password: "{{postgresql_admin_pwd}}" + with_items: "{{postgresql_user_privileges}}" + when: postgresql_users|length > 0 diff --git a/templates/postgresql.conf-9.1.j2 b/templates/postgresql.conf-9.1.j2 index e682c671..572cb1b7 100644 --- a/templates/postgresql.conf-9.1.j2 +++ b/templates/postgresql.conf-9.1.j2 @@ -560,3 +560,9 @@ restart_after_crash = {{'on' if postgresql_restart_after_crash else 'off'}} # r #------------------------------------------------------------------------------ #custom_variable_classes = '' # list of custom variable class names + +{% for option in postgresql_custom_options %} +{% for k,v in option.items() %} +{{k}} = {{v}} +{% endfor %} +{% endfor %} diff --git a/templates/postgresql.conf-9.2.j2 b/templates/postgresql.conf-9.2.j2 index e2a44401..b91a1c91 100644 --- a/templates/postgresql.conf-9.2.j2 +++ b/templates/postgresql.conf-9.2.j2 @@ -577,3 +577,8 @@ restart_after_crash = {{'on' if postgresql_restart_after_crash else 'off'}} # r #------------------------------------------------------------------------------ # Add settings for extensions here +{% for option in postgresql_custom_options %} +{% for k,v in option.items() %} +{{k}} = {{v}} +{% endfor %} +{% endfor %} diff --git a/templates/postgresql.conf-9.3.j2 b/templates/postgresql.conf-9.3.j2 index 9896f7c9..961d9dc6 100644 --- a/templates/postgresql.conf-9.3.j2 +++ b/templates/postgresql.conf-9.3.j2 @@ -599,3 +599,8 @@ include_dir = 'conf.d' # include files ending in '.conf' from #------------------------------------------------------------------------------ # Add settings for extensions here +{% for option in postgresql_custom_options %} +{% for k,v in option.items() %} +{{k}} = {{v}} +{% endfor %} +{% endfor %} diff --git a/templates/postgresql.conf-9.4.j2 b/templates/postgresql.conf-9.4.j2 index b2de2ad4..95a943ad 100644 --- a/templates/postgresql.conf-9.4.j2 +++ b/templates/postgresql.conf-9.4.j2 @@ -617,3 +617,8 @@ include_dir = 'conf.d' # include files ending in '.conf' from #------------------------------------------------------------------------------ # Add settings for extensions here +{% for option in postgresql_custom_options %} +{% for k,v in option.items() %} +{{k}} = {{v}} +{% endfor %} +{% endfor %} diff --git a/templates/postgresql.conf-9.5.j2 b/templates/postgresql.conf-9.5.j2 index 41c88262..20fec286 100644 --- a/templates/postgresql.conf-9.5.j2 +++ b/templates/postgresql.conf-9.5.j2 @@ -621,3 +621,8 @@ include_dir = 'conf.d' # include files ending in '.conf' from #------------------------------------------------------------------------------ # Add settings for extensions here +{% for option in postgresql_custom_options %} +{% for k,v in option.items() %} +{{k}} = {{v}} +{% endfor %} +{% endfor %} diff --git a/templates/postgresql.conf-9.6.j2 b/templates/postgresql.conf-9.6.j2 index 801de26d..2b6a83f3 100644 --- a/templates/postgresql.conf-9.6.j2 +++ b/templates/postgresql.conf-9.6.j2 @@ -633,3 +633,8 @@ include_dir = 'conf.d' # include files ending in '.conf' from #------------------------------------------------------------------------------ # Add settings for extensions here +{% for option in postgresql_custom_options %} +{% for k,v in option.items() %} +{{k}} = {{v}} +{% endfor %} +{% endfor %}