diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b88527bc42b9163e0265bf05cebb842bf765326e..fdd013414fe837347159cafede7f562cc68c538a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -71,4 +71,18 @@ test: script: - make test +test-ha-pgsql: + image: registry.ubicast.net/mediaserver/envsetup:root + stage: test + tags: + - docker + rules: + - if: '$CI_PIPELINE_SOURCE == "web"' + - if: '$CI_PIPELINE_SOURCE == "merge_requests"' + - if: '$CI_PIPELINE_SOURCE == "push"' + changes: + - ansible/**/* + script: + - make test ha-pgsql=1 + ... diff --git a/Makefile b/Makefile index d095bdfb9a6d9ec642b3e7c66c0468aeeaa3bc29..dfba16e865d1a440423fe0d8366ca66a8918bfc3 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ endif ifdef keep MOLECULE_TEST_FLAGS += --destroy=never --parallel endif +ifdef ha-pgsql + MOLECULE_TEST_FLAGS += --scenario-name ha-pgsql +endif .PHONY: all ## TARGET: DESCRIPTION: ARGS @@ -58,7 +61,7 @@ lint: ANSIBLE_CONFIG=$(ANSIBLE_CONFIG) $(ANSIBLE_LINT_BIN) ansible/playbooks/site.yml .PHONY: test -## test: Run development tests on the project : debug=1, keep=1, SKYREACH_SYSTEM_KEY=<xxx> +## test: Run development tests on the project : debug=1, keep=1, SKYREACH_SYSTEM_KEY=<xxx>, ha-pgsql=1 test: ifndef SKYREACH_SYSTEM_KEY $(error SKYREACH_SYSTEM_KEY is undefined) diff --git a/ansible/molecule/default/molecule.yml b/ansible/molecule/default/molecule.yml index 97d2cd3968781fdcfb75965dbc11c8cb63ce69d4..d63f4715dfff22585692d6ea5e9dd98cfb712f22 100644 --- a/ansible/molecule/default/molecule.yml +++ b/ansible/molecule/default/molecule.yml @@ -24,6 +24,8 @@ platforms: - netcapture provisioner: name: ansible + options: + D: true env: ANSIBLE_ROLES_PATH: ../../roles ANSIBLE_LIBRARY: ../../library diff --git a/ansible/molecule/ha-pgsql/converge.yml b/ansible/molecule/ha-pgsql/converge.yml new file mode 100644 index 0000000000000000000000000000000000000000..58ea8718716da92a4a5e63aa39d7ef016c1bc3bd --- /dev/null +++ b/ansible/molecule/ha-pgsql/converge.yml @@ -0,0 +1,40 @@ +#!/usr/bin/env ansible-playbook +--- + +- name: PYTHON + hosts: all + gather_facts: false + tasks: + - name: ensure python3 is installed + register: python_install + changed_when: "'es_pyinstall' in python_install.stdout_lines" + raw: command -v python3 || echo es_pyinstall && apt update && apt install -y python3-minimal python3-apt + +- name: Converge + hosts: postgres + pre_tasks: + - name: check running in a docker container + register: check_if_docker + stat: + path: /.dockerenv + - name: set docker flag variable + set_fact: + in_docker: "{{ check_if_docker.stat.exists | d(false) }}" + roles: + - base + - postgres-ha + post_tasks: + - name: deploy letsencrypt certificate + when: letsencrypt_enabled | d(false) + include_role: + name: letsencrypt + - name: configure network + when: network_apply | d(false) + include_role: + name: network + - name: configure proxy + when: proxy_apply | d(false) + include_role: + name: proxy + +... diff --git a/ansible/molecule/ha-pgsql/molecule.yml b/ansible/molecule/ha-pgsql/molecule.yml new file mode 100644 index 0000000000000000000000000000000000000000..7dc2309583092056804d3cba5f3df7b27f962096 --- /dev/null +++ b/ansible/molecule/ha-pgsql/molecule.yml @@ -0,0 +1,56 @@ +--- +driver: + name: docker +platforms: + - name: db0-default + image: registry.ubicast.net/docker/debian-systemd:buster + command: /lib/systemd/systemd + privileged: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + tmpfs: + - /tmp + - /run + groups: + - postgres + - name: db1-default + image: registry.ubicast.net/docker/debian-systemd:buster + command: /lib/systemd/systemd + privileged: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + tmpfs: + - /tmp + - /run + groups: + - postgres + - name: db2-default + image: registry.ubicast.net/docker/debian-systemd:buster + command: /lib/systemd/systemd + privileged: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + tmpfs: + - /tmp + - /run + groups: + - postgres +provisioner: + name: ansible + options: + D: true + inventory: + group_vars: + postgres: + repmgr_password: "testrepmgr" + env: + ANSIBLE_ROLES_PATH: ../../roles + ANSIBLE_LIBRARY: ../../library + ANSIBLE_ACTION_PLUGINS: ../../plugins/action + ANSIBLE_PYTHON_INTERPRETER: /usr/bin/python3 + SKYREACH_SYSTEM_KEY: s1121eb6e7593525bf3e0302586c82d2 + +verifier: + name: testinfra + options: + verbose: true diff --git a/ansible/molecule/ha-pgsql/tests/commons.py b/ansible/molecule/ha-pgsql/tests/commons.py new file mode 100644 index 0000000000000000000000000000000000000000..e7318b13789ba836201d1f683dc0aed4f4fc9937 --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/commons.py @@ -0,0 +1,9 @@ +import socket + + +def get_status(host): + ip = host.interface('eth0').addresses[0] + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((ip, 8543)) + data = s.recv(1024) + return data.rstrip().decode('utf-8') diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_a_setup.py b/ansible/molecule/ha-pgsql/tests/test_postgres_a_setup.py new file mode 100644 index 0000000000000000000000000000000000000000..3a2adcbbbac8685d89bbce661941943250336bb6 --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_a_setup.py @@ -0,0 +1,39 @@ +import os + +import testinfra.utils.ansible_runner + +# /!\ This test run accross all servers +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("postgres") + + +def test_psycopg2_is_installed(host): + p = host.package("python3-psycopg2") + + assert p.is_installed + + +def test_postgres_is_installed(host): + p = host.package("postgresql-11") + + assert p.is_installed + assert p.version.startswith("11") + + +def test_postgres_user(host): + u = host.user("postgres") + + assert u.name == "postgres" + + +def test_postgres_service(host): + s = host.service("postgresql@11-main") + + assert s.is_running + + +def test_postgresql_socket(host): + s = host.socket("tcp://127.0.0.1:5432") + + assert s.is_listening diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_b_cluster_status.py b/ansible/molecule/ha-pgsql/tests/test_postgres_b_cluster_status.py new file mode 100644 index 0000000000000000000000000000000000000000..b7de4bd3aad37a485af73f44f98109d661886d32 --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_b_cluster_status.py @@ -0,0 +1,22 @@ +import os + +import testinfra.utils.ansible_runner + +import commons + +# This test run accross all servers +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("postgres") + + +def test_postgresql_check_repmgr_status(host): + ''' check if repmgr is working correctly on each node''' + + if host.ansible.get_variables()["inventory_hostname"].startswith("db0-default"): + data = commons.get_status(host) + assert data == "primary" + if host.ansible.get_variables()["inventory_hostname"].startswith("db1-default"): + data = commons.get_status(host) + assert data == "standby" + if host.ansible.get_variables()["inventory_hostname"].startswith("db2-default"): + data = commons.get_status(host) + assert data == "witness" diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_c_test_cluster_primary.py b/ansible/molecule/ha-pgsql/tests/test_postgres_c_test_cluster_primary.py new file mode 100644 index 0000000000000000000000000000000000000000..b9a391fb77277cb549867ba0db5c8a65e62b62bf --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_c_test_cluster_primary.py @@ -0,0 +1,27 @@ +import os + +import testinfra.utils.ansible_runner + +# This test run accross all servers +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("db0-default") + + +def test_postgresql_create_db(host): + ''' check if we can only create db on the primary node of the cluster ''' + + s = host.ansible("postgresql_db", "name=test", become=True, check=False, become_user='postgres') + assert s["changed"] + + +def test_postgresql_create_table(host): + ''' check if we can only create a table on the primary node of the cluster ''' + + s = host.ansible("postgresql_query", "db=test query='CREATE TABLE test_ha (id SERIAL PRIMARY KEY, name VARCHAR(100) );'", become=True, check=False, become_user='postgres') + assert s["changed"] + + +def test_postgresql_insert(host): + ''' check if we can only write to the primary node of the cluster ''' + + s = host.ansible("postgresql_query", "db=test query='INSERT INTO test_ha (name) VALUES (\'test\');'", become=True, check=False, become_user='postgres') + assert s["changed"] diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_d_test_cluster_secondary.py b/ansible/molecule/ha-pgsql/tests/test_postgres_d_test_cluster_secondary.py new file mode 100644 index 0000000000000000000000000000000000000000..981b98be92ad96bc1575914b11d969f9eb71f7a9 --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_d_test_cluster_secondary.py @@ -0,0 +1,27 @@ +import os + +import testinfra.utils.ansible_runner + +# This test run accross all servers +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("db1-default") + + +def test_postgresql_create_db(host): + ''' check if we can only create db on the primary node of the cluster ''' + + s = host.ansible("postgresql_db", "name=test", become=True, check=False, become_user='postgres') + assert not s["changed"] + + +def test_postgresql_create_table(host): + ''' check if we can only create a table on the primary node of the cluster ''' + + s = host.ansible("postgresql_query", "db=test query='CREATE TABLE test_ha (id SERIAL PRIMARY KEY, name VARCHAR(100) );'", become=True, check=False, become_user='postgres') + assert not s["changed"] + + +def test_postgresql_insert(host): + ''' check if we can only write to the primary node of the cluster ''' + + s = host.ansible("postgresql_query", "db=test query='INSERT INTO test_ha (name) VALUES (\'test\');'", become=True, check=False, become_user='postgres') + assert not s["changed"] diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_e_shutdown_primary.py b/ansible/molecule/ha-pgsql/tests/test_postgres_e_shutdown_primary.py new file mode 100644 index 0000000000000000000000000000000000000000..df5b3a51d096463ac4259b7d907374dfd9916788 --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_e_shutdown_primary.py @@ -0,0 +1,20 @@ +import os + +import testinfra.utils.ansible_runner + +import time + + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("db0-default") + + +def test_postgresql_check_shutdown_primary(host): + ''' Shutdown the primary server ''' + + s = host.ansible("command", "systemctl stop postgresql", become=True, check=False) + assert s['changed'] + + time.sleep(40) + + s = host.socket("tcp://127.0.0.1:5432") + assert not s.is_listening diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_f_new_primary_cluster_status.py b/ansible/molecule/ha-pgsql/tests/test_postgres_f_new_primary_cluster_status.py new file mode 100644 index 0000000000000000000000000000000000000000..9f9c8edb95a0391f2703739aad596b9042e2c391 --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_f_new_primary_cluster_status.py @@ -0,0 +1,22 @@ +import os + +import testinfra.utils.ansible_runner + +import commons + +# /!\ This test run accross all servers +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("postgres") + + +def test_postgresql_check_repmgr_new_master(host): + ''' check repmgr status for each node after new master election ''' + + if host.ansible.get_variables()["inventory_hostname"].startswith("db0-default"): + data = commons.get_status(host) + assert data == "fenced" + if host.ansible.get_variables()["inventory_hostname"].startswith("db1-default"): + data = commons.get_status(host) + assert data == "primary" + if host.ansible.get_variables()["inventory_hostname"].startswith("db2-default"): + data = commons.get_status(host) + assert data == "witness" diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_g_new_primary_write.py b/ansible/molecule/ha-pgsql/tests/test_postgres_g_new_primary_write.py new file mode 100644 index 0000000000000000000000000000000000000000..0ff31ac0b54b59129843c42a055af19c957170db --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_g_new_primary_write.py @@ -0,0 +1,11 @@ +import os + +import testinfra.utils.ansible_runner + + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("db1-default") + + +def test_postgresql_insert_new_master(host): + s = host.ansible("postgresql_query", "db=test query='INSERT INTO test_ha (name) VALUES (\'test2\');'", become=True, check=False, become_user='postgres') + assert s["changed"] diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_h_reintegrate_server.py b/ansible/molecule/ha-pgsql/tests/test_postgres_h_reintegrate_server.py new file mode 100644 index 0000000000000000000000000000000000000000..e61ff3dcd483e86d6ef8e36fb0ed5841627e8476 --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_h_reintegrate_server.py @@ -0,0 +1,39 @@ +import os + +import testinfra.utils.ansible_runner +import time + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("db0-default") + + +def test_postgresql_delete_data(host): + ''' delete data directory ''' + + s = host.ansible("command", "rm -rf /var/lib/postgresql/11/main/", become=True, check=False) + assert s['changed'] + + +def test_postgresql_launch_repmgr_sync(host): + ''' sync data with primary server using repmgr ''' + + current_master = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_host("db1-default") + current_master_ip = current_master.interface('eth0').addresses[0] + rep_mgr_command = "repmgr -f /etc/postgresql/11/main/repmgr.conf --force --verbose standby clone -h " + current_master_ip + " -d repmgr -U repmgr -c" + s = host.ansible("command", rep_mgr_command, become=True, become_user='postgres', check=False) + assert s['changed'] + + +def test_postgresql_start_postgresql(host): + ''' start postgresql ''' + + s = host.ansible("command", "systemctl start postgresql", become=True, check=False) + time.sleep(20) + assert s['changed'] + + +def test_pogresql_register_as_standby(host): + ''' register server as standby in repmgr ''' + + s = host.ansible("command", "repmgr -f /etc/postgresql/11/main/repmgr.conf --force --verbose standby register", become=True, become_user='postgres', check=False) + time.sleep(20) + assert s['changed'] diff --git a/ansible/molecule/ha-pgsql/tests/test_postgres_i_final_cluster_status.py b/ansible/molecule/ha-pgsql/tests/test_postgres_i_final_cluster_status.py new file mode 100644 index 0000000000000000000000000000000000000000..1956ddf37fc56ed9363c9862eb0a8f71bcc3c14a --- /dev/null +++ b/ansible/molecule/ha-pgsql/tests/test_postgres_i_final_cluster_status.py @@ -0,0 +1,22 @@ +import os + +import testinfra.utils.ansible_runner + +import commons + +# /!\ This test run accross all servers +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(os.environ["MOLECULE_INVENTORY_FILE"]).get_hosts("postgres") + + +def test_postgresql_check_status_after_shutdown(host): + ''' check repmgr status accross server after primary change and server reintegration ''' + + if host.ansible.get_variables()["inventory_hostname"].startswith("db0-default"): + data = commons.get_status(host) + assert data == "standby" + if host.ansible.get_variables()["inventory_hostname"].startswith("db1-default"): + data = commons.get_status(host) + assert data == "primary" + if host.ansible.get_variables()["inventory_hostname"].startswith("db2-default"): + data = commons.get_status(host) + assert data == "witness" diff --git a/ansible/playbooks/postgres-maintenance.yml b/ansible/playbooks/postgres-maintenance.yml new file mode 100755 index 0000000000000000000000000000000000000000..80ae73554800a8ef472cb2bde533dd6f5631648f --- /dev/null +++ b/ansible/playbooks/postgres-maintenance.yml @@ -0,0 +1,70 @@ +#!/usr/bin/env ansible-playbook +--- + +- name: GATHER FACTS + hosts: postgres_primary:postgres_standby:postgres_fenced + tags: always + tasks: + - name: get cluster state + command: "rephacheck" + register: rephacheck + - name: show status for each node + debug: + msg: "Current node {{ ansible_hostname }} status {{ rephacheck['stdout'] }}" + when: rephacheck['stdout'] != "" + +- name: POSTGRESQL SWITCH CURRENT STANDBY TO PRIMARY + hosts: postgres_standby + tags: [ 'never', 'standby-to-primary' ] + tasks: + - name: fail if node status if not standby + fail: + msg: "Current status {{ rephacheck['stdout'] }} must be standby." + when: rephacheck['stdout'] != "standby" + - name: check if node is currently in standby + command: "repmgr standby switchover -f /etc/postgresql/11/main/repmgr.conf --siblings-follow --dry-run" + become: yes + become_user: postgres + when: rephacheck['stdout'] == "standby" + register: standby_dry_run + - name: switch standby node to primary + command: "repmgr standby switchover -f /etc/postgresql/11/main/repmgr.conf --siblings-follow" + become: yes + become_user: postgres + when: + - standby_dry_run is succeeded + - rephacheck['stdout'] == "standby" + +- name: POSTGRESQL SWITCH CURRENT FENCED TO STANDBY + hosts: postgres_fenced + tags: [ 'never' , 'fenced-to-standby' ] + tasks: + - name: fail if node status if not fenced + fail: + msg: "Current status {{ rephacheck['stdout'] }} must be fenced." + when: rephacheck['stdout'] != "fenced" + - name: stop postgresql + systemd: + name: postgresql + state: stopped + - name: delete postgresql data directory + file: + path: /var/lib/postgresql/11/main/ + state: absent + force: yes + - name: copy data from primary + command: "repmgr -f /etc/postgresql/11/main/repmgr.conf --force --verbose standby clone -h {{ hostvars[groups['postgres_primary'][0]]['ansible_default_ipv4']['address'] }} -d repmgr -U repmgr -c" + become: yes + become_user: postgres + register: copy_from_primary + - name: start postgresql + systemd: + name: postgresql + state: started + when: copy_from_primary is succeeded + - name: register node as standby + command: "repmgr -f /etc/postgresql/11/main/repmgr.conf --force --verbose standby register" + become: yes + become_user: postgres + when: copy_from_primary is succeeded +... diff --git a/ansible/playbooks/site.yml b/ansible/playbooks/site.yml index e86b5c07195cb3df11c576dcc2fca3d9de5b8273..64c4184a7e39c53e35b8cb4e647b50ae0f9355d8 100755 --- a/ansible/playbooks/site.yml +++ b/ansible/playbooks/site.yml @@ -8,7 +8,7 @@ - name: ensure python3 is installed register: python_install changed_when: "'es_pyinstall' in python_install.stdout_lines" - raw: command -v python3 || echo es_pyinstall && apt update && apt install -y python3-minimal python3-apt + raw: command -v python3 || echo es_pyinstall && apt update && apt install -y python3-minimal python3-apt iproute2 tags: always - import_playbook: "{{ 'postgres-ha' if groups['postgres']|d('') | length > 1 else 'postgres' }}.yml" tags: postgres diff --git a/ansible/playbooks/site_docker.yml b/ansible/playbooks/site_docker.yml new file mode 100644 index 0000000000000000000000000000000000000000..daf8889e44443733721831ac6b3cea5486668a80 --- /dev/null +++ b/ansible/playbooks/site_docker.yml @@ -0,0 +1,33 @@ +--- +- name: DOCKER CONTAINERS PROVISIONING + hosts: localhost + connection: local + tags: always + tasks: + - name: Create docker containers from inventory + docker_container: + name: "{{ item }}" + image: registry.ubicast.net/docker/debian-systemd:buster + privileged: true + command: /lib/systemd/systemd + state: started + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + tmpfs: + - /tmp + - /run + with_inventory_hostnames: + - all:!localhost + + - name: add host to inventory + add_host: + name: "{{ item }}" + ansible_host: "{{ item }}" + ansible_connection: docker + ansible_python_interpreter: /usr/bin/python3 + with_inventory_hostnames: + - all:!localhost + +- import_playbook: site.yml + +... diff --git a/ansible/requirements.dev.in b/ansible/requirements.dev.in index a5e18ddbce783e11e723c9821e1a20695325550d..b07ede02b94ad7945f410b6d164a552c4e79caf1 100644 --- a/ansible/requirements.dev.in +++ b/ansible/requirements.dev.in @@ -1,7 +1,8 @@ -r requirements.in ansible-lint flake8 -molecule[docker] +git+git://github.com/atmaniak/molecule@e03437923b302fca1bd7b4f6030c6956ad00367a#egg=molecule[docker] +#molecule[docker] pip-tools testinfra yamllint diff --git a/ansible/requirements.dev.txt b/ansible/requirements.dev.txt index 85866dba3d6dcc80ba49a9a4caada2cfb177a211..77d9cc012d5dae6357589f23c492f55561819cbb 100644 --- a/ansible/requirements.dev.txt +++ b/ansible/requirements.dev.txt @@ -27,12 +27,11 @@ fasteners==0.15 # via python-gilt flake8==3.7.9 # via -r requirements.dev.in future==0.18.2 # via cookiecutter idna==2.9 # via requests -importlib-metadata==1.6.0 # via pluggy, pytest jinja2-time==0.2.0 # via cookiecutter jinja2==2.11.2 # via ansible, click-completion, cookiecutter, jinja2-time, molecule markupsafe==1.1.1 # via jinja2 mccabe==0.6.1 # via flake8 -molecule[docker]==3.0.3 # via -r requirements.dev.in +git+git://github.com/atmaniak/molecule@e03437923b302fca1bd7b4f6030c6956ad00367a#egg=molecule[docker] # via -r requirements.dev.in monotonic==1.5 # via fasteners more-itertools==8.2.0 # via pytest netaddr==0.7.19 # via -r requirements.in @@ -58,7 +57,7 @@ requests==2.23.0 # via cookiecutter, docker ruamel.yaml.clib==0.2.0 # via ruamel.yaml ruamel.yaml==0.16.10 # via ansible-lint selinux==0.2.1 # via molecule -sh==1.12.14 # via molecule, python-gilt +sh==1.13.1 # via molecule, python-gilt shellingham==1.3.2 # via click-completion six==1.14.0 # via ansible-lint, bcrypt, click-completion, cryptography, docker, fasteners, packaging, pip-tools, pynacl, python-dateutil, websocket-client tabulate==0.8.7 # via molecule @@ -69,7 +68,6 @@ wcwidth==0.1.9 # via pytest websocket-client==0.57.0 # via docker whichcraft==0.6.1 # via cookiecutter yamllint==1.22.1 # via -r requirements.dev.in, molecule -zipp==3.1.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # pip diff --git a/ansible/roles/ferm-configure/handlers/main.yml b/ansible/roles/ferm-configure/handlers/main.yml index 1df71e19ab322054f7a1de2cf01b075a5a4749a8..920efd0e606e42d3ad642e2cc27a7f93fa5d29f6 100644 --- a/ansible/roles/ferm-configure/handlers/main.yml +++ b/ansible/roles/ferm-configure/handlers/main.yml @@ -1,9 +1,9 @@ --- -- name: reload ferm +- name: restart ferm when: ansible_facts.services['ferm.service'] is defined systemd: name: ferm - state: reloaded + state: restarted ... diff --git a/ansible/roles/ferm-configure/tasks/main.yml b/ansible/roles/ferm-configure/tasks/main.yml index c09fe079df02e741b4523e19065903b2e0eb44e4..ac28a7e94ee161bd67b4bb6a330569f487740f15 100644 --- a/ansible/roles/ferm-configure/tasks/main.yml +++ b/ansible/roles/ferm-configure/tasks/main.yml @@ -15,28 +15,28 @@ - name: global when: ferm_global_settings | d(false) - notify: reload ferm + notify: restart ferm copy: dest: /etc/ferm/ferm.d/{{ ferm_rules_filename }}.conf content: "{{ ferm_global_settings }}" - name: input when: ferm_input_rules | length > 0 - notify: reload ferm + notify: restart ferm template: src: ferm_rules_input.conf.j2 dest: /etc/ferm/input.d/{{ ferm_rules_filename }}.conf - name: output when: ferm_output_rules | length > 0 - notify: reload ferm + notify: restart ferm template: src: ferm_rules_output.conf.j2 dest: /etc/ferm/output.d/{{ ferm_rules_filename }}.conf - name: forward when: ferm_forward_rules | length > 0 - notify: reload ferm + notify: restart ferm template: src: ferm_rules_forward.conf.j2 dest: /etc/ferm/forward.d/{{ ferm_rules_filename }}.conf diff --git a/ansible/roles/postgres-ha/defaults/main.yml b/ansible/roles/postgres-ha/defaults/main.yml index 5def4111a6ede281683ac58f854befd3371456ad..038debef0316c504031f3fd4cffb37f6bf28aac9 100644 --- a/ansible/roles/postgres-ha/defaults/main.yml +++ b/ansible/roles/postgres-ha/defaults/main.yml @@ -18,11 +18,11 @@ repmgr_password: repmgr_db: repmgr repmgr_roles: LOGIN,REPLICATION,SUPERUSER -repmgr_primary_node: +repmgr_primary_node: "{{ hostvars[groups['postgres'][0]]['ansible_default_ipv4']['address'] }}" repmgr_timeout: 5 -repmgr_node_id: +repmgr_node_id: "{{ (groups['postgres'].index(inventory_hostname))+1|int }}" repmgr_node_name: "{{ ansible_hostname }}" repmgr_conninfo: host={{ ansible_default_ipv4.address }} dbname={{ repmgr_db }} user={{ repmgr_user }} connect_timeout={{ repmgr_timeout }} diff --git a/ansible/roles/postgres-ha/tasks/main.yml b/ansible/roles/postgres-ha/tasks/main.yml index c7f55bbd5255cd02d1b90470959a7f75ae113ba6..3ef4b24dffbe9485c28192d0ca952d4954fb8660 100644 --- a/ansible/roles/postgres-ha/tasks/main.yml +++ b/ansible/roles/postgres-ha/tasks/main.yml @@ -138,7 +138,7 @@ # REGISTER PRIMARY - name: setup primary - when: db_role == "primary" + when: (db_role is defined and db_role == "primary") or (db_role is undefined and inventory_hostname == groups['postgres'][0]) block: - name: check if primary already joined @@ -162,7 +162,7 @@ # REGISTER STANDBY - name: setup standby - when: db_role == "standby" + when: (db_role is defined and db_role == "standby") or (db_role is undefined and inventory_hostname == groups['postgres'][1]) block: - name: check if standby already joined @@ -244,7 +244,7 @@ # REGISTER WITNESS - name: setup witness - when: db_role == "witness" + when: (db_role is defined and db_role == "witness") or (db_role is undefined and inventory_hostname == groups['postgres'][2]) block: - name: check if witness already joined diff --git a/doc/deploy-ha.md b/doc/deploy-ha.md index 3613f00f680984e6d134292ea1c062cf7fb190fc..837e333a419d499774575f474c34a29e933bf696 100644 --- a/doc/deploy-ha.md +++ b/doc/deploy-ha.md @@ -82,3 +82,28 @@ You can edit the skyreach configuration manual with the following command : ansible -i inventories/<client-ha> -m shell -a "sed -i \"s/'PORT': .*/'PORT': '54321'/g\" /home/skyreach/skyreach_data/private/settings_override.py" ms1 ``` and then deploy again as described in the previous section + + +# Database maintenance + +Main documentation about repmgrd is here : https://redmine.ubicast.net/projects/ubicloud/wiki/Gestion_du_cluster_de_base_de_donn%C3%A9es + +Before using `postgres-maintenance.yml`, you need to add 3 groups to your inventory : +```sh +[postgres_primary] +db1 + +[postgres_standby] +db2 + +[postgres_fenced] +db1 +``` + +The playbook `postgres-maintenance.yml` can help in 3 scenarios : +If you want to know the state of every node in the cluster, just launch the playbook without any tags + +If you want to promote a standby node (specified in postgres_standby group) to primary, launch the playbook with the tag `standby-to-primary` + +If you want a fenced (failed, specified in postgres_fenced group) node to join the cluster as standby node, launch the playbook with the tag `fenced-to-standby` + diff --git a/doc/deploy.md b/doc/deploy.md index 26561c626315dd6b3446686180a45d05a61646d6..3eaab4d00095bd4241526f6bc22f686073df981b 100644 --- a/doc/deploy.md +++ b/doc/deploy.md @@ -117,6 +117,16 @@ echo 'conf_repo_version: mycustombranch' > /root/envsetup/inventories/local-medi make deploy i=inventories/local-mediaimport -l=mediaimport ``` +## Test setup with docker + +You can deploy everything specified in the inventory directly to local docker containers by calling the `site_docker.yml` playbook. + +``` +ansible-playbook -i inventory/example-ha site_docker.yml +``` + +This playbook will parse the inventory and create a docker container for each server, then launch the site.yml playbook as usual. + ## Known issues - Proxy