commit c3b5ab3f91895d598506e1d4f19c9ab581c028c3 Author: ace Date: Wed Feb 8 02:34:53 2023 +0300 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba6d390 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.galaxy_install_info diff --git a/README.md b/README.md new file mode 100644 index 0000000..15dc334 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Setup pgbouncer for RHEL8 diff --git a/defaults/main.yaml b/defaults/main.yaml new file mode 100644 index 0000000..5a838ee --- /dev/null +++ b/defaults/main.yaml @@ -0,0 +1,45 @@ +pgbouncer_conf_dir: "/etc/pgbouncer" +pgbouncer_conf_name: "pgbouncer.ini" +pgbouncer_log_dir: "/var/log/pgbouncer" +pgbouncer_pid_dir: "/var/run/pgbouncer" +pgbouncer_pid_name: "pgbouncer.pid" +pgbouncer_log_name: "pgbouncer.log" +pgbouncer_listen_port: 6432 +pgbouncer_systemd_user: "pgbouncer" +pgbouncer_systemd_group: "pgbouncer" +pgbouncer_max_client_conn: 10000 +pgbouncer_max_db_connections: 1000 +pgbouncer_default_pool_size: 20 +pgbouncer_default_pool_mode: "session" +pgbouncer_ignore_startup_parameters: "extra_float_digits,geqo" +pgbouncer_auth_type: "hba" +pgbouncer_auth_user: "postgres" +pgbouncer_auth_hba_file: "{{ pgbouncer_postgresql_home_dir }}/{{ pgbouncer_postgresql_major_version }}/data/pg_hba.conf" +pgbouncer_auth_file_name: "userlist.txt" +pgbouncer_auth_file: "{{ pgbouncer_conf_dir }}/{{ pgbouncer_auth_file_name }}" +pgbouncer_admin_users: "postgres" +pgbouncer_client_tls_sslmode: "require" +pgbouncer_client_tls_key_file: "/etc/pki/tls/private/cert.key" +pgbouncer_client_tls_cert_file: "/etc/pki/tls/cert/cert.crt" +pgbouncer_client_tls_protocols: "tlsv1.3" +pgbouncer_client_tls_ciphers: "secure" +pgbouncer_server_tls_sslmode: "require" +pgbouncer_server_tls_key_file: "/etc/pki/tls/private/cert.key" +pgbouncer_server_tls_cert_file: "/etc/pki/tls/cert/cert.crt" +pgbouncer_server_tls_protocols: "tlsv1.3" +pgbouncer_server_tls_ciphers: "secure" +pgbouncer_postgresql_host: "localhost" +pgbouncer_postgresql_db: "postgres" +pgbouncer_postgresql_superuser_username: "postgres" +pgbouncer_postgresql_superuser_password: "postgres" +pgbouncer_postgresql_auth_query: "select passwd from pg_shadow where usename = %s" +pgbouncer_pools: + - {name: "postgres", dbname: "postgres", pool_parameters: ""} +# - {name: "mydatabase", dbname: "mydatabase", pool_parameters: "pool_size=20 pool_mode=transaction"} +# - {name: "", dbname: "", pool_parameters: ""} +# - {name: "", dbname: "", pool_parameters: ""} + +pgbouncer_postgresql_supported_versions: + - 13 + - 14 + - 15 diff --git a/handlers/main.yaml b/handlers/main.yaml new file mode 100644 index 0000000..12358ae --- /dev/null +++ b/handlers/main.yaml @@ -0,0 +1,22 @@ +--- + +- name: Restart pgbouncer service + systemd: + daemon_reload: true + name: pgbouncer + enabled: true + state: restarted + listen: "restart pgbouncer" + when: not pgbouncer_enable_and_start.changed + +- name: Wait for port "{{ pgbouncer_listen_port }}" to become open on the host + wait_for: + port: "{{ pgbouncer_listen_port }}" + host: "{{ hostvars[inventory_hostname]['inventory_hostname'] }}" + state: started + timeout: 120 + delay: 5 + ignore_errors: false + listen: "restart pgbouncer" + +... diff --git a/tasks/main.yaml b/tasks/main.yaml new file mode 100644 index 0000000..c0fefe3 --- /dev/null +++ b/tasks/main.yaml @@ -0,0 +1,174 @@ +--- +# yamllint disable rule:line-length + +- name: Make sure handlers are flushed immediately + meta: flush_handlers + +- name: Load a variable file based on the OS type + include_vars: "{{ lookup('first_found', params) }}" + vars: + params: + files: + - "{{ ansible_facts['distribution'] }}.yaml" + - "{{ ansible_facts['os_family'] }}.yaml" + paths: + - "vars" + tags: pgbouncer_vars + +- name: "Gather packages" + package_facts: + manager: auto + +- name: "Set fact about PostgreSQL package" + set_fact: + pgbouncer_postgresql_package_name: "{{ ansible_facts.packages | list | select('match', pgbouncer_postgresql_package_name_regex) | first }}" + +- name: "Get PostgreSQL major and minor versions" + set_fact: + pgbouncer_postgresql_major_version: "{{ ansible_facts.packages[pgbouncer_postgresql_package_name][0]['version'] | split('.') | first }}" + pgbouncer_postgresql_minor_version: "{{ ansible_facts.packages[pgbouncer_postgresql_package_name][0]['version'] | split('.') | last }}" + +- name: Install pgbouncer package + package: + name: pgbouncer + environment: "{{ proxy_env | default({}) }}" + when: ansible_os_family == "Debian" or + (ansible_os_family == "RedHat" and + ansible_distribution_major_version == '7') + tags: pgbouncer_install, pgbouncer + +# RHEL 8 +- name: Install pgbouncer package + dnf: + name: pgbouncer + disablerepo: AppStream + environment: "{{ proxy_env | default({}) }}" + when: ansible_os_family == "RedHat" and + ansible_distribution_major_version >= '8' + tags: pgbouncer_install, pgbouncer + +- name: Ensure config directory "{{ pgbouncer_conf_dir }}" exist + file: + path: "{{ pgbouncer_conf_dir }}" + state: directory + owner: "{{ pgbouncer_systemd_user }}" + group: "{{ pgbouncer_systemd_group }}" + mode: 0750 + tags: pgbouncer_conf, pgbouncer + +- name: Stop and disable standard init script + service: + name: pgbouncer + state: stopped + enabled: false + when: ansible_os_family == "Debian" + tags: pgbouncer_service, pgbouncer + +- name: Add pgbouncer systemd unit user and group override + block: + - name: Ensure override dir for pgbouncer exists + file: + path: /etc/systemd/system/pgbouncer.service.d + state: directory + + - name: Set user and group for pgbouncer + copy: + dest: /etc/systemd/system/pgbouncer.service.d/override.conf + content: | + [Service] + User= + User={{ pgbouncer_systemd_user }} + Group= + Group={{ pgbouncer_systemd_group }} + +- name: Enable log rotation with logrotate + copy: + content: | + "{{ pgbouncer_log_dir }}/{{ pgbouncer_log_name }}" { + daily + rotate 7 + copytruncate + delaycompress + compress + notifempty + missingok + su root root + } + dest: /etc/logrotate.d/pgbouncer + tags: pgbouncer_logrotate, pgbouncer + +- name: Configure pgbouncer.ini + template: + src: templates/pgbouncer.ini.j2 + dest: "{{ pgbouncer_conf_dir }}/{{ pgbouncer_conf_name }}" + owner: "{{ pgbouncer_systemd_user }}" + group: "{{ pgbouncer_systemd_group }}" + mode: 0640 + notify: "restart pgbouncer" + when: existing_pgcluster is not defined or not existing_pgcluster|bool + tags: pgbouncer_conf, pgbouncer + +- name: Ensure user and group applied to all files and dirs + file: + path: "{{ item }}" + owner: "{{ pgbouncer_systemd_user }}" + group: "{{ pgbouncer_systemd_group }}" + recurse: yes + state: directory + loop: + - "{{ pgbouncer_conf_dir }}" + - "{{ pgbouncer_log_dir }}" + - "{{ pgbouncer_pid_dir }}" + +- name: Ping PostgreSQL server + community.postgresql.postgresql_ping: + db: "{{ pgbouncer_postgresql_db }}" + login_host: "{{ pgbouncer_postgresql_host }}" + login_user: "{{ pgbouncer_postgresql_superuser_username }}" + login_password: "{{ pgbouncer_postgresql_superuser_password }}" + register: postgresql_ping + until: postgresql_ping.is_available + retries: 60 + delay: 20 + +- name: Get auth user {{ pgbouncer_auth_user }} password hash + community.postgresql.postgresql_query: + db: "{{ pgbouncer_postgresql_db }}" + login_host: "{{ pgbouncer_postgresql_host }}" + login_user: "{{ pgbouncer_postgresql_superuser_username }}" + login_password: "{{ pgbouncer_postgresql_superuser_password }}" + query: "{{ pgbouncer_postgresql_auth_query }}" + positional_args: "{{ pgbouncer_auth_user }}" + register: pgbouncer_postgresql_superuser_password_hash + +- name: Create auth_file + template: + src: templates/userlist.txt.j2 + dest: "{{ pgbouncer_auth_file }}" + owner: postgres + group: postgres + mode: 0640 + when: existing_pgcluster is not defined or not existing_pgcluster|bool + tags: pgbouncer + +- name: Ensure pgbouncer enabled and started + systemd: + daemon_reload: true + name: pgbouncer + enabled: true + state: started + masked: no + register: pgbouncer_enable_and_start + tags: pgbouncer, pgbouncer_start + +- name: Ensure user and group applied to all files and dirs one more time + file: + path: "{{ item }}" + owner: "{{ pgbouncer_systemd_user }}" + group: "{{ pgbouncer_systemd_group }}" + recurse: yes + state: directory + loop: + - "{{ pgbouncer_conf_dir }}" + - "{{ pgbouncer_log_dir }}" + - "{{ pgbouncer_pid_dir }}" diff --git a/templates/pgbouncer.ini.j2 b/templates/pgbouncer.ini.j2 new file mode 100644 index 0000000..132b5b4 --- /dev/null +++ b/templates/pgbouncer.ini.j2 @@ -0,0 +1,48 @@ +[databases] +{% for pool in pgbouncer_pools %} +{{ pool.name }} = host={{ pool.host | default('127.0.0.1') }} port={{ pool.port | default('5432') }} dbname={{ pool.dbname }} {{ pool.pool_parameters }} +{% endfor %} + +* = host=127.0.0.1 port={{ pgbouncer_postgresql_port | default('5432') }} + +[pgbouncer] +{% if pgbouncer_client_tls_sslmode != 'disable' %} +client_tls_sslmode = {{ pgbouncer_client_tls_sslmode }} +client_tls_protocols = {{ pgbouncer_client_tls_protocols }} +client_tls_ciphers = {{ pgbouncer_client_tls_ciphers }} +client_tls_key_file = {{ pgbouncer_client_tls_key_file }} +client_tls_cert_file = {{ pgbouncer_client_tls_cert_file }} +{% endif %} +{% if pgbouncer_server_tls_sslmode != 'disable' %} +server_tls_sslmode = {{ pgbouncer_server_tls_sslmode }} +{% endif %} +logfile = {{ pgbouncer_log_dir }}/{{ pgbouncer_log_name }} +pidfile = {{ pgbouncer_pid_dir }}/{{ pgbouncer_pid_name }} +listen_addr = {{ hostvars[inventory_hostname]['inventory_hostname'] }} +listen_port = {{ pgbouncer_listen_port | default(6432) }} +unix_socket_dir = /var/run/postgresql +auth_type = {{ pgbouncer_auth_type }} +auth_file = {{ pgbouncer_auth_file }} +{% if pgbouncer_auth_user is defined %} +auth_user = {{ pgbouncer_auth_user }} +{% endif %} +{% if pgbouncer_auth_type == 'hba' %} +auth_hba_file = {{ pgbouncer_auth_hba_file }} +{% endif %} +admin_users = {{ pgbouncer_admin_users }} +ignore_startup_parameters = {{ pgbouncer_ignore_startup_parameters }} + +pool_mode = {{ pgbouncer_default_pool_mode }} +server_reset_query = DISCARD ALL +max_client_conn = {{ pgbouncer_max_client_conn }} +default_pool_size = {{ pgbouncer_default_pool_size }} +reserve_pool_size = 1 +reserve_pool_timeout = 1 +max_db_connections = {{ pgbouncer_max_db_connections }} +pkt_buf = 8192 +listen_backlog = 4096 + +log_connections = 0 +log_disconnections = 0 + +# Documentation https://pgbouncer.github.io/config.html diff --git a/templates/pgbouncer.service.j2 b/templates/pgbouncer.service.j2 new file mode 100644 index 0000000..59b8866 --- /dev/null +++ b/templates/pgbouncer.service.j2 @@ -0,0 +1,27 @@ +[Unit] +Description=pgBouncer connection pooling for PostgreSQL +After=syslog.target network.target + +[Service] +Type=forking + +User=postgres +Group=postgres + +PermissionsStartOnly=true +ExecStartPre=-/bin/mkdir -p /var/run/pgbouncer {{ pgbouncer_log_dir }} +ExecStartPre=/bin/chown -R postgres:postgres /var/run/pgbouncer {{ pgbouncer_log_dir }} +{% if ansible_os_family == "Debian" %} +ExecStart=/usr/sbin/pgbouncer -d {{ pgbouncer_conf_dir }}/pgbouncer.ini +{% endif %} +{% if ansible_os_family == "RedHat" %} +ExecStart=/usr/bin/pgbouncer -d {{ pgbouncer_conf_dir }}/pgbouncer.ini +{% endif %} +ExecReload=/bin/kill -SIGHUP $MAINPID +PIDFile=/var/run/pgbouncer/pgbouncer.pid +Restart=on-failure + +LimitNOFILE=100000 + +[Install] +WantedBy=multi-user.target diff --git a/templates/userlist.txt.j2 b/templates/userlist.txt.j2 new file mode 100644 index 0000000..eab7227 --- /dev/null +++ b/templates/userlist.txt.j2 @@ -0,0 +1 @@ +"{{ pgbouncer_postgresql_superuser_username }}" "{{ pgbouncer_postgresql_superuser_password_hash.query_result.0.passwd }}" diff --git a/vars/Debian.yaml b/vars/Debian.yaml new file mode 100644 index 0000000..1e76d07 --- /dev/null +++ b/vars/Debian.yaml @@ -0,0 +1,2 @@ +pgbouncer_postgresql_home_dir: "/var/lib/postgresql" +pgbouncer_postgresql_package_name_regex: 'postgresql-.[{{ pgbouncer_postgresql_supported_versions | join(",") }}]' diff --git a/vars/RedHat.yaml b/vars/RedHat.yaml new file mode 100644 index 0000000..b6aea46 --- /dev/null +++ b/vars/RedHat.yaml @@ -0,0 +1,2 @@ +pgbouncer_postgresql_home_dir: "/var/lib/pgsql" +pgbouncer_postgresql_package_name_regex: 'postgresql.[{{ pgbouncer_postgresql_supported_versions | join(",") }}]-server'