├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── run-tests.yml ├── .gitignore ├── .readthedocs.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── Dockerfile.docs ├── LICENSE ├── Makefile ├── Makefile.azure ├── Makefile.citus ├── NOTICE ├── README.md ├── cgmanifest.json ├── ci ├── Dockerfile ├── banned.h.sh └── tools.mk ├── docker-compose.yml ├── docs ├── .gitignore ├── Makefile ├── _static │ └── css │ │ ├── citus.css │ │ └── pygments.css ├── architecture-multi-standby.rst ├── architecture.rst ├── azure-tutorial.rst ├── citus-quickstart.rst ├── citus.rst ├── citus │ ├── Dockerfile │ ├── Dockerfile.app │ ├── Makefile │ ├── app.py │ ├── docker-compose-scale.yml │ └── docker-compose.yml ├── conf.py ├── failover-state-machine.rst ├── faq.rst ├── fault-tolerance.rst ├── fsm.png ├── how-to.rst ├── index.rst ├── install.rst ├── intro.rst ├── operations.rst ├── pg_auto_failover-arch.png ├── ref │ ├── configuration.rst │ ├── manual.rst │ ├── pg_autoctl.rst │ ├── pg_autoctl_activate.rst │ ├── pg_autoctl_config.rst │ ├── pg_autoctl_config_check.rst │ ├── pg_autoctl_config_get.rst │ ├── pg_autoctl_config_set.rst │ ├── pg_autoctl_create.rst │ ├── pg_autoctl_create_coordinator.rst │ ├── pg_autoctl_create_formation.rst │ ├── pg_autoctl_create_monitor.rst │ ├── pg_autoctl_create_postgres.rst │ ├── pg_autoctl_create_worker.rst │ ├── pg_autoctl_disable.rst │ ├── pg_autoctl_disable_maintenance.rst │ ├── pg_autoctl_disable_monitor.rst │ ├── pg_autoctl_disable_secondary.rst │ ├── pg_autoctl_disable_ssl.rst │ ├── pg_autoctl_do.rst │ ├── pg_autoctl_do_demo.rst │ ├── pg_autoctl_do_pgsetup.rst │ ├── pg_autoctl_do_service_restart.rst │ ├── pg_autoctl_do_show.rst │ ├── pg_autoctl_do_tmux.rst │ ├── pg_autoctl_drop.rst │ ├── pg_autoctl_drop_formation.rst │ ├── pg_autoctl_drop_monitor.rst │ ├── pg_autoctl_drop_node.rst │ ├── pg_autoctl_enable.rst │ ├── pg_autoctl_enable_maintenance.rst │ ├── pg_autoctl_enable_monitor.rst │ ├── pg_autoctl_enable_secondary.rst │ ├── pg_autoctl_enable_ssl.rst │ ├── pg_autoctl_get.rst │ ├── pg_autoctl_get_formation_number_sync_standbys.rst │ ├── pg_autoctl_get_formation_settings.rst │ ├── pg_autoctl_get_node_candidate_priority.rst │ ├── pg_autoctl_get_node_replication_quorum.rst │ ├── pg_autoctl_perform.rst │ ├── pg_autoctl_perform_failover.rst │ ├── pg_autoctl_perform_promotion.rst │ ├── pg_autoctl_perform_switchover.rst │ ├── pg_autoctl_reload.rst │ ├── pg_autoctl_run.rst │ ├── pg_autoctl_set.rst │ ├── pg_autoctl_set_formation_number_sync_standbys.rst │ ├── pg_autoctl_set_node_candidate_priority.rst │ ├── pg_autoctl_set_node_replication_quorum.rst │ ├── pg_autoctl_show.rst │ ├── pg_autoctl_show_events.rst │ ├── pg_autoctl_show_file.rst │ ├── pg_autoctl_show_settings.rst │ ├── pg_autoctl_show_standby_names.rst │ ├── pg_autoctl_show_state.rst │ ├── pg_autoctl_show_systemd.rst │ ├── pg_autoctl_show_uri.rst │ ├── pg_autoctl_status.rst │ ├── pg_autoctl_stop.rst │ └── pg_autoctl_watch.rst ├── requirements.txt ├── security.rst ├── tikz │ ├── Makefile │ ├── arch-citus.svg │ ├── arch-citus.tex │ ├── arch-multi-standby.svg │ ├── arch-multi-standby.tex │ ├── arch-single-standby.svg │ ├── arch-single-standby.tex │ ├── arch-three-standby-one-async.svg │ ├── arch-three-standby-one-async.tex │ ├── arch-three-standby.svg │ ├── arch-three-standby.tex │ ├── common.tex │ ├── fsm.svg │ └── fsm.tex ├── tutorial.rst └── tutorial │ ├── Dockerfile │ ├── Dockerfile.app │ ├── Makefile │ ├── app.py │ └── docker-compose.yml ├── pyproject.toml ├── src ├── Makefile ├── bin │ ├── Makefile │ ├── lib │ │ ├── README.md │ │ ├── libs │ │ │ ├── docs │ │ │ │ └── ini.md │ │ │ └── ini.h │ │ ├── log │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── src │ │ │ │ ├── log.c │ │ │ │ └── log.h │ │ ├── parson │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── meson.build │ │ │ ├── package.json │ │ │ ├── parson.c │ │ │ ├── parson.h │ │ │ ├── tests.c │ │ │ └── tests │ │ │ │ ├── test_1_1.txt │ │ │ │ ├── test_1_2.txt │ │ │ │ ├── test_1_3.txt │ │ │ │ ├── test_2.txt │ │ │ │ ├── test_2_comments.txt │ │ │ │ ├── test_2_pretty.txt │ │ │ │ └── test_5.txt │ │ ├── pg │ │ │ ├── README.md │ │ │ ├── snprintf.c │ │ │ ├── snprintf.h │ │ │ └── strerror.c │ │ └── subcommands.c │ │ │ ├── commandline.c │ │ │ ├── commandline.h │ │ │ └── runprogram.h │ └── pg_autoctl │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── README.md │ │ ├── azure.c │ │ ├── azure.h │ │ ├── azure_config.c │ │ ├── azure_config.h │ │ ├── cli_common.c │ │ ├── cli_common.h │ │ ├── cli_config.c │ │ ├── cli_create_node.c │ │ ├── cli_do_azure.c │ │ ├── cli_do_coordinator.c │ │ ├── cli_do_demoapp.c │ │ ├── cli_do_demoapp.h │ │ ├── cli_do_fsm.c │ │ ├── cli_do_misc.c │ │ ├── cli_do_monitor.c │ │ ├── cli_do_root.c │ │ ├── cli_do_root.h │ │ ├── cli_do_service.c │ │ ├── cli_do_show.c │ │ ├── cli_do_tmux.c │ │ ├── cli_do_tmux.h │ │ ├── cli_do_tmux_azure.c │ │ ├── cli_do_tmux_compose.c │ │ ├── cli_drop_node.c │ │ ├── cli_enable_disable.c │ │ ├── cli_formation.c │ │ ├── cli_get_set_properties.c │ │ ├── cli_perform.c │ │ ├── cli_root.c │ │ ├── cli_root.h │ │ ├── cli_service.c │ │ ├── cli_show.c │ │ ├── cli_systemd.c │ │ ├── cli_watch.c │ │ ├── config.c │ │ ├── config.h │ │ ├── coordinator.c │ │ ├── coordinator.h │ │ ├── debian.c │ │ ├── debian.h │ │ ├── defaults.h │ │ ├── demoapp.c │ │ ├── demoapp.h │ │ ├── env_utils.c │ │ ├── env_utils.h │ │ ├── file_utils.c │ │ ├── file_utils.h │ │ ├── formation_config.h │ │ ├── fsm.c │ │ ├── fsm.h │ │ ├── fsm_transition.c │ │ ├── fsm_transition_citus.c │ │ ├── ini_file.c │ │ ├── ini_file.h │ │ ├── ini_implementation.c │ │ ├── ipaddr.c │ │ ├── ipaddr.h │ │ ├── keeper.c │ │ ├── keeper.h │ │ ├── keeper_config.c │ │ ├── keeper_config.h │ │ ├── keeper_pg_init.c │ │ ├── keeper_pg_init.h │ │ ├── lock_utils.c │ │ ├── lock_utils.h │ │ ├── main.c │ │ ├── monitor.c │ │ ├── monitor.h │ │ ├── monitor_config.c │ │ ├── monitor_config.h │ │ ├── monitor_pg_init.c │ │ ├── monitor_pg_init.h │ │ ├── nodestate_utils.c │ │ ├── nodestate_utils.h │ │ ├── parsing.c │ │ ├── parsing.h │ │ ├── pgctl.c │ │ ├── pgctl.h │ │ ├── pghba.c │ │ ├── pghba.h │ │ ├── pgsetup.c │ │ ├── pgsetup.h │ │ ├── pgsql.c │ │ ├── pgsql.h │ │ ├── pgtuning.c │ │ ├── pgtuning.h │ │ ├── pidfile.c │ │ ├── pidfile.h │ │ ├── primary_standby.c │ │ ├── primary_standby.h │ │ ├── service_keeper.c │ │ ├── service_keeper.h │ │ ├── service_keeper_init.c │ │ ├── service_keeper_init.h │ │ ├── service_monitor.c │ │ ├── service_monitor.h │ │ ├── service_monitor_init.c │ │ ├── service_monitor_init.h │ │ ├── service_postgres.c │ │ ├── service_postgres.h │ │ ├── service_postgres_ctl.c │ │ ├── service_postgres_ctl.h │ │ ├── signals.c │ │ ├── signals.h │ │ ├── state.c │ │ ├── state.h │ │ ├── string_utils.c │ │ ├── string_utils.h │ │ ├── supervisor.c │ │ ├── supervisor.h │ │ ├── system_utils.c │ │ ├── system_utils.h │ │ ├── systemd_config.c │ │ ├── systemd_config.h │ │ ├── watch.c │ │ ├── watch.h │ │ └── watch_colspecs.h ├── monitor │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── conninfo.c │ ├── conninfo.h │ ├── expected │ │ ├── create_extension.out │ │ ├── drop_extension.out │ │ ├── dummy_update.out │ │ ├── monitor.out │ │ ├── upgrade.out │ │ └── workers.out │ ├── formation_metadata.c │ ├── formation_metadata.h │ ├── group_state_machine.c │ ├── group_state_machine.h │ ├── health_check.h │ ├── health_check_metadata.c │ ├── health_check_worker.c │ ├── metadata.c │ ├── metadata.h │ ├── node_active_protocol.c │ ├── node_metadata.c │ ├── node_metadata.h │ ├── notifications.c │ ├── notifications.h │ ├── pg_auto_failover.c │ ├── pgautofailover--1.0--1.1.sql │ ├── pgautofailover--1.0.sql │ ├── pgautofailover--1.1--1.2.sql │ ├── pgautofailover--1.2--1.3.sql │ ├── pgautofailover--1.3--1.4.sql │ ├── pgautofailover--1.4--1.5.sql │ ├── pgautofailover--1.5--1.6.sql │ ├── pgautofailover--1.6--2.0.sql │ ├── pgautofailover--2.0--2.1.sql │ ├── pgautofailover--2.1--2.2.sql │ ├── pgautofailover--2.2--dummy.sql │ ├── pgautofailover.control │ ├── pgautofailover.sql │ ├── replication_state.c │ ├── replication_state.h │ ├── sql │ │ ├── create_extension.sql │ │ ├── drop_extension.sql │ │ ├── dummy_update.sql │ │ ├── monitor.sql │ │ ├── upgrade.sql │ │ └── workers.sql │ ├── version_compat.c │ └── version_compat.h └── tools │ ├── pg_autoctl.valgrind │ └── remove_useless_declarations.sh ├── tests ├── Pipfile ├── Pipfile.lock ├── __init__.py ├── network.py ├── pgautofailover_utils.py ├── ssl_cert_utils.py ├── tablespaces │ ├── Dockerfile │ ├── Makefile │ ├── docker-compose.yml │ ├── tablespace_utils.py │ ├── test_tablespaces_01.py │ ├── test_tablespaces_02.py │ ├── test_tablespaces_03.py │ ├── test_tablespaces_04.py │ ├── test_tablespaces_05.py │ └── test_tablespaces_06.py ├── test_auth.py ├── test_basic_citus_operation.py ├── test_basic_operation.py ├── test_basic_operation_listen_flag.py ├── test_citus_cluster_name.py ├── test_citus_force_failover.py ├── test_citus_multi_standbys.py ├── test_citus_skip_pg_hba.py ├── test_config_get_set.py ├── test_create_run.py ├── test_create_standby_with_pgdata.py ├── test_debian_clusters.py ├── test_enable_ssl.py ├── test_ensure.py ├── test_extension_update.py ├── test_installcheck.py ├── test_monitor_disabled.py ├── test_multi_alternate_primary_failures.py ├── test_multi_async.py ├── test_multi_ifdown.py ├── test_multi_maintenance.py ├── test_multi_standbys.py ├── test_nonha_citus_operation.py ├── test_replace_monitor.py ├── test_skip_pg_hba.py ├── test_ssl_cert.py ├── test_ssl_self_signed.py └── upgrade │ ├── Makefile │ ├── README.md │ ├── docker-compose.yml │ └── monitor-upgrade-1.7.patch └── valgrind └── .gitignore /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | src/bin/pg_autoctl/pg_autoctl 3 | Dockerfile 4 | 5 | docs/tutorial/monitor 6 | docs/tutorial/node1 7 | docs/tutorial/node2 8 | docs/tikz/*svg 9 | docs/tikz/*pdf 10 | docs/tikz/*png 11 | 12 | # Global excludes across all subdirectories 13 | *.o 14 | *.bc 15 | *.so 16 | *.so.[0-9] 17 | *.so.[0-9].[0-9] 18 | *.sl 19 | *.sl.[0-9] 20 | *.sl.[0-9].[0-9] 21 | *.dylib 22 | *.dll 23 | *.a 24 | *.mo 25 | *.pot 26 | objfiles.txt 27 | .deps/ 28 | *.gcno 29 | *.gcda 30 | *.gcov 31 | *.gcov.out 32 | lcov.info 33 | coverage/ 34 | *.vcproj 35 | *.vcxproj 36 | win32ver.rc 37 | *.exe 38 | lib*dll.def 39 | lib*.pc 40 | *.log 41 | 42 | # Local excludes in root directory 43 | /config.log 44 | /config.status 45 | /pgsql.sln 46 | /pgsql.sln.cache 47 | /Debug/ 48 | /Release/ 49 | /autom4te.cache 50 | /Makefile.global 51 | /src/Makefile.custom 52 | /tests/__pycache__/ 53 | /env/ 54 | 55 | # Exclude generated SQL files 56 | pgautofailover--?.?.sql 57 | !pgautofailover--1.0.sql 58 | 59 | # Exclude generated PDF and PNG files for the graphics 60 | docs/tikz/*.pdf 61 | docs/tikz/*.png 62 | 63 | # Exclude our demo/test tmux directory 64 | tmux/ 65 | valgrind/* 66 | 67 | .ccls-cache/ 68 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # rules for all files 5 | # we use tabs with indent size 4 6 | [*] 7 | indent_style = tab 8 | indent_size = 4 9 | tab_width = 4 10 | end_of_line = lf 11 | insert_final_newline = true 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | 15 | # Don't change test output files, pngs or test data files 16 | [*.{out,png,data}] 17 | insert_final_newline = unset 18 | trim_trailing_whitespace = unset 19 | 20 | [*.{sql,sh,py,tex}] 21 | indent_style = space 22 | indent_size = 4 23 | tab_width = 4 24 | 25 | [*.yml] 26 | indent_style = space 27 | indent_size = 2 28 | tab_width = 2 29 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * whitespace=space-before-tab,trailing-space 2 | *.[chly] whitespace=space-before-tab,trailing-space,indent-with-non-tab,tabwidth=4 3 | *.dsl whitespace=space-before-tab,trailing-space,tab-in-indent 4 | *.patch -whitespace 5 | *.pl whitespace=space-before-tab,trailing-space,tabwidth=4 6 | *.po whitespace=space-before-tab,trailing-space,tab-in-indent,-blank-at-eof 7 | *.sgml whitespace=space-before-tab,trailing-space,tab-in-indent,-blank-at-eol 8 | *.x[ms]l whitespace=space-before-tab,trailing-space,tab-in-indent 9 | 10 | # Avoid confusing ASCII underlines with leftover merge conflict markers 11 | README conflict-marker-size=32 12 | README.* conflict-marker-size=32 13 | 14 | 15 | # These files are maintained or generated elsewhere. We take them as is. 16 | configure -whitespace 17 | 18 | # all C files (implementation and header) use our style... 19 | *.[ch] citus-style 20 | 21 | # except these exceptions... 22 | src/bin/lib/parson/** -citus-style 23 | src/bin/lib/log/** -citus-style 24 | src/bin/lib/libs/** -citus-style 25 | src/bin/lib/pg/** -citus-style 26 | src/bin/lib/subcommands.c/** -citus-style 27 | src/monitor/version_compat.c -citus-style 28 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | workflow_dispatch: 12 | 13 | jobs: 14 | run_tests: 15 | name: Run test 16 | runs-on: ubuntu-latest 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | PGVERSION: 21 | - 13 22 | - 14 23 | - 15 24 | - 16 25 | - 17 26 | TEST: 27 | - multi 28 | - single 29 | - monitor 30 | - ssl 31 | - citus 32 | include: 33 | - PGVERSION: 14 34 | TEST: tablespaces 35 | - PGVERSION: 14 36 | TEST: linting 37 | steps: 38 | - name: Checkout repository 39 | uses: actions/checkout@v3 40 | 41 | - name: Set environment variables 42 | run: | 43 | echo "PGVERSION=${{ matrix.PGVERSION }}" >> $GITHUB_ENV 44 | echo "TEST=${{ matrix.TEST }}" >> $GITHUB_ENV 45 | echo "LINTING=${{ matrix.LINTING }}" >> $GITHUB_ENV 46 | echo "TRAVIS_BUILD_DIR=$(pwd)" >> $GITHUB_ENV 47 | 48 | - name: Clone and install linting tools 49 | if: ${{ env.TEST == 'linting' }} 50 | run: | 51 | sudo apt-get install python3-pip 52 | pip3 install --user black 53 | black --version 54 | gcc --version 55 | # Install uncrustify the Citus way 56 | make -C ci -f tools.mk tools 57 | 58 | - name: Check code formatting and banned function 59 | if: ${{ env.TEST == 'linting' }} 60 | run: | 61 | make lint 62 | 63 | - name: Build documentation 64 | if: ${{ env.TEST == 'linting' }} 65 | run: | 66 | make build-docs 67 | 68 | - name: Build Docker Test Image 69 | if: ${{ env.TEST != 'linting' }} 70 | run: | 71 | make build-test-image 72 | 73 | - name: Run Test 74 | if: ${{ env.TEST != 'linting' }} 75 | timeout-minutes: 15 76 | run: | 77 | make ci-test 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Global excludes across all subdirectories 2 | *.o 3 | *.bc 4 | *.so 5 | *.so.[0-9] 6 | *.so.[0-9].[0-9] 7 | *.sl 8 | *.sl.[0-9] 9 | *.sl.[0-9].[0-9] 10 | *.dylib 11 | *.dll 12 | *.a 13 | *.mo 14 | *.pot 15 | objfiles.txt 16 | .deps/ 17 | *.gcno 18 | *.gcda 19 | *.gcov 20 | *.gcov.out 21 | lcov.info 22 | coverage/ 23 | *.vcproj 24 | *.vcxproj 25 | win32ver.rc 26 | *.exe 27 | lib*dll.def 28 | lib*.pc 29 | *.log 30 | 31 | # Local excludes in root directory 32 | /config.log 33 | /config.status 34 | /pgsql.sln 35 | /pgsql.sln.cache 36 | /Debug/ 37 | /Release/ 38 | /autom4te.cache 39 | /Makefile.global 40 | /src/Makefile.custom 41 | /tests/__pycache__/ 42 | /env/ 43 | 44 | # Exclude generated SQL files 45 | pgautofailover--?.?.sql 46 | !pgautofailover--1.0.sql 47 | 48 | # Exclude generated PDF and PNG files for the graphics 49 | docs/tikz/*.pdf 50 | docs/tikz/*.png 51 | 52 | # Exclude our demo/test tmux directory 53 | tmux/ 54 | valgrind/ 55 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-lts-latest 5 | tools: 6 | python: "3.12" 7 | 8 | # Build from the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: docs/conf.py 11 | 12 | # declare the Python requirements to build the documentation 13 | python: 14 | install: 15 | - requirements: docs/requirements.txt 16 | -------------------------------------------------------------------------------- /Dockerfile.docs: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | RUN apt-get update \ 4 | && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 5 | curl \ 6 | git \ 7 | gawk \ 8 | make \ 9 | python3 \ 10 | python3-sphinx \ 11 | python3-pip \ 12 | sudo \ 13 | texlive \ 14 | texlive-luatex \ 15 | texlive-latex-extra \ 16 | texlive-fonts-extra \ 17 | latexmk \ 18 | poppler-utils \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | RUN pip3 install sphinx_rtd_theme 22 | 23 | WORKDIR /usr/src/pg_auto_failover 24 | 25 | COPY Makefile ./ 26 | COPY Makefile.azure ./ 27 | COPY Makefile.citus ./ 28 | COPY ./src ./src 29 | COPY ./docs ./docs 30 | 31 | # avoid building the main binary to generate the FSM graphics 32 | RUN touch docs/fsm.png 33 | RUN touch src/bin/pg_autoctl/git-version.h 34 | 35 | # still make sure we can produce the tikz graphics (pdf, svg) 36 | # use TERM=dumb to avoid tput error messages when we don't have a terminal 37 | RUN make TERM=dumb -C docs/tikz clean all 38 | 39 | # and finally use python-sphinx to produce the docs in html 40 | RUN make -C docs html 41 | 42 | RUN find docs 43 | 44 | EXPOSE 8000/tcp 45 | CMD ["python3", "-m", "http.server", "--directory", "docs/_build/html"] 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | PostgreSQL License 4 | 5 | Permission to use, copy, modify, and distribute this software and its 6 | documentation for any purpose, without fee, and without a written agreement 7 | is hereby granted, provided that the above copyright notice and this 8 | paragraph and the following two paragraphs appear in all copies. 9 | 10 | IN NO EVENT SHALL MICROSOFT CORPORATION BE LIABLE TO ANY PARTY FOR DIRECT, 11 | INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 12 | PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 13 | IF MICROSOFT CORPORATION HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 | 15 | MICROSOFT CORPORATION SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 17 | PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND 18 | MICROSOFT CORPORATION HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, 19 | UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 20 | -------------------------------------------------------------------------------- /Makefile.azure: -------------------------------------------------------------------------------- 1 | # 2 | # AZURE related 3 | # 4 | 5 | # make azcluster arguments 6 | AZURE_PREFIX ?= ha-demo-$(shell whoami) 7 | AZURE_REGION ?= paris 8 | AZURE_LOCATION ?= francecentral 9 | 10 | # Pick a version of Postgres and pg_auto_failover packages to install 11 | # in our target Azure VMs when provisionning 12 | # 13 | # sudo apt-get install -q -y postgresql-13-auto-failover-1.5=1.5.2 14 | # postgresql-${AZ_PG_VERSION}-auto-failover-${AZ_PGAF_DEB_VERSION}=${AZ_PGAF_VERSION} 15 | AZ_PG_VERSION ?= 13 16 | AZ_PGAF_DEB_VERSION ?= 1.6 17 | AZ_PGAF_DEB_REVISION ?= 1.6.4-1 18 | 19 | export AZ_PG_VERSION 20 | export AZ_PGAF_DEB_VERSION 21 | export AZ_PGAF_DEB_REVISION 22 | 23 | .PHONY: azcluster 24 | azcluster: all 25 | $(PG_AUTOCTL) do azure create \ 26 | --prefix $(AZURE_PREFIX) \ 27 | --region $(AZURE_REGION) \ 28 | --location $(AZURE_LOCATION) \ 29 | --nodes $(NODES) 30 | 31 | # make azcluster has been done before, just re-attach 32 | .PHONY: az 33 | az: all 34 | $(PG_AUTOCTL) do azure tmux session 35 | 36 | .PHONY: azdrop 37 | azdrop: all 38 | $(PG_AUTOCTL) do azure drop 39 | -------------------------------------------------------------------------------- /Makefile.citus: -------------------------------------------------------------------------------- 1 | # Default Citus Data version 2 | CITUSTAG ?= v13.0.1 3 | 4 | # Citus testing 5 | CITUS = 0 6 | WORKERS = 2 7 | NODES_SECONDARY = 0 8 | 9 | FIRST_PGPORT ?= 5600 10 | CLUSTER_OPTS += --citus 11 | TMUX_TOP_DIR = ./tmux/citus 12 | 13 | # If this Makefile is included then we are only interested in Citus testing 14 | ifeq ($(TEST),citus) 15 | TESTS_CITUS = test_basic_citus_operation 16 | TESTS_CITUS += test_citus_cluster_name 17 | TESTS_CITUS += test_citus_force_failover 18 | TESTS_CITUS += test_citus_multi_standbys 19 | TESTS_CITUS += test_nonha_citus_operation 20 | TESTS_CITUS += test_citus_skip_pg_hba 21 | 22 | TEST_ARGUMENT = --where=tests --tests=$(TESTS_CITUS) 23 | endif 24 | 25 | # this target is defined and used later in the main Makefile 26 | $(TMUX_SCRIPT): TMUX_CITUS=--citus-workers $(WORKERS) --citus-secondaries $(NODES_SECONDARY) 27 | -------------------------------------------------------------------------------- /ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | RUN apt-get update \ 4 | && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 5 | build-essential \ 6 | ca-certificates \ 7 | curl \ 8 | git \ 9 | gawk \ 10 | make \ 11 | cmake \ 12 | python3 \ 13 | sudo \ 14 | && rm -rf /var/lib/apt/lists/* 15 | 16 | WORKDIR /usr/src/pg_auto_failover/ci 17 | COPY tools.mk ./ 18 | 19 | WORKDIR /usr/src/pg_auto_failover 20 | RUN make -C ci -f tools.mk tools 21 | -------------------------------------------------------------------------------- /ci/tools.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Install CI tools, mostly Citus style checker and linter for C code. 3 | # 4 | # See https://github.com/citusdata/citus/blob/main/STYLEGUIDE.md 5 | # 6 | 7 | CITUS_TOOLS = https://github.com/citusdata/tools.git 8 | UNCRUSTIFY = https://github.com/uncrustify/uncrustify/archive/uncrustify-0.68.1.tar.gz 9 | UNCRUSTIFY_DIR = uncrustify-uncrustify-0.68.1 10 | 11 | CMAKE_OPTS = -DCMAKE_POLICY_VERSION_MINIMUM=3.5 12 | 13 | tools: citus-tools ; 14 | 15 | mkdir: 16 | mkdir tools 17 | 18 | uncrustify: mkdir 19 | curl -L $(UNCRUSTIFY) | tar -C tools -xz 20 | mkdir tools/$(UNCRUSTIFY_DIR)/build 21 | cd tools/$(UNCRUSTIFY_DIR)/build && cmake $(CMAKE_OPTS) .. 22 | make -C tools/$(UNCRUSTIFY_DIR)/build -j5 23 | sudo make -C tools/$(UNCRUSTIFY_DIR)/build install 24 | 25 | citus-tools: uncrustify 26 | git clone --depth 1 $(CITUS_TOOLS) tools/tools 27 | sudo make -C tools/tools uncrustify/.install 28 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | monitor: 3 | image: citusdata/pg_auto_failover:demo 4 | environment: 5 | PGDATA: /tmp/pgaf 6 | PG_AUTOCTL_DEBUG: 1 7 | command: pg_autoctl create monitor --ssl-self-signed --auth trust --run 8 | expose: 9 | - 5432 10 | node1: 11 | image: citusdata/pg_auto_failover:demo 12 | environment: 13 | PGDATA: /tmp/pgaf 14 | PGUSER: ad 15 | PGDATABASE: analytics 16 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 17 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 18 | expose: 19 | - 5432 20 | node2: 21 | image: citusdata/pg_auto_failover:demo 22 | environment: 23 | PGDATA: /tmp/pgaf 24 | PGUSER: ad 25 | PGDATABASE: analytics 26 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 27 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 28 | expose: 29 | - 5432 30 | node3: 31 | image: citusdata/pg_auto_failover:demo 32 | environment: 33 | PGDATA: /tmp/pgaf 34 | PGUSER: ad 35 | PGDATABASE: analytics 36 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 37 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 38 | expose: 39 | - 5432 40 | demo-app: 41 | image: citusdata/pg_auto_failover:demo 42 | environment: 43 | PGDATA: /tmp/pgaf 44 | PGUSER: ad 45 | PGDATABASE: analytics 46 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 47 | PG_AUTOCTL_DEMO_CLIENTS: 10 48 | PG_AUTOCTL_DEMO_DURATION: 125 49 | PG_AUTOCTL_DEMO_FAILOVER_FREQ: 30 50 | PG_AUTOCTL_DEMO_FAILOVER_FIRST: 45 51 | command: pg_autoctl do demo run 52 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | .venv 3 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = pg_auto_failover 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/citus/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | ARG PGVERSION=14 4 | ARG CITUS=postgresql-14-citus-11.1 5 | 6 | RUN apt-get update \ 7 | && apt-get install -y --no-install-recommends \ 8 | ca-certificates \ 9 | gnupg \ 10 | make \ 11 | curl \ 12 | sudo \ 13 | tmux \ 14 | watch \ 15 | lsof \ 16 | psutils \ 17 | postgresql-common \ 18 | libpq-dev \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | # we use apt.postgresql.org 22 | RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - 23 | RUN echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.list 24 | RUN echo "deb-src http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.src.list 25 | 26 | # bypass initdb of a "main" cluster 27 | RUN echo 'create_main_cluster = false' | sudo tee -a /etc/postgresql-common/createcluster.conf 28 | RUN apt-get update \ 29 | && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 30 | postgresql-${PGVERSION} \ 31 | postgresql-server-dev-${PGVERSION} \ 32 | && rm -rf /var/lib/apt/lists/* 33 | 34 | # See https://packagecloud.io/citusdata/community/install 35 | RUN curl -s https://packagecloud.io/install/repositories/citusdata/community/script.deb.sh | sudo bash 36 | 37 | RUN apt-get update \ 38 | && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 39 | postgresql-${PGVERSION} \ 40 | ${CITUS} \ 41 | && rm -rf /var/lib/apt/lists/* 42 | 43 | RUN adduser --disabled-password --gecos '' docker 44 | RUN adduser docker sudo 45 | RUN adduser docker postgres 46 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 47 | 48 | # build pg_auto_failover from local sources 49 | RUN apt-get update \ 50 | && apt-get build-dep -y --no-install-recommends postgresql-${PGVERSION} \ 51 | && rm -rf /var/lib/apt/lists/* 52 | WORKDIR /usr/src/pg_auto_failover 53 | 54 | COPY Makefile ./ 55 | COPY Makefile.azure ./ 56 | COPY Makefile.citus ./ 57 | COPY src/ ./src 58 | RUN make -s clean && make -s install -j8 59 | RUN cp /usr/lib/postgresql/${PGVERSION}/bin/pg_autoctl /usr/local/bin 60 | 61 | USER docker 62 | ENV PG_AUTOCTL_DEBUG 1 63 | -------------------------------------------------------------------------------- /docs/citus/Dockerfile.app: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | ARG PGVERSION=14 4 | 5 | RUN apt-get update \ 6 | && apt-get install -y --no-install-recommends \ 7 | ca-certificates \ 8 | gnupg \ 9 | make \ 10 | curl \ 11 | sudo \ 12 | tmux \ 13 | watch \ 14 | lsof \ 15 | psutils \ 16 | python3 \ 17 | && rm -rf /var/lib/apt/lists/* 18 | 19 | # we use apt.postgresql.org 20 | RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - 21 | RUN echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.list 22 | RUN echo "deb-src http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.src.list 23 | 24 | RUN apt-get update \ 25 | && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 26 | postgresql-client-${PGVERSION} \ 27 | && rm -rf /var/lib/apt/lists/* 28 | 29 | RUN adduser --disabled-password --gecos '' docker 30 | RUN adduser docker sudo 31 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 32 | 33 | COPY ./app.py /usr/src/app/app.py 34 | 35 | USER docker 36 | ENTRYPOINT [ "/usr/src/app/app.py" ] 37 | -------------------------------------------------------------------------------- /docs/citus/Makefile: -------------------------------------------------------------------------------- 1 | CONTAINER_NAME = pg_auto_failover:citus 2 | 3 | all: build down up ; 4 | 5 | scale: build scale-down scale-up ; 6 | 7 | build: 8 | docker build -t $(CONTAINER_NAME) -f Dockerfile ../.. 9 | docker compose build 10 | 11 | scale-up: 12 | docker compose -f docker-compose-scale.yml up --scale coord=2 --scale worker=6 13 | 14 | scale-down: 15 | docker compose -f docker-compose-scale.yml down 16 | 17 | up: 18 | docker compose up 19 | 20 | down: 21 | docker compose down 22 | 23 | state: 24 | docker compose exec monitor pg_autoctl show state 25 | 26 | failover: 27 | docker compose exec monitor pg_autoctl perform failover --group 1 28 | 29 | nodes: 30 | docker compose exec coord psql -d analytics -c 'table pg_dist_node' 31 | 32 | .PHONY: all scale build scale-up scale-down up down state failover nodes 33 | -------------------------------------------------------------------------------- /docs/citus/app.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | # 4 | # Write a Python application that knows how to exit gracefully when 5 | # receiving SIGTERM (at docker compose down time), but doesn't know how to 6 | # do much else. 7 | # 8 | 9 | import sys 10 | import time 11 | import signal 12 | from datetime import datetime 13 | 14 | 15 | def sigterm_handler(_signo, _stack_frame): 16 | sys.exit(0) 17 | 18 | 19 | signal.signal(signal.SIGTERM, sigterm_handler) 20 | 21 | if __name__ == "__main__": 22 | try: 23 | while True: 24 | print("%s" % datetime.now()) 25 | time.sleep(600) 26 | except BaseException: 27 | # Keyboard Interrupt or something 28 | pass 29 | -------------------------------------------------------------------------------- /docs/citus/docker-compose-scale.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" # optional since v1.27.0 2 | 3 | services: 4 | 5 | monitor: 6 | image: pg_auto_failover:citus 7 | environment: 8 | PGDATA: /tmp/pgaf 9 | command: | 10 | pg_autoctl create monitor --ssl-self-signed --auth trust --run 11 | expose: 12 | - 5432 13 | 14 | coord: 15 | image: pg_auto_failover:citus 16 | environment: 17 | PGDATA: /tmp/pgaf 18 | PGUSER: citus 19 | PGDATABASE: citus 20 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 21 | expose: 22 | - 5432 23 | command: | 24 | pg_autoctl create coordinator --ssl-self-signed --auth trust --pg-hba-lan --run 25 | 26 | worker: 27 | image: pg_auto_failover:citus 28 | environment: 29 | PGDATA: /tmp/pgaf 30 | PGUSER: citus 31 | PGDATABASE: citus 32 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 33 | expose: 34 | - 5432 35 | command: | 36 | pg_autoctl create worker --ssl-self-signed --auth trust --pg-hba-lan --run 37 | -------------------------------------------------------------------------------- /docs/citus/docker-compose.yml: -------------------------------------------------------------------------------- 1 | x-coord: &coordinator 2 | image: pg_auto_failover:citus 3 | environment: 4 | PGDATA: /tmp/pgaf 5 | PGUSER: citus 6 | PGDATABASE: citus 7 | PG_AUTOCTL_HBA_LAN: true 8 | PG_AUTOCTL_AUTH_METHOD: "trust" 9 | PG_AUTOCTL_SSL_SELF_SIGNED: true 10 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 11 | expose: 12 | - 5432 13 | 14 | x-worker: &worker 15 | image: pg_auto_failover:citus 16 | environment: 17 | PGDATA: /tmp/pgaf 18 | PGUSER: citus 19 | PGDATABASE: citus 20 | PG_AUTOCTL_HBA_LAN: true 21 | PG_AUTOCTL_AUTH_METHOD: "trust" 22 | PG_AUTOCTL_SSL_SELF_SIGNED: true 23 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 24 | expose: 25 | - 5432 26 | 27 | services: 28 | app: 29 | build: 30 | context: . 31 | dockerfile: Dockerfile.app 32 | environment: 33 | PGUSER: citus 34 | PGDATABASE: citus 35 | PGHOST: coord0a,coord0b 36 | PGPORT: 5432 37 | PGAPPNAME: demo 38 | PGSSLMODE: require 39 | PGTARGETSESSIONATTRS: read-write 40 | 41 | monitor: 42 | image: pg_auto_failover:citus 43 | environment: 44 | PGDATA: /tmp/pgaf 45 | PG_AUTOCTL_SSL_SELF_SIGNED: true 46 | expose: 47 | - 5432 48 | command: | 49 | pg_autoctl create monitor --auth trust --run 50 | 51 | coord0a: 52 | <<: *coordinator 53 | hostname: coord0a 54 | command: | 55 | pg_autoctl create coordinator --name coord0a --run 56 | 57 | coord0b: 58 | <<: *coordinator 59 | hostname: coord0b 60 | command: | 61 | pg_autoctl create coordinator --name coord0b --run 62 | 63 | worker1a: 64 | <<: *worker 65 | hostname: worker1a 66 | command: | 67 | pg_autoctl create worker --group 1 --name worker1a --run 68 | 69 | worker1b: 70 | <<: *worker 71 | hostname: worker1b 72 | command: | 73 | pg_autoctl create worker --group 1 --name worker1b --run 74 | 75 | worker2a: 76 | <<: *worker 77 | hostname: worker2a 78 | command: | 79 | pg_autoctl create worker --group 2 --name worker2a --run 80 | 81 | worker2b: 82 | <<: *worker 83 | hostname: worker2b 84 | command: | 85 | pg_autoctl create worker --group 2 --name worker2b --run 86 | 87 | worker3a: 88 | <<: *worker 89 | hostname: worker3a 90 | command: | 91 | pg_autoctl create worker --group 3 --name worker3a --run 92 | 93 | worker3b: 94 | <<: *worker 95 | hostname: worker3b 96 | command: | 97 | pg_autoctl create worker --group 3 --name worker3b --run 98 | -------------------------------------------------------------------------------- /docs/fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hapostgres/pg_auto_failover/19bc0563b8e3b032ba48ec6b49073fab8e077233/docs/fsm.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. pg_auto_failover documentation master file, created by 2 | sphinx-quickstart on Sat May 5 14:33:23 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to pg_auto_failover's documentation! 7 | ============================================ 8 | 9 | The pg_auto_failover project is an Open Source Software project. The 10 | development happens at `https://github.com/hapostgres/pg_auto_failover`__ and 11 | is public: everyone is welcome to participate by opening issues or pull 12 | requests, giving feedback, etc. 13 | 14 | Remember that the first steps are to actually play with the pg_autoctl 15 | command, then read the entire available documentation (after all, I took the 16 | time to write it), and then to address the community in a kind and polite 17 | way — the same way you would expect people to use when addressing you. 18 | 19 | __ https://github.com/hapostgres/pg_auto_failover 20 | 21 | .. note:: 22 | 23 | The development of pg_auto_failover has been driven by Citus Data, since 24 | then a team at Microsoft. The Citus Data team at Microsoft generously 25 | maintains the pg_auto_failover Open Source Software so that its users may 26 | continue using it in production. 27 | 28 | For enhancements, improvements, and new features, consider contributing 29 | to the project. Pull Requests are reviewed as part of the offered 30 | maintenance. 31 | 32 | .. note:: 33 | 34 | Assistance is provided as usual with Open Source projects, on a voluntary 35 | basis. If you need help to cook a patch, enhance the documentation, or 36 | even to use the software, you're welcome to ask questions and expect some 37 | level of free guidance. 38 | 39 | .. toctree:: 40 | :hidden: 41 | :caption: Getting Started 42 | 43 | intro 44 | how-to 45 | tutorial 46 | azure-tutorial 47 | install 48 | 49 | .. toctree:: 50 | :hidden: 51 | :caption: Architecture 52 | 53 | architecture 54 | architecture-multi-standby 55 | failover-state-machine 56 | fault-tolerance 57 | security 58 | 59 | .. toctree:: 60 | :hidden: 61 | :caption: Citus 62 | 63 | citus 64 | citus-quickstart 65 | 66 | .. toctree:: 67 | :hidden: 68 | :caption: Manual Pages 69 | 70 | ref/manual 71 | ref/configuration 72 | 73 | .. toctree:: 74 | :hidden: 75 | :caption: Operations 76 | 77 | operations 78 | faq 79 | 80 | .. 81 | Indices and tables 82 | ================== 83 | 84 | * :ref:`genindex` 85 | * :ref:`modindex` 86 | * :ref:`search` 87 | -------------------------------------------------------------------------------- /docs/pg_auto_failover-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hapostgres/pg_auto_failover/19bc0563b8e3b032ba48ec6b49073fab8e077233/docs/pg_auto_failover-arch.png -------------------------------------------------------------------------------- /docs/ref/manual.rst: -------------------------------------------------------------------------------- 1 | .. _manual: 2 | 3 | Manual Pages 4 | ============ 5 | 6 | The ``pg_autoctl`` tool hosts many commands and sub-commands. Each of them 7 | have their own manual page. 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | :caption: Manual Pages: 12 | 13 | pg_autoctl 14 | pg_autoctl_create 15 | pg_autoctl_drop 16 | pg_autoctl_config 17 | pg_autoctl_show 18 | pg_autoctl_enable 19 | pg_autoctl_disable 20 | pg_autoctl_get 21 | pg_autoctl_set 22 | pg_autoctl_perform 23 | pg_autoctl_do 24 | pg_autoctl_run 25 | pg_autoctl_watch 26 | pg_autoctl_stop 27 | pg_autoctl_reload 28 | pg_autoctl_status 29 | pg_autoctl_activate 30 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_activate.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_activate: 2 | 3 | pg_autoctl activate 4 | =================== 5 | 6 | pg_autoctl activate - Activate a Citus worker from the Citus coordinator 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command calls the Citus “activation” API so that a node can be used to 12 | host shards for your reference and distributed tables. 13 | 14 | :: 15 | 16 | usage: pg_autoctl activate [ --pgdata ] 17 | 18 | --pgdata path to data directory 19 | 20 | Description 21 | ----------- 22 | 23 | When creating a Citus worker, ``pg_autoctl create worker`` automatically 24 | activates the worker node to the coordinator. You only need this command 25 | when something unexpected have happened and you want to manually make sure 26 | the worker node has been activated at the Citus coordinator level. 27 | 28 | Starting with Citus 10 it is also possible to activate the coordinator 29 | itself as a node with shard placement. Use ``pg_autoctl activate`` on your 30 | Citus coordinator node manually to use that feature. 31 | 32 | When the Citus coordinator is activated, an extra step is then needed for it 33 | to host shards of distributed tables. If you want your coordinator to have 34 | shards, then have a look at the Citus API citus_set_node_property_ to set 35 | the ``shouldhaveshards`` property to ``true``. 36 | 37 | .. _citus_set_node_property: 38 | http://docs.citusdata.com/en/v10.0/develop/api_udf.html#citus-set-node-property 39 | 40 | Options 41 | ------- 42 | 43 | --pgdata 44 | 45 | Location of the Postgres node being managed locally. Defaults to the 46 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 47 | from anywhere, rather than the monitor URI used by a local Postgres node 48 | managed with ``pg_autoctl``. 49 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_config.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_config: 2 | 3 | pg_autoctl config 4 | ================= 5 | 6 | pg_autoctl config - Manages the pg_autoctl configuration 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_config_get 12 | pg_autoctl_config_set 13 | pg_autoctl_config_check 14 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_config_check.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_config_check: 2 | 3 | pg_autoctl config check 4 | ======================= 5 | 6 | pg_autoctl config check - Check pg_autoctl configuration 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command implements a very basic list of sanity checks for a pg_autoctl 12 | node setup:: 13 | 14 | usage: pg_autoctl config check [ --pgdata ] [ --json ] 15 | 16 | --pgdata path to data directory 17 | --json output data in the JSON format 18 | 19 | Options 20 | ------- 21 | 22 | --pgdata 23 | 24 | Location of the Postgres node being managed locally. Defaults to the 25 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 26 | from anywhere, rather than the monitor URI used by a local Postgres node 27 | managed with ``pg_autoctl``. 28 | 29 | --json 30 | 31 | Output JSON formatted data. 32 | 33 | 34 | Environment 35 | ----------- 36 | 37 | PGDATA 38 | 39 | Postgres directory location. Can be used instead of the ``--pgdata`` 40 | option. 41 | 42 | PG_AUTOCTL_MONITOR 43 | 44 | Postgres URI to connect to the monitor node, can be used instead of the 45 | ``--monitor`` option. 46 | 47 | XDG_CONFIG_HOME 48 | 49 | The pg_autoctl command stores its configuration files in the standard 50 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 51 | 52 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 53 | 54 | XDG_DATA_HOME 55 | 56 | The pg_autoctl command stores its internal states files in the standard 57 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 58 | Base Directory Specification`__. 59 | 60 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 61 | 62 | Examples 63 | -------- 64 | 65 | :: 66 | 67 | $ pg_autoctl config check --pgdata node1 68 | 18:37:27 63749 INFO Postgres setup for PGDATA "/Users/dim/dev/MS/pg_auto_failover/tmux/node1" is ok, running with PID 5501 and port 99698 69 | 18:37:27 63749 INFO Connection to local Postgres ok, using "port=5501 dbname=demo host=/tmp" 70 | 18:37:27 63749 INFO Postgres configuration settings required for pg_auto_failover are ok 71 | 18:37:27 63749 WARN Postgres 12.1 does not support replication slots on a standby node 72 | 18:37:27 63749 INFO Connection to monitor ok, using "postgres://autoctl_node@localhost:5500/pg_auto_failover?sslmode=prefer" 73 | 18:37:27 63749 INFO Monitor is running version "1.5.0.1", as expected 74 | pgdata: /Users/dim/dev/MS/pg_auto_failover/tmux/node1 75 | pg_ctl: /Applications/Postgres.app/Contents/Versions/12/bin/pg_ctl 76 | pg_version: 12.3 77 | pghost: /tmp 78 | pgport: 5501 79 | proxyport: 0 80 | pid: 99698 81 | is in recovery: no 82 | Control Version: 1201 83 | Catalog Version: 201909212 84 | System Identifier: 6941034382470571312 85 | Latest checkpoint LSN: 0/6000098 86 | Postmaster status: ready 87 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_create.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_create: 2 | 3 | pg_autoctl create 4 | ================= 5 | 6 | pg_autoctl create - Create a pg_auto_failover node, or formation 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_create_monitor 12 | pg_autoctl_create_postgres 13 | pg_autoctl_create_coordinator 14 | pg_autoctl_create_worker 15 | pg_autoctl_create_formation 16 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_disable.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_disable: 2 | 3 | pg_autoctl disable 4 | ================== 5 | 6 | pg_autoctl disable - Disable a feature on a formation 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_disable_secondary 12 | pg_autoctl_disable_maintenance 13 | pg_autoctl_disable_ssl 14 | pg_autoctl_disable_monitor 15 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_disable_secondary.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_disable_secondary: 2 | 3 | pg_autoctl disable secondary 4 | ============================ 5 | 6 | pg_autoctl disable secondary - Disable secondary nodes on a formation 7 | 8 | Synopsis 9 | -------- 10 | 11 | This feature makes the most sense when using the Enterprise Edition of 12 | pg_auto_failover, which is fully compatible with Citus formations. When 13 | ``secondary`` are disabled, then Citus workers creation policy is to assign a 14 | primary node then a standby node for each group. When ``secondary`` is 15 | disabled the Citus workers creation policy is to assign only the primary 16 | nodes. 17 | 18 | :: 19 | 20 | usage: pg_autoctl disable secondary [ --pgdata --formation ] 21 | 22 | --pgdata path to data directory 23 | --formation Formation to disable secondary on 24 | 25 | 26 | Options 27 | ------- 28 | 29 | --pgdata 30 | 31 | Location of the Postgres node being managed locally. Defaults to the 32 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 33 | from anywhere, rather than the monitor URI used by a local Postgres node 34 | managed with ``pg_autoctl``. 35 | 36 | --formation 37 | 38 | Target formation where to disable secondary feature. 39 | 40 | 41 | Environment 42 | ----------- 43 | 44 | PGDATA 45 | 46 | Postgres directory location. Can be used instead of the ``--pgdata`` 47 | option. 48 | 49 | PG_AUTOCTL_MONITOR 50 | 51 | Postgres URI to connect to the monitor node, can be used instead of the 52 | ``--monitor`` option. 53 | 54 | XDG_CONFIG_HOME 55 | 56 | The pg_autoctl command stores its configuration files in the standard 57 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 58 | 59 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 60 | 61 | XDG_DATA_HOME 62 | 63 | The pg_autoctl command stores its internal states files in the standard 64 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 65 | Base Directory Specification`__. 66 | 67 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 68 | 69 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_do_service_restart.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_do_service_restart: 2 | 3 | pg_autoctl do service restart 4 | ============================= 5 | 6 | pg_autoctl do service restart - Run pg_autoctl sub-processes (services) 7 | 8 | Synopsis 9 | -------- 10 | 11 | pg_autoctl do service restart provides the following commands:: 12 | 13 | pg_autoctl do service restart 14 | postgres Restart the pg_autoctl postgres controller service 15 | listener Restart the pg_autoctl monitor listener service 16 | node-active Restart the pg_autoctl keeper node-active service 17 | 18 | 19 | Description 20 | ----------- 21 | 22 | It is possible to restart the ``pg_autoctl`` or the Postgres service without 23 | affecting the other running service. Typically, to restart the 24 | ``pg_autoctl`` parts without impacting Postgres:: 25 | 26 | $ pg_autoctl do service restart node-active --pgdata node1 27 | 14:52:06 31223 INFO Sending the TERM signal to service "node-active" with pid 26626 28 | 14:52:06 31223 INFO Service "node-active" has been restarted with pid 31230 29 | 31230 30 | 31 | The Postgres service has not been impacted by the restart of the 32 | ``pg_autoctl`` process. 33 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_drop.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_drop: 2 | 3 | pg_autoctl drop 4 | =============== 5 | 6 | pg_autoctl drop - Drop a pg_auto_failover node, or formation 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_drop_monitor 12 | pg_autoctl_drop_node 13 | pg_autoctl_drop_formation 14 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_drop_formation.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_drop_formation: 2 | 3 | pg_autoctl drop formation 4 | ========================= 5 | 6 | pg_autoctl drop formation - Drop a formation on the pg_auto_failover monitor 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command drops an existing formation on the monitor:: 12 | 13 | usage: pg_autoctl drop formation [ --pgdata --formation ] 14 | 15 | --pgdata path to data directory 16 | --monitor pg_auto_failover Monitor Postgres URL 17 | --formation name of the formation to drop 18 | 19 | Options 20 | ------- 21 | 22 | --pgdata 23 | 24 | Location of the Postgres node being managed locally. Defaults to the 25 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 26 | from anywhere, rather than the monitor URI used by a local Postgres node 27 | managed with ``pg_autoctl``. 28 | 29 | --monitor 30 | 31 | Postgres URI used to connect to the monitor. Must use the ``autoctl_node`` 32 | username and target the ``pg_auto_failover`` database name. It is possible 33 | to show the Postgres URI from the monitor node using the command 34 | :ref:`pg_autoctl_show_uri`. 35 | 36 | --formation 37 | 38 | Name of the formation to drop from the monitor. 39 | 40 | Environment 41 | ----------- 42 | 43 | PGDATA 44 | 45 | Postgres directory location. Can be used instead of the ``--pgdata`` 46 | option. 47 | 48 | PG_AUTOCTL_MONITOR 49 | 50 | Postgres URI to connect to the monitor node, can be used instead of the 51 | ``--monitor`` option. 52 | 53 | XDG_CONFIG_HOME 54 | 55 | The pg_autoctl command stores its configuration files in the standard 56 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 57 | 58 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 59 | 60 | XDG_DATA_HOME 61 | 62 | The pg_autoctl command stores its internal states files in the standard 63 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 64 | Base Directory Specification`__. 65 | 66 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 67 | 68 | 69 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_drop_monitor.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_drop_monitor: 2 | 3 | pg_autoctl drop monitor 4 | ======================= 5 | 6 | pg_autoctl drop monitor - Drop the pg_auto_failover monitor 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command allows to review all the replication settings of a given 12 | formation (defaults to `'default'` as usual):: 13 | 14 | usage: pg_autoctl drop monitor [ --pgdata --destroy ] 15 | 16 | --pgdata path to data directory 17 | --destroy also destroy Postgres database 18 | 19 | Options 20 | ------- 21 | 22 | --pgdata 23 | 24 | Location of the Postgres node being managed locally. Defaults to the 25 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 26 | from anywhere, rather than the monitor URI used by a local Postgres node 27 | managed with ``pg_autoctl``. 28 | 29 | --destroy 30 | 31 | By default the ``pg_autoctl drop monitor`` commands does not remove the 32 | Postgres database for the monitor. When using ``--destroy``, the Postgres 33 | installation is also deleted. 34 | 35 | Environment 36 | ----------- 37 | 38 | PGDATA 39 | 40 | Postgres directory location. Can be used instead of the ``--pgdata`` 41 | option. 42 | 43 | XDG_CONFIG_HOME 44 | 45 | The pg_autoctl command stores its configuration files in the standard 46 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 47 | 48 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 49 | 50 | XDG_DATA_HOME 51 | 52 | The pg_autoctl command stores its internal states files in the standard 53 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 54 | Base Directory Specification`__. 55 | 56 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_enable.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_enable: 2 | 3 | pg_autoctl enable 4 | ================= 5 | 6 | pg_autoctl enable - Enable a feature on a formation 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_enable_secondary 12 | pg_autoctl_enable_maintenance 13 | pg_autoctl_enable_ssl 14 | pg_autoctl_enable_monitor 15 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_enable_secondary.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_enable_secondary: 2 | 3 | pg_autoctl enable secondary 4 | =========================== 5 | 6 | pg_autoctl enable secondary - Enable secondary nodes on a formation 7 | 8 | Synopsis 9 | -------- 10 | 11 | This feature makes the most sense when using the Enterprise Edition of 12 | pg_auto_failover, which is fully compatible with Citus formations. When 13 | ``secondary`` are enabled, then Citus workers creation policy is to assign a 14 | primary node then a standby node for each group. When ``secondary`` is 15 | disabled the Citus workers creation policy is to assign only the primary 16 | nodes. 17 | 18 | :: 19 | 20 | usage: pg_autoctl enable secondary [ --pgdata --formation ] 21 | 22 | --pgdata path to data directory 23 | --formation Formation to enable secondary on 24 | 25 | 26 | Options 27 | ------- 28 | 29 | --pgdata 30 | 31 | Location of the Postgres node being managed locally. Defaults to the 32 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 33 | from anywhere, rather than the monitor URI used by a local Postgres node 34 | managed with ``pg_autoctl``. 35 | 36 | --formation 37 | 38 | Target formation where to enable secondary feature. 39 | 40 | Environment 41 | ----------- 42 | 43 | PGDATA 44 | 45 | Postgres directory location. Can be used instead of the ``--pgdata`` 46 | option. 47 | 48 | PG_AUTOCTL_MONITOR 49 | 50 | Postgres URI to connect to the monitor node, can be used instead of the 51 | ``--monitor`` option. 52 | 53 | XDG_CONFIG_HOME 54 | 55 | The pg_autoctl command stores its configuration files in the standard 56 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 57 | 58 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 59 | 60 | XDG_DATA_HOME 61 | 62 | The pg_autoctl command stores its internal states files in the standard 63 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 64 | Base Directory Specification`__. 65 | 66 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 67 | 68 | 69 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_get.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_get: 2 | 3 | pg_autoctl get 4 | ============== 5 | 6 | pg_autoctl get - Get a pg_auto_failover node, or formation setting 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_get_formation_settings 12 | pg_autoctl_get_formation_number_sync_standbys 13 | pg_autoctl_get_node_replication_quorum 14 | pg_autoctl_get_node_candidate_priority 15 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_get_formation_number_sync_standbys.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_get_formation_number_sync_standbys: 2 | 3 | pg_autoctl get formation number-sync-standbys 4 | ============================================= 5 | 6 | pg_autoctl get formation number-sync-standbys - get number_sync_standbys for a formation from the monitor 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command prints a ``pg_autoctl`` replication settings for number sync 12 | standbys:: 13 | 14 | usage: pg_autoctl get formation number-sync-standbys [ --pgdata ] [ --json ] [ --formation ] 15 | 16 | --pgdata path to data directory 17 | --json output data in the JSON format 18 | --formation pg_auto_failover formation 19 | 20 | Description 21 | ----------- 22 | 23 | See also :ref:`pg_autoctl_show_settings` for the full list of replication 24 | settings. 25 | 26 | Options 27 | ------- 28 | 29 | --pgdata 30 | 31 | Location of the Postgres node being managed locally. Defaults to the 32 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 33 | from anywhere, rather than the monitor URI used by a local Postgres node 34 | managed with ``pg_autoctl``. 35 | 36 | --json 37 | 38 | Output JSON formatted data. 39 | 40 | --formation 41 | 42 | Show replication settings for given formation. Defaults to ``default``. 43 | 44 | Environment 45 | ----------- 46 | 47 | PGDATA 48 | 49 | Postgres directory location. Can be used instead of the ``--pgdata`` 50 | option. 51 | 52 | PG_AUTOCTL_MONITOR 53 | 54 | Postgres URI to connect to the monitor node, can be used instead of the 55 | ``--monitor`` option. 56 | 57 | XDG_CONFIG_HOME 58 | 59 | The pg_autoctl command stores its configuration files in the standard 60 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 61 | 62 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 63 | 64 | XDG_DATA_HOME 65 | 66 | The pg_autoctl command stores its internal states files in the standard 67 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 68 | Base Directory Specification`__. 69 | 70 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 71 | 72 | 73 | Examples 74 | -------- 75 | 76 | :: 77 | 78 | $ pg_autoctl get formation number-sync-standbys 79 | 1 80 | 81 | $ pg_autoctl get formation number-sync-standbys --json 82 | { 83 | "number-sync-standbys": 1 84 | } 85 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_get_node_candidate_priority.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_get_node_candidate_priority: 2 | 3 | pg_autoctl get node candidate-priority 4 | ====================================== 5 | 6 | pg_autoctl get candidate-priority - get candidate-priority property from the monitor 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command prints ``pg_autoctl`` candidate priority for a given node:: 12 | 13 | usage: pg_autoctl get node candidate-priority [ --pgdata ] [ --json ] [ --formation ] [ --name ] 14 | 15 | --pgdata path to data directory 16 | --formation pg_auto_failover formation 17 | --name pg_auto_failover node name 18 | --json output data in the JSON format 19 | 20 | Description 21 | ----------- 22 | 23 | See also :ref:`pg_autoctl_show_settings` for the full list of replication 24 | settings. 25 | 26 | Options 27 | ------- 28 | 29 | --pgdata 30 | 31 | Location of the Postgres node being managed locally. Defaults to the 32 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 33 | from anywhere, rather than the monitor URI used by a local Postgres node 34 | managed with ``pg_autoctl``. 35 | 36 | --json 37 | 38 | Output JSON formatted data. 39 | 40 | --formation 41 | 42 | Show replication settings for given formation. Defaults to ``default``. 43 | 44 | --name 45 | 46 | Show replication settings for given node, selected by name. 47 | 48 | Examples 49 | -------- 50 | 51 | :: 52 | 53 | $ pg_autoctl get node candidate-priority --name node1 54 | 50 55 | 56 | $ pg_autoctl get node candidate-priority --name node1 --json 57 | { 58 | "name": "node1", 59 | "candidate-priority": 50 60 | } 61 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_get_node_replication_quorum.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_get_node_replication_quorum: 2 | 3 | pg_autoctl get node replication-quorum 4 | ====================================== 5 | 6 | pg_autoctl get replication-quorum - get replication-quorum property from the monitor 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command prints ``pg_autoctl`` replication quorum for a given node:: 12 | 13 | usage: pg_autoctl get node replication-quorum [ --pgdata ] [ --json ] [ --formation ] [ --name ] 14 | 15 | --pgdata path to data directory 16 | --formation pg_auto_failover formation 17 | --name pg_auto_failover node name 18 | --json output data in the JSON format 19 | 20 | Description 21 | ----------- 22 | 23 | See also :ref:`pg_autoctl_show_settings` for the full list of replication 24 | settings. 25 | 26 | Options 27 | ------- 28 | 29 | --pgdata 30 | 31 | Location of the Postgres node being managed locally. Defaults to the 32 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 33 | from anywhere, rather than the monitor URI used by a local Postgres node 34 | managed with ``pg_autoctl``. 35 | 36 | --json 37 | 38 | Output JSON formatted data. 39 | 40 | --formation 41 | 42 | Show replication settings for given formation. Defaults to ``default``. 43 | 44 | --name 45 | 46 | Show replication settings for given node, selected by name. 47 | 48 | Environment 49 | ----------- 50 | 51 | PGDATA 52 | 53 | Postgres directory location. Can be used instead of the ``--pgdata`` 54 | option. 55 | 56 | PG_AUTOCTL_MONITOR 57 | 58 | Postgres URI to connect to the monitor node, can be used instead of the 59 | ``--monitor`` option. 60 | 61 | XDG_CONFIG_HOME 62 | 63 | The pg_autoctl command stores its configuration files in the standard 64 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 65 | 66 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 67 | 68 | XDG_DATA_HOME 69 | 70 | The pg_autoctl command stores its internal states files in the standard 71 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 72 | Base Directory Specification`__. 73 | 74 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 75 | 76 | 77 | Examples 78 | -------- 79 | 80 | :: 81 | 82 | $ pg_autoctl get node replication-quorum --name node1 83 | true 84 | 85 | $ pg_autoctl get node replication-quorum --name node1 --json 86 | { 87 | "name": "node1", 88 | "replication-quorum": true 89 | } 90 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_perform.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_perform: 2 | 3 | pg_autoctl perform 4 | ================== 5 | 6 | pg_autoctl perform - Perform an action orchestrated by the monitor 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_perform_failover 12 | pg_autoctl_perform_switchover 13 | pg_autoctl_perform_promotion 14 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_reload.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_reload: 2 | 3 | pg_autoctl reload 4 | ================= 5 | 6 | pg_autoctl reload - signal the pg_autoctl for it to reload its configuration 7 | 8 | Synopsis 9 | -------- 10 | 11 | This commands signals a running ``pg_autoctl`` process to reload its 12 | configuration from disk, and also signal the managed Postgres service to 13 | reload its configuration. 14 | 15 | :: 16 | 17 | usage: pg_autoctl reload [ --pgdata ] [ --json ] 18 | 19 | --pgdata path to data directory 20 | 21 | Description 22 | ----------- 23 | 24 | The ``pg_autoctl reload`` commands finds the PID of the running service for 25 | the given ``--pgdata``, and if the process is still running, sends a 26 | ``SIGHUP`` signal to the process. 27 | 28 | Options 29 | ------- 30 | 31 | --pgdata 32 | 33 | Location of the Postgres node being managed locally. Defaults to the 34 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 35 | from anywhere, rather than the monitor URI used by a local Postgres node 36 | managed with ``pg_autoctl``. 37 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_set.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_set: 2 | 3 | pg_autoctl set 4 | ============== 5 | 6 | pg_autoctl set - Set a pg_auto_failover node, or formation setting 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_set_formation_number_sync_standbys 12 | pg_autoctl_set_node_replication_quorum 13 | pg_autoctl_set_node_candidate_priority 14 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_set_formation_number_sync_standbys.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_set_formation_number_sync_standbys: 2 | 3 | pg_autoctl set formation number-sync-standbys 4 | ============================================= 5 | 6 | pg_autoctl set formation number-sync-standbys - set number_sync_standbys for a formation from the monitor 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command set a ``pg_autoctl`` replication settings for number sync 12 | standbys:: 13 | 14 | usage: pg_autoctl set formation number-sync-standbys [ --pgdata ] [ --json ] [ --formation ] 15 | 16 | --pgdata path to data directory 17 | --formation pg_auto_failover formation 18 | --json output data in the JSON format 19 | 20 | Description 21 | ----------- 22 | 23 | The pg_auto_failover monitor ensures that at least N+1 candidate standby 24 | nodes are registered when number-sync-standbys is N. This means that to be 25 | able to run the following command, at least 3 standby nodes with a non-zero 26 | candidate priority must be registered to the monitor:: 27 | 28 | $ pg_autoctl set formation number-sync-standbys 2 29 | 30 | See also :ref:`pg_autoctl_show_settings` for the full list of replication 31 | settings. 32 | 33 | Options 34 | ------- 35 | 36 | --pgdata 37 | 38 | Location of the Postgres node being managed locally. Defaults to the 39 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 40 | from anywhere, rather than the monitor URI used by a local Postgres node 41 | managed with ``pg_autoctl``. 42 | 43 | --json 44 | 45 | Output JSON formatted data. 46 | 47 | --formation 48 | 49 | Show replication settings for given formation. Defaults to ``default``. 50 | 51 | Environment 52 | ----------- 53 | 54 | PGDATA 55 | 56 | Postgres directory location. Can be used instead of the ``--pgdata`` 57 | option. 58 | 59 | PG_AUTOCTL_MONITOR 60 | 61 | Postgres URI to connect to the monitor node, can be used instead of the 62 | ``--monitor`` option. 63 | 64 | XDG_CONFIG_HOME 65 | 66 | The pg_autoctl command stores its configuration files in the standard 67 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 68 | 69 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 70 | 71 | XDG_DATA_HOME 72 | 73 | The pg_autoctl command stores its internal states files in the standard 74 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 75 | Base Directory Specification`__. 76 | 77 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 78 | 79 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_show.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_show: 2 | 3 | pg_autoctl show 4 | =============== 5 | 6 | pg_autoctl show - Show pg_auto_failover information 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | pg_autoctl_show_uri 12 | pg_autoctl_show_events 13 | pg_autoctl_show_state 14 | pg_autoctl_show_settings 15 | pg_autoctl_show_standby_names 16 | pg_autoctl_show_file 17 | pg_autoctl_show_systemd 18 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_show_systemd.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_show_systemd: 2 | 3 | pg_autoctl show systemd 4 | ======================= 5 | 6 | pg_autoctl show systemd - Print systemd service file for this node 7 | 8 | Synopsis 9 | -------- 10 | 11 | This command outputs a configuration unit that is suitable for registering 12 | ``pg_autoctl`` as a systemd service. 13 | 14 | Examples 15 | -------- 16 | 17 | :: 18 | 19 | $ pg_autoctl show systemd --pgdata node1 20 | 17:38:29 99778 INFO HINT: to complete a systemd integration, run the following commands: 21 | 17:38:29 99778 INFO pg_autoctl -q show systemd --pgdata "node1" | sudo tee /etc/systemd/system/pgautofailover.service 22 | 17:38:29 99778 INFO sudo systemctl daemon-reload 23 | 17:38:29 99778 INFO sudo systemctl enable pgautofailover 24 | 17:38:29 99778 INFO sudo systemctl start pgautofailover 25 | [Unit] 26 | Description = pg_auto_failover 27 | 28 | [Service] 29 | WorkingDirectory = /Users/dim 30 | Environment = 'PGDATA=node1' 31 | User = dim 32 | ExecStart = /Applications/Postgres.app/Contents/Versions/12/bin/pg_autoctl run 33 | Restart = always 34 | StartLimitBurst = 0 35 | ExecReload = /Applications/Postgres.app/Contents/Versions/12/bin/pg_autoctl reload 36 | 37 | [Install] 38 | WantedBy = multi-user.target 39 | 40 | To avoid the logs output, use the ``-q`` option: 41 | 42 | :: 43 | 44 | $ pg_autoctl show systemd --pgdata node1 -q 45 | [Unit] 46 | Description = pg_auto_failover 47 | 48 | [Service] 49 | WorkingDirectory = /Users/dim 50 | Environment = 'PGDATA=node1' 51 | User = dim 52 | ExecStart = /Applications/Postgres.app/Contents/Versions/12/bin/pg_autoctl run 53 | Restart = always 54 | StartLimitBurst = 0 55 | ExecReload = /Applications/Postgres.app/Contents/Versions/12/bin/pg_autoctl reload 56 | 57 | [Install] 58 | WantedBy = multi-user.target 59 | -------------------------------------------------------------------------------- /docs/ref/pg_autoctl_stop.rst: -------------------------------------------------------------------------------- 1 | .. _pg_autoctl_stop: 2 | 3 | pg_autoctl stop 4 | =============== 5 | 6 | pg_autoctl stop - signal the pg_autoctl service for it to stop 7 | 8 | Synopsis 9 | -------- 10 | 11 | This commands stops the processes needed to run a monitor node or a keeper 12 | node, depending on the configuration file that belongs to the ``--pgdata`` 13 | option or ``PGDATA`` environment variable. 14 | 15 | :: 16 | 17 | usage: pg_autoctl stop [ --pgdata --fast --immediate ] 18 | 19 | --pgdata path to data directory 20 | --fast fast shutdown mode for the keeper 21 | --immediate immediate shutdown mode for the keeper 22 | 23 | Description 24 | ----------- 25 | 26 | The ``pg_autoctl stop`` commands finds the PID of the running service for 27 | the given ``--pgdata``, and if the process is still running, sends a 28 | ``SIGTERM`` signal to the process. 29 | 30 | When ``pg_autoclt`` receives a shutdown signal a shutdown sequence is 31 | triggered. Depending on the signal received, an operation that has been 32 | started (such as a state transition) is either run to completion, stopped as 33 | the next opportunity, or stopped immediately even when in the middle of the 34 | transition. 35 | 36 | Options 37 | ------- 38 | 39 | --pgdata 40 | 41 | Location of the Postgres node being managed locally. Defaults to the 42 | environment variable ``PGDATA``. Use ``--monitor`` to connect to a monitor 43 | from anywhere, rather than the monitor URI used by a local Postgres node 44 | managed with ``pg_autoctl``. 45 | 46 | --fast 47 | 48 | Fast Shutdown mode for ``pg_autoctl``. Sends the ``SIGINT`` signal to the 49 | running service, which is the same as using ``C-c`` on an interactive 50 | process running as a foreground shell job. 51 | 52 | --immediate 53 | 54 | Immediate Shutdown mode for ``pg_autoctl``. Sends the ``SIGQUIT`` signal 55 | to the running service. 56 | 57 | Environment 58 | ----------- 59 | 60 | PGDATA 61 | 62 | Postgres directory location. Can be used instead of the ``--pgdata`` 63 | option. 64 | 65 | PG_AUTOCTL_MONITOR 66 | 67 | Postgres URI to connect to the monitor node, can be used instead of the 68 | ``--monitor`` option. 69 | 70 | XDG_CONFIG_HOME 71 | 72 | The pg_autoctl command stores its configuration files in the standard 73 | place XDG_CONFIG_HOME. See the `XDG Base Directory Specification`__. 74 | 75 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 76 | 77 | XDG_DATA_HOME 78 | 79 | The pg_autoctl command stores its internal states files in the standard 80 | place XDG_DATA_HOME, which defaults to ``~/.local/share``. See the `XDG 81 | Base Directory Specification`__. 82 | 83 | __ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 84 | 85 | 86 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx==8.2.3 2 | sphinx-rtd-theme==3.0.2 3 | docutils==0.21.2 4 | readthedocs-sphinx-search==0.1.0 5 | -------------------------------------------------------------------------------- /docs/tikz/Makefile: -------------------------------------------------------------------------------- 1 | SRC = $(wildcard arch*.tex fsm.tex) 2 | PDF = $(SRC:.tex=.pdf) 3 | SVG = $(SRC:.tex=.svg) 4 | PNG = $(SRC:.tex=.png) 5 | 6 | all: pdf svg png ; 7 | 8 | pdf: $(SRC) $(PDF) ; 9 | svg: $(SRC) $(SVG) ; 10 | png: $(SRC) $(PNG) ; 11 | 12 | clean: 13 | latexmk -C 14 | rm -rf $(PDF) 15 | rm -rf $(SVG) 16 | rm -rf $(PNG) 17 | 18 | %.pdf: %.tex common.tex 19 | latexmk -silent -lualatex --interaction=nonstopmode -shell-escape $< 20 | latexmk -c 21 | 22 | %.png: %.pdf 23 | pdftocairo -singlefile -r 300 -transp -png $< 24 | 25 | %.svg: %.pdf 26 | pdftocairo -svg $< 27 | 28 | .PHONY: clean 29 | -------------------------------------------------------------------------------- /docs/tikz/arch-multi-standby.tex: -------------------------------------------------------------------------------- 1 | % Fix for: https://tex.stackexchange.com/a/315027/43228 2 | \RequirePackage{luatex85} 3 | \documentclass[border=10pt,17pt]{standalone} 4 | 5 | \usepackage{cfr-lm} 6 | \usepackage{pgf} 7 | \usepackage{tikz} 8 | \usetikzlibrary{arrows,shapes,snakes} 9 | \usetikzlibrary{shapes.multipart} 10 | 11 | \begin{document} 12 | 13 | %% sans-serif fonts, large by default, and bold too 14 | \sffamily 15 | \sbweight 16 | \bfseries 17 | \large 18 | 19 | \begin{tikzpicture}[>=stealth',auto,rounded corners] 20 | 21 | \input{common.tex} 22 | 23 | %% \draw [help lines] (-10,0) grid (10,20); 24 | 25 | \node (flegend) at (8,18) {\textt{number\_sync\_standby = 1}} ; 26 | 27 | \node (a) at (0,18) [primary] 28 | {\textbf{\normalsize Node A} 29 | \nodepart{second} 30 | \textbf{\Large Primary} 31 | \nodepart[text=stxt]{third} 32 | \texttt{replication quorum = true} \\ 33 | \texttt{candidate priority = 50} 34 | }; 35 | 36 | \node (b) at (0,12) [standby] 37 | {\textbf{\normalsize Node B} 38 | \nodepart{second} 39 | \textbf{\Large Secondary} 40 | \nodepart{third} 41 | \texttt{replication quorum = true} \\ 42 | \texttt{candidate priority = 50} 43 | }; 44 | 45 | \node (c) at (0,6) [standby] 46 | {\textbf{\normalsize Node C} 47 | \nodepart{second} 48 | \textbf{\Large Secondary} 49 | \nodepart{third} 50 | \texttt{replication quorum = true} \\ 51 | \texttt{candidate priority = 50} 52 | }; 53 | 54 | \node (app) at (-8,12) [app] {\textbf{\Large Application}}; 55 | \node (m) at (8,12) [monitor] {\textbf{\Large Monitor}}; 56 | 57 | \path (app) edge [sql,out=90,in=180] node[near start] {SQL} (a.west) 58 | edge [sqlf] (b) 59 | edge [sqlf,out=-90,in=180] node[near start,above] {SQL (fallback)} (c.west) 60 | 61 | (a.south east) edge [sr,out=0,in=35] node[left,near start] {Streaming Replication} (b.north east) 62 | (a.south east) edge [sr,out=0,in=35] (c.north east) 63 | 64 | (m) edge [hc,out=90,in=0] (a.east) 65 | edge [hc,out=180,in=0] (b.east) 66 | edge [hc,out=-90,in=0] node[below,near end] {Health checks} (c.east); 67 | \end{tikzpicture} 68 | 69 | \end{document} 70 | -------------------------------------------------------------------------------- /docs/tikz/arch-single-standby.tex: -------------------------------------------------------------------------------- 1 | % Fix for: https://tex.stackexchange.com/a/315027/43228 2 | \RequirePackage{luatex85} 3 | \documentclass[border=10pt,17pt]{standalone} 4 | 5 | \usepackage{cfr-lm} 6 | \usepackage{pgf} 7 | \usepackage{tikz} 8 | \usetikzlibrary{arrows,shapes,snakes,automata,backgrounds,petri} 9 | 10 | \begin{document} 11 | 12 | %% sans-serif fonts, large by default, and bold too 13 | \sffamily 14 | \sbweight 15 | \bfseries 16 | \large 17 | 18 | \begin{tikzpicture}[>=stealth',bend angle=45,auto,rounded corners] 19 | 20 | \input{common.tex} 21 | 22 | %% \draw [help lines] (-10,0) grid (10,20); 23 | 24 | \tikzstyle{primary}=[node,text=ptxt,fill=pbox,draw=white] 25 | \tikzstyle{standby}=[node,text=stxt,fill=sbox,draw=white] 26 | 27 | \node (p) at (0,18) [primary] {\textbf{Primary}}; 28 | \node (s) at (0,12) [standby] {\textbf{Secondary}}; 29 | \node (app) at (-6,15) [app] {\textbf{Application}}; 30 | \node (m) at (6,15) [monitor] {\textbf{Monitor}}; 31 | 32 | \path (app.north east) edge [sql,out=90,in=180] node {SQL} (p) 33 | (app.south east) edge [sqlf,out=-90,in=180] node[below] {SQL (fallback)} (s) 34 | (p) edge [sr] 35 | node[left] {Streaming} 36 | node [right] {Replication} (s) 37 | (m) edge [hc,out=90,in=0] node[above] {Health checks} (p) 38 | edge [hc,out=-90,in=0] node {Health checks} (s); 39 | \end{tikzpicture} 40 | 41 | \end{document} 42 | -------------------------------------------------------------------------------- /docs/tikz/arch-three-standby-one-async.tex: -------------------------------------------------------------------------------- 1 | % Fix for: https://tex.stackexchange.com/a/315027/43228 2 | \RequirePackage{luatex85} 3 | \documentclass[border=10pt,17pt]{standalone} 4 | 5 | \usepackage{cfr-lm} 6 | \usepackage{pgf} 7 | \usepackage{tikz} 8 | \usetikzlibrary{arrows,shapes,snakes} 9 | \usetikzlibrary{shapes.multipart} 10 | 11 | \begin{document} 12 | 13 | %% sans-serif fonts, large by default, and bold too 14 | \sffamily 15 | \sbweight 16 | \bfseries 17 | \large 18 | 19 | \begin{tikzpicture}[>=stealth',auto,rounded corners] 20 | 21 | \input{common.tex} 22 | 23 | %% \draw [help lines] (-10,0) grid (10,20); 24 | 25 | \node (flegend) at (8,18) {\textbf{\textt{number\_sync\_standby = 2}}} ; 26 | 27 | \node (a) at (0,18) [primary] 28 | {\textbf{\normalsize Node A} 29 | \nodepart{second} 30 | \textbf{\Large Primary} 31 | \nodepart[text=stxt]{third} 32 | \texttt{replication quorum = true} \\ 33 | \texttt{candidate priority = 50} 34 | }; 35 | 36 | \node (b) at (0,12) [standby] 37 | {\textbf{\normalsize Node B} 38 | \nodepart{second} 39 | \textbf{\Large Secondary} 40 | \nodepart[align=left]{third} 41 | \texttt{replication quorum = true} \\ 42 | \texttt{candidate priority = 50} 43 | }; 44 | 45 | \node (c) at (0,6) [standby] 46 | {\textbf{\normalsize Node C} 47 | \nodepart{second} 48 | \textbf{\Large Secondary} 49 | \nodepart[align=left]{third} 50 | \texttt{replication quorum = true} \\ 51 | \texttt{candidate priority = 50} 52 | }; 53 | 54 | \draw (-9,3) -- (9,3); 55 | 56 | \node (d) at (0,0) [standby,rectangle split part fill={sbox,sbox,async}] 57 | {\textbf{\normalsize Node D} 58 | \nodepart{second} 59 | \textbf{\Large Secondary} 60 | \nodepart[align=left]{third} 61 | \texttt{replication quorum = false} \\ 62 | \texttt{candidate priority = 0} 63 | }; 64 | 65 | \node (app) at (-8,9) [app] {\Large Application}; 66 | \node (m) at (8,9) [monitor] {\Large Monitor}; 67 | 68 | \path (app) edge [sql,out=90,in=180] node[near start] {SQL} (a.west) 69 | edge [sqlf,out=90,in=180] (b) 70 | edge [sqlf,out=-90,in=180] node[near start,above] {SQL (fallback)} (c.west) 71 | edge [sqlf,out=-90,in=180] (d) 72 | 73 | (a.south east) edge [sr,out=0,in=35,bend left=30] node[left,near start] {Streaming Replication} (b.north east) 74 | (a.south east) edge [sr,out=0,in=35,bend left=30] (c.north east) 75 | (a.south east) edge [sr,out=0,in=35,bend left=30] (d.north east) 76 | 77 | (m) edge [hc,out=90,in=0] (a.east) 78 | edge [hc,out=90,in=0] (b.east) 79 | edge [hc,out=-90,in=0] node[below,near end] {Health checks} (c.east) 80 | edge [hc,out=-90,in=0] (d.east); 81 | 82 | \end{tikzpicture} 83 | 84 | \end{document} 85 | -------------------------------------------------------------------------------- /docs/tikz/arch-three-standby.tex: -------------------------------------------------------------------------------- 1 | % Fix for: https://tex.stackexchange.com/a/315027/43228 2 | \RequirePackage{luatex85} 3 | \documentclass[border=10pt,17pt]{standalone} 4 | 5 | \usepackage{cfr-lm} 6 | \usepackage{pgf} 7 | \usepackage{tikz} 8 | \usetikzlibrary{arrows,shapes,snakes} 9 | \usetikzlibrary{shapes.multipart} 10 | 11 | \begin{document} 12 | 13 | %% sans-serif fonts, large by default, and bold too 14 | \sffamily 15 | \sbweight 16 | \bfseries 17 | \large 18 | 19 | \begin{tikzpicture}[>=stealth',auto,rounded corners] 20 | 21 | \input{common.tex} 22 | 23 | %% \draw [help lines] (-10,0) grid (10,20); 24 | 25 | \node (flegend) at (8,18) {\textbf{\textt{number\_sync\_standby = 2}}} ; 26 | 27 | \node (a) at (0,18) [primary] 28 | {\textbf{\normalsize Node A} 29 | \nodepart{second} 30 | \textbf{\Large Primary} 31 | \nodepart[text=stxt]{third} 32 | \texttt{replication quorum = true} \\ 33 | \texttt{candidate priority = 50} 34 | }; 35 | 36 | \node (b) at (0,12) [standby] 37 | {\textbf{\normalsize Node B} 38 | \nodepart{second} 39 | \textbf{\Large Secondary} 40 | \nodepart[align=left]{third} 41 | \texttt{replication quorum = true} \\ 42 | \texttt{candidate priority = 50} 43 | }; 44 | 45 | \node (c) at (0,6) [standby] 46 | {\textbf{\normalsize Node C} 47 | \nodepart{second} 48 | \textbf{\Large Secondary} 49 | \nodepart[align=left]{third} 50 | \texttt{replication quorum = true} \\ 51 | \texttt{candidate priority = 50} 52 | }; 53 | 54 | \node (d) at (0,0) [standby] 55 | {\textbf{\normalsize Node D} 56 | \nodepart{second} 57 | \textbf{\Large Secondary} 58 | \nodepart[align=left]{third} 59 | \texttt{replication quorum = true} \\ 60 | \texttt{candidate priority = 50} 61 | }; 62 | 63 | \node (app) at (-8,9) [app] {\Large Application}; 64 | \node (m) at (8,9) [monitor] {\Large Monitor}; 65 | 66 | \path (app) edge [sql,out=90,in=180] node[near start] {SQL} (a.west) 67 | edge [sqlf,out=90,in=180] (b) 68 | edge [sqlf,out=-90,in=180] node[near start,above] {SQL (fallback)} (c.west) 69 | edge [sqlf,out=-90,in=180] (d) 70 | 71 | (a.south east) edge [sr,out=0,in=35,bend left=30] node[left,near start] {Streaming Replication} (b.north east) 72 | (a.south east) edge [sr,out=0,in=35,bend left=30] (c.north east) 73 | (a.south east) edge [sr,out=0,in=35,bend left=30] (d.north east) 74 | 75 | (m) edge [hc,out=90,in=0] (a.east) 76 | edge [hc,out=90,in=0] (b.east) 77 | edge [hc,out=-90,in=0] node[below,near end] {Health checks} (c.east) 78 | edge [hc,out=-90,in=0] (d.east); 79 | 80 | \end{tikzpicture} 81 | 82 | \end{document} 83 | -------------------------------------------------------------------------------- /docs/tikz/common.tex: -------------------------------------------------------------------------------- 1 | \definecolor{pbox}{HTML}{0078D4} % MS blue 2 | \definecolor{ptxt}{HTML}{FFFFFF} % white 3 | 4 | \definecolor{sbox}{HTML}{50E6FF} % MS cyan 5 | \definecolor{stxt}{HTML}{2F2F2F} % off-black 6 | 7 | \definecolor{mbox}{HTML}{9BF00B} % MS light green 8 | \definecolor{mtxt}{HTML}{2F2F2F} % off-black 9 | 10 | \definecolor{apbox}{HTML}{0078D4} % MS blue 11 | \definecolor{aptxt}{HTML}{2F2F2F} % off-black 12 | 13 | \definecolor{async}{HTML}{EBEFF5} % very light grey 14 | 15 | \tikzstyle{app}=[circle,thick, 16 | text=aptxt,draw=apbox,fill=white, 17 | line width=0.25em,minimum size=4cm] 18 | 19 | \tikzstyle{node}=[rectangle,minimum height=2.5cm,minimum width=4cm] 20 | 21 | \tikzstyle{mpnode}=[rectangle split,rectangle split parts=3, 22 | align=center, 23 | rectangle split part align={center, center, left}, 24 | minimum height=2.5cm,minimum width=4cm,inner sep=0.5cm] 25 | 26 | \tikzstyle{primary}=[mpnode,text=ptxt,draw=white, 27 | rectangle split part fill={pbox,pbox,white}] 28 | 29 | \tikzstyle{standby}=[mpnode,text=stxt,draw=white, 30 | rectangle split part fill={sbox,sbox,white}] 31 | 32 | \tikzstyle{monitor}=[node,text=mtxt,draw=mbox,fill=mbox] 33 | 34 | \tikzstyle{citusnode}=[rectangle split,rectangle split parts=2, 35 | align=center, 36 | rectangle split part align={center, center}, 37 | minimum height=2.5cm,minimum width=4cm,inner sep=0.5cm] 38 | 39 | \tikzstyle{cprimary}=[citusnode,text=ptxt,draw=white, 40 | rectangle split part fill={pbox,pbox,white}] 41 | 42 | \tikzstyle{cstandby}=[citusnode,text=stxt,draw=white, 43 | rectangle split part fill={sbox,sbox,white}] 44 | 45 | \tikzstyle{sql}=[->,color=pbox,text=stxt,line width=0.15em] 46 | \tikzstyle{sqlf}=[->,color=sbox,text=stxt,line width=0.15em,loosely dashed] 47 | \tikzstyle{sr}=[>->,color=stxt,text=stxt,line width=0.15em] 48 | \tikzstyle{hc}=[<->,color=mbox,text=mtxt,line width=0.15em,dotted] 49 | \tikzstyle{hcmid}=[color=mbox,text=mtxt,line width=0.15em,dotted] 50 | \tikzstyle{cw}=[<->,color=stxt,text=stxt,line width=0.1em] 51 | -------------------------------------------------------------------------------- /docs/tutorial/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | ARG PGVERSION=14 4 | ARG CITUS=postgresql-14-citus-11.1 5 | 6 | RUN apt-get update \ 7 | && apt-get install -y --no-install-recommends \ 8 | ca-certificates \ 9 | gnupg \ 10 | make \ 11 | curl \ 12 | sudo \ 13 | tmux \ 14 | watch \ 15 | lsof \ 16 | psutils \ 17 | postgresql-common \ 18 | libpq-dev \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | # we use apt.postgresql.org 22 | RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - 23 | RUN echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.list 24 | RUN echo "deb-src http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.src.list 25 | 26 | # bypass initdb of a "main" cluster 27 | RUN echo 'create_main_cluster = false' | sudo tee -a /etc/postgresql-common/createcluster.conf 28 | RUN apt-get update \ 29 | && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 30 | postgresql-${PGVERSION} \ 31 | postgresql-server-dev-${PGVERSION} \ 32 | && rm -rf /var/lib/apt/lists/* 33 | 34 | RUN adduser --disabled-password --gecos '' docker 35 | RUN adduser docker sudo 36 | RUN adduser docker postgres 37 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 38 | 39 | # build pg_auto_failover from local sources 40 | RUN apt-get update \ 41 | && apt-get build-dep -y --no-install-recommends postgresql-${PGVERSION} \ 42 | && rm -rf /var/lib/apt/lists/* 43 | WORKDIR /usr/src/pg_auto_failover 44 | 45 | COPY Makefile ./ 46 | COPY Makefile.azure ./ 47 | COPY Makefile.citus ./ 48 | COPY src/ ./src 49 | RUN make -s clean && make -s install -j8 50 | RUN cp /usr/lib/postgresql/${PGVERSION}/bin/pg_autoctl /usr/local/bin 51 | 52 | RUN install -o docker -m 0755 -d /var/lib/postgres 53 | VOLUME /var/lib/postgres 54 | 55 | USER docker 56 | ENV PG_AUTOCTL_DEBUG 1 57 | -------------------------------------------------------------------------------- /docs/tutorial/Dockerfile.app: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | ARG PGVERSION=14 4 | 5 | RUN apt-get update \ 6 | && apt-get install -y --no-install-recommends \ 7 | ca-certificates \ 8 | gnupg \ 9 | make \ 10 | curl \ 11 | sudo \ 12 | tmux \ 13 | watch \ 14 | lsof \ 15 | psutils \ 16 | python3 \ 17 | && rm -rf /var/lib/apt/lists/* 18 | 19 | # we use apt.postgresql.org 20 | RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - 21 | RUN echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.list 22 | RUN echo "deb-src http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main ${PGVERSION}" > /etc/apt/sources.list.d/pgdg.src.list 23 | 24 | RUN apt-get update \ 25 | && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 26 | postgresql-client-${PGVERSION} \ 27 | && rm -rf /var/lib/apt/lists/* 28 | 29 | RUN adduser --disabled-password --gecos '' docker 30 | RUN adduser docker sudo 31 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 32 | 33 | COPY ./app.py /usr/src/app/app.py 34 | 35 | USER docker 36 | ENTRYPOINT [ "/usr/src/app/app.py" ] 37 | -------------------------------------------------------------------------------- /docs/tutorial/Makefile: -------------------------------------------------------------------------------- 1 | CONTAINER_NAME = pg_auto_failover:tutorial 2 | 3 | all: build down up; 4 | 5 | build: 6 | docker compose build 7 | 8 | up: 9 | docker compose up app monitor node1 node2 10 | 11 | node3: 12 | docker compose up -d node3 13 | 14 | down: 15 | docker compose down 16 | 17 | state: 18 | docker compose exec monitor pg_autoctl show state 19 | 20 | switchover: 21 | docker compose exec monitor pg_autoctl perform switchover 22 | 23 | watch: 24 | docker compose exec monitor pg_autoctl watch 25 | -------------------------------------------------------------------------------- /docs/tutorial/app.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | # 4 | # Write a Python application that knows how to exit gracefully when 5 | # receiving SIGTERM (at docker compose down time), but doesn't know how to 6 | # do much else. 7 | # 8 | 9 | import sys 10 | import time 11 | import signal 12 | from datetime import datetime 13 | 14 | 15 | def sigterm_handler(_signo, _stack_frame): 16 | sys.exit(0) 17 | 18 | 19 | signal.signal(signal.SIGTERM, sigterm_handler) 20 | 21 | if __name__ == "__main__": 22 | try: 23 | while True: 24 | print("%s" % datetime.now()) 25 | time.sleep(600) 26 | except BaseException: 27 | # Keyboard Interrupt or something 28 | pass 29 | -------------------------------------------------------------------------------- /docs/tutorial/docker-compose.yml: -------------------------------------------------------------------------------- 1 | x-node: &node 2 | build: 3 | context: ../.. 4 | dockerfile: Dockerfile 5 | tags: 6 | - pg_auto_failover:tutorial 7 | volumes: 8 | - /var/lib/postgres 9 | environment: 10 | PGDATA: /var/lib/postgres/pgaf 11 | PGUSER: tutorial 12 | PGDATABASE: tutorial 13 | PG_AUTOCTL_HBA_LAN: true 14 | PG_AUTOCTL_AUTH_METHOD: "trust" 15 | PG_AUTOCTL_SSL_SELF_SIGNED: true 16 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 17 | expose: 18 | - 5432 19 | 20 | services: 21 | 22 | app: 23 | build: 24 | context: . 25 | dockerfile: Dockerfile.app 26 | environment: 27 | PGUSER: tutorial 28 | PGDATABASE: tutorial 29 | PGHOST: node1,node2 30 | PGPORT: 5432 31 | PGAPPNAME: tutorial 32 | PGSSLMODE: require 33 | PGTARGETSESSIONATTRS: read-write 34 | 35 | monitor: 36 | image: pg_auto_failover:tutorial 37 | volumes: 38 | - /var/lib/postgres 39 | environment: 40 | PGDATA: /var/lib/postgres/pgaf 41 | PG_AUTOCTL_SSL_SELF_SIGNED: true 42 | expose: 43 | - 5432 44 | command: | 45 | pg_autoctl create monitor --auth trust --run 46 | 47 | node1: 48 | <<: *node 49 | hostname: node1 50 | command: | 51 | pg_autoctl create postgres --name node1 --run 52 | 53 | node2: 54 | <<: *node 55 | hostname: node2 56 | command: | 57 | pg_autoctl create postgres --name node2 --run 58 | 59 | node3: 60 | <<: *node 61 | hostname: node3 62 | command: | 63 | pg_autoctl create postgres --name node3 --run 64 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 80 3 | target-version = ['py36'] 4 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the PostgreSQL License. 3 | 4 | all: monitor bin ; 5 | clean: clean-monitor clean-bin ; 6 | install: install-monitor install-bin ; 7 | 8 | monitor: 9 | $(MAKE) -C monitor all 10 | 11 | install-monitor: 12 | $(MAKE) -C monitor install 13 | 14 | clean-monitor: 15 | $(MAKE) -C monitor clean 16 | 17 | bin: 18 | $(MAKE) -C bin all 19 | 20 | install-bin: 21 | $(MAKE) -C bin install 22 | 23 | clean-bin: 24 | $(MAKE) -C bin clean 25 | 26 | 27 | .PHONY: all clean bin test monitor 28 | .PHONY: clean-monitor clean-bin install-monitor install-bin 29 | -------------------------------------------------------------------------------- /src/bin/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the PostgreSQL License. 3 | 4 | all: pg_autoctl ; 5 | 6 | pg_autoctl: 7 | $(MAKE) -C pg_autoctl pg_autoctl 8 | 9 | clean: 10 | $(MAKE) -C pg_autoctl clean 11 | 12 | install: $(pg_autoctl) 13 | $(MAKE) -C pg_autoctl install 14 | 15 | .PHONY: all pg_autoctl install clean 16 | -------------------------------------------------------------------------------- /src/bin/lib/README.md: -------------------------------------------------------------------------------- 1 | # Vendored-in libraries 2 | 3 | ## log.c 4 | 5 | A very simple lib for handling logs in C is available at 6 | 7 | https://github.com/rxi/log.c 8 | 9 | It says that 10 | 11 | log.c and log.h should be dropped into an existing project and compiled 12 | along with it. 13 | 14 | So this directory contains a _vendored-in_ copy of the log.c repository. 15 | 16 | ## SubCommands.c 17 | 18 | The single-header library is used to implement parsing "modern" command lines. 19 | 20 | ## Configuration file parsing 21 | 22 | We utilize the "ini.h" ini-file reader from https://github.com/mattiasgustavsson/libs 23 | 24 | ## JSON 25 | 26 | The parson library at https://github.com/kgabis/parson is a single C file 27 | and MIT licenced. It allows parsing from and serializing to JSON. 28 | 29 | ## pg 30 | 31 | We vendor-in some code from the Postgres project at 32 | https://git.postgresql.org/gitweb/?p=postgresql.git;a=summary. This code is 33 | licenced under The PostgreSQL Licence, a derivative of the BSD licence. 34 | -------------------------------------------------------------------------------- /src/bin/lib/log/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 rxi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/bin/lib/log/README.md: -------------------------------------------------------------------------------- 1 | # log.c 2 | A simple logging library implemented in C99 3 | 4 | ![screenshot](https://cloud.githubusercontent.com/assets/3920290/23831970/a2415e96-0723-11e7-9886-f8f5d2de60fe.png) 5 | 6 | 7 | ## Usage 8 | **[log.c](src/log.c?raw=1)** and **[log.h](src/log.h?raw=1)** should be dropped 9 | into an existing project and compiled along with it. The library provides 6 10 | function-like macros for logging: 11 | 12 | ```c 13 | log_trace(const char *fmt, ...); 14 | log_debug(const char *fmt, ...); 15 | log_info(const char *fmt, ...); 16 | log_warn(const char *fmt, ...); 17 | log_error(const char *fmt, ...); 18 | log_fatal(const char *fmt, ...); 19 | ``` 20 | 21 | Each function takes a printf format string followed by additional arguments: 22 | 23 | ```c 24 | log_trace("Hello %s", "world") 25 | ``` 26 | 27 | Resulting in a line with the given format printed to stderr: 28 | 29 | ``` 30 | 20:18:26 TRACE src/main.c:11: Hello world 31 | ``` 32 | 33 | 34 | #### log_set_quiet(int enable) 35 | Quiet-mode can be enabled by passing `1` to the `log_set_quiet()` function. 36 | While this mode is enabled the library will not output anything to stderr, but 37 | will continue to write to the file if one is set. 38 | 39 | 40 | #### log_set_level(int level) 41 | The current logging level can be set by using the `log_set_level()` function. 42 | All logs below the given level will be ignored. By default the level is 43 | `LOG_TRACE`, such that nothing is ignored. 44 | 45 | 46 | #### log_set_fp(FILE *fp) 47 | A file pointer where the log should be written can be provided to the library by 48 | using the `log_set_fp()` function. The data written to the file output is 49 | of the following format: 50 | 51 | ``` 52 | 2047-03-11 20:18:26 TRACE src/main.c:11: Hello world 53 | ``` 54 | 55 | 56 | #### log_set_lock(log_LockFn fn) 57 | If the log will be written to from multiple threads a lock function can be set. 58 | The function is passed a `udata` value (set by `log_set_udata()`) and the 59 | integer `1` if the lock should be acquired or `0` if the lock should be 60 | released. 61 | 62 | 63 | #### log_use_colors(int enable) 64 | Colors in the log output can be enabled by passing `1` to the `log_use_colors()` 65 | function. 66 | 67 | 68 | ## License 69 | This library is free software; you can redistribute it and/or modify it under 70 | the terms of the MIT license. See [LICENSE](LICENSE) for details. 71 | -------------------------------------------------------------------------------- /src/bin/lib/log/src/log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See `log.c` for details. 6 | */ 7 | 8 | #ifndef LOG_H 9 | #define LOG_H 10 | 11 | #include 12 | #include 13 | 14 | #define LOG_VERSION "0.1.0" 15 | 16 | typedef void (*log_LockFn)(void *udata, int lock); 17 | 18 | enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; 19 | 20 | #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) 21 | #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 22 | #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 23 | #define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) 24 | #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) 25 | #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) 26 | 27 | #define log_level(level, ...) log_log(level, __FILE__, __LINE__, __VA_ARGS__) 28 | 29 | void log_set_udata(void *udata); 30 | void log_set_lock(log_LockFn fn); 31 | void log_set_fp(FILE *fp); 32 | void log_set_level(int level); 33 | int log_get_level(void); 34 | void log_set_quiet(int enable); 35 | void log_use_colors(int enable); 36 | 37 | void log_log(int level, const char *file, int line, const char *fmt, ...) 38 | __attribute__((format(printf, 4, 5))); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/bin/lib/parson/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | test 3 | *.o 4 | testcpp 5 | tests/test_2_serialized.txt 6 | tests/test_2_serialized_pretty.txt 7 | test_hash_collisions 8 | build/** 9 | -------------------------------------------------------------------------------- /src/bin/lib/parson/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(parson C) 3 | 4 | include (GNUInstallDirs) 5 | 6 | set(PARSON_VERSION 1.5.3) 7 | add_library(parson parson.c) 8 | target_include_directories(parson PUBLIC $) 9 | 10 | set_target_properties(parson PROPERTIES PUBLIC_HEADER "parson.h") 11 | set_target_properties(parson PROPERTIES VERSION ${PARSON_VERSION}) 12 | set_target_properties(parson PROPERTIES SOVERSION ${PARSON_VERSION}) 13 | 14 | install( 15 | TARGETS parson 16 | EXPORT parsonTargets 17 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT shlib 18 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 19 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 20 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 21 | ) 22 | 23 | install( 24 | EXPORT parsonTargets 25 | FILE parsonConfig.cmake 26 | NAMESPACE parson:: 27 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} 28 | ) 29 | 30 | -------------------------------------------------------------------------------- /src/bin/lib/parson/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012 - 2022 Krzysztof Gabis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/bin/lib/parson/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O0 -g -Wall -Wextra -std=c89 -pedantic-errors -DTESTS_MAIN 3 | 4 | CPPC = g++ 5 | CPPFLAGS = -O0 -g -Wall -Wextra -DTESTS_MAIN 6 | 7 | all: test testcpp test_hash_collisions 8 | 9 | .PHONY: test testcpp test_hash_collisions 10 | test: tests.c parson.c 11 | $(CC) $(CFLAGS) -o $@ tests.c parson.c 12 | ./$@ 13 | 14 | testcpp: tests.c parson.c 15 | $(CPPC) $(CPPFLAGS) -o $@ tests.c parson.c 16 | ./$@ 17 | 18 | test_hash_collisions: tests.c parson.c 19 | $(CC) $(CFLAGS) -DPARSON_FORCE_HASH_COLLISIONS -o $@ tests.c parson.c 20 | ./$@ 21 | 22 | clean: 23 | rm -f test *.o 24 | 25 | -------------------------------------------------------------------------------- /src/bin/lib/parson/meson.build: -------------------------------------------------------------------------------- 1 | project('parson', 'c', 2 | version : '1.5.3', 3 | license : 'MIT', 4 | meson_version : '>=0.46.0', 5 | default_options : [ 6 | 'c_std=c89', 'optimization=2', 7 | 'warning_level=2' 8 | ] 9 | ) 10 | 11 | parson_sources = ['parson.c'] 12 | 13 | parson_inc = include_directories('.') 14 | 15 | parson_lib = library( 16 | meson.project_name(), 17 | sources: parson_sources, 18 | install: true 19 | ) 20 | 21 | install_headers('parson.h') 22 | 23 | parson = declare_dependency( 24 | include_directories : parson_inc, 25 | link_with : parson_lib 26 | ) 27 | 28 | pkgconfig = import('pkgconfig') 29 | 30 | # will create a pkg config 31 | pkgconfig.generate(parson_lib, 32 | version: meson.project_version(), 33 | filebase: meson.project_name(), 34 | name: meson.project_name(), 35 | description: 'Lightweight JSON library written in C.', 36 | ) 37 | -------------------------------------------------------------------------------- /src/bin/lib/parson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parson", 3 | "version": "1.5.3", 4 | "repo": "kgabis/parson", 5 | "description": "Small json parser and reader", 6 | "keywords": [ "json", "parser" ], 7 | "license": "MIT", 8 | "src": [ 9 | "parson.c", 10 | "parson.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/bin/lib/parson/tests/test_1_1.txt: -------------------------------------------------------------------------------- 1 | 2 | [ 3 | "JSON Test Pattern pass1", 4 | {"object with 1 member":["array with 1 element"]}, 5 | {}, 6 | [], 7 | -42, 8 | true, 9 | false, 10 | null, 11 | { 12 | "integer": 1234567890, 13 | "real": -9876.543210, 14 | "e": 0.123456789e-12, 15 | "E": 1.234567890E+34, 16 | "": 23456789012E66, 17 | "zero": 0, 18 | "one": 1, 19 | "space": " ", 20 | "quote": "\"", 21 | "backslash": "\\", 22 | "controls": "\b\f\n\r\t", 23 | "slash": "/ & \/", 24 | "alpha": "abcdefghijklmnopqrstuvwyz", 25 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 26 | "digit": "0123456789", 27 | "0123456789": "digit", 28 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 29 | "nullchar": "abc\u0000def", 30 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 31 | "true": true, 32 | "false": false, 33 | "null": null, 34 | "array":[ ], 35 | "object":{ }, 36 | "address": "50 St. James Street", 37 | "url": "http://www.JSON.org/", 38 | "comment": "// /* */": " ", 40 | " s p a c e d " :[1,2 , 3 41 | 42 | , 43 | 44 | 4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], 45 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 46 | "quotes": "" \u0022 %22 0x22 034 "", 47 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 48 | : "A key can be any string" 49 | }, 50 | 0.5 ,98.6 51 | , 52 | 99.44 53 | , 54 | 55 | 1066, 56 | 1e1, 57 | 0.1e1, 58 | 1e-1, 59 | 1e00,2e+00,2e-00 60 | ,"rosebud"] -------------------------------------------------------------------------------- /src/bin/lib/parson/tests/test_1_3.txt: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/bin/lib/parson/tests/test_2.txt: -------------------------------------------------------------------------------- 1 | { 2 | "string" : "lorem ipsum", 3 | "utf string" : "\u006corem\u0020ipsum", 4 | "utf-8 string": "あいうえお", 5 | "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", 6 | "string with null": "abc\u0000def", 7 | "positive one" : 1, 8 | "negative one" : -1, 9 | "pi" : 3.14, 10 | "hard to parse number" : -3.14e-4, 11 | "big int": 2147483647, 12 | "big uint": 4294967295, 13 | "double underflow": 6.9041432094973937e-310, 14 | "boolean true" : true, 15 | "boolean false" : false, 16 | "null" : null, 17 | "string array" : ["lorem", "ipsum"], 18 | "x^2 array" : [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100], 19 | "/*" : null, 20 | "object" : { "nested string" : "str", 21 | "nested true" : true, 22 | "nested false" : false, 23 | "nested null" : null, 24 | "nested number" : 123, 25 | "nested array" : ["lorem", "ipsum"], 26 | "nested object" : {"lorem": "ipsum"} 27 | }, 28 | "*/" : null, 29 | "/**/" : "comment", 30 | "//" : "comment", 31 | "url" : "https:\/\/www.example.com\/search?q=12345", 32 | "escaped chars" : "\" \\ \/", 33 | "empty object" : {}, 34 | "empty array" : [], 35 | } 36 | -------------------------------------------------------------------------------- /src/bin/lib/parson/tests/test_2_comments.txt: -------------------------------------------------------------------------------- 1 | /* 2 | *Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 3 | *ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud 4 | *dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 5 | */ 6 | // Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 7 | { /* lorem ipsum */ 8 | "string" : "lorem ipsum", // lorem ipsum 9 | "utf string" : "\u006corem\u0020ipsum", // lorem ipsum // 10 | "utf-8 string": "あいうえお", // /* lorem ipsum */ 11 | "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", 12 | "string with null": "abc\u0000def", 13 | "positive one" : 1, 14 | "negative one" : -1, 15 | "pi" : 3.14, 16 | "hard to parse number" : -3.14e-4, 17 | "big int": 2147483647, 18 | "big uint": 4294967295, 19 | "double underflow": 6.9041432094973937e-310, 20 | "boolean true" : true, 21 | "boolean false" : false, 22 | "null" : null, 23 | "string array" : ["lorem",/*in array*/"ipsum"], 24 | "x^2 array" : [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100], 25 | /* "x^2 array" : [], 26 | */ 27 | "/*" : null, 28 | "object" : { "nested string" : "str", 29 | "nested true" : /* lorem ipsum */ true, 30 | "nested false" : false, 31 | "nested null" : null, // lorem ipsum 32 | "nested number" : 123, 33 | "nested array" : ["lorem", "ipsum"], 34 | "nested object" : {"lorem": "ipsum"} 35 | }, 36 | "*/" : null, 37 | "/**/" : "comment", 38 | "//" : "comment", 39 | "url" : "https:\/\/www.example.com\/search?q=12345", 40 | "escaped chars" : "\" \\ \/", 41 | "empty object" : {}, 42 | "empty array" : [] 43 | } 44 | /**/ 45 | // -------------------------------------------------------------------------------- /src/bin/lib/parson/tests/test_2_pretty.txt: -------------------------------------------------------------------------------- 1 | { 2 | "string": "lorem ipsum", 3 | "utf string": "lorem ipsum", 4 | "utf-8 string": "あいうえお", 5 | "surrogate string": "lorem𝄞ipsum𝍧lorem", 6 | "string with null": "abc\u0000def", 7 | "positive one": 1, 8 | "negative one": -1, 9 | "pi": 3.1400000000000001, 10 | "hard to parse number": -0.00031399999999999999, 11 | "big int": 2147483647, 12 | "big uint": 4294967295, 13 | "double underflow": 6.9041432094973937e-310, 14 | "boolean true": true, 15 | "boolean false": false, 16 | "null": null, 17 | "string array": [ 18 | "lorem", 19 | "ipsum" 20 | ], 21 | "x^2 array": [ 22 | 0, 23 | 1, 24 | 4, 25 | 9, 26 | 16, 27 | 25, 28 | 36, 29 | 49, 30 | 64, 31 | 81, 32 | 100 33 | ], 34 | "\/*": null, 35 | "object": { 36 | "nested string": "str", 37 | "nested true": true, 38 | "nested false": false, 39 | "nested null": null, 40 | "nested number": 123, 41 | "nested array": [ 42 | "lorem", 43 | "ipsum" 44 | ] 45 | }, 46 | "*\/": null, 47 | "\/**\/": "comment", 48 | "\/\/": "comment", 49 | "url": "https:\/\/www.example.com\/search?q=12345", 50 | "escaped chars": "\" \\ \/", 51 | "empty object": {}, 52 | "empty array": [] 53 | } -------------------------------------------------------------------------------- /src/bin/lib/parson/tests/test_5.txt: -------------------------------------------------------------------------------- 1 | { 2 | "first": "John", 3 | "last": "Doe", 4 | "age": 25, 5 | "registered": true, 6 | "interests": [ "Reading", "Mountain Biking" ], 7 | "favorites": { 8 | "color": "blue", 9 | "sport": "running" 10 | }, 11 | "utf string" : "\u006corem\u0020ipsum", 12 | "utf-8 string": "あいうえお", 13 | "surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem", 14 | "string with null": "abc\u0000def", 15 | "windows path": "C:\\Windows\\Path" 16 | } -------------------------------------------------------------------------------- /src/bin/lib/pg/README.md: -------------------------------------------------------------------------------- 1 | # Postgres code 2 | 3 | This directory contains PostgreSQL code that we have vendored-in. 4 | 5 | -------------------------------------------------------------------------------- /src/bin/lib/pg/snprintf.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * port.h 4 | * Header for src/port/ compatibility functions. 5 | * 6 | * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group 7 | * Portions Copyright (c) 1994, Regents of the University of California 8 | * 9 | * src/include/port.h 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | #ifndef PG_SNPRINTF_H 14 | #define PG_SNPRINTF_H 15 | 16 | #include "postgres_fe.h" 17 | 18 | #ifndef USE_REPL_SNPRINTF 19 | 20 | int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) 21 | __attribute__((format(printf, 3, 0))); 22 | int pg_snprintf(char *str, size_t count, const char *fmt,...) 23 | __attribute__((format(printf, 3, 4))); 24 | int pg_vsprintf(char *str, const char *fmt, va_list args); 25 | int pg_sprintf(char *str, const char *fmt,...) 26 | __attribute__((format(printf, 2, 3))); 27 | int pg_vfprintf(FILE *stream, const char *fmt, va_list args); 28 | int pg_fprintf(FILE *stream, const char *fmt,...) 29 | __attribute__((format(printf, 2, 3))); 30 | int pg_vprintf(const char *fmt, va_list args); 31 | int pg_printf(const char *fmt,...) 32 | __attribute__((format(printf, 1, 2))); 33 | 34 | /* This is also provided by snprintf.c */ 35 | int pg_strfromd(char *str, size_t count, int precision, double value); 36 | 37 | /* Replace strerror() with our own, somewhat more robust wrapper */ 38 | extern char *pg_strerror(int errnum); 39 | #define strerror pg_strerror 40 | 41 | /* Likewise for strerror_r(); note we prefer the GNU API for that */ 42 | extern char *pg_strerror_r(int errnum, char *buf, size_t buflen); 43 | #define strerror_r pg_strerror_r 44 | #define PG_STRERROR_R_BUFLEN 256 /* Recommended buffer size for strerror_r */ 45 | 46 | #endif /* USE_REPL_SNPRINTF */ 47 | 48 | #endif /* PG_SNPRINTF_H */ 49 | -------------------------------------------------------------------------------- /src/bin/lib/subcommands.c/commandline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * commandline.h 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * Licensed under the PostgreSQL License. 6 | * 7 | */ 8 | 9 | #ifndef COMMANDLINE_H 10 | #define COMMANDLINE_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | typedef int (*command_getopt)(int argc, char **argv); 18 | typedef void (*command_run)(int argc, char **argv); 19 | 20 | typedef struct CommandLine 21 | { 22 | const char *name; 23 | const char *shortDescription; 24 | const char *usageSuffix; 25 | const char *help; 26 | 27 | command_getopt getopt; 28 | command_run run; 29 | 30 | struct CommandLine **subcommands; 31 | char *breadcrumb; 32 | } CommandLine; 33 | 34 | extern CommandLine *current_command; 35 | 36 | #define make_command_set(name, desc, usage, help, getopt, set) \ 37 | { name, desc, usage, help, getopt, NULL, set, NULL } 38 | 39 | #define make_command(name, desc, usage, help, getopt, run) \ 40 | { name, desc, usage, help, getopt, run, NULL, NULL } 41 | 42 | bool commandline_run(CommandLine *command, int argc, char **argv); 43 | void commandline_help(FILE *stream); 44 | void commandline_print_usage(CommandLine *command, FILE *stream); 45 | void commandline_print_subcommands(CommandLine *command, FILE *stream); 46 | void commandline_print_command_tree(CommandLine *command, FILE *stream); 47 | void commandline_add_breadcrumb(CommandLine *command, CommandLine *subcommand); 48 | 49 | #define streq(a, b) (a != NULL && b != NULL && strcmp(a, b) == 0) 50 | 51 | #endif /* COMMANDLINE_H */ 52 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/.gitignore: -------------------------------------------------------------------------------- 1 | pg_autoctl 2 | git-version.h 3 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/azure_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/azure_config.h 3 | * Implementation of a CLI which lets you call `az` cli commands to prepare 4 | * a pg_auto_failover demo or QA environment. 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef AZURE_CONFIG_H 12 | #define AZURE_CONFIG_H 13 | 14 | #include 15 | 16 | #include "postgres_fe.h" 17 | #include "pqexpbuffer.h" 18 | 19 | #include "azure.h" 20 | #include "defaults.h" 21 | 22 | bool azure_config_read_file(AzureRegionResources *azRegion); 23 | bool azure_config_write(FILE *stream, AzureRegionResources *azRegion); 24 | bool azure_config_write_file(AzureRegionResources *azRegion); 25 | 26 | void azure_config_prepare(AzureOptions *options, AzureRegionResources *azRegion); 27 | bool azure_get_remote_ip(char *ipAddress, size_t ipAddressSize); 28 | 29 | #endif /* AZURE_CONFIG_H */ 30 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/cli_do_demoapp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/cli_do_demoapp.h 3 | * Implementation of a demo application that shows how to handle automatic 4 | * reconnection when a failover happened, and uses a single URI. 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef CLI_DO_DEMOAPP_H 12 | #define CLI_DO_DEMOAPP_H 13 | 14 | #include "postgres_fe.h" 15 | #include "pqexpbuffer.h" 16 | #include "snprintf.h" 17 | 18 | #include "cli_common.h" 19 | #include "cli_do_root.h" 20 | #include "cli_root.h" 21 | #include "commandline.h" 22 | #include "config.h" 23 | #include "env_utils.h" 24 | #include "log.h" 25 | #include "pidfile.h" 26 | #include "signals.h" 27 | #include "string_utils.h" 28 | 29 | #define MAX_CLIENTS_COUNT 128 30 | 31 | typedef struct DemoAppOptions 32 | { 33 | char monitor_pguri[MAXCONNINFO]; 34 | char formation[NAMEDATALEN]; 35 | char username[NAMEDATALEN]; 36 | int groupId; 37 | 38 | int clientsCount; 39 | int duration; 40 | int firstFailover; 41 | int failoverFreq; 42 | bool doFailover; 43 | } DemoAppOptions; 44 | 45 | extern DemoAppOptions demoAppOptions; 46 | 47 | #endif /* CLI_DO_DEMOAPP_H */ 48 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/cli_root.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/cli_root.h 3 | * Implementation of a CLI which lets you run individual keeper routines 4 | * directly 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef CLI_ROOT_H 12 | #define CLI_ROOT_H 13 | 14 | #include "commandline.h" 15 | #include "lock_utils.h" 16 | 17 | extern char pg_autoctl_argv0[]; 18 | extern char pg_autoctl_program[]; 19 | extern int pgconnect_timeout; 20 | extern int logLevel; 21 | 22 | extern Semaphore log_semaphore; 23 | 24 | extern char *ps_buffer; 25 | extern size_t ps_buffer_size; 26 | extern size_t last_status_len; 27 | 28 | extern CommandLine help; 29 | extern CommandLine version; 30 | 31 | extern CommandLine create_commands; 32 | extern CommandLine *create_subcommands[]; 33 | 34 | extern CommandLine show_commands; 35 | extern CommandLine *show_subcommands[]; 36 | 37 | extern CommandLine show_commands_with_debug; 38 | extern CommandLine *show_subcommands_with_debug[]; 39 | 40 | extern CommandLine drop_commands; 41 | extern CommandLine *drop_subcommands[]; 42 | 43 | extern CommandLine root_with_debug; 44 | extern CommandLine *root_subcommands_with_debug[]; 45 | 46 | extern CommandLine root; 47 | extern CommandLine *root_subcommands[]; 48 | 49 | int root_options(int argc, char **argv); 50 | 51 | 52 | #endif /* CLI_ROOT_H */ 53 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/config.h 3 | * Common configuration data structure and function definitions 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef CONFIG_H 11 | #define CONFIG_H 12 | 13 | #include 14 | #include 15 | 16 | #include "pgctl.h" 17 | #include "pgsql.h" 18 | 19 | #define KEEPER_ROLE "keeper" 20 | #define MONITOR_ROLE "monitor" 21 | 22 | typedef enum 23 | { 24 | PG_AUTOCTL_ROLE_UNKNOWN, 25 | PG_AUTOCTL_ROLE_MONITOR, 26 | PG_AUTOCTL_ROLE_KEEPER 27 | } pgAutoCtlNodeRole; 28 | 29 | typedef struct MinimalConfig 30 | { 31 | char role[NAMEDATALEN]; 32 | } MinimalConfig; 33 | 34 | typedef struct ConfigFilePaths 35 | { 36 | char config[MAXPGPATH]; /* ~/.config/pg_autoctl/${PGDATA}/pg_autoctl.cfg */ 37 | char state[MAXPGPATH]; /* ~/.local/share/pg_autoctl/${PGDATA}/pg_autoctl.state */ 38 | char pid[MAXPGPATH]; /* /tmp/${PGDATA}/pg_autoctl.pid */ 39 | char init[MAXPGPATH]; /* /tmp/${PGDATA}/pg_autoctl.init */ 40 | char nodes[MAXPGPATH]; /* ~/.local/share/pg_autoctl/${PGDATA}/nodes.json */ 41 | char systemd[MAXPGPATH]; /* ~/.config/systemd/user/pgautofailover.service */ 42 | } ConfigFilePaths; 43 | 44 | /* 45 | * We implement XDG Base Directory Specification (in parts), and the following 46 | * XDGResourceType makes it possible to make some decisions in the generic 47 | * build_xdg_path() helper function: 48 | * 49 | * - XDG_DATA resource uses XDG_DATA_HOME environment variable and defaults to 50 | * ${HOME}.local/share 51 | * 52 | * - XDG_CONFIG resource uses XDG_CONFIG_HOME environement variable and 53 | * defaults to ${HOME}/.config 54 | * 55 | * - XDG_CACHE and XDG_RUNTIME are not implemented yet. 56 | * 57 | * https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html 58 | */ 59 | typedef enum 60 | { 61 | XDG_DATA, 62 | XDG_CONFIG, 63 | XDG_CACHE, 64 | XDG_RUNTIME 65 | } XDGResourceType; 66 | 67 | 68 | bool build_xdg_path(char *dst, XDGResourceType xdgType, 69 | const char *pgdata, const char *name); 70 | 71 | bool SetConfigFilePath(ConfigFilePaths *pathnames, const char *pgdata); 72 | bool SetStateFilePath(ConfigFilePaths *pathnames, const char *pgdata); 73 | bool SetNodesFilePath(ConfigFilePaths *pathnames, const char *pgdata); 74 | bool SetPidFilePath(ConfigFilePaths *pathnames, const char *pgdata); 75 | 76 | pgAutoCtlNodeRole ProbeConfigurationFileRole(const char *filename); 77 | 78 | 79 | #define strneq(x, y) \ 80 | ((x != NULL) && (y != NULL) && (strcmp(x, y) != 0)) 81 | 82 | bool config_accept_new_ssloptions(PostgresSetup *pgSetup, 83 | PostgresSetup *newPgSetup); 84 | 85 | #endif /* CONFIG_H */ 86 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/coordinator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/coordinator.h 3 | * Functions for interacting with a Citus coordinator 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef COORDINATOR_H 11 | #define COORDINATOR_H 12 | 13 | #include 14 | 15 | #include "keeper.h" 16 | #include "nodestate_utils.h" 17 | #include "pgsql.h" 18 | #include "state.h" 19 | 20 | 21 | /* interface to the monitor */ 22 | typedef struct Coordinator 23 | { 24 | NodeAddress node; 25 | PGSQL pgsql; 26 | } Coordinator; 27 | 28 | typedef struct CoordinatorNode 29 | { 30 | int nodeid; 31 | int groupid; 32 | char nodename[_POSIX_HOST_NAME_MAX]; 33 | int nodeport; 34 | char noderack[NAMEDATALEN]; 35 | bool hasmetadata; 36 | bool isactive; 37 | char state[NAMEDATALEN]; /* primary, secondary, unavailable */ 38 | char nodecluster[NAMEDATALEN]; 39 | } CoordinatorNode; 40 | 41 | 42 | bool coordinator_init(Coordinator *coordinator, 43 | NodeAddress *node, Keeper *keeper); 44 | bool coordinator_init_from_monitor(Coordinator *coordinator, Keeper *keeper); 45 | bool coordinator_init_from_keeper(Coordinator *coordinator, Keeper *keeper); 46 | bool coordinator_add_node(Coordinator *coordinator, Keeper *keeper, 47 | int *nodeid); 48 | bool coordinator_add_inactive_node(Coordinator *coordinator, Keeper *keeper, 49 | int *nodeid); 50 | bool coordinator_activate_node(Coordinator *coordinator, Keeper *keeper, 51 | int *nodeid); 52 | bool coordinator_remove_node(Coordinator *coordinator, Keeper *keeper); 53 | 54 | bool coordinator_udpate_node_transaction_is_prepared(Coordinator *coordinator, 55 | Keeper *keeper, 56 | bool *transactionHasBeenPrepared); 57 | 58 | bool coordinator_update_node_prepare(Coordinator *coordinator, Keeper *keeper); 59 | bool coordinator_update_node_commit(Coordinator *coordinator, Keeper *keeper); 60 | bool coordinator_update_node_rollback(Coordinator *coordinator, Keeper *keeper); 61 | void GetPreparedTransactionName(int nodeid, char *name); 62 | bool coordinator_upsert_poolinfo_port(Coordinator *coordinator, Keeper *keeper); 63 | bool coordinator_node_is_registered(Coordinator *coordinator, bool *isRegistered); 64 | 65 | bool coordinator_remove_dropped_nodes(Coordinator *coordinator, 66 | CurrentNodeStateArray *nodesArray); 67 | 68 | #endif /* COORDINATOR_H */ 69 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/debian.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/debian.h 3 | * 4 | * Debian specific code to support registering a pg_autoctl node from a 5 | * Postgres cluster created with pg_createcluster. We need to move the 6 | * configuration files back to PGDATA. 7 | * 8 | * Copyright (c) Microsoft Corporation. All rights reserved. 9 | * Licensed under the PostgreSQL License. 10 | * 11 | */ 12 | 13 | #ifndef DEBIAN_H 14 | #define DEBIAN_H 15 | 16 | #include "keeper_config.h" 17 | #include "pgsetup.h" 18 | 19 | /* 20 | * We know how to find configuration files in either PGDATA as per Postgres 21 | * core, or in the debian cluster configuration directory as per debian 22 | * postgres-common packaging, implemented in pg_createcluster. 23 | */ 24 | typedef enum 25 | { 26 | PG_CONFIG_TYPE_UNKNOWN = 0, 27 | PG_CONFIG_TYPE_POSTGRES, 28 | PG_CONFIG_TYPE_DEBIAN 29 | } PostgresConfigurationKind; 30 | 31 | /* 32 | * debian's pg_createcluster moves the 3 configuration files to a place in /etc: 33 | * 34 | * - postgresql.conf 35 | * - pg_ident.conf 36 | * - pg_hba.conf 37 | * 38 | * On top of that debian also manages a "start.conf" file to decide if their 39 | * systemd integration should manage a given cluster. 40 | */ 41 | typedef struct pg_config_files 42 | { 43 | PostgresConfigurationKind kind; 44 | char conf[MAXPGPATH]; 45 | char ident[MAXPGPATH]; 46 | char hba[MAXPGPATH]; 47 | } PostgresConfigFiles; 48 | 49 | 50 | /* 51 | * debian handles paths for data_directory and configuration directory that 52 | * depend on two components: Postgres version string ("11", "12", etc) and 53 | * debian cluster name (defaults to "main"). 54 | */ 55 | typedef struct debian_pathnames 56 | { 57 | char versionName[PG_VERSION_STRING_MAX]; 58 | char clusterName[MAXPGPATH]; 59 | 60 | char dataDirectory[MAXPGPATH]; 61 | char confDirectory[MAXPGPATH]; 62 | } DebianPathnames; 63 | 64 | 65 | bool keeper_ensure_pg_configuration_files_in_pgdata(PostgresSetup *pgSetup); 66 | 67 | 68 | #endif /* DEBIAN_H */ 69 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/demoapp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/demoapp.h 3 | * Demo application for pg_auto_failover 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef DEMOAPP_H 11 | #define DEMOAPP_H 12 | 13 | #include 14 | 15 | #include "cli_do_demoapp.h" 16 | 17 | #define DEMO_DEFAULT_RETRY_CAP_TIME 200 18 | #define DEMO_DEFAULT_RETRY_SLEEP_TIME 500 19 | 20 | bool demoapp_grab_formation_uri(DemoAppOptions *options, 21 | char *pguri, size_t size, 22 | bool *mayRetry); 23 | bool demoapp_prepare_schema(const char *pguri); 24 | bool demoapp_run(const char *pguri, DemoAppOptions *demoAppOptions); 25 | 26 | void demoapp_print_histogram(const char *pguri, DemoAppOptions *demoAppOptions); 27 | void demoapp_print_summary(const char *pguri, DemoAppOptions *demoAppOptions); 28 | 29 | #endif /* DEMOAPP_H */ 30 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/env_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/env_utils.h 3 | * Utility functions for interacting with environment settings. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef ENV_UTILS_H 11 | #define ENV_UTILS_H 12 | 13 | #include "postgres_fe.h" 14 | 15 | bool env_found_empty(const char *name); 16 | bool env_exists(const char *name); 17 | bool get_env_copy(const char *name, char *outbuffer, int maxLength); 18 | bool get_env_copy_with_fallback(const char *name, char *result, int maxLength, 19 | const char *fallback); 20 | bool get_env_pgdata(char *pgdata); 21 | void get_env_pgdata_or_exit(char *pgdata); 22 | #endif /* ENV_UTILS_H */ 23 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/file_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/file_utils.h 3 | * Utility functions for reading and writing files 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef FILE_UTILS_H 11 | #define FILE_UTILS_H 12 | 13 | #include 14 | 15 | #include "postgres_fe.h" 16 | 17 | #include 18 | 19 | 20 | #if defined(__APPLE__) 21 | #define ST_MTIME_S(st) ((int64_t) st.st_mtimespec.tv_sec) 22 | #else 23 | #define ST_MTIME_S(st) ((int64_t) st.st_mtime) 24 | #endif 25 | 26 | 27 | /* 28 | * In order to avoid dynamic memory allocations and tracking when searching the 29 | * PATH environment, we pre-allocate 1024 paths entries. That should be way 30 | * more than enough for all situations, and only costs 1024*1024 = 1MB of 31 | * memory. 32 | */ 33 | typedef struct SearchPath 34 | { 35 | int found; 36 | char matches[1024][MAXPGPATH]; 37 | } SearchPath; 38 | 39 | 40 | bool file_exists(const char *filename); 41 | bool directory_exists(const char *path); 42 | bool ensure_empty_dir(const char *dirname, int mode); 43 | FILE * fopen_with_umask(const char *filePath, const char *modes, int flags, mode_t umask); 44 | FILE * fopen_read_only(const char *filePath); 45 | bool write_file(char *data, long fileSize, const char *filePath); 46 | bool append_to_file(char *data, long fileSize, const char *filePath); 47 | bool read_file(const char *filePath, char **contents, long *fileSize); 48 | bool read_file_if_exists(const char *filePath, char **contents, long *fileSize); 49 | bool move_file(char *sourcePath, char *destinationPath); 50 | bool duplicate_file(char *sourcePath, char *destinationPath); 51 | bool create_symbolic_link(char *sourcePath, char *targetPath); 52 | 53 | void path_in_same_directory(const char *basePath, 54 | const char *fileName, 55 | char *destinationPath); 56 | 57 | bool search_path_first(const char *filename, char *result, int logLevel); 58 | bool search_path(const char *filename, SearchPath *result); 59 | bool search_path_deduplicate_symlinks(SearchPath *results, SearchPath *dedup); 60 | bool unlink_file(const char *filename); 61 | bool set_program_absolute_path(char *program, int size); 62 | bool normalize_filename(const char *filename, char *dst, int size); 63 | 64 | void init_ps_buffer(int argc, char **argv); 65 | void set_ps_title(const char *title); 66 | 67 | int fformat(FILE *stream, const char *fmt, ...) 68 | __attribute__((format(printf, 2, 3))); 69 | 70 | int sformat(char *str, size_t count, const char *fmt, ...) 71 | __attribute__((format(printf, 3, 4))); 72 | 73 | #endif /* FILE_UTILS_H */ 74 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/formation_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/formation_config.h 3 | * Formation configuration data structure and function definitions for cli 4 | * commands targeting formations. 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef FORMATION_CONFIG_H 12 | #define FORMATION_CONFIG_H 13 | 14 | #include "pgctl.h" 15 | 16 | typedef struct FormationConfig 17 | { 18 | /* pg_auto_failover formation setup */ 19 | char monitor_pguri[MAXCONNINFO]; 20 | 21 | char formation[NAMEDATALEN]; 22 | char formationKind[NAMEDATALEN]; 23 | char dbname[NAMEDATALEN]; 24 | bool formationHasSecondary; 25 | int numberSyncStandbys; 26 | 27 | /* PostgreSQL setup */ 28 | PostgresSetup pgSetup; 29 | } FormationConfig; 30 | 31 | #endif /*FORMATION_CONFIG_H */ 32 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/ini_implementation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/ini_implementation.c 3 | * The file containing library code used to parse files with .INI syntax 4 | * 5 | * The main reason this is in a separate file is so you can exclude a file 6 | * during static analysis. This way we exclude vendored in library code, 7 | * but not our code using it. 8 | * 9 | * Copyright (c) Microsoft Corporation. All rights reserved. 10 | * Licensed under the PostgreSQL License. 11 | */ 12 | #define INI_IMPLEMENTATION 13 | #include "ini.h" 14 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/ipaddr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/ipaddr.h 3 | * Find local ip used as source ip in ip packets, using getsockname and a udp 4 | * connection. 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef __IPADDRH__ 12 | #define __IPADDRH__ 13 | 14 | #include 15 | 16 | 17 | typedef enum 18 | { 19 | IPTYPE_V4, IPTYPE_V6, IPTYPE_NONE 20 | } IPType; 21 | 22 | 23 | IPType ip_address_type(const char *hostname); 24 | bool fetchLocalIPAddress(char *localIpAddress, int size, 25 | const char *serviceName, int servicePort, 26 | int logLevel, bool *mayRetry); 27 | bool fetchLocalCIDR(const char *localIpAddress, char *localCIDR, int size); 28 | bool findHostnameLocalAddress(const char *hostname, 29 | char *localIpAddress, int size); 30 | bool findHostnameFromLocalIpAddress(char *localIpAddress, 31 | char *hostname, int size); 32 | 33 | bool resolveHostnameForwardAndReverse(const char *hostname, 34 | char *ipaddr, int size, 35 | bool *foundHostnameFromAddress); 36 | 37 | bool ipaddrGetLocalHostname(char *hostname, size_t size); 38 | 39 | 40 | #endif /* __IPADDRH__ */ 41 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/keeper_pg_init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/keeper_init.h 3 | * Keeper configuration data structure and function definitions 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef KEEPER_INIT_H 11 | #define KEEPER_INIT_H 12 | 13 | #include 14 | 15 | #include "keeper.h" 16 | #include "keeper_config.h" 17 | 18 | extern bool keeperInitWarnings; 19 | 20 | bool keeper_pg_init(Keeper *keeper); 21 | bool keeper_pg_init_continue(Keeper *keeper); 22 | bool keeper_pg_init_and_register(Keeper *keeper); 23 | bool create_database_and_extension(Keeper *keeper); 24 | 25 | #endif /* KEEPER_INIT_H */ 26 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/lock_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/lock_utils.h 3 | * Utility functions for inter-process locking 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef LOCK_UTILS_H 11 | #define LOCK_UTILS_H 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | typedef struct Semaphore 20 | { 21 | int semId; 22 | pid_t owner; 23 | } Semaphore; 24 | 25 | 26 | bool semaphore_init(Semaphore *semaphore); 27 | bool semaphore_finish(Semaphore *semaphore); 28 | 29 | bool semaphore_create(Semaphore *semaphore); 30 | bool semaphore_open(Semaphore *semaphore); 31 | bool semaphore_unlink(Semaphore *semaphore); 32 | 33 | bool semaphore_cleanup(const char *pidfile); 34 | 35 | bool semaphore_lock(Semaphore *semaphore); 36 | bool semaphore_unlock(Semaphore *semaphore); 37 | 38 | void semaphore_log_lock_function(void *udata, int mode); 39 | 40 | #endif /* LOCK_UTILS_H */ 41 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/monitor_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/monitor_config.h 3 | * Monitor configuration data structure and function definitions 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef MONITOR_CONFIG_H 11 | #define MONITOR_CONFIG_H 12 | 13 | #include 14 | #include 15 | 16 | #include "config.h" 17 | #include "pgctl.h" 18 | #include "parson.h" 19 | #include "pgsql.h" 20 | 21 | typedef struct MonitorConfig 22 | { 23 | /* in-memory configuration related variables */ 24 | ConfigFilePaths pathnames; 25 | 26 | /* pg_autoctl setup */ 27 | char hostname[_POSIX_HOST_NAME_MAX]; 28 | 29 | /* PostgreSQL setup */ 30 | char role[NAMEDATALEN]; 31 | 32 | /* PostgreSQL setup */ 33 | PostgresSetup pgSetup; 34 | } MonitorConfig; 35 | 36 | 37 | bool monitor_config_set_pathnames_from_pgdata(MonitorConfig *config); 38 | void monitor_config_init(MonitorConfig *config, 39 | bool missing_pgdata_is_ok, 40 | bool pg_is_not_running_is_ok); 41 | bool monitor_config_init_from_pgsetup(MonitorConfig *mconfig, 42 | PostgresSetup *pgSetup, 43 | bool missingPgdataIsOk, 44 | bool pgIsNotRunningIsOk); 45 | bool monitor_config_read_file(MonitorConfig *config, 46 | bool missing_pgdata_is_ok, 47 | bool pg_not_running_is_ok); 48 | bool monitor_config_write_file(MonitorConfig *config); 49 | bool monitor_config_write(FILE *stream, MonitorConfig *config); 50 | bool monitor_config_to_json(MonitorConfig *config, JSON_Value *js); 51 | void monitor_config_log_settings(MonitorConfig config); 52 | bool monitor_config_merge_options(MonitorConfig *config, 53 | MonitorConfig *options); 54 | bool monitor_config_get_postgres_uri(MonitorConfig *config, char *connectionString, 55 | size_t size); 56 | 57 | bool monitor_config_get_setting(MonitorConfig *config, 58 | const char *path, char *value, size_t size); 59 | bool monitor_config_set_setting(MonitorConfig *config, 60 | const char *path, char *value); 61 | 62 | bool monitor_config_update_with_absolute_pgdata(MonitorConfig *config); 63 | 64 | bool monitor_config_accept_new(MonitorConfig *config, MonitorConfig *newConfig); 65 | 66 | #endif /* MONITOR_CONFIG_H */ 67 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/monitor_pg_init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/monitor_pg_init.h 3 | * Monitor configuration data structure and function definitions 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef MONITOR_PG_INIT_H 11 | #define MONITOR_PG_INIT_H 12 | 13 | #include 14 | 15 | #include "monitor.h" 16 | #include "monitor_config.h" 17 | 18 | bool monitor_pg_init(Monitor *monitor); 19 | bool monitor_install(const char *hostname, 20 | PostgresSetup pgSetupOption, 21 | bool checkSettings); 22 | bool monitor_add_postgres_default_settings(Monitor *monitor); 23 | 24 | #endif /* MONITOR_PG_INIT_H */ 25 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/pgctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/pgctl.h 3 | * API for controling PostgreSQL, using its binary tooling (pg_ctl, 4 | * pg_controldata, pg_basebackup and such). 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef PGCTL_H 12 | #define PGCTL_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "postgres_fe.h" 19 | #include "utils/pidfile.h" 20 | 21 | #include "defaults.h" 22 | #include "file_utils.h" 23 | #include "pgsetup.h" 24 | #include "pgsql.h" 25 | 26 | #define AUTOCTL_DEFAULTS_CONF_FILENAME "postgresql-auto-failover.conf" 27 | #define AUTOCTL_STANDBY_CONF_FILENAME "postgresql-auto-failover-standby.conf" 28 | 29 | #define PG_CTL_STATUS_NOT_RUNNING 3 30 | 31 | bool pg_controldata(PostgresSetup *pgSetup, bool missing_ok); 32 | bool set_pg_ctl_from_PG_CONFIG(PostgresSetup *pgSetup); 33 | bool set_pg_ctl_from_pg_config(PostgresSetup *pgSetup); 34 | bool config_find_pg_ctl(PostgresSetup *pgSetup); 35 | bool find_extension_control_file(const char *pg_ctl, const char *extName); 36 | bool pg_ctl_version(PostgresSetup *pgSetup); 37 | bool set_pg_ctl_from_config_bindir(PostgresSetup *pgSetup, const char *pg_config); 38 | bool find_pg_config_from_pg_ctl(const char *pg_ctl, char *pg_config, size_t size); 39 | 40 | bool pg_add_auto_failover_default_settings(PostgresSetup *pgSetup, 41 | const char *hostname, 42 | const char *configFilePath, 43 | GUC *settings); 44 | 45 | bool pg_auto_failover_default_settings_file_exists(PostgresSetup *pgSetup); 46 | 47 | bool pg_basebackup(const char *pgdata, 48 | const char *pg_ctl, 49 | ReplicationSource *replicationSource); 50 | bool pg_rewind(const char *pgdata, 51 | const char *pg_ctl, 52 | ReplicationSource *replicationSource); 53 | 54 | bool pg_ctl_initdb(const char *pg_ctl, const char *pgdata); 55 | bool pg_ctl_postgres(const char *pg_ctl, const char *pgdata, int pgport, 56 | char *listen_addresses, bool listen); 57 | bool pg_log_startup(const char *pgdata, int logLevel); 58 | bool pg_log_recovery_setup(const char *pgdata, int logLevel); 59 | bool pg_ctl_stop(const char *pg_ctl, const char *pgdata); 60 | int pg_ctl_status(const char *pg_ctl, const char *pgdata, bool log_output); 61 | bool pg_ctl_promote(const char *pg_ctl, const char *pgdata); 62 | 63 | bool pg_setup_standby_mode(uint32_t pg_control_version, 64 | const char *pgdata, 65 | const char *pg_ctl, 66 | ReplicationSource *replicationSource); 67 | 68 | bool pg_cleanup_standby_mode(uint32_t pg_control_version, 69 | const char *pg_ctl, 70 | const char *pgdata, 71 | PGSQL *pgsql); 72 | 73 | bool pgctl_identify_system(ReplicationSource *replicationSource); 74 | 75 | bool pg_is_running(const char *pg_ctl, const char *pgdata); 76 | bool pg_create_self_signed_cert(PostgresSetup *pgSetup, const char *hostname); 77 | 78 | #endif /* PGCTL_H */ 79 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/pghba.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/pghba.h 3 | * API for manipulating pg_hba.conf files 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef PGHBA_H 11 | #define PGHBA_H 12 | 13 | #include "pgsetup.h" 14 | #include "pgsql.h" 15 | 16 | /* supported HBA database values */ 17 | typedef enum HBADatabaseType 18 | { 19 | HBA_DATABASE_ALL, 20 | HBA_DATABASE_REPLICATION, 21 | HBA_DATABASE_DBNAME 22 | } HBADatabaseType; 23 | 24 | 25 | bool pghba_ensure_host_rule_exists(const char *hbaFilePath, 26 | bool ssl, 27 | HBADatabaseType, 28 | const char *database, 29 | const char *username, 30 | const char *hostname, 31 | const char *authenticationScheme, 32 | HBAEditLevel hbaLevel); 33 | 34 | bool pghba_ensure_host_rules_exist(const char *hbaFilePath, 35 | NodeAddressArray *nodesArray, 36 | bool ssl, 37 | const char *database, 38 | const char *username, 39 | const char *authenticationScheme, 40 | HBAEditLevel hbaLevel); 41 | 42 | bool pghba_enable_lan_cidr(PGSQL *pgsql, 43 | bool ssl, 44 | HBADatabaseType databaseType, 45 | const char *database, 46 | const char *hostname, 47 | const char *username, 48 | const char *authenticationScheme, 49 | HBAEditLevel hbaLevel, 50 | const char *pgdata); 51 | 52 | bool pghba_check_hostname(const char *hostname, char *ipaddr, size_t size, 53 | bool *useHostname); 54 | 55 | #endif /* PGHBA_H */ 56 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/pgtuning.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/pgtuning.h 3 | * Adjust some very basic Postgres tuning to the system properties. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef PGTUNING_H 11 | #define PGTUNING_H 12 | 13 | #include 14 | 15 | extern GUC postgres_tuning[]; 16 | 17 | bool pgtuning_prepare_guc_settings(GUC *settings, char *config, size_t size); 18 | 19 | #endif /* PGTUNING_H */ 20 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/pidfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/pidfile.h 3 | * Utilities to manage the pg_autoctl pidfile. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | #ifndef PIDFILE_H 10 | #define PIDFILE_H 11 | 12 | #include 13 | #include 14 | 15 | #include "postgres_fe.h" 16 | #include "pqexpbuffer.h" 17 | 18 | #include "keeper.h" 19 | #include "keeper_config.h" 20 | #include "monitor.h" 21 | #include "monitor_config.h" 22 | 23 | /* 24 | * As of pg_autoctl 1.4, the contents of the pidfile is: 25 | * 26 | * line # 27 | * 1 supervisor PID 28 | * 2 data directory path 29 | * 3 version number (PG_AUTOCTL_VERSION) 30 | * 4 extension version number (PG_AUTOCTL_EXTENSION_VERSION) 31 | * 5 shared semaphore id (used to serialize log writes) 32 | * 6 first supervised service pid line 33 | * 7 second supervised service pid line 34 | * ... 35 | * 36 | * The supervised service lines are added later, not the first time we create 37 | * the pidfile. Each service line contains 2 bits of information, separated 38 | * with spaces: 39 | * 40 | * pid service-name 41 | * 42 | * Each service creates its own pidfile with its own version number. At 43 | * pg_autoctl upgrade time, we might have a supervisor process that's running 44 | * with a different version than one of the restarted pg_autoctl services. 45 | */ 46 | #define PIDFILE_LINE_PID 1 47 | #define PIDFILE_LINE_DATA_DIR 2 48 | #define PIDFILE_LINE_VERSION_STRING 3 49 | #define PIDFILE_LINE_EXTENSION_VERSION 4 50 | #define PIDFILE_LINE_SEM_ID 5 51 | #define PIDFILE_LINE_FIRST_SERVICE 6 52 | 53 | bool create_pidfile(const char *pidfile, pid_t pid); 54 | 55 | bool prepare_pidfile_buffer(PQExpBuffer content, pid_t pid); 56 | bool create_service_pidfile(const char *pidfile, const char *serviceName); 57 | void get_service_pidfile(const char *pidfile, 58 | const char *serviceName, 59 | char *filename); 60 | bool read_service_pidfile_version_strings(const char *pidfile, 61 | char *versionString, 62 | char *extensionVersionString); 63 | 64 | bool read_pidfile(const char *pidfile, pid_t *pid); 65 | bool remove_pidfile(const char *pidfile); 66 | void check_pidfile(const char *pidfile, pid_t start_pid); 67 | 68 | void pidfile_as_json(JSON_Value *js, const char *pidfile, bool includeStatus); 69 | 70 | bool is_process_stopped(const char *pidfile, bool *stopped, pid_t *pid); 71 | bool wait_for_process_to_stop(const char *pidfile, int timeout, bool *stopped, 72 | pid_t *pid); 73 | 74 | #endif /* PIDFILE_H */ 75 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/service_keeper.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * src/bin/pg_autoctl/keeper_service.h 4 | * Utilities to start the keeper services. 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef KEEPER_SERVICE_H 12 | #define KEEPER_SERVICE_H 13 | 14 | #include 15 | 16 | #include "keeper.h" 17 | #include "keeper_config.h" 18 | 19 | bool start_keeper(Keeper *keeper); 20 | bool service_keeper_start(void *context, pid_t *pid); 21 | void service_keeper_runprogram(Keeper *keeper); 22 | bool service_keeper_node_active_init(Keeper *keeper); 23 | bool keeper_node_active_loop(Keeper *keeper, pid_t start_pid); 24 | 25 | 26 | #endif /* KEEPER_SERVICE_INIT_H */ 27 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/service_keeper_init.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * src/bin/pg_autoctl/keeper_service_init.h 4 | * Utilities to start the keeper init services. 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef KEEPER_SERVICE_INIT_H 12 | #define KEEPER_SERVICE_INIT_H 13 | 14 | #include 15 | 16 | #include "pgsql.h" 17 | #include "keeper_config.h" 18 | 19 | bool service_keeper_init(Keeper *keeper); 20 | bool service_keeper_init_start(void *context, pid_t *pid); 21 | 22 | 23 | #endif /* KEEPER_SERVICE_INIT_H */ 24 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/service_monitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/monitor_service.h 3 | * Utilities to start/stop the pg_autoctl service on a monitor node. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef MONITOR_SERVICE_H 11 | #define MONITOR_SERVICE_H 12 | 13 | #include 14 | 15 | #include "pgsql.h" 16 | #include "monitor_config.h" 17 | 18 | bool start_monitor(Monitor *monitor); 19 | bool service_monitor_start(void *context, pid_t *pid); 20 | bool service_monitor_stop(void *context); 21 | bool monitor_service_run(Monitor *monitor); 22 | void service_monitor_runprogram(Monitor *monitor); 23 | void service_monitor_reload(void *context); 24 | 25 | #endif /* MONITOR_SERVICE_H */ 26 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/service_monitor_init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/monitor_service_init.h 3 | * Utilities to start the monitor init services. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef MONITOR_SERVICE_INIT_H 11 | #define MONITOR_SERVICE_INIT_H 12 | 13 | #include 14 | 15 | #include "pgsql.h" 16 | #include "monitor_config.h" 17 | 18 | bool service_monitor_init(Monitor *monitor); 19 | 20 | #endif /* MONITOR_SERVICE_INIT_H */ 21 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/service_postgres.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/service_postgres.h 3 | * Utilities to start/stop the pg_autoctl service on a monitor node. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | #ifndef SERVICE_POSTGRES_H 10 | #define SERVICE_POSTGRES_H 11 | 12 | #include 13 | #include 14 | 15 | #include "keeper.h" 16 | #include "keeper_config.h" 17 | #include "supervisor.h" 18 | 19 | extern int countPostgresStart; 20 | 21 | bool service_postgres_start(void *context, pid_t *pid); 22 | bool service_postgres_stop(Service *service); 23 | void service_postgres_reload(Service *service); 24 | 25 | #endif /* SERVICE_POSTGRES_H */ 26 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/service_postgres_ctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/service_postgres_ctl.h 3 | * Utilities to start/stop the pg_autoctl service on a keeper node. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | #ifndef SERVICE_POSTGRES_CTL_H 10 | #define SERVICE_POSTGRES_CTL_H 11 | 12 | #include 13 | #include 14 | 15 | #include "keeper.h" 16 | #include "keeper_config.h" 17 | 18 | bool service_postgres_ctl_start(void *context, pid_t *pid); 19 | void service_postgres_ctl_runprogram(void); 20 | void service_postgres_ctl_loop(LocalPostgresServer *postgres); 21 | 22 | #endif /* SERVICE_POSTGRES_CTL_H */ 23 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/signals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/signals.h 3 | * Signal handlers for pg_autoctl, used in loop.c and pgsetup.c 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef SIGNALS_H 11 | #define SIGNALS_H 12 | 13 | #include 14 | #include 15 | 16 | /* This flag controls termination of the main loop. */ 17 | extern volatile sig_atomic_t asked_to_stop; /* SIGTERM */ 18 | extern volatile sig_atomic_t asked_to_stop_fast; /* SIGINT */ 19 | extern volatile sig_atomic_t asked_to_reload; /* SIGHUP */ 20 | extern volatile sig_atomic_t asked_to_quit; /* SIGQUIT */ 21 | 22 | #define CHECK_FOR_FAST_SHUTDOWN { if (asked_to_stop_fast) { break; } \ 23 | } 24 | 25 | void set_signal_handlers(bool exitOnQuit); 26 | bool block_signals(sigset_t *mask, sigset_t *orig_mask); 27 | void unblock_signals(sigset_t *orig_mask); 28 | void catch_reload(int sig); 29 | void catch_int(int sig); 30 | void catch_term(int sig); 31 | void catch_quit(int sig); 32 | void catch_quit_and_exit(int sig); 33 | 34 | int get_current_signal(int defaultSignal); 35 | int pick_stronger_signal(int sig1, int sig2); 36 | char * signal_to_string(int signal); 37 | 38 | #endif /* SIGNALS_H */ 39 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/string_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/string_utils.h 3 | * Utility functions for string handling 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | #ifndef STRING_UTILS_H 10 | #define STRING_UTILS_H 11 | 12 | #include 13 | 14 | 15 | /* maximum decimal int64 length with minus and NUL */ 16 | #define INTSTRING_MAX_DIGITS 21 17 | typedef struct IntString 18 | { 19 | int64_t intValue; 20 | char strValue[INTSTRING_MAX_DIGITS]; 21 | } IntString; 22 | 23 | IntString intToString(int64_t number); 24 | 25 | bool stringToInt(const char *str, int *number); 26 | bool stringToUInt(const char *str, unsigned int *number); 27 | 28 | bool stringToInt64(const char *str, int64_t *number); 29 | bool stringToUInt64(const char *str, uint64_t *number); 30 | 31 | bool stringToShort(const char *str, short *number); 32 | bool stringToUShort(const char *str, unsigned short *number); 33 | 34 | bool stringToInt32(const char *str, int32_t *number); 35 | bool stringToUInt32(const char *str, uint32_t *number); 36 | 37 | bool stringToDouble(const char *str, double *number); 38 | bool IntervalToString(double seconds, char *buffer, size_t size); 39 | 40 | int countLines(char *buffer); 41 | int splitLines(char *errorMessage, char **linesArray, int size); 42 | void processBufferCallback(const char *buffer, bool error); 43 | 44 | #endif /* STRING_UTILS_h */ 45 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/system_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/system_utils.h 3 | * Utility functions for getting CPU and Memory information. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef SYSTEM_UTILS_H 11 | #define SYSTEM_UTILS_H 12 | 13 | #include 14 | 15 | 16 | /* taken from sysinfo(2) on Linux */ 17 | typedef struct SystemInfo 18 | { 19 | uint64_t totalram; /* Total usable main memory size */ 20 | unsigned short ncpu; /* Number of current processes */ 21 | } SystemInfo; 22 | 23 | bool get_system_info(SystemInfo *sysInfo); 24 | void pretty_print_bytes(char *buffer, size_t size, uint64_t bytes); 25 | 26 | 27 | #endif /* SYSTEM_UTILS_H */ 28 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/systemd_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/systemd_config.h 3 | * Keeper integration with systemd service configuration file 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the PostgreSQL License. 7 | * 8 | */ 9 | 10 | #ifndef SYSTEMD_CONFIG_H 11 | #define SYSTEMD_CONFIG_H 12 | 13 | #include 14 | #include 15 | 16 | #include "config.h" 17 | 18 | typedef struct SystemdServiceConfig 19 | { 20 | ConfigFilePaths pathnames; 21 | 22 | /* UNIT */ 23 | char Description[BUFSIZE]; 24 | 25 | /* Service */ 26 | char WorkingDirectory[MAXPGPATH]; 27 | char EnvironmentPGDATA[BUFSIZE]; 28 | char User[NAMEDATALEN]; 29 | char ExecStart[BUFSIZE]; 30 | char Restart[BUFSIZE]; 31 | int StartLimitBurst; 32 | char ExecReload[BUFSIZE]; 33 | 34 | /* Install */ 35 | char WantedBy[BUFSIZE]; 36 | 37 | /* PostgreSQL setup */ 38 | PostgresSetup pgSetup; 39 | } SystemdServiceConfig; 40 | 41 | void systemd_config_init(SystemdServiceConfig *config, const char *pgdata); 42 | bool systemd_config_write_file(SystemdServiceConfig *config); 43 | bool systemd_config_write(FILE *stream, SystemdServiceConfig *config); 44 | 45 | #endif /* SYSTEMD_CONFIG_H */ 46 | -------------------------------------------------------------------------------- /src/bin/pg_autoctl/watch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * src/bin/pg_autoctl/watch.h 3 | * Implementation of a CLI to show events, states, and URI from the 4 | * pg_auto_failover monitor. 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | */ 10 | 11 | #ifndef WATCH_H 12 | #define WATCH_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "defaults.h" 21 | #include "monitor.h" 22 | #include "nodestate_utils.h" 23 | 24 | typedef enum 25 | { 26 | WATCH_MOVE_FOCUS_NONE = 0, 27 | WATCH_MOVE_FOCUS_LEFT, 28 | WATCH_MOVE_FOCUS_RIGHT, 29 | WATCH_MOVE_FOCUS_HOME, 30 | WATCH_MOVE_FOCUS_END, 31 | WATCH_MOVE_FOCUS_UP, 32 | WATCH_MOVE_FOCUS_DOWN 33 | } WatchMoveFocus; 34 | 35 | /* compute max size of items to display for events */ 36 | typedef struct MonitorEventsHeaders 37 | { 38 | int maxEventIdSize; 39 | int maxEventTimeSize; 40 | int maxEventNodeNameSize; 41 | int maxEventDescSize; 42 | } MonitorEventsHeaders; 43 | 44 | #define EVENTS_BUFFER_COUNT 80 45 | 46 | /* share a context between the update and render functions */ 47 | typedef struct WatchContext 48 | { 49 | /* state of the display */ 50 | int rows; 51 | int cols; 52 | int selectedRow; 53 | int selectedArea; /* area 1: node states, area 2: node events */ 54 | int startCol; 55 | WatchMoveFocus move; 56 | 57 | /* internal state */ 58 | bool initialized; 59 | bool cookedMode; 60 | bool shouldExit; /* true when q or F1 have been pressed */ 61 | bool couldContactMonitor; 62 | 63 | /* parameters used to fetch the data we display */ 64 | Monitor monitor; 65 | char formation[NAMEDATALEN]; 66 | int groupId; 67 | int number_sync_standbys; 68 | 69 | /* data to display */ 70 | CurrentNodeStateArray nodesArray; 71 | MonitorEventsArray eventsArray; 72 | MonitorEventsHeaders eventsHeaders; 73 | } WatchContext; 74 | 75 | void cli_watch_main_loop(WatchContext *context); 76 | void cli_watch_init_window(WatchContext *context); 77 | void cli_watch_end_window(WatchContext *context); 78 | 79 | bool cli_watch_update(WatchContext *context, int step); 80 | bool cli_watch_render(WatchContext *context, WatchContext *previous); 81 | 82 | #endif /* WATCH_H */ 83 | -------------------------------------------------------------------------------- /src/monitor/.gitignore: -------------------------------------------------------------------------------- 1 | results 2 | -------------------------------------------------------------------------------- /src/monitor/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the PostgreSQL License. 3 | 4 | EXTENSION = pgautofailover 5 | EXTVERSION = 2.2 6 | 7 | SRC_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 8 | 9 | DATA_built = $(EXTENSION)--$(EXTVERSION).sql 10 | DATA = $(EXTENSION)--1.0.sql $(patsubst ${SRC_DIR}%,%,$(wildcard ${SRC_DIR}$(EXTENSION)--*--*.sql)) 11 | 12 | # compilation configuration 13 | MODULE_big = $(EXTENSION) 14 | OBJS = $(patsubst ${SRC_DIR}%.c,%.o,$(wildcard ${SRC_DIR}*.c)) 15 | PG_CPPFLAGS = -std=c99 -Wall -Werror -Wno-unused-parameter -Iinclude -I$(libpq_srcdir) -g 16 | SHLIB_LINK = $(libpq) 17 | REGRESS = create_extension monitor workers dummy_update drop_extension upgrade 18 | 19 | PG_CONFIG ?= pg_config 20 | PGXS = $(shell $(PG_CONFIG) --pgxs) 21 | USE_PGXS = 1 22 | 23 | .PHONY: cleanup-before-install 24 | 25 | DEFAULT_CFLAGS = -std=c99 -D_GNU_SOURCE -g 26 | DEFAULT_CFLAGS += $(shell $(PG_CONFIG) --cflags) 27 | DEFAULT_CFLAGS += -Wformat 28 | DEFAULT_CFLAGS += -Wall 29 | DEFAULT_CFLAGS += -Werror=implicit-int 30 | DEFAULT_CFLAGS += -Werror=implicit-function-declaration 31 | DEFAULT_CFLAGS += -Werror=return-type 32 | DEFAULT_CFLAGS += -Wno-declaration-after-statement 33 | 34 | # Needed for OSX 35 | DEFAULT_CFLAGS += -Wno-missing-braces 36 | 37 | ifdef USE_SECURITY_FLAGS 38 | # Flags taken from: https://liquid.microsoft.com/Web/Object/Read/ms.security/Requirements/Microsoft.Security.SystemsADM.10203#guide 39 | SECURITY_CFLAGS=-fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 -z noexecstack -fpic -shared -Wl,-z,relro -Wl,-z,now -Wformat -Wformat-security -Werror=format-security 40 | DEFAULT_CFLAGS += $(SECURITY_CFLAGS) 41 | endif 42 | 43 | override CFLAGS := $(DEFAULT_CFLAGS) $(CFLAGS) 44 | 45 | include $(PGXS) 46 | 47 | ifdef USE_SECURITY_FLAGS 48 | # Flags taken from: https://liquid.microsoft.com/Web/Object/Read/ms.security/Requirements/Microsoft.Security.SystemsADM.10203#guide 49 | SECURITY_BITCODE_CFLAGS=-fsanitize=safe-stack -fstack-protector-strong -flto -fPIC -Wformat -Wformat-security -Werror=format-security 50 | override BITCODE_CFLAGS := $(BITCODE_CFLAGS) $(SECURITY_BITCODE_CFLAGS) 51 | endif 52 | 53 | cleanup-before-install: 54 | rm -f $(DESTDIR)$(datadir)/$(datamoduledir)/pgautofailover* 55 | 56 | install: cleanup-before-install 57 | 58 | $(EXTENSION)--$(EXTVERSION).sql: $(EXTENSION).sql 59 | cat $^ > $@ 60 | -------------------------------------------------------------------------------- /src/monitor/README.md: -------------------------------------------------------------------------------- 1 | # pg_auto_failover: the Monitor 2 | 3 | This directory contains the pg_auto_failover monitor. The monitor handles 4 | the group state machines of one or more groups of servers. Each group of 5 | servers implements a single Highly Available PostgreSQL Service. Several 6 | groups can be organized as part of the same formation. 7 | 8 | The pg_auto_failover monitor is implemented as a PostgreSQL extension. 9 | 10 | -------------------------------------------------------------------------------- /src/monitor/conninfo.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/conninfo.h 4 | * 5 | * Declarations for public functions and types related to reading 6 | * connection info from recovery.conf. 7 | * 8 | * Copyright (c) Microsoft Corporation. All rights reserved. 9 | * Licensed under the PostgreSQL License. 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #pragma once 15 | 16 | extern int ReadPrimaryHostAddress(char **primaryName, char **primaryPort); 17 | -------------------------------------------------------------------------------- /src/monitor/expected/create_extension.out: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | create extension pgautofailover cascade; 4 | NOTICE: installing required extension "btree_gist" 5 | -------------------------------------------------------------------------------- /src/monitor/expected/drop_extension.out: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | drop extension pgautofailover; 4 | -------------------------------------------------------------------------------- /src/monitor/expected/dummy_update.out: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | select version 4 | from pg_available_extension_versions 5 | where name = 'pgautofailover' and version = 'dummy'; 6 | version 7 | --------- 8 | dummy 9 | (1 row) 10 | 11 | alter extension pgautofailover update to dummy; 12 | select installed_version 13 | from pg_available_extensions where name = 'pgautofailover'; 14 | installed_version 15 | ------------------- 16 | dummy 17 | (1 row) 18 | 19 | -- should error because installed extension isn't compatible with .so 20 | select * from pgautofailover.get_primary('unknown formation'); 21 | ERROR: loaded "pgautofailover" library version differs from installed extension version 22 | DETAIL: Loaded library requires 2.2, but the installed extension version is dummy. 23 | HINT: Run ALTER EXTENSION pgautofailover UPDATE and try again. 24 | -------------------------------------------------------------------------------- /src/monitor/expected/upgrade.out: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | CREATE EXTENSION pgautofailover VERSION '1.0'; 4 | \dx pgautofailover 5 | List of installed extensions 6 | Name | Version | Schema | Description 7 | ----------------+---------+--------+------------------ 8 | pgautofailover | 1.0 | public | pg_auto_failover 9 | (1 row) 10 | 11 | ALTER EXTENSION pgautofailover UPDATE TO '1.1'; 12 | \dx pgautofailover 13 | List of installed extensions 14 | Name | Version | Schema | Description 15 | ----------------+---------+--------+------------------ 16 | pgautofailover | 1.1 | public | pg_auto_failover 17 | (1 row) 18 | 19 | ALTER EXTENSION pgautofailover UPDATE TO '1.2'; 20 | \dx pgautofailover 21 | List of installed extensions 22 | Name | Version | Schema | Description 23 | ----------------+---------+--------+------------------ 24 | pgautofailover | 1.2 | public | pg_auto_failover 25 | (1 row) 26 | 27 | ALTER EXTENSION pgautofailover UPDATE TO '1.3'; 28 | \dx pgautofailover 29 | List of installed extensions 30 | Name | Version | Schema | Description 31 | ----------------+---------+--------+------------------ 32 | pgautofailover | 1.3 | public | pg_auto_failover 33 | (1 row) 34 | 35 | DROP EXTENSION pgautofailover; 36 | -------------------------------------------------------------------------------- /src/monitor/expected/workers.out: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | -- This only tests that names are assigned properly 4 | \x on 5 | -- create a citus formation 6 | select * 7 | from pgautofailover.create_formation('citus', 'citus', 'citus', true, 0); 8 | -[ RECORD 1 ]--------+------ 9 | formation_id | citus 10 | kind | citus 11 | dbname | citus 12 | opt_secondary | t 13 | number_sync_standbys | 0 14 | 15 | -- register the first coordinator 16 | select * 17 | from pgautofailover.register_node('citus', 'localhost', 9876, 18 | dbname => 'citus', 19 | desired_group_id => 0, 20 | node_kind => 'coordinator'); 21 | -[ RECORD 1 ]---------------+-------- 22 | assigned_node_id | 4 23 | assigned_group_id | 0 24 | assigned_group_state | single 25 | assigned_candidate_priority | 100 26 | assigned_replication_quorum | t 27 | assigned_node_name | coord0a 28 | 29 | select * 30 | from pgautofailover.set_node_system_identifier(4, 6862008014275870855); 31 | -[ RECORD 1 ]-------- 32 | node_id | 4 33 | node_name | coord0a 34 | node_host | localhost 35 | node_port | 9876 36 | 37 | -- coordinator_1 reports single 38 | select * 39 | from pgautofailover.node_active('citus', 4, 0, 40 | current_group_role => 'single'); 41 | -[ RECORD 1 ]---------------+------- 42 | assigned_node_id | 4 43 | assigned_group_id | 0 44 | assigned_group_state | single 45 | assigned_candidate_priority | 100 46 | assigned_replication_quorum | t 47 | 48 | -- register first worker 49 | select * 50 | from pgautofailover.register_node('citus', 'localhost', 9878, 51 | dbname => 'citus', 52 | desired_group_id => 1, 53 | node_kind => 'worker'); 54 | -[ RECORD 1 ]---------------+--------- 55 | assigned_node_id | 5 56 | assigned_group_id | 1 57 | assigned_group_state | single 58 | assigned_candidate_priority | 100 59 | assigned_replication_quorum | t 60 | assigned_node_name | worker1a 61 | 62 | -------------------------------------------------------------------------------- /src/monitor/formation_metadata.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * stc/monitor/formation_metadata.h 4 | * 5 | * Declarations for public functions and types related to formation metadata. 6 | * 7 | * Copyright (c) Microsoft Corporation. All rights reserved. 8 | * Licensed under the PostgreSQL License. 9 | * 10 | *------------------------------------------------------------------------- 11 | */ 12 | 13 | #pragma once 14 | 15 | #include "access/xlogdefs.h" 16 | #include "datatype/timestamp.h" 17 | 18 | #include "health_check.h" 19 | #include "node_metadata.h" 20 | #include "replication_state.h" 21 | 22 | #define AUTO_FAILOVER_FORMATION_TABLE_NAME "formation" 23 | 24 | /* column indexes for pgautofailover.node */ 25 | #define Natts_pgautofailover_formation 4 26 | #define Anum_pgautofailover_formation_formationid 1 27 | #define Anum_pgautofailover_formation_kind 2 28 | #define Anum_pgautofailover_formation_dbname 3 29 | #define Anum_pgautofailover_formation_opt_secondary 4 30 | #define Anum_pgautofailover_formation_number_sync_standbys 5 31 | 32 | 33 | /* 34 | * AutoFailoverFormation represents a formation that is being managed by the 35 | * pg_auto_failover monitor. 36 | */ 37 | typedef struct AutoFailoverFormation 38 | { 39 | char *formationId; 40 | FormationKind kind; 41 | char dbname[NAMEDATALEN]; 42 | bool opt_secondary; 43 | int number_sync_standbys; 44 | } AutoFailoverFormation; 45 | 46 | 47 | /* public function declarations */ 48 | extern AutoFailoverFormation * GetFormation(const char *formationId); 49 | extern void AddFormation(const char *formationId, FormationKind kind, Name dbname, 50 | bool optionSecondary, int numberSyncStandbys); 51 | extern void RemoveFormation(const char *formationId); 52 | extern void SetFormationKind(const char *formationId, FormationKind kind); 53 | extern void SetFormationDBName(const char *formationId, const char *dbname); 54 | extern void SetFormationOptSecondary(const char *formationId, bool optSecondary); 55 | extern bool IsCitusFormation(AutoFailoverFormation *formation); 56 | 57 | extern bool FormationNumSyncStandbyIsValid(AutoFailoverFormation *formation, 58 | AutoFailoverNode *primaryNode, 59 | int groupId, 60 | int *standbyCount); 61 | 62 | extern bool SetFormationNumberSyncStandbys(const char *formationId, 63 | int numberSyncStandbys); 64 | 65 | extern FormationKind FormationKindFromString(const char *kind); 66 | extern char * FormationKindToString(FormationKind kind); 67 | extern FormationKind FormationKindFromNodeKindString(const char *nodeKind); 68 | -------------------------------------------------------------------------------- /src/monitor/group_state_machine.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/group_state_machine.h 4 | * 5 | * Declarations for public functions and types related to a group state 6 | * machine. 7 | * 8 | * Copyright (c) Microsoft Corporation. All rights reserved. 9 | * Licensed under the PostgreSQL License. 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | #pragma once 14 | 15 | #include "postgres.h" 16 | 17 | #include "access/xlogdefs.h" 18 | #include "node_metadata.h" 19 | 20 | /* 21 | * AutoFailoverNodeState describes the current state of a node in a group. 22 | */ 23 | typedef struct AutoFailoverNodeState 24 | { 25 | int64 nodeId; 26 | int32 groupId; 27 | ReplicationState replicationState; 28 | int32 reportedTLI; 29 | XLogRecPtr reportedLSN; 30 | SyncState pgsrSyncState; 31 | bool pgIsRunning; 32 | int candidatePriority; 33 | bool replicationQuorum; 34 | } AutoFailoverNodeState; 35 | 36 | 37 | /* public function declarations */ 38 | extern bool ProceedGroupState(AutoFailoverNode *activeNode); 39 | 40 | /* GUCs */ 41 | extern int EnableSyncXlogThreshold; 42 | extern int PromoteXlogThreshold; 43 | extern int DrainTimeoutMs; 44 | extern int UnhealthyTimeoutMs; 45 | extern int StartupGracePeriodMs; 46 | -------------------------------------------------------------------------------- /src/monitor/health_check.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/health_check_metadata.h 4 | * 5 | * Declarations for public functions and types related to health check 6 | * metadata. 7 | * 8 | * Copyright (c) Microsoft Corporation. All rights reserved. 9 | * Licensed under the PostgreSQL License. 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "postgres.h" 17 | 18 | #include "access/htup.h" 19 | #include "access/tupdesc.h" 20 | #include "nodes/pg_list.h" 21 | 22 | 23 | /* 24 | * NodeHealthState represents the last-known health state of a node after 25 | * the last round of health checks. 26 | */ 27 | typedef enum 28 | { 29 | NODE_HEALTH_UNKNOWN = -1, 30 | NODE_HEALTH_BAD = 0, 31 | NODE_HEALTH_GOOD = 1 32 | } NodeHealthState; 33 | 34 | /* 35 | * NodeHealth represents a node that is to be health-checked and its last-known 36 | * health state. 37 | */ 38 | typedef struct NodeHealth 39 | { 40 | int64 nodeId; 41 | char *nodeName; 42 | char *nodeHost; 43 | int nodePort; 44 | NodeHealthState healthState; 45 | } NodeHealth; 46 | 47 | 48 | /* GUCs to configure health checks */ 49 | extern bool HealthChecksEnabled; 50 | extern int HealthCheckPeriod; 51 | extern int HealthCheckTimeout; 52 | extern int HealthCheckMaxRetries; 53 | extern int HealthCheckRetryDelay; 54 | 55 | extern size_t HealthCheckWorkerShmemSize(void); 56 | 57 | extern void InitializeHealthCheckWorker(void); 58 | extern PGDLLEXPORT void HealthCheckWorkerMain(Datum arg); 59 | extern PGDLLEXPORT void HealthCheckWorkerLauncherMain(Datum arg); 60 | extern List * LoadNodeHealthList(void); 61 | extern NodeHealth * TupleToNodeHealth(HeapTuple heapTuple, 62 | TupleDesc tupleDescriptor); 63 | extern void SetNodeHealthState(int64 nodeId, 64 | char *nodeName, 65 | char *nodeHost, 66 | uint16 nodePort, 67 | int previousHealthState, 68 | int healthState); 69 | extern void StopHealthCheckWorker(Oid databaseId); 70 | extern char * NodeHealthToString(NodeHealthState health); 71 | -------------------------------------------------------------------------------- /src/monitor/metadata.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/metadata.h 4 | * 5 | * Declarations for public functions and types related to pg_auto_failover 6 | * metadata. 7 | * 8 | * Copyright (c) Microsoft Corporation. All rights reserved. 9 | * Licensed under the PostgreSQL License. 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "storage/lockdefs.h" 17 | 18 | #define AUTO_FAILOVER_EXTENSION_VERSION "2.2" 19 | #define AUTO_FAILOVER_EXTENSION_NAME "pgautofailover" 20 | #define AUTO_FAILOVER_SCHEMA_NAME "pgautofailover" 21 | #define AUTO_FAILOVER_FORMATION_TABLE "pgautofailover.formation" 22 | #define AUTO_FAILOVER_NODE_TABLE "pgautofailover.node" 23 | #define AUTO_FAILOVER_EVENT_TABLE "pgautofailover.event" 24 | #define REPLICATION_STATE_TYPE_NAME "replication_state" 25 | 26 | 27 | /* 28 | * Postgres' advisory locks use 'field4' to discern between different kind of 29 | * advisory locks. It only uses values 1 and 2, whereas Citus uses values 4, 5 30 | * 6. We start counting at 10 to avoid conflict. 31 | */ 32 | typedef enum AutoFailoverHALocktagClass 33 | { 34 | ADV_LOCKTAG_CLASS_AUTO_FAILOVER_FORMATION = 10, 35 | ADV_LOCKTAG_CLASS_AUTO_FAILOVER_NODE_GROUP = 11 36 | } AutoFailoverHALocktagClass; 37 | 38 | /* GUC variable for version checks, true by default */ 39 | extern bool EnableVersionChecks; 40 | 41 | /* public function declarations */ 42 | extern Oid pgAutoFailoverRelationId(const char *relname); 43 | extern Oid pgAutoFailoverSchemaId(void); 44 | extern Oid pgAutoFailoverExtensionOwner(void); 45 | extern void LockFormation(char *formationId, LOCKMODE lockMode); 46 | extern void LockNodeGroup(char *formationId, int groupId, LOCKMODE lockMode); 47 | extern void checkPgAutoFailoverVersion(void); 48 | -------------------------------------------------------------------------------- /src/monitor/notifications.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/notifications.h 4 | * 5 | * Declarations for public functions and types related to monitor 6 | * notifications. 7 | * 8 | * Copyright (c) Microsoft Corporation. All rights reserved. 9 | * Licensed under the PostgreSQL License. 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "postgres.h" 17 | #include "c.h" 18 | 19 | #include "node_metadata.h" 20 | #include "replication_state.h" 21 | 22 | /* 23 | * pg_auto_failover notifies on different channels about every event it 24 | * produces: 25 | * 26 | * - the "state" channel is used when a node's state is assigned to something 27 | * new 28 | * 29 | * - the "log" channel is used to duplicate message that are sent to the 30 | * PostgreSQL logs, in order for a pg_auto_failover monitor client to subscribe to 31 | * the chatter without having to actually have the privileges to tail the 32 | * PostgreSQL server logs. 33 | */ 34 | #define CHANNEL_STATE "state" 35 | #define CHANNEL_LOG "log" 36 | #define BUFSIZE 8192 37 | 38 | 39 | void LogAndNotifyMessage(char *message, size_t size, const char *fmt, ...) __attribute__( 40 | (format(printf, 3, 4))); 41 | 42 | int64 NotifyStateChange(AutoFailoverNode *node, char *description); 43 | int64 InsertEvent(AutoFailoverNode *node, char *description); 44 | -------------------------------------------------------------------------------- /src/monitor/pgautofailover--1.1--1.2.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- extension update file from 1.1 to 1.2 3 | -- 4 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 5 | \echo Use "ALTER EXTENSION pgautofailover UPDATE TO 1.2" to load this file. \quit 6 | 7 | 8 | DROP FUNCTION IF EXISTS pgautofailover.formation_uri(text); 9 | 10 | CREATE FUNCTION pgautofailover.formation_uri 11 | ( 12 | IN formation_id text DEFAULT 'default', 13 | IN sslmode text DEFAULT 'prefer' 14 | ) 15 | RETURNS text LANGUAGE SQL STRICT 16 | AS $$ 17 | select case 18 | when string_agg(format('%s:%s', nodename, nodeport),',') is not null 19 | then format('postgres://%s/%s?target_session_attrs=read-write&sslmode=%s', 20 | string_agg(format('%s:%s', nodename, nodeport),','), 21 | -- as we join formation on node we get the same dbname for all 22 | -- entries, pick one. 23 | min(dbname), 24 | min(sslmode) 25 | ) 26 | end as uri 27 | from pgautofailover.node as node 28 | join pgautofailover.formation using(formationid) 29 | where formationid = formation_id 30 | and groupid = 0; 31 | $$; 32 | -------------------------------------------------------------------------------- /src/monitor/pgautofailover--1.6--2.0.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- extension update file from 1.6 to 2.0 3 | -- 4 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 5 | \echo Use "CREATE EXTENSION pgautofailover" to load this file. \quit 6 | 7 | -- no changes, just the version number 8 | -------------------------------------------------------------------------------- /src/monitor/pgautofailover--2.0--2.1.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- extension update file from 2.0 to 2.1 3 | -- 4 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 5 | \echo Use "CREATE EXTENSION pgautofailover" to load this file. \quit 6 | 7 | -- no changes, just the version number 8 | -------------------------------------------------------------------------------- /src/monitor/pgautofailover--2.1--2.2.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- extension update file from 2.1 to 2.2 3 | -- 4 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 5 | \echo Use "CREATE EXTENSION pgautofailover" to load this file. \quit 6 | 7 | -- no changes, just the version number 8 | -------------------------------------------------------------------------------- /src/monitor/pgautofailover--2.2--dummy.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- dummy extension update file that does nothing 3 | -- 4 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 5 | \echo Use "ALTER EXTENSION pgautofailover UPDATE TO dummy" to load this file. \quit 6 | 7 | -------------------------------------------------------------------------------- /src/monitor/pgautofailover.control: -------------------------------------------------------------------------------- 1 | comment = 'pg_auto_failover' 2 | default_version = '2.2' 3 | module_pathname = '$libdir/pgautofailover' 4 | relocatable = false 5 | requires = 'btree_gist' 6 | -------------------------------------------------------------------------------- /src/monitor/replication_state.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/replication_state.h 4 | * 5 | * Declarations for public functions and types related to (de)serialising 6 | * replication states. 7 | * 8 | * Copyright (c) Microsoft Corporation. All rights reserved. 9 | * Licensed under the PostgreSQL License. 10 | * 11 | *------------------------------------------------------------------------- 12 | */ 13 | 14 | #pragma once 15 | 16 | 17 | /* 18 | * ReplicationState represents the current role of a node in a group. 19 | */ 20 | typedef enum ReplicationState 21 | { 22 | REPLICATION_STATE_INITIAL = 0, 23 | REPLICATION_STATE_SINGLE = 1, 24 | REPLICATION_STATE_WAIT_PRIMARY = 2, 25 | REPLICATION_STATE_PRIMARY = 3, 26 | REPLICATION_STATE_DRAINING = 4, 27 | REPLICATION_STATE_DEMOTE_TIMEOUT = 5, 28 | REPLICATION_STATE_DEMOTED = 6, 29 | REPLICATION_STATE_CATCHINGUP = 7, 30 | REPLICATION_STATE_SECONDARY = 8, 31 | REPLICATION_STATE_PREPARE_PROMOTION = 9, 32 | REPLICATION_STATE_STOP_REPLICATION = 10, 33 | REPLICATION_STATE_WAIT_STANDBY = 11, 34 | REPLICATION_STATE_MAINTENANCE = 12, 35 | REPLICATION_STATE_JOIN_PRIMARY = 13, 36 | REPLICATION_STATE_APPLY_SETTINGS = 14, 37 | REPLICATION_STATE_PREPARE_MAINTENANCE = 15, 38 | REPLICATION_STATE_WAIT_MAINTENANCE = 16, 39 | REPLICATION_STATE_REPORT_LSN = 17, 40 | REPLICATION_STATE_FAST_FORWARD = 18, 41 | REPLICATION_STATE_JOIN_SECONDARY = 19, 42 | REPLICATION_STATE_DROPPED = 20, 43 | REPLICATION_STATE_UNKNOWN = 21 44 | } ReplicationState; 45 | 46 | 47 | /* declarations of public functions */ 48 | extern Oid ReplicationStateTypeOid(void); 49 | extern ReplicationState EnumGetReplicationState(Oid replicationStateOid); 50 | extern Oid ReplicationStateGetEnum(ReplicationState replicationState); 51 | extern ReplicationState NameGetReplicationState(char *replicationStateName); 52 | extern const char * ReplicationStateGetName(ReplicationState replicationState); 53 | -------------------------------------------------------------------------------- /src/monitor/sql/create_extension.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | 4 | create extension pgautofailover cascade; 5 | -------------------------------------------------------------------------------- /src/monitor/sql/drop_extension.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | 4 | drop extension pgautofailover; 5 | -------------------------------------------------------------------------------- /src/monitor/sql/dummy_update.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | 4 | select version 5 | from pg_available_extension_versions 6 | where name = 'pgautofailover' and version = 'dummy'; 7 | 8 | alter extension pgautofailover update to dummy; 9 | 10 | select installed_version 11 | from pg_available_extensions where name = 'pgautofailover'; 12 | 13 | -- should error because installed extension isn't compatible with .so 14 | select * from pgautofailover.get_primary('unknown formation'); 15 | 16 | -------------------------------------------------------------------------------- /src/monitor/sql/monitor.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | 4 | \x on 5 | 6 | select * 7 | from pgautofailover.register_node('default', 'localhost', 9876, 'postgres'); 8 | 9 | select * 10 | from pgautofailover.set_node_system_identifier(1, 6852685710417058800); 11 | 12 | -- node_1 reports single 13 | select * 14 | from pgautofailover.node_active('default', 1, 0, 15 | current_group_role => 'single'); 16 | 17 | -- register node_2 18 | select * 19 | from pgautofailover.register_node('default', 'localhost', 9877, 'postgres'); 20 | 21 | -- node_2 reports wait_standby already 22 | select * 23 | from pgautofailover.node_active('default', 2, 0, 24 | current_group_role => 'wait_standby'); 25 | 26 | -- node_1 reports single again, and gets assigned wait_primary 27 | select * 28 | from pgautofailover.node_active('default', 1, 0, 29 | current_group_role => 'single'); 30 | 31 | -- node_1 now reports wait_primary 32 | select * 33 | from pgautofailover.node_active('default', 1, 0, 34 | current_group_role => 'wait_primary'); 35 | 36 | -- node_2 now reports wait_standby, gets assigned catchingup 37 | select * 38 | from pgautofailover.node_active('default', 2, 0, 39 | current_group_role => 'wait_standby'); 40 | 41 | -- register node_3 concurrently to node2 (probably) doing pg_basebackup 42 | select * 43 | from pgautofailover.register_node('default', 'localhost', 9879, 'postgres'); 44 | 45 | select formationid, nodename, goalstate, reportedstate 46 | from pgautofailover.node; 47 | 48 | table pgautofailover.formation; 49 | 50 | -- dump the pgautofailover.node table, omitting the timely columns 51 | select formationid, nodeid, groupid, nodehost, nodeport, 52 | goalstate, reportedstate, reportedpgisrunning, reportedrepstate 53 | from pgautofailover.node 54 | order by nodeid; 55 | 56 | select * from pgautofailover.get_primary('unknown formation'); 57 | select * from pgautofailover.get_primary(group_id => -10); 58 | select * from pgautofailover.get_primary(); 59 | 60 | select * from pgautofailover.get_primary('default', 0); 61 | select * from pgautofailover.get_other_nodes(1); 62 | 63 | -- remove the primary node 64 | select pgautofailover.remove_node(1); 65 | 66 | table pgautofailover.formation; 67 | 68 | select pgautofailover.remove_node(1, force => 'true'); 69 | 70 | -- dump the pgautofailover.node table, omitting the timely columns 71 | select formationid, nodeid, groupid, nodehost, nodeport, 72 | goalstate, reportedstate, reportedpgisrunning, reportedrepstate 73 | from pgautofailover.node 74 | order by nodeid; 75 | 76 | select * 77 | from pgautofailover.set_node_system_identifier(2, 6852685710417058800); 78 | 79 | -- should fail as there's no primary at this point 80 | select pgautofailover.perform_failover(); 81 | -------------------------------------------------------------------------------- /src/monitor/sql/upgrade.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | 4 | CREATE EXTENSION pgautofailover VERSION '1.0'; 5 | \dx pgautofailover 6 | 7 | ALTER EXTENSION pgautofailover UPDATE TO '1.1'; 8 | \dx pgautofailover 9 | 10 | ALTER EXTENSION pgautofailover UPDATE TO '1.2'; 11 | \dx pgautofailover 12 | 13 | ALTER EXTENSION pgautofailover UPDATE TO '1.3'; 14 | \dx pgautofailover 15 | 16 | DROP EXTENSION pgautofailover; 17 | -------------------------------------------------------------------------------- /src/monitor/sql/workers.sql: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the PostgreSQL License. 3 | 4 | -- This only tests that names are assigned properly 5 | 6 | \x on 7 | 8 | -- create a citus formation 9 | select * 10 | from pgautofailover.create_formation('citus', 'citus', 'citus', true, 0); 11 | 12 | -- register the first coordinator 13 | select * 14 | from pgautofailover.register_node('citus', 'localhost', 9876, 15 | dbname => 'citus', 16 | desired_group_id => 0, 17 | node_kind => 'coordinator'); 18 | 19 | select * 20 | from pgautofailover.set_node_system_identifier(4, 6862008014275870855); 21 | 22 | -- coordinator_1 reports single 23 | select * 24 | from pgautofailover.node_active('citus', 4, 0, 25 | current_group_role => 'single'); 26 | 27 | -- register first worker 28 | select * 29 | from pgautofailover.register_node('citus', 'localhost', 9878, 30 | dbname => 'citus', 31 | desired_group_id => 1, 32 | node_kind => 'worker'); 33 | -------------------------------------------------------------------------------- /src/monitor/version_compat.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/version_compat.h 4 | * Compatibility macros for writing code agnostic to PostgreSQL versions 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | *------------------------------------------------------------------------- 10 | */ 11 | 12 | #include "postgres.h" 13 | 14 | #if (PG_VERSION_NUM < 110000) 15 | 16 | /* 17 | * The list_qsort API was introduced in Postgres 11: 18 | * 19 | * https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=ab72716778128fb63d54ac256adf7fe6820a1185 20 | */ 21 | 22 | #include "nodes/pg_list.h" 23 | #include "version_compat.h" 24 | 25 | /* 26 | * Sort a list using qsort. A sorted list is built but the cells of the 27 | * original list are re-used. The comparator function receives arguments of 28 | * type ListCell ** 29 | */ 30 | List * 31 | list_qsort(const List *list, list_qsort_comparator cmp) 32 | { 33 | ListCell *cell; 34 | int i; 35 | int len = list_length(list); 36 | ListCell **list_arr; 37 | List *new_list; 38 | 39 | if (len == 0) 40 | { 41 | return NIL; 42 | } 43 | 44 | i = 0; 45 | list_arr = palloc(sizeof(ListCell *) * len); 46 | foreach(cell, list) 47 | list_arr[i++] = cell; 48 | 49 | qsort(list_arr, len, sizeof(ListCell *), cmp); 50 | 51 | new_list = (List *) palloc(sizeof(List)); 52 | new_list->type = list->type; 53 | new_list->length = len; 54 | new_list->head = list_arr[0]; 55 | new_list->tail = list_arr[len - 1]; 56 | 57 | for (i = 0; i < len - 1; i++) 58 | { 59 | list_arr[i]->next = list_arr[i + 1]; 60 | } 61 | 62 | list_arr[len - 1]->next = NULL; 63 | pfree(list_arr); 64 | return new_list; 65 | } 66 | 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/monitor/version_compat.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * src/monitor/version_compat.h 4 | * Compatibility macros for writing code agnostic to PostgreSQL versions 5 | * 6 | * Copyright (c) Microsoft Corporation. All rights reserved. 7 | * Licensed under the PostgreSQL License. 8 | * 9 | *------------------------------------------------------------------------- 10 | */ 11 | 12 | #ifndef VERSION_COMPAT_H 13 | #define VERSION_COMPAT_H 14 | 15 | #include "postgres.h" 16 | 17 | /* we support Postgres versions 10, 11, 12, 13, 14, 15, 16, and 17. */ 18 | #if (PG_VERSION_NUM < 100000 || PG_VERSION_NUM >= 180000) 19 | #error "Unknown or unsupported postgresql version" 20 | #endif 21 | 22 | #if (PG_VERSION_NUM < 110000) 23 | 24 | #include "postmaster/bgworker.h" 25 | #include "utils/memutils.h" 26 | 27 | #define DEFAULT_XLOG_SEG_SIZE XLOG_SEG_SIZE 28 | 29 | #define BackgroundWorkerInitializeConnection(dbname, username, flags) \ 30 | BackgroundWorkerInitializeConnection(dbname, username) 31 | 32 | #define BackgroundWorkerInitializeConnectionByOid(dboid, useroid, flags) \ 33 | BackgroundWorkerInitializeConnectionByOid(dboid, useroid) 34 | 35 | #include "nodes/pg_list.h" 36 | 37 | typedef int (*list_qsort_comparator) (const void *a, const void *b); 38 | extern List * list_qsort(const List *list, list_qsort_comparator cmp); 39 | 40 | #endif 41 | 42 | #if (PG_VERSION_NUM < 120000) 43 | 44 | #define table_beginscan_catalog heap_beginscan_catalog 45 | #define TableScanDesc HeapScanDesc 46 | 47 | #endif 48 | 49 | #if (PG_VERSION_NUM >= 120000) 50 | 51 | #include "access/htup_details.h" 52 | #include "catalog/pg_database.h" 53 | 54 | static inline Oid 55 | HeapTupleGetOid(HeapTuple tuple) 56 | { 57 | Form_pg_database dbForm = (Form_pg_database) GETSTRUCT(tuple); 58 | return dbForm->oid; 59 | } 60 | 61 | 62 | #endif 63 | 64 | #if (PG_VERSION_NUM >= 130000) 65 | 66 | #include "common/hashfn.h" 67 | 68 | #define heap_open(r, l) table_open(r, l) 69 | #define heap_close(r, l) table_close(r, l) 70 | 71 | #endif 72 | 73 | #if (PG_VERSION_NUM < 130000) 74 | 75 | /* Compatibility for ProcessUtility hook */ 76 | #define QueryCompletion char 77 | 78 | #endif 79 | 80 | /* Removed in Postgres 16 development */ 81 | #ifndef Abs 82 | 83 | /* 84 | * Abs 85 | * Return the absolute value of the argument. 86 | */ 87 | #define Abs(x) ((x) >= 0 ? (x) : -(x)) 88 | 89 | #endif 90 | 91 | #endif /* VERSION_COMPAT_H */ 92 | -------------------------------------------------------------------------------- /src/tools/pg_autoctl.valgrind: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | script_dir="${0%/*}" 4 | pid=$$ 5 | mkdir -p valgrind 6 | exec /usr/bin/valgrind --quiet --leak-check=yes --error-markers=VALGRINDERROR-BEGIN,VALGRINDERROR-END --max-stackframe=16000000 --log-file=./valgrind/log.${pid} "${script_dir}/../bin/pg_autoctl/pg_autoctl" "$@" 7 | 8 | -------------------------------------------------------------------------------- /tests/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.python.org/simple" 4 | verify_ssl = true 5 | 6 | [packages] 7 | pyroute2 = "==0.5.15" 8 | nose = "==1.3.7" 9 | psycopg2 = "==2.7.5" 10 | 11 | [dev-packages] 12 | 13 | [requires] 14 | python_version = "3.6" 15 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Initialize the tests package 2 | # https://docs.python.org/3/tutorial/modules.html#packages 3 | -------------------------------------------------------------------------------- /tests/tablespaces/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG PGVERSION=14 2 | 3 | FROM pg_auto_failover_test:pg${PGVERSION} as test 4 | 5 | USER root 6 | RUN mkdir -p /extra_volumes/extended_a && chown -R docker /extra_volumes/extended_a 7 | RUN mkdir -p /extra_volumes/extended_b && chown -R docker /extra_volumes/extended_b 8 | RUN mkdir -p /extra_volumes/extended_c && chown -R docker /extra_volumes/extended_c 9 | RUN mkdir -p /var/lib/postgres && chown -R docker /var/lib/postgres 10 | 11 | USER docker 12 | -------------------------------------------------------------------------------- /tests/tablespaces/Makefile: -------------------------------------------------------------------------------- 1 | PGVERSION ?= 14 2 | 3 | build: 4 | $(MAKE) -C ../../ build-test-pg$(PGVERSION) 5 | docker compose build --build-arg "PGVERSION=$(PGVERSION)" 6 | 7 | teardown: 8 | docker compose down --volumes --remove-orphans 9 | 10 | tail: 11 | docker compose logs -f 12 | 13 | state: 14 | docker compose exec -T monitor pg_autoctl show state 15 | 16 | watch: 17 | docker compose exec -T monitor pg_autoctl watch 18 | 19 | test_01: 20 | docker compose up -d node1 21 | TEST_NUM="01" docker compose up --exit-code-from=test test 22 | 23 | test_02: 24 | docker compose up -d node2 25 | TEST_NUM="02" docker compose up --exit-code-from=test test 26 | 27 | test_03: 28 | # Pollute the data dir so pg_rewind fails 29 | docker compose exec -T node2 mkdir '/var/lib/postgres/data/base/1/99999999' 30 | docker compose exec -T monitor pg_autoctl perform failover 31 | TEST_NUM="03" docker compose up --exit-code-from=test test 32 | 33 | test_04: 34 | docker compose pause node1 35 | TEST_NUM="04" docker compose up --exit-code-from=test test 36 | 37 | test_05: 38 | docker compose unpause node1 39 | TEST_NUM="05" docker compose up --exit-code-from=test test 40 | 41 | test_06: 42 | docker compose exec -T monitor pg_autoctl perform failover 43 | TEST_NUM="06" docker compose up --exit-code-from=test test 44 | 45 | test: build test_01 test_02 test_03 test_04 test_05 test_06 46 | 47 | # The test containers only connect to each other via the postgres protocol. 48 | # For this reason, the Makefile uses `docker compose exec` to perform 49 | # `pg_autoctl` commands, such as failover. Starting/stopping the pg_autoctl 50 | # process is also done using `docker compose` so as not to complicate the 51 | # command used to run each container. 52 | # See CONTRIBUTING.md for more detailed instructions. 53 | run-test: test teardown 54 | 55 | .PHONY: build state watch run-test test tail teardown test_01 test_02 test_03 test_04 test_05 test_06 56 | -------------------------------------------------------------------------------- /tests/tablespaces/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | monitor: 3 | build: . 4 | environment: 5 | PGDATA: /tmp/pgdata 6 | PG_AUTOCTL_DEBUG: 1 7 | command: pg_autoctl create monitor --ssl-self-signed --auth trust --run 8 | expose: 9 | - 5432 10 | container_name: monitor 11 | node1: 12 | build: . 13 | environment: 14 | PGDATA: /var/lib/postgres/data 15 | PGPORT: 5433 16 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor:5432/pg_auto_failover" 17 | HOSTNAME: "node1.tablespaces_default" 18 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 19 | expose: 20 | - 5433 21 | links: 22 | - monitor 23 | container_name: node1 24 | volumes: 25 | - node1-volume:/var/lib/postgres:rw 26 | - node1-a-volume:/extra_volumes/extended_a:rw 27 | - node1-b-volume:/extra_volumes/extended_b:rw 28 | - node1-c-volume:/extra_volumes/extended_c:rw 29 | node2: 30 | build: . 31 | environment: 32 | PGDATA: /var/lib/postgres/data 33 | PGPORT: 5434 34 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor:5432/pg_auto_failover" 35 | HOSTNAME: "node2.tablespaces_default" 36 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 37 | expose: 38 | - 5433 39 | links: 40 | - monitor 41 | container_name: node2 42 | volumes: 43 | - node2-volume:/var/lib/postgres:rw 44 | - node2-a-volume:/extra_volumes/extended_a:rw 45 | - node2-b-volume:/extra_volumes/extended_b:rw 46 | - node2-c-volume:/extra_volumes/extended_c:rw 47 | test: 48 | build: 49 | context: . 50 | target: test 51 | environment: 52 | TEST_NUM: 53 | command: [ 54 | "make", "-C", "/usr/src/pg_auto_failover", "test", "TEST=tablespaces/test_tablespaces_$${TEST_NUM}" 55 | ] 56 | container_name: pg_auto_failover_tablespaces_test 57 | links: 58 | - monitor 59 | 60 | volumes: 61 | node1-volume: 62 | node1-a-volume: 63 | node1-b-volume: 64 | node1-c-volume: 65 | node2-volume: 66 | node2-a-volume: 67 | node2-b-volume: 68 | node2-c-volume: 69 | -------------------------------------------------------------------------------- /tests/tablespaces/tablespace_utils.py: -------------------------------------------------------------------------------- 1 | import time 2 | from tests.pgautofailover_utils import QueryRunner 3 | from tests.pgautofailover_utils import StatefulNode 4 | 5 | 6 | class PGNodeTS(QueryRunner): 7 | def run_sql_query(self, query, *args): 8 | return super().run_sql_query(query, True, *args) 9 | 10 | def connection_string(self): 11 | return "postgresql://%s@%s:%s/%s" % ( 12 | self.username, 13 | self.service_name, 14 | self.port, 15 | self.database, 16 | ) 17 | 18 | 19 | class MonitorNodeTS(PGNodeTS): 20 | def __init__(self, port, service_name): 21 | self.port = port 22 | self.service_name = service_name 23 | self.monitor = self 24 | self.username = "autoctl_node" 25 | self.database = "pg_auto_failover" 26 | 27 | 28 | class DataNodeTS(PGNodeTS, StatefulNode): 29 | def __init__(self, port, service_name, monitor_node): 30 | self.port = port 31 | self.service_name = service_name 32 | self.monitor = monitor_node 33 | self.username = "docker" 34 | self.database = "postgres" 35 | 36 | def logger_name(self): 37 | return self.service_name 38 | 39 | def sleep(self, sleep_time): 40 | time.sleep(sleep_time) 41 | 42 | def print_debug_logs(self): 43 | # no-op, can't get logs easily in this test-type 44 | return 45 | 46 | def get_state(self): 47 | return super().get_state( 48 | "node with port %s not found on the monitor" % self.port, 49 | """ 50 | SELECT reportedstate, goalstate 51 | FROM pgautofailover.node 52 | WHERE nodeport=%s 53 | """, 54 | self.port, 55 | ) 56 | 57 | 58 | monitor = MonitorNodeTS( 59 | "5432", 60 | "monitor", 61 | ) 62 | node1 = DataNodeTS( 63 | "5433", 64 | "node1", 65 | monitor, 66 | ) 67 | node2 = DataNodeTS( 68 | "5434", 69 | "node2", 70 | monitor, 71 | ) 72 | -------------------------------------------------------------------------------- /tests/tablespaces/test_tablespaces_01.py: -------------------------------------------------------------------------------- 1 | from nose.tools import * 2 | from tests.tablespaces.tablespace_utils import node1 3 | 4 | 5 | # Node 1 is spun up by Makefile, wait until it's up 6 | def test_000_init_monitor_and_primary(): 7 | # Wait a bit longer than normal for start up 8 | assert node1.wait_until_state( 9 | target_state="single", timeout=90, sleep_time=3 10 | ) 11 | 12 | 13 | def test_002_create_t1(): 14 | node1.run_sql_query("CREATE TABLE t1(a int)") 15 | node1.run_sql_query("INSERT INTO t1 VALUES (1), (2)") 16 | 17 | 18 | def test_003_create_tablespace(): 19 | node1.run_sql_query( 20 | "CREATE TABLESPACE extended_a LOCATION '/extra_volumes/extended_a';" 21 | ) 22 | node1.run_sql_query("CREATE TABLE t2(i int) TABLESPACE extended_a;") 23 | node1.run_sql_query("INSERT INTO t2 VALUES (3), (4);") 24 | -------------------------------------------------------------------------------- /tests/tablespaces/test_tablespaces_02.py: -------------------------------------------------------------------------------- 1 | from nose.tools import * 2 | from tests.tablespaces.tablespace_utils import node1 3 | from tests.tablespaces.tablespace_utils import node2 4 | 5 | 6 | # Node 2 is spun up by Makefile, wait until it's up and replicating 7 | def test_001_init_secondary(): 8 | assert node2.wait_until_state(target_state="secondary") 9 | assert node1.wait_until_state(target_state="primary") 10 | 11 | 12 | def test_002_read_from_secondary(): 13 | results = node2.run_sql_query("SELECT * FROM t1") 14 | assert results == [(1,), (2,)] 15 | results = node2.run_sql_query("SELECT * FROM t2") 16 | assert results == [(3,), (4,)] 17 | 18 | 19 | def test_003_create_tablespace_while_streaming(): 20 | node1.run_sql_query( 21 | "CREATE TABLESPACE extended_b LOCATION '/extra_volumes/extended_b';" 22 | ) 23 | node1.run_sql_query("CREATE TABLE t3(i int) TABLESPACE extended_b;") 24 | node1.run_sql_query("INSERT INTO t3 VALUES (5), (6)") 25 | 26 | 27 | def test_004_read_from_secondary_again(): 28 | results = node2.run_sql_query("SELECT * FROM t3") 29 | assert results == [(5,), (6,)] 30 | -------------------------------------------------------------------------------- /tests/tablespaces/test_tablespaces_03.py: -------------------------------------------------------------------------------- 1 | from nose.tools import * 2 | from tests.tablespaces.tablespace_utils import node1 3 | from tests.tablespaces.tablespace_utils import node2 4 | 5 | 6 | # Failover is performed by the makefile Makefile, wait for it to complete 7 | def test_001_wait_for_failover_and_insert(): 8 | assert node2.wait_until_state(target_state="primary") 9 | assert node1.wait_until_state(target_state="secondary") 10 | 11 | node2.run_sql_query("INSERT INTO t2 VALUES (7)") 12 | results = node1.run_sql_query("SELECT * FROM t2") 13 | assert results == [(3,), (4,), (7,)] 14 | 15 | node2.run_sql_query("INSERT INTO t3 VALUES (8)") 16 | results = node1.run_sql_query("SELECT * FROM t3") 17 | assert results == [(5,), (6,), (8,)] 18 | -------------------------------------------------------------------------------- /tests/tablespaces/test_tablespaces_04.py: -------------------------------------------------------------------------------- 1 | from nose.tools import * 2 | from tests.tablespaces.tablespace_utils import node2 3 | 4 | 5 | # Node 1 is paused by the Makefile, wait for pgaf to acknowledge 6 | def test_001_old_primary_goes_down(): 7 | assert node2.wait_until_state(target_state="wait_primary") 8 | 9 | node2.run_sql_query( 10 | "CREATE TABLESPACE extended_c LOCATION '/extra_volumes/extended_c';" 11 | ) 12 | node2.run_sql_query("CREATE TABLE t4(i int) TABLESPACE extended_c;") 13 | node2.run_sql_query("INSERT INTO t4 VALUES (10), (11)") 14 | node2.run_sql_query("INSERT INTO t2 VALUES (12)") 15 | node2.run_sql_query("INSERT INTO t3 VALUES (13)") 16 | -------------------------------------------------------------------------------- /tests/tablespaces/test_tablespaces_05.py: -------------------------------------------------------------------------------- 1 | from nose.tools import * 2 | from tests.tablespaces.tablespace_utils import node1 3 | from tests.tablespaces.tablespace_utils import node2 4 | 5 | 6 | # Node 1 is brought back online by makefile, wait until it's up and replicating 7 | def test_001_original_primary_comes_back_up(): 8 | assert node1.wait_until_state(target_state="secondary") 9 | assert node2.wait_until_state(target_state="primary") 10 | 11 | results = node1.run_sql_query("SELECT * FROM t4") 12 | assert results == [(10,), (11,)] 13 | results = node1.run_sql_query("SELECT * FROM t2") 14 | assert results == [(3,), (4,), (7,), (12,)] 15 | results = node1.run_sql_query("SELECT * FROM t3") 16 | assert results == [(5,), (6,), (8,), (13,)] 17 | -------------------------------------------------------------------------------- /tests/tablespaces/test_tablespaces_06.py: -------------------------------------------------------------------------------- 1 | from nose.tools import * 2 | from tests.tablespaces.tablespace_utils import node1 3 | from tests.tablespaces.tablespace_utils import node2 4 | 5 | 6 | # Failover is performed by the makefile Makefile, wait for it to complete 7 | def test_001_promote_the_original_primary_successfully(): 8 | assert node1.wait_until_state(target_state="primary") 9 | assert node2.wait_until_state(target_state="secondary") 10 | -------------------------------------------------------------------------------- /tests/test_basic_operation_listen_flag.py: -------------------------------------------------------------------------------- 1 | import tests.pgautofailover_utils as pgautofailover 2 | from nose.tools import * 3 | 4 | cluster = None 5 | node1 = None 6 | node2 = None 7 | 8 | 9 | def setup_module(): 10 | global cluster 11 | cluster = pgautofailover.Cluster() 12 | 13 | 14 | def teardown_module(): 15 | cluster.destroy() 16 | 17 | 18 | def test_000_create_monitor(): 19 | monitor = cluster.create_monitor("/tmp/listen/monitor") 20 | monitor.run() 21 | 22 | 23 | def test_001_init_primary(): 24 | global node1 25 | node1 = cluster.create_datanode("/tmp/listen/node1", listen_flag=True) 26 | node1.create() 27 | node1.run() 28 | assert node1.wait_until_state(target_state="single") 29 | node1.wait_until_pg_is_running() 30 | 31 | 32 | def test_002_create_t1(): 33 | node1.run_sql_query("CREATE TABLE t1(a int)") 34 | node1.run_sql_query("INSERT INTO t1 VALUES (1), (2)") 35 | 36 | 37 | def test_003_init_secondary(): 38 | global node2 39 | node2 = cluster.create_datanode("/tmp/listen/node2", listen_flag=True) 40 | node2.create() 41 | node2.run() 42 | assert node2.wait_until_state(target_state="secondary") 43 | assert node1.wait_until_state(target_state="primary") 44 | 45 | 46 | def test_004_read_from_secondary(): 47 | results = node2.run_sql_query("SELECT * FROM t1") 48 | assert results == [(1,), (2,)] 49 | 50 | 51 | @raises(Exception) 52 | def test_005_writes_to_node2_fail(): 53 | node2.run_sql_query("INSERT INTO t1 VALUES (3)") 54 | 55 | 56 | def test_006_fail_primary(): 57 | node1.fail() 58 | assert node2.wait_until_state(target_state="wait_primary") 59 | 60 | 61 | def test_007_writes_to_node2_succeed(): 62 | node2.run_sql_query("INSERT INTO t1 VALUES (3)") 63 | results = node2.run_sql_query("SELECT * FROM t1") 64 | assert results == [(1,), (2,), (3,)] 65 | 66 | 67 | def test_008_start_node1_again(): 68 | node1.run() 69 | assert node2.wait_until_state(target_state="primary") 70 | assert node1.wait_until_state(target_state="secondary") 71 | 72 | 73 | def test_009_read_from_new_secondary(): 74 | results = node1.run_sql_query("SELECT * FROM t1") 75 | assert results == [(1,), (2,), (3,)] 76 | 77 | 78 | @raises(Exception) 79 | def test_010_writes_to_node1_fail(): 80 | node1.run_sql_query("INSERT INTO t1 VALUES (3)") 81 | 82 | 83 | def test_011_fail_secondary(): 84 | node1.fail() 85 | assert node2.wait_until_state(target_state="wait_primary") 86 | -------------------------------------------------------------------------------- /tests/test_config_get_set.py: -------------------------------------------------------------------------------- 1 | import tests.pgautofailover_utils as pgautofailover 2 | from nose.tools import assert_raises, raises, eq_ 3 | 4 | import os 5 | import shutil 6 | import subprocess 7 | import time 8 | 9 | cluster = None 10 | monitor = None 11 | node1 = None 12 | 13 | 14 | def setup_module(): 15 | global cluster 16 | cluster = pgautofailover.Cluster() 17 | 18 | 19 | def teardown_module(): 20 | cluster.destroy() 21 | 22 | 23 | def test_000_create_monitor(): 24 | global monitor 25 | monitor = cluster.create_monitor("/tmp/config_test/monitor") 26 | monitor.run() 27 | 28 | 29 | def test_001_init_primary(): 30 | global node1 31 | node1 = cluster.create_datanode("/tmp/config_test/node1") 32 | node1.create() 33 | 34 | # the name of the node should be "%s_%d" % ("node", node1.nodeid) 35 | eq_(node1.get_nodename(), "node_%d" % node1.get_nodeid()) 36 | 37 | # we can change the name on the monitor with pg_autoctl set node metadata 38 | node1.set_metadata(name="node a") 39 | eq_(node1.get_nodename(), "node a") 40 | 41 | node1.run() 42 | assert node1.wait_until_state(target_state="single") 43 | 44 | # we can also change the name directly in the configuration file 45 | node1.config_set("pg_autoctl.name", "a") 46 | 47 | # wait until the reload signal has been processed before checking 48 | time.sleep(2) 49 | eq_(node1.get_nodename(), "a") 50 | 51 | 52 | def test_002_config_set_monitor(): 53 | pg_ctl = monitor.config_get("postgresql.pg_ctl") 54 | 55 | # set something non-default to assert no side-effects later 56 | sslmode = "prefer" 57 | monitor.config_set("ssl.sslmode", sslmode) 58 | 59 | # set monitor config postgresql.pg_ctl to something invalid 60 | with assert_raises(subprocess.CalledProcessError): 61 | monitor.config_set("postgresql.pg_ctl", "invalid") 62 | 63 | # it should not get changed 64 | eq_(monitor.config_get("postgresql.pg_ctl"), pg_ctl) 65 | 66 | # try again with a keeper 67 | pg_ctl = node1.config_get("postgresql.pg_ctl") 68 | 69 | # set the keeper to something invalid 70 | with assert_raises(subprocess.CalledProcessError): 71 | node1.config_set("postgresql.pg_ctl", "invalid") 72 | 73 | # it should not get changed 74 | eq_(node1.config_get("postgresql.pg_ctl"), pg_ctl) 75 | 76 | # pg_ctl can be moved and `config set` will still operate. 77 | shutil.copy(pg_ctl, "/tmp/pg_ctl") 78 | monitor.config_set("postgresql.pg_ctl", "/tmp/pg_ctl") 79 | # "move" pg_ctl 80 | os.remove("/tmp/pg_ctl") 81 | monitor.config_set("postgresql.pg_ctl", pg_ctl) 82 | 83 | eq_(monitor.config_get("postgresql.pg_ctl"), pg_ctl) 84 | 85 | # no side effects 86 | eq_(monitor.config_get("ssl.sslmode"), sslmode) 87 | -------------------------------------------------------------------------------- /tests/test_create_run.py: -------------------------------------------------------------------------------- 1 | import tests.pgautofailover_utils as pgautofailover 2 | import time 3 | 4 | cluster = None 5 | monitor = None 6 | node1 = None 7 | node2 = None 8 | node3 = None 9 | 10 | 11 | def setup_module(): 12 | global cluster 13 | cluster = pgautofailover.Cluster() 14 | 15 | 16 | def teardown_module(): 17 | cluster.destroy() 18 | 19 | 20 | def test_000_create_monitor(): 21 | global monitor 22 | monitor = cluster.create_monitor("/tmp/create-run/monitor") 23 | monitor.run() 24 | 25 | 26 | def test_001_init_primary(): 27 | global node1 28 | node1 = cluster.create_datanode("/tmp/create-run/node1") 29 | node1.create(run=True) 30 | assert node1.wait_until_state(target_state="single") 31 | 32 | 33 | def test_002_create_t1(): 34 | node1.run_sql_query("CREATE TABLE t1(a int)") 35 | node1.run_sql_query("INSERT INTO t1 VALUES (1), (2)") 36 | 37 | 38 | def test_003_init_secondary(): 39 | global node2 40 | node2 = cluster.create_datanode("/tmp/create-run/node2") 41 | node2.create(run=True) 42 | assert node2.wait_until_state(target_state="secondary") 43 | assert node1.wait_until_state(target_state="primary") 44 | 45 | 46 | def test_004_read_from_secondary(): 47 | results = node2.run_sql_query("SELECT * FROM t1") 48 | assert results == [(1,), (2,)] 49 | 50 | 51 | def test_005_maintenance(): 52 | node2.enable_maintenance() 53 | assert node2.wait_until_state(target_state="maintenance") 54 | node2.fail() 55 | node1.run_sql_query("INSERT INTO t1 VALUES (3)") 56 | node2.run() 57 | node2.disable_maintenance() 58 | assert node2.wait_until_pg_is_running() 59 | assert node2.wait_until_state(target_state="secondary") 60 | assert node1.wait_until_state(target_state="primary") 61 | 62 | 63 | def test_006_fail_primary(): 64 | node1.fail() 65 | assert node2.wait_until_state(target_state="wait_primary", timeout=180) 66 | 67 | 68 | def test_007_start_node1_again(): 69 | node1.create(run=True) 70 | assert node2.wait_until_state(target_state="primary") 71 | assert node1.wait_until_state(target_state="secondary") 72 | 73 | 74 | def test_008_read_from_new_secondary(): 75 | results = node1.run_sql_query("SELECT * FROM t1 ORDER BY a") 76 | assert results == [(1,), (2,), (3,)] 77 | 78 | 79 | def test_009_fail_secondary(): 80 | node1.fail() 81 | assert node2.wait_until_state(target_state="wait_primary") 82 | 83 | 84 | def test_010_drop_secondary(): 85 | node1.run() 86 | assert node1.wait_until_state(target_state="secondary") 87 | node1.drop() 88 | time.sleep(2) # avoid timing issue 89 | assert not node1.pg_is_running() 90 | assert node2.wait_until_pg_is_running() 91 | assert node2.wait_until_state(target_state="single") 92 | -------------------------------------------------------------------------------- /tests/test_extension_update.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | import tests.pgautofailover_utils as pgautofailover 5 | from nose.tools import eq_ 6 | 7 | cluster = None 8 | 9 | 10 | def setup_module(): 11 | global cluster 12 | cluster = pgautofailover.Cluster() 13 | 14 | 15 | def teardown_module(): 16 | cluster.monitor.stop_pg_autoctl() 17 | cluster.destroy() 18 | 19 | 20 | def test_000_create_monitor(): 21 | monitor = cluster.create_monitor("/tmp/update/monitor") 22 | 23 | 24 | def test_001_update_extension(): 25 | os.environ["PG_AUTOCTL_DEBUG"] = "1" 26 | os.environ["PG_AUTOCTL_EXTENSION_VERSION"] = "dummy" 27 | 28 | cluster.monitor.run() 29 | 30 | cluster.monitor.wait_until_pg_is_running() 31 | 32 | # Wait until extension is installed 33 | time.sleep(1) 34 | 35 | results = cluster.monitor.run_sql_query( 36 | """SELECT installed_version 37 | FROM pg_available_extensions 38 | WHERE name = 'pgautofailover' 39 | """ 40 | ) 41 | 42 | if results[0][0] != "dummy": 43 | cluster.monitor.print_debug_logs() 44 | 45 | eq_(results, [("dummy",)]) 46 | 47 | del os.environ["PG_AUTOCTL_EXTENSION_VERSION"] 48 | assert "PG_AUTOCTL_EXTENSION_VERSION" not in os.environ 49 | -------------------------------------------------------------------------------- /tests/test_installcheck.py: -------------------------------------------------------------------------------- 1 | import tests.pgautofailover_utils as pgautofailover 2 | from nose.tools import * 3 | 4 | import subprocess 5 | import shutil 6 | import os 7 | import os.path 8 | 9 | cluster = None 10 | node1 = None 11 | node2 = None 12 | 13 | 14 | def setup_module(): 15 | global cluster 16 | cluster = pgautofailover.Cluster() 17 | 18 | 19 | def teardown_module(): 20 | cluster.destroy() 21 | 22 | 23 | def test_000_create_monitor(): 24 | monitor = cluster.create_monitor("/tmp/check/monitor") 25 | monitor.run() 26 | monitor.wait_until_pg_is_running() 27 | 28 | 29 | def test_001_add_hba_entry(): 30 | with open(os.path.join("/tmp/check/monitor", "pg_hba.conf"), "a") as hba: 31 | hba.write("host all all %s trust\n" % cluster.networkSubnet) 32 | 33 | # print() 34 | # with open(os.path.join("/tmp/check/monitor", "pg_hba.conf"), "r") as hba: 35 | # lines = hba.readlines() 36 | # for line in lines[-10:]: 37 | # print("%s" % line[:-1]) 38 | 39 | cluster.monitor.reload_postgres() 40 | 41 | 42 | def test_002_make_installcheck(): 43 | # support both the local Dockerfile and also Travis build environments 44 | if "TRAVIS_BUILD_DIR" in os.environ: 45 | topdir = os.environ["TRAVIS_BUILD_DIR"] 46 | else: 47 | topdir = "/usr/src/pg_auto_failover" 48 | 49 | p = subprocess.Popen( 50 | [ 51 | "sudo", 52 | shutil.which("chmod"), 53 | "-R", 54 | "go+w", 55 | os.path.join(topdir, "src/monitor"), 56 | ] 57 | ) 58 | assert p.wait() == 0 59 | 60 | p = subprocess.Popen( 61 | [ 62 | "sudo", 63 | "-E", 64 | "-u", 65 | os.getenv("USER"), 66 | "env", 67 | "PATH=" + os.getenv("PATH"), 68 | "PGHOST=" + str(cluster.monitor.vnode.address), 69 | "make", 70 | "-C", 71 | os.path.join(topdir, "src/monitor"), 72 | "installcheck", 73 | ] 74 | ) 75 | 76 | if p.wait() != 0: 77 | diff = os.path.join(topdir, "src/monitor/regression.diffs") 78 | with open(diff, "r") as d: 79 | print("%s" % d.read()) 80 | 81 | raise Exception("make installcheck failed") 82 | -------------------------------------------------------------------------------- /tests/test_monitor_disabled.py: -------------------------------------------------------------------------------- 1 | import tests.pgautofailover_utils as pgautofailover 2 | from nose.tools import * 3 | 4 | import os 5 | import json 6 | 7 | cluster = None 8 | node1 = None 9 | node2 = None 10 | node3 = None 11 | 12 | 13 | def setup_module(): 14 | global cluster 15 | cluster = pgautofailover.Cluster() 16 | 17 | 18 | def teardown_module(): 19 | cluster.destroy() 20 | 21 | 22 | def test_001_init_primary(): 23 | global node1 24 | node1 = cluster.create_datanode("/tmp/no-monitor/node1") 25 | node1.create(monitorDisabled=True, host=str(node1.vnode.address), nodeId=1) 26 | node1.run(name="a") 27 | 28 | 29 | def test_002_init_to_single(): 30 | node1.do_fsm_assign("single") 31 | 32 | 33 | def test_003_create_t1(): 34 | node1.run_sql_query("CREATE TABLE t1(a int)") 35 | node1.run_sql_query("INSERT INTO t1 VALUES (1), (2)") 36 | 37 | 38 | def test_004_init_secondary(): 39 | global node2 40 | node2 = cluster.create_datanode("/tmp/no-monitor/node2") 41 | node2.create(monitorDisabled=True, host=str(node2.vnode.address), nodeId=2) 42 | node2.run(name="b") 43 | 44 | 45 | def test_005_fsm_nodes_set(): 46 | nodesArray = [node1.jsDict("0/1", True), node2.jsDict("0/1", False)] 47 | 48 | node1.do_fsm_nodes_set(nodesArray) 49 | node2.do_fsm_nodes_set(nodesArray) 50 | 51 | 52 | def test_006_init_to_wait_standby(): 53 | node2.do_fsm_assign("wait_standby") 54 | 55 | 56 | def test_007_catchingup(): 57 | node1.do_fsm_assign("wait_primary") 58 | node2.do_fsm_assign("catchingup") 59 | 60 | 61 | def test_008_secondary(): 62 | node1.do_fsm_assign("primary") 63 | node2.do_fsm_assign("secondary") 64 | 65 | eq_(node1.get_synchronous_standby_names_local(), "*") 66 | 67 | 68 | def test_009_init_secondary(): 69 | global node3 70 | node3 = cluster.create_datanode("/tmp/no-monitor/node3") 71 | node3.create(monitorDisabled=True, host=str(node3.vnode.address), nodeId=3) 72 | node3.run(name="c") 73 | 74 | 75 | def test_010_fsm_nodes_set(): 76 | LSN1 = node1.run_sql_query("select pg_current_wal_flush_lsn()")[0][0] 77 | LSN2 = node2.run_sql_query("select pg_last_wal_receive_lsn()")[0][0] 78 | nodesArray = [ 79 | node1.jsDict(LSN1, True), 80 | node2.jsDict(LSN2, False), 81 | node3.jsDict("0/1", False), 82 | ] 83 | 84 | node1.do_fsm_nodes_set(nodesArray) 85 | node2.do_fsm_nodes_set(nodesArray) 86 | node3.do_fsm_nodes_set(nodesArray) 87 | 88 | 89 | def test_011_init_to_wait_standby(): 90 | node1.do_fsm_assign("primary") 91 | node3.do_fsm_assign("wait_standby") 92 | 93 | eq_(node1.get_synchronous_standby_names_local(), "*") 94 | 95 | 96 | def test_012_catchingup(): 97 | node3.do_fsm_assign("catchingup") 98 | 99 | eq_(node1.get_synchronous_standby_names_local(), "*") 100 | 101 | 102 | def test_013_secondary(): 103 | node3.do_fsm_assign("secondary") 104 | node1.do_fsm_assign("primary") 105 | 106 | # no monitor: use the generic value '*' 107 | eq_(node1.get_synchronous_standby_names_local(), "*") 108 | -------------------------------------------------------------------------------- /tests/test_ssl_self_signed.py: -------------------------------------------------------------------------------- 1 | import tests.pgautofailover_utils as pgautofailover 2 | 3 | from nose.tools import eq_ 4 | 5 | import os.path 6 | 7 | cluster = None 8 | node1 = None 9 | node2 = None 10 | 11 | 12 | def setup_module(): 13 | global cluster 14 | cluster = pgautofailover.Cluster() 15 | 16 | 17 | def teardown_module(): 18 | cluster.destroy() 19 | 20 | 21 | def test_000_create_monitor(): 22 | monitor = cluster.create_monitor( 23 | "/tmp/ssl-self-signed/monitor", sslSelfSigned=True 24 | ) 25 | 26 | monitor.run() 27 | monitor.wait_until_pg_is_running() 28 | monitor.check_ssl("on", "require") 29 | 30 | 31 | def test_001_init_primary(): 32 | global node1 33 | node1 = cluster.create_datanode( 34 | "/tmp/ssl-self-signed/node1", sslSelfSigned=True 35 | ) 36 | node1.create() 37 | node1.run() 38 | assert node1.wait_until_state(target_state="single") 39 | 40 | node1.wait_until_pg_is_running() 41 | node1.check_ssl("on", "require", primary=True) 42 | 43 | 44 | def test_002_create_t1(): 45 | node1.run_sql_query("CREATE TABLE t1(a int)") 46 | node1.run_sql_query("INSERT INTO t1 VALUES (1), (2)") 47 | 48 | 49 | def test_003_init_secondary(): 50 | global node2 51 | node2 = cluster.create_datanode( 52 | "/tmp/ssl-self-signed/node2", sslSelfSigned=True, sslMode="require" 53 | ) 54 | 55 | node2.create() 56 | node2.run() 57 | 58 | assert node2.wait_until_state(target_state="secondary") 59 | assert node1.wait_until_state(target_state="primary") 60 | 61 | node2.wait_until_pg_is_running() 62 | node2.check_ssl("on", "require") 63 | 64 | 65 | def test_004_failover(): 66 | print() 67 | print("Calling pgautofailover.failover() on the monitor") 68 | cluster.monitor.failover() 69 | assert node2.wait_until_state(target_state="primary") 70 | assert node1.wait_until_state(target_state="secondary") 71 | -------------------------------------------------------------------------------- /tests/upgrade/Makefile: -------------------------------------------------------------------------------- 1 | NODES ?= 3 2 | 3 | PATCH = tests/upgrade/monitor-upgrade-1.7.patch 4 | Q_VERSION = select default_version, installed_version 5 | Q_VERSION += from pg_available_extensions where name = 'pgautofailover' 6 | 7 | build: 8 | docker compose build 9 | 10 | patch: 11 | cd ../.. && git apply $(PATCH) 12 | 13 | clean: 14 | cd ../.. && git apply --reverse $(PATCH) 15 | 16 | up: create-volumes compose-up tail ; 17 | 18 | down: compose-down rm-volumes ; 19 | 20 | compose-down: 21 | docker compose down --volumes --remove-orphans 22 | 23 | compose-up: 24 | docker compose up -d 25 | 26 | tail: 27 | docker compose logs -f 28 | 29 | create-volumes: 30 | for v in volm vol1 vol2 vol3; do docker volume create $$v; done 31 | 32 | rm-volumes: 33 | for v in volm vol1 vol2 vol3; do docker volume rm $$v; done 34 | 35 | upgrade-monitor: patch 36 | docker compose up -d --no-deps --build monitor 37 | 38 | upgrade-nodes: 39 | docker compose up -d --no-deps --build node3 node2 40 | docker compose up -d --no-deps --build node1 41 | 42 | state: 43 | docker compose exec monitor pg_autoctl show state 44 | 45 | version: 46 | docker compose exec monitor pg_autoctl version 47 | docker compose exec monitor psql -d pg_auto_failover -c "$(Q_VERSION)" 48 | 49 | failover: 50 | docker compose exec monitor pg_autoctl perform failover 51 | 52 | watch: 53 | docker compose exec monitor watch -n 0.2 pg_autoctl show state 54 | 55 | .PHONY: build patch clean up down upgrade-monitor state watch 56 | .PHONY: compose-down compose-up create-volumes rm-volumes 57 | -------------------------------------------------------------------------------- /tests/upgrade/README.md: -------------------------------------------------------------------------------- 1 | # Testing monitor upgrades 2 | 3 | This directory contains some docker compose based tooling to manually test 4 | monitor upgrades. The tooling is built around the idea that we want to test 5 | what happens at upgrade from the code in the local branch. 6 | 7 | It might be possible to also test what happens when we upgrade from a 8 | previously released version with some edits in this tooling, though that's 9 | not the main use-case here. 10 | 11 | A typical manual session looks like the following. First, let us prepare a 12 | tmux environment with two panes. The top pane will show the logs from all 13 | the nodes running within the docker compose orchestration: 14 | 15 | ```bash 16 | $ tmux 17 | $ tmux split-window -v 18 | ``` 19 | 20 | Now, in the first pane, build our images and start all our services: 21 | 22 | ```bash 23 | # in the first pane 24 | $ make build 25 | $ make up 26 | ``` 27 | 28 | Now, in the second pane, watch until the cluster has reached a stable state 29 | (primary/secondary/secondary) before we go on to upgrade the monitor. 30 | 31 | ```bash 32 | # in the second pane 33 | $ make watch 34 | ``` 35 | 36 | To upgrade the monitor we apply a local patch that provides version 1.7 37 | (with no schema changes, just version number hacking), build an updated 38 | docker image using the patch, and restart the monitor with this new version: 39 | 40 | ```bash 41 | # in the second pane 42 | $ make version 43 | $ make upgrade-monitor 44 | ``` 45 | 46 | To check that the upgrade went well, we can do: 47 | 48 | ```bash 49 | # in the second pane 50 | $ make version 51 | $ make state 52 | ``` 53 | 54 | We should see the Postgres nodes being verbose about the monitor having been 55 | upgraded, but not the nodes. It is possible to now upgrade the nodes to the 56 | current version too, though that's not the goal of this work at the moment. 57 | 58 | ```bash 59 | # in the second pane 60 | $ make upgrade-nodes 61 | 62 | # in the first pane, C-c the current logs session, and re-attach 63 | $ make tail 64 | 65 | # in the second page 66 | $ make version 67 | $ make state 68 | ``` 69 | 70 | To test a failover: 71 | 72 | ```bash 73 | $ make failover 74 | $ make state 75 | ``` 76 | 77 | Time to clean-up our local repository: 78 | 79 | ```bash 80 | # in the second pane 81 | $ make down 82 | $ make clean 83 | ``` 84 | -------------------------------------------------------------------------------- /tests/upgrade/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | monitor: 3 | build: ../.. 4 | hostname: monitor 5 | volumes: 6 | - monitor_data:/var/lib/postgres:rw 7 | environment: 8 | PGDATA: /var/lib/postgres/pgaf 9 | command: pg_autoctl create monitor --ssl-self-signed --auth trust --run 10 | expose: 11 | - 5432 12 | node1: 13 | build: ../.. 14 | hostname: node1 15 | volumes: 16 | - node1_data:/var/lib/postgres:rw 17 | environment: 18 | PGDATA: /var/lib/postgres/pgaf 19 | PGUSER: ad 20 | PGDATABASE: analytics 21 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 22 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 23 | expose: 24 | - 5432 25 | node2: 26 | build: ../.. 27 | hostname: node2 28 | volumes: 29 | - node2_data:/var/lib/postgres:rw 30 | environment: 31 | PGDATA: /var/lib/postgres/pgaf 32 | PGUSER: ad 33 | PGDATABASE: analytics 34 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 35 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 36 | expose: 37 | - 5432 38 | node3: 39 | build: ../.. 40 | hostname: node3 41 | volumes: 42 | - node3_data:/var/lib/postgres:rw 43 | environment: 44 | PGDATA: /var/lib/postgres/pgaf 45 | PGUSER: ad 46 | PGDATABASE: analytics 47 | PG_AUTOCTL_MONITOR: "postgresql://autoctl_node@monitor/pg_auto_failover" 48 | command: pg_autoctl create postgres --ssl-self-signed --auth trust --pg-hba-lan --run 49 | expose: 50 | - 5432 51 | 52 | volumes: 53 | monitor_data: 54 | external: true 55 | name: volm 56 | node1_data: 57 | external: true 58 | name: vol1 59 | node2_data: 60 | external: true 61 | name: vol2 62 | node3_data: 63 | external: true 64 | name: vol3 65 | -------------------------------------------------------------------------------- /tests/upgrade/monitor-upgrade-1.7.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/bin/pg_autoctl/defaults.h b/src/bin/pg_autoctl/defaults.h 2 | index 8e7e2eaf..643dc96a 100644 3 | --- a/src/bin/pg_autoctl/defaults.h 4 | +++ b/src/bin/pg_autoctl/defaults.h 5 | @@ -17,7 +17,7 @@ 6 | #define PG_AUTOCTL_VERSION "1.6.2" 7 | 8 | /* version of the extension that we requite to talk to on the monitor */ 9 | -#define PG_AUTOCTL_EXTENSION_VERSION "1.6" 10 | +#define PG_AUTOCTL_EXTENSION_VERSION "1.7" 11 | 12 | /* environment variable to use to make DEBUG facilities available */ 13 | #define PG_AUTOCTL_DEBUG "PG_AUTOCTL_DEBUG" 14 | diff --git a/src/monitor/Makefile b/src/monitor/Makefile 15 | index 8e6bf321..478fb2a7 100644 16 | --- a/src/monitor/Makefile 17 | +++ b/src/monitor/Makefile 18 | @@ -2,7 +2,7 @@ 19 | # Licensed under the PostgreSQL License. 20 | 21 | EXTENSION = pgautofailover 22 | -EXTVERSION = 1.6 23 | +EXTVERSION = 1.7 24 | 25 | SRC_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 26 | 27 | diff --git a/src/monitor/metadata.h b/src/monitor/metadata.h 28 | index 9e50ab72..0f8b39a3 100644 29 | --- a/src/monitor/metadata.h 30 | +++ b/src/monitor/metadata.h 31 | @@ -15,7 +15,7 @@ 32 | 33 | #include "storage/lockdefs.h" 34 | 35 | -#define AUTO_FAILOVER_EXTENSION_VERSION "1.6" 36 | +#define AUTO_FAILOVER_EXTENSION_VERSION "1.7" 37 | #define AUTO_FAILOVER_EXTENSION_NAME "pgautofailover" 38 | #define AUTO_FAILOVER_SCHEMA_NAME "pgautofailover" 39 | #define AUTO_FAILOVER_FORMATION_TABLE "pgautofailover.formation" 40 | diff --git a/src/monitor/pgautofailover--1.6--1.7.sql b/src/monitor/pgautofailover--1.6--1.7.sql 41 | new file mode 100644 42 | index 00000000..7167ee17 43 | --- /dev/null 44 | +++ b/src/monitor/pgautofailover--1.6--1.7.sql 45 | @@ -0,0 +1,6 @@ 46 | +-- 47 | +-- dummy extension update file that does nothing 48 | +-- 49 | +-- complain if script is sourced in psql, rather than via CREATE EXTENSION 50 | +\echo Use "ALTER EXTENSION pgautofailover UPDATE TO dummy" to load this file. \quit 51 | + 52 | diff --git a/src/monitor/pgautofailover.control b/src/monitor/pgautofailover.control 53 | index a649eb76..d0504410 100644 54 | --- a/src/monitor/pgautofailover.control 55 | +++ b/src/monitor/pgautofailover.control 56 | @@ -1,5 +1,5 @@ 57 | comment = 'pg_auto_failover' 58 | -default_version = '1.6' 59 | +default_version = '1.7' 60 | module_pathname = '$libdir/pgautofailover' 61 | relocatable = false 62 | requires = 'btree_gist' 63 | -------------------------------------------------------------------------------- /valgrind/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | --------------------------------------------------------------------------------