├── .gitignore ├── LICENSE ├── README.md ├── defaults └── main.yml ├── files └── pgpool2 ├── handlers └── main.yml ├── meta └── main.yml ├── tasks ├── configure.yml ├── install.yml └── main.yml └── templates ├── pcp.conf.j2 ├── pcpctl.j2 ├── pgpool.conf.j2 ├── pgpool2.j2 ├── pgpool2_reattach.sh.j2 └── pool_hba.conf.j2 /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pgpool2 2 | ======= 3 | 4 | This role configures PgPool2 PostgreSQL connection mux utility. 5 | 6 | TODO 7 | ------- 8 | 9 | * Examples, variables, explanation 10 | 11 | License 12 | ------- 13 | 14 | LGPL 15 | 16 | Author Information 17 | ------------------ 18 | 19 | - Evgeniy Dekhtyarev, 2GIS, LLC 20 | - Alexey Medvedchikov, 2GIS, LLC 21 | 22 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | pgpool2_packages: 4 | - pgpool2 5 | - rsync 6 | - arping 7 | - postgresql-client 8 | 9 | pgpool2_package_state: present 10 | pgpool2_user: postgres 11 | pgpool2_group: postgres 12 | pgpool2_confdir: /etc/pgpool2 13 | pgpool2_pcp_user_name: pcpAdmin 14 | pgpool2_pcp_user_password: passw0rd 15 | 16 | pgpool2_auto_reattach: off 17 | 18 | pgpool2_hba_default: 19 | - comment: unix socket connections 20 | type: local 21 | database: all 22 | user: all 23 | address: "" 24 | method: trust 25 | - comment: local IPv4 connections 26 | type: host 27 | database: all 28 | user: all 29 | address: 127.0.0.1/32 30 | method: md5 31 | 32 | pgpool2_hba_custom: [] 33 | 34 | # Enabling md5 auth on pgpool2 35 | # 36 | # pgpool2_pool_users: 37 | # - name: test 38 | # pass: 1qa2ws3ed 39 | # 40 | 41 | pgpool2_pool_users: [] 42 | 43 | # pgpool2_backends: 44 | # - name: name_of_host 45 | # host: hostname or 10.10.10.10 46 | # port: 5432 47 | # weight: 1 48 | # data_directory: /var/lib/postgresql/9.4/main 49 | # flag: ALLOW_TO_FAILOVER 50 | 51 | pgpool2_backends: [] 52 | 53 | # pgpool2_heartbeat_nodes: 54 | # - hostname: hostname2 55 | # address: 10.10.10.10 56 | # port: 9694 57 | # device: eth0 58 | 59 | pgpool2_heartbeat_nodes: [] 60 | 61 | # pgpool2_query_nodes: 62 | # - hostname: hostname1 63 | # address: 10.10.10.10 64 | # port: 5432 65 | # wd_port: 9000 66 | 67 | pgpool2_query_nodes: [] 68 | 69 | pgpool2_allow_sql_comments: off 70 | pgpool2_app_name_redirect_preference_list: '' 71 | pgpool2_arping_cmd: sudo /usr/sbin/arping -c 2 -q $_IP_$ 72 | pgpool2_arping_path: /usr/bin 73 | pgpool2_authentication_timeout: 60 74 | pgpool2_black_function_list: nextval,setval 75 | pgpool2_black_memqcache_table_list: '' 76 | pgpool2_check_temp_table: on 77 | pgpool2_check_unlogged_table: on 78 | pgpool2_child_life_time: 300 79 | pgpool2_child_max_connections: 0 80 | pgpool2_clear_memqcache_on_escalation: on 81 | pgpool2_client_idle_limit: 0 82 | pgpool2_client_idle_limit_in_recovery: 0 83 | pgpool2_client_min_messages: notice 84 | pgpool2_connect_timeout: 10000 85 | pgpool2_connection_cache: on 86 | pgpool2_connection_life_time: 0 87 | pgpool2_database_redirect_preference_list: '' 88 | pgpool2_debug_level: 0 89 | pgpool2_delay_threshold: 0 90 | pgpool2_delegate_IP: '' 91 | pgpool2_enable_pool_hba: off 92 | pgpool2_fail_over_on_backend_error: on 93 | pgpool2_failback_command: '' 94 | pgpool2_failover_command: '' 95 | pgpool2_failover_if_affected_tuples_mismatch: off 96 | pgpool2_follow_master_command: '' 97 | pgpool2_health_check_database: '' 98 | pgpool2_health_check_max_retries: 0 99 | pgpool2_health_check_password: '' 100 | pgpool2_health_check_period: 0 101 | pgpool2_health_check_retry_delay: 1 102 | pgpool2_health_check_timeout: 20 103 | pgpool2_health_check_user: nobody 104 | pgpool2_hostname: '' 105 | pgpool2_if_cmd_path: '/sbin' 106 | pgpool2_if_down_cmd: sudo /sbin/ifconfig eth0:0 down 107 | pgpool2_if_up_cmd: sudo /sbin/ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0 108 | pgpool2_ignore_leading_white_space: on 109 | pgpool2_insert_lock: on 110 | pgpool2_listen_addresses: localhost 111 | pgpool2_listen_backlog_multiplier: 2 112 | pgpool2_load_balance_mode: off 113 | pgpool2_lobj_lock_table: '' 114 | pgpool2_log_connections: off 115 | pgpool2_log_destination: syslog 116 | pgpool2_log_error_verbosity: default 117 | pgpool2_log_hostname: off 118 | pgpool2_log_line_prefix: '%t: pid %p: ' 119 | pgpool2_log_min_messages: warning 120 | pgpool2_log_per_node_statement: off 121 | pgpool2_log_standby_delay: none 122 | pgpool2_log_statement: off 123 | pgpool2_logdir: /var/log/postgresql 124 | pgpool2_master_slave_mode: off 125 | pgpool2_master_slave_sub_mode: slony 126 | pgpool2_max_pool: 4 127 | pgpool2_memory_cache_enabled: off 128 | pgpool2_memqcache_auto_cache_invalidation: on 129 | pgpool2_memqcache_cache_block_size: 1048576 130 | pgpool2_memqcache_expire: 0 131 | pgpool2_memqcache_max_num_cache: 1000000 132 | pgpool2_memqcache_maxcache: 409600 133 | pgpool2_memqcache_memcached_host: localhost 134 | pgpool2_memqcache_memcached_port: 11211 135 | pgpool2_memqcache_method: shmem 136 | pgpool2_memqcache_oiddir: /var/log/pgpool/oiddir 137 | pgpool2_memqcache_total_size: 67108864 138 | pgpool2_num_init_children: 32 139 | pgpool2_pcp_listen_addresses: '*' 140 | pgpool2_pcp_port: 9898 141 | pgpool2_pcp_socket_dir: /var/run/postgresql 142 | pgpool2_pid_file_name: /var/run/postgresql/pgpool.pid 143 | pgpool2_ping_path: /bin 144 | pgpool2_pool_passwd: 'passwd_file' 145 | pgpool2_port: 5433 146 | pgpool2_recovery_1st_stage_command: '' 147 | pgpool2_recovery_2nd_stage_command: '' 148 | pgpool2_recovery_password: '' 149 | pgpool2_recovery_timeout: 90 150 | pgpool2_recovery_user: nobody 151 | pgpool2_relcache_expire: 0 152 | pgpool2_relcache_size: 256 153 | pgpool2_replicate_select: off 154 | pgpool2_replication_mode: off 155 | pgpool2_replication_stop_on_mismatch: off 156 | pgpool2_reset_query_list: ABORT; DISCARD ALL 157 | pgpool2_search_primary_node_timeout: 10 158 | pgpool2_serialize_accept: off 159 | pgpool2_socket_dir: /var/run/postgresql 160 | pgpool2_sr_check_database: 'postgres' 161 | pgpool2_sr_check_password: '' 162 | pgpool2_sr_check_period: 0 163 | pgpool2_sr_check_user: nobody 164 | pgpool2_ssl: off 165 | pgpool2_ssl_ca_cert: '' 166 | pgpool2_ssl_ca_cert_dir: '' 167 | pgpool2_ssl_cert: ./server.cert 168 | pgpool2_ssl_key: ./server.key 169 | pgpool2_syslog_facility: LOCAL0 170 | pgpool2_syslog_ident: pgpool 171 | pgpool2_trusted_servers: '' 172 | pgpool2_use_watchdog: off 173 | pgpool2_wd_authkey: '' 174 | pgpool2_wd_de_escalation_command: '' 175 | pgpool2_wd_escalation_command: '' 176 | pgpool2_wd_heartbeat_deadtime: 30 177 | pgpool2_wd_heartbeat_keepalive: 2 178 | pgpool2_wd_heartbeat_port: 9694 179 | pgpool2_wd_interval: 10 180 | pgpool2_wd_ipc_socket_dir: '/tmp' 181 | pgpool2_wd_life_point: 3 182 | pgpool2_wd_lifecheck_dbname: template1 183 | pgpool2_wd_lifecheck_method: heartbeat 184 | pgpool2_wd_lifecheck_password: '' 185 | pgpool2_wd_lifecheck_query: SELECT 1 186 | pgpool2_wd_lifecheck_user: nobody 187 | pgpool2_wd_monitoring_interfaces_list: '' 188 | pgpool2_wd_port: 9000 189 | pgpool2_wd_priority: 1 190 | pgpool2_white_function_list: '' 191 | pgpool2_white_memqcache_table_list: '' 192 | -------------------------------------------------------------------------------- /files/pgpool2: -------------------------------------------------------------------------------- 1 | Cmnd_Alias NETCFG_CMD = /sbin/ifconfig, /usr/sbin/arping 2 | postgres ALL=(ALL) NOPASSWD: NETCFG_CMD 3 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start pgpool2 4 | service: 5 | name: pgpool2 6 | state: started 7 | 8 | - name: stop pgpool2 9 | service: 10 | name: pgpool2 11 | state: stopped 12 | 13 | - name: restart pgpool2 14 | service: 15 | name: pgpool2 16 | state: restarted 17 | 18 | - name: reload pgpool2 19 | service: 20 | name: pgpool2 21 | state: reloaded 22 | 23 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: 2GIS IT 4 | description: Role for PostgreSQL load balancer and replication system pgpool2 5 | min_ansible_version: 2.0.0 6 | license: LGPL 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | categories: 12 | - database 13 | - postgresql 14 | 15 | dependencies: [] 16 | -------------------------------------------------------------------------------- /tasks/configure.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create "/var/log/postgresql/" directory with necessary privileges 4 | file: 5 | dest: "/var/log/postgresql/" 6 | owner: "{{ pgpool2_user }}" 7 | group: "{{ pgpool2_group }}" 8 | mode: 0755 9 | state: directory 10 | 11 | - name: Divert PCP authentication registry file {{ pgpool2_confdir }}/pcp.conf 12 | command: dpkg-divert --quiet --local --divert {{ pgpool2_confdir }}/pcp.conf.dpkg-divert --rename {{ pgpool2_confdir }}/pcp.conf 13 | args: 14 | creates: "{{ pgpool2_confdir }}/pcp.conf.dpkg-divert" 15 | 16 | - name: PCP authentication registry file {{ pgpool2_confdir }}/pcp.conf 17 | template: 18 | src: pcp.conf.j2 19 | dest: "{{ pgpool2_confdir }}/pcp.conf" 20 | owner: "{{ pgpool2_user }}" 21 | group: "{{ pgpool2_group }}" 22 | mode: 0640 23 | 24 | - name: Divert pgpool2 main configuration file {{ pgpool2_confdir }}/pgpool.conf 25 | command: dpkg-divert --quiet --local --divert {{ pgpool2_confdir }}/pgpool.conf.dpkg-divert --rename {{ pgpool2_confdir }}/pgpool.conf 26 | args: 27 | creates: "{{ pgpool2_confdir }}/pgpool.conf.dpkg-divert" 28 | 29 | - name: pgpool2 main configuration file {{ pgpool2_confdir }}/pgpool.conf 30 | template: 31 | src: pgpool.conf.j2 32 | dest: "{{ pgpool2_confdir }}/pgpool.conf" 33 | owner: "{{ pgpool2_user }}" 34 | group: "{{ pgpool2_group }}" 35 | mode: 0640 36 | notify: 37 | - restart pgpool2 38 | 39 | - name: Divert pgpool2 pool hba file {{ pgpool2_confdir }}/pool_hba.conf 40 | command: dpkg-divert --quiet --local --divert {{ pgpool2_confdir }}/pool_hba.conf.dpkg-divert --rename {{ pgpool2_confdir }}/pool_hba.conf 41 | args: 42 | creates: "{{ pgpool2_confdir }}/pool_hba.conf.dpkg-divert" 43 | 44 | - name: pgpool2 pool hba file {{ pgpool2_confdir }}/pool_hba.conf 45 | template: 46 | src: pool_hba.conf.j2 47 | dest: "{{ pgpool2_confdir }}/pool_hba.conf" 48 | owner: "{{ pgpool2_user }}" 49 | group: "{{ pgpool2_group }}" 50 | mode: 0640 51 | notify: 52 | - restart pgpool2 53 | 54 | - name: Divert pgpool2 initscript /etc/init.d/pgpool2 55 | command: dpkg-divert --quiet --local --divert /etc/init.d/pgpool2.dpkg-divert --rename /etc/init.d/pgpool2 56 | args: 57 | creates: "/etc/init.d/pgpool2.dpkg-divert" 58 | 59 | - name: pgpool2 initscript /etc/init.d/pgpool2 60 | template: 61 | src: pgpool2.j2 62 | dest: "/etc/init.d/pgpool2" 63 | mode: 0755 64 | notify: 65 | - restart pgpool2 66 | 67 | - name: pgpool2 node reattach script 68 | template: 69 | src: pgpool2_reattach.sh.j2 70 | dest: "{{ pgpool2_confdir }}/pgpool2_reattach.sh" 71 | mode: 0700 72 | 73 | - name: try to reattach nodes every 10 seconds 74 | cron: 75 | name: "pgpool2 reattach detached backends" 76 | job: "for i in 0 1 2 3 4 5 ; do {{ pgpool2_confdir }}/pgpool2_reattach.sh >/dev/null 2>&1; sleep 10 ; done" 77 | state: "{{'present' if pgpool2_auto_reattach else 'absent'}}" 78 | 79 | - name: add users to pool_passwd 80 | copy: 81 | dest: "{{ pgpool2_confdir }}/{{ pgpool2_pool_passwd }}" 82 | owner: "{{ pgpool2_user }}" 83 | group: "{{ pgpool2_group }}" 84 | mode: 0640 85 | content: | 86 | {% for user in pgpool2_pool_users %} 87 | {{ user.name }}:md5{{ (user.pass + user.name) | hash('md5') }} 88 | {% endfor %} 89 | notify: 90 | - reload pgpool2 91 | 92 | - name: Create sudo permissions for pgpool2 93 | copy: 94 | src: pgpool2 95 | dest: "/etc/sudoers.d/pgpool2" 96 | owner: "root" 97 | group: "root" 98 | mode: 0440 99 | 100 | - name: ensure pgpool2 is running 101 | service: 102 | name: pgpool2 103 | state: started 104 | 105 | -------------------------------------------------------------------------------- /tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install required pgpool2 packages 4 | apt: 5 | pkg: "{{ item }}" 6 | state: "{{ pgpool2_package_state }}" 7 | with_items: "{{ pgpool2_packages }}" 8 | 9 | - name: short command wrapper 10 | template: 11 | src: pcpctl.j2 12 | dest: /usr/local/bin/pcpctl 13 | owner: root 14 | group: root 15 | mode: 0755 16 | 17 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include: install.yml 4 | tags: [pgpool2, pgpool2-install] 5 | 6 | - include: configure.yml 7 | tags: [pgpool2, pgpool2-configure] 8 | -------------------------------------------------------------------------------- /templates/pcp.conf.j2: -------------------------------------------------------------------------------- 1 | # PCP Client Authentication Configuration File 2 | # ============================================ 3 | # 4 | # This file contains user ID and his password for pgpool 5 | # communication manager authentication. 6 | # 7 | # Note that users defined here do not need to be PostgreSQL 8 | # users. These users are authorized ONLY for pgpool 9 | # communication manager. 10 | # 11 | # File Format 12 | # =========== 13 | # 14 | # List one UserID and password on a single line. They must 15 | # be concatenated together using ':' (colon) between them. 16 | # No spaces or tabs are allowed anywhere in the line. 17 | # 18 | # Example: 19 | # postgres:e8a48653851e28c69d0506508fb27fc5 20 | # 21 | # Be aware that there will be no spaces or tabs at the 22 | # beginning of the line! although the above example looks 23 | # like so. 24 | # 25 | # Lines beginning with '#' (pound) are comments and will 26 | # be ignored. Again, no spaces or tabs allowed before '#'. 27 | 28 | # USERID:MD5PASSWD 29 | 30 | {{ pgpool2_pcp_user_name }}:{{ pgpool2_pcp_user_password|hash('md5') }} 31 | 32 | -------------------------------------------------------------------------------- /templates/pcpctl.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # pgpool-II pcp wrapper 4 | # 5 | # Interfaces with pgpool's pcp command-line tools to provide access to common functions for managing 6 | # load-balancing and failover. 7 | # 8 | 9 | PATH="/bin:/sbin:/usr/bin:/usr/sbin" 10 | 11 | # PCP configuration 12 | pcp_host="127.0.0.1" 13 | pcp_port="{{ pgpool2_pcp_port }}" 14 | pcp_username="{{ pgpool2_pcp_user_name }}" 15 | pcp_password="{{ pgpool2_pcp_user_password }}" 16 | pcp_timeout="10" 17 | 18 | # Health check uses psql to connect to each backend server. Specify options required to connect here 19 | psql_healthcheck_opts="-U postgres" 20 | 21 | # Default options to send to pcp commands 22 | pcp_cmd_preamble="$pcp_timeout $pcp_host $pcp_port $pcp_username $pcp_password" 23 | 24 | # 25 | # Get the node ID of the first master 26 | # 27 | _get_master_node() 28 | { 29 | # Get total number of nodes 30 | nodes=$(_get_node_count) 31 | 32 | if [ $? -gt 0 ]; then 33 | echo "ERROR: Failed getting node count: $nodes" >&2 34 | exit 1 35 | fi 36 | 37 | c=0 38 | 39 | # Loop through each node to check if it's the master 40 | while [ $c -lt $nodes ]; do 41 | if [ "$(_is_standby $c)" == "0" ]; then 42 | echo $c 43 | return 0 44 | fi 45 | let c=c+1 46 | done 47 | 48 | echo "-1" 49 | return 1 50 | } 51 | 52 | # 53 | # Checks if the node is in postgresql recovery mode (ie. if it is a slave) 54 | # 55 | _is_standby() 56 | { 57 | if [ -z $1 ]; then 58 | echo "Usage: $0 _is_standby " >&2 59 | return 99 60 | fi 61 | 62 | # Get node connection information 63 | node_info=($(_get_node_info $1)) 64 | 65 | if [ $? -gt 0 ]; then 66 | echo "ERROR: Failed getting node info for node $1" >&2 67 | return 1 68 | fi 69 | 70 | export PGCONNECT_TIMEOUT=2 71 | result=$(psql $psql_healthcheck_opts -h "${node_info[0]}" -p "${node_info[1]}" -Atc "SELECT pg_is_in_recovery();" 2>/dev/null) 72 | 73 | if [ "$result" == "t" ]; then 74 | echo 1 75 | return 1 76 | else 77 | echo 0 78 | return 0 79 | fi 80 | } 81 | 82 | # 83 | # Prints whether the postgresql service on the specified node is responding. 84 | # 85 | _is_node_alive() 86 | { 87 | if [ -z $1 ]; then 88 | echo "Usage: $0 _is_node_alive " >&2 89 | return 99 90 | fi 91 | 92 | # Get node connection information 93 | node_info=($(_get_node_info $1)) 94 | 95 | if [ $? -gt 0 ]; then 96 | echo "ERROR: Failed getting node info for node $1" >&2 97 | return 1 98 | fi 99 | 100 | export PGCONNECT_TIMEOUT=2 101 | result=$(psql $psql_healthcheck_opts -h "${node_info[0]}" -p "${node_info[1]}" -Atc "SELECT 1;" 2>/dev/null) 102 | 103 | if [ "$result" == "1" ]; then 104 | echo 1 105 | return 1 106 | else 107 | echo 0 108 | return 0 109 | fi 110 | } 111 | 112 | # 113 | # Prints the status of the specified node in human readable format. 114 | # 115 | _get_node_status() 116 | { 117 | if [ -z $1 ]; then 118 | echo "Usage: $0 _get_node_status " >&2 119 | return 99 120 | fi 121 | 122 | node_info=($(_get_node_info $1)) 123 | 124 | if [ $? -gt 0 ]; then 125 | echo "ERROR: Failed getting node info for node $1" >&2 126 | else 127 | node_role="" 128 | node_alive="" 129 | case "$(_is_node_alive $1)" in 130 | 1) 131 | node_alive="Up" 132 | ;; 133 | *) 134 | node_alive="Down" 135 | ;; 136 | esac 137 | if [ "$node_alive" == "Up" ]; then 138 | 139 | # Find out what role this node has 140 | if [ "$(_is_standby $1)" == "1" ]; then 141 | node_role="Slave" 142 | else 143 | node_role="Master" 144 | fi 145 | fi 146 | case "${node_info[2]}" in 147 | 3) 148 | node_status="detached from pool" 149 | ;; 150 | 2) 151 | node_status="in pool and connected" 152 | ;; 153 | 1) 154 | node_status="in pool" 155 | ;; 156 | *) 157 | node_status="Unknown" 158 | ;; 159 | esac 160 | 161 | # Print status information about this node 162 | echo "Node: $1" 163 | echo "Host: ${node_info[0]}" 164 | echo "Port: ${node_info[1]}" 165 | echo "Weight: ${node_info[3]}" 166 | echo "Status: $node_alive, $node_status (${node_info[2]})" 167 | [ -n "$node_role" ] && echo "Role: $node_role" 168 | echo "" 169 | fi 170 | } 171 | 172 | # 173 | # Prints the total number of pgpool nodes. 174 | # 175 | _get_node_count() { 176 | pcp_node_count $pcp_cmd_preamble 177 | } 178 | 179 | # 180 | # Prints out node information for the specified pgpool node 181 | # 182 | _get_node_info() { 183 | if [ -z $1 ]; then 184 | echo "Usage: $0 _get_node_info " >&2 185 | return 99 186 | fi 187 | pcp_node_info $pcp_cmd_preamble $1 188 | } 189 | 190 | # 191 | # Attaches the specified node to the pool 192 | # 193 | attach() { 194 | if [ -z $1 ]; then 195 | echo "Usage: $0 attach " >&2 196 | return 99 197 | fi 198 | pcp_attach_node $pcp_cmd_preamble $1 199 | } 200 | 201 | # 202 | # Detaches the specified node from the pool 203 | # 204 | detach() { 205 | if [ -z $1 ]; then 206 | echo "Usage: $0 detach " >&2 207 | return 99 208 | fi 209 | pcp_detach_node $pcp_cmd_preamble $1 210 | } 211 | 212 | # 213 | # Recovers the specified node (restores it from current master and re-attaches) 214 | # 215 | recover() { 216 | if [ -z $1 ]; then 217 | echo "Usage: $0 recover " >&2 218 | return 99 219 | fi 220 | pcp_recovery_node $pcp_cmd_preamble $1 221 | } 222 | 223 | # 224 | # Prints out the status of all pgpool nodes in human readable form. 225 | # 226 | status() { 227 | # Get total number of nodes 228 | nodes=$(_get_node_count) 229 | if [ $? -gt 0 ]; then 230 | echo "ERROR: Failed getting node count: $nodes" >&2 231 | exit 1 232 | fi 233 | c=0 234 | # Loop through each node to retrieve info 235 | while [ $c -lt $nodes ]; do 236 | _get_node_status $c 237 | let c=c+1 238 | done 239 | } 240 | 241 | main() 242 | { 243 | if [ ! "$(type -t $1)" ]; then 244 | echo "Usage $0