From 5b9cd1929e7431279cc8ca629beca5f40e89c204 Mon Sep 17 00:00:00 2001 From: pwalczysko Date: Wed, 13 Nov 2024 17:34:41 +0000 Subject: [PATCH] roles --- .../.github/workflows/molecule.yml | 59 + omero/roles/iptables_raw/LICENSE.md | 22 + omero/roles/iptables_raw/README.md | 68 + .../iptables_raw/library/iptables_raw_25.py | 1107 +++++++++++++++++ .../iptables_raw/meta/.galaxy_install_info | 2 + omero/roles/iptables_raw/meta/main.yml | 16 + .../molecule/default/molecule.yml | 26 + .../molecule/default/playbook.yml | 27 + .../molecule/default/tests/test_default.py | 26 + omero/roles/iptables_raw/tasks/main.yml | 32 + omero/roles/nfs_mount/.gitignore | 175 +++ omero/roles/nfs_mount/.travis.yml | 35 + omero/roles/nfs_mount/README.md | 38 + omero/roles/nfs_mount/defaults/main.yml | 11 + omero/roles/nfs_mount/licence.txt | 13 + .../roles/nfs_mount/meta/.galaxy_install_info | 2 + omero/roles/nfs_mount/meta/main.yml | 33 + .../nfs_mount/molecule/default/molecule.yml | 36 + .../nfs_mount/molecule/default/playbook.yml | 18 + .../nfs_mount/molecule/default/yaml-lint.yml | 6 + omero/roles/nfs_mount/tasks/main.yml | 23 + omero/roles/nfs_mount/vars/Debian.yml | 2 + omero/roles/nfs_mount/vars/RedHat.yml | 2 + omero/roles/nfs_share/.gitignore | 1 + omero/roles/nfs_share/.travis.yml | 29 + omero/roles/nfs_share/README.md | 39 + omero/roles/nfs_share/defaults/main.yml | 5 + omero/roles/nfs_share/handlers/main.yml | 6 + .../roles/nfs_share/meta/.galaxy_install_info | 2 + omero/roles/nfs_share/meta/main.yml | 13 + omero/roles/nfs_share/tasks/main.yml | 24 + omero/roles/nfs_share/templates/exports.j2 | 3 + omero/roles/nfs_share/tests/inventory | 1 + omero/roles/nfs_share/tests/test.yml | 5 + .../.github/workflows/molecule.yml | 55 + omero/roles/ome.basedeps/.gitignore | 2 + omero/roles/ome.basedeps/LICENSE.md | 22 + omero/roles/ome.basedeps/README.md | 28 + .../ome.basedeps/meta/.galaxy_install_info | 2 + omero/roles/ome.basedeps/meta/main.yml | 19 + .../molecule/default/converge.yml | 5 + .../molecule/default/molecule.yml | 22 + .../molecule/default/tests/test_default.py | 15 + omero/roles/ome.basedeps/tasks/main.yml | 32 + omero/roles/ome.basedeps/vars/main.yml | 19 + .../.github/workflows/molecule.yml | 55 + omero/roles/ome.cli_utils/.gitignore | 1 + omero/roles/ome.cli_utils/LICENSE.md | 22 + omero/roles/ome.cli_utils/README.md | 21 + .../ome.cli_utils/meta/.galaxy_install_info | 2 + omero/roles/ome.cli_utils/meta/main.yml | 14 + .../roles/ome.cli_utils/meta/requirements.yml | 2 + .../molecule/default/molecule.yml | 20 + .../molecule/default/playbook.yml | 5 + .../molecule/default/requirements.yml | 2 + .../molecule/default/tests/test_default.py | 11 + omero/roles/ome.cli_utils/tasks/main.yml | 28 + omero/roles/ome.cli_utils/tests/inventory | 1 + omero/roles/ome.cli_utils/tests/test.yml | 5 + .../roles/ome.cli_utils/tests/test_default.py | 11 + .../.github/workflows/molecule.yml | 55 + omero/roles/ome.deploy_archive/.gitignore | 2 + omero/roles/ome.deploy_archive/LICENSE.md | 22 + omero/roles/ome.deploy_archive/README.md | 43 + .../ome.deploy_archive/defaults/main.yml | 18 + .../meta/.galaxy_install_info | 2 + omero/roles/ome.deploy_archive/meta/main.yml | 17 + .../molecule/default/molecule.yml | 22 + .../molecule/default/playbook.yml | 25 + .../molecule/default/tests/test_default.py | 32 + omero/roles/ome.deploy_archive/tasks/main.yml | 43 + .../ome.docker/.github/workflows/molecule.yml | 56 + omero/roles/ome.docker/.gitignore | 2 + omero/roles/ome.docker/CHANGES.md | 13 + omero/roles/ome.docker/LICENSE.md | 22 + omero/roles/ome.docker/README.md | 114 ++ omero/roles/ome.docker/defaults/main.yml | 48 + omero/roles/ome.docker/handlers/main.yml | 9 + .../ome.docker/meta/.galaxy_install_info | 2 + omero/roles/ome.docker/meta/main.yml | 14 + omero/roles/ome.docker/meta/requirements.yml | 2 + .../ome.docker/molecule/default/molecule.yml | 50 + .../ome.docker/molecule/default/playbook.yml | 16 + .../molecule/default/requirements.yml | 3 + .../default/tests/test_docker-inactive.py | 13 + .../molecule/default/tests/test_docker.py | 40 + omero/roles/ome.docker/tasks/main.yml | 83 ++ omero/roles/ome.docker/tasks/pre_tasks.yml | 13 + .../templates/etc-docker-daemon-json.j2 | 27 + .../ome.ice/.github/workflows/molecule.yml | 55 + omero/roles/ome.ice/.gitignore | 2 + omero/roles/ome.ice/LICENSE.md | 22 + omero/roles/ome.ice/README.md | 39 + omero/roles/ome.ice/defaults/main.yml | 22 + omero/roles/ome.ice/meta/.galaxy_install_info | 2 + omero/roles/ome.ice/meta/main.yml | 17 + omero/roles/ome.ice/meta/requirements.yml | 4 + .../molecule/ice36-ubuntu2204/molecule.yml | 32 + .../ome.ice/molecule/ice36all/molecule.yml | 28 + .../molecule/ice36all/tests/test_default.py | 22 + .../molecule/ice36minimal/molecule.yml | 30 + .../ice36minimal/tests/test_default.py | 23 + .../ome.ice/molecule/resources/playbook.yml | 5 + .../molecule/resources/requirements.yml | 4 + .../resources/tests-built/test_default.py | 19 + omero/roles/ome.ice/tasks/debian.yml | 15 + omero/roles/ome.ice/tasks/main.yml | 28 + omero/roles/ome.ice/tasks/pre_tasks.yml | 51 + omero/roles/ome.ice/tasks/redhat9.yml | 100 ++ .../ome.java/.github/workflows/molecule.yml | 58 + omero/roles/ome.java/.gitignore | 2 + omero/roles/ome.java/LICENSE.md | 22 + omero/roles/ome.java/README.md | 35 + omero/roles/ome.java/defaults/main.yml | 9 + .../roles/ome.java/meta/.galaxy_install_info | 2 + omero/roles/ome.java/meta/main.yml | 21 + .../ome.java/molecule/resources/playbook.yml | 5 + .../molecule/resources/tests/test_jdk.py | 20 + .../molecule/resources/tests/test_jdk11.py | 21 + .../molecule/resources/tests/test_jre.py | 17 + .../molecule/resources/tests/test_jre11.py | 17 + .../molecule/rockylinux-9/molecule.yml | 41 + .../molecule/ubuntu-2204/molecule.yml | 41 + omero/roles/ome.java/tasks/debian.yml | 22 + omero/roles/ome.java/tasks/main.yml | 24 + omero/roles/ome.java/tasks/redhat.yml | 21 + omero/roles/ome.java/vars/main.yml | 8 + .../.github/workflows/molecule.yml | 55 + omero/roles/ome.lvm_partition/.gitignore | 1 + omero/roles/ome.lvm_partition/LICENSE.md | 22 + omero/roles/ome.lvm_partition/README.md | 30 + .../roles/ome.lvm_partition/defaults/main.yml | 4 + .../meta/.galaxy_install_info | 2 + omero/roles/ome.lvm_partition/meta/main.yml | 16 + .../molecule/default/molecule.yml | 24 + .../molecule/default/playbook.yml | 5 + .../molecule/default/tests/test_default.py | 15 + omero/roles/ome.lvm_partition/tasks/main.yml | 28 + omero/roles/ome.lvm_partition/tests/inventory | 1 + omero/roles/ome.lvm_partition/tests/test.yml | 5 + .../ome.nginx/.github/workflows/molecule.yml | 56 + omero/roles/ome.nginx/.gitignore | 2 + omero/roles/ome.nginx/LICENSE.md | 22 + omero/roles/ome.nginx/README.md | 30 + omero/roles/ome.nginx/defaults/main.yml | 20 + .../roles/ome.nginx/files/nginx-mainline.repo | 5 + omero/roles/ome.nginx/handlers/main.yml | 9 + .../roles/ome.nginx/meta/.galaxy_install_info | 2 + omero/roles/ome.nginx/meta/main.yml | 16 + .../ome.nginx/molecule/resources/playbook.yml | 5 + .../molecule/rockylinux9/molecule.yml | 59 + .../rockylinux9/tests/test_default.py | 56 + omero/roles/ome.nginx/tasks/debian.yaml | 26 + omero/roles/ome.nginx/tasks/main.yml | 23 + omero/roles/ome.nginx/tasks/redhat.yaml | 45 + .../ome.nginx/templates/logrotated-nginx.j2 | 19 + .../.github/workflows/molecule.yml | 56 + omero/roles/ome.omero_common/.gitignore | 3 + omero/roles/ome.omero_common/LICENSE.md | 22 + omero/roles/ome.omero_common/README.md | 40 + .../roles/ome.omero_common/defaults/main.yml | 4 + .../roles/ome.omero_common/handlers/main.yml | 50 + .../meta/.galaxy_install_info | 2 + omero/roles/ome.omero_common/meta/main.yml | 19 + .../molecule/default/molecule.yml | 26 + .../molecule/default/playbook.yml | 35 + .../molecule/default/tests/test_default.py | 13 + omero/roles/ome.omero_common/tasks/main.yml | 21 + .../.github/workflows/molecule.yml | 62 + omero/roles/ome.omero_server/.gitignore | 3 + omero/roles/ome.omero_server/CHANGES.md | 106 ++ omero/roles/ome.omero_server/LICENSE.md | 22 + omero/roles/ome.omero_server/README.md | 119 ++ .../roles/ome.omero_server/defaults/main.yml | 195 +++ .../roles/ome.omero_server/handlers/main.yml | 17 + .../meta/.galaxy_install_info | 2 + omero/roles/ome.omero_server/meta/main.yml | 17 + .../ome.omero_server/meta/requirements.yml | 7 + .../molecule/resources/playbook.yml | 61 + .../molecule/resources/requirements.yml | 8 + .../molecule/resources/tests/test_default.py | 76 ++ .../molecule/resources/tests/test_python3.py | 50 + .../molecule/resources/upgrade-omero.yml | 53 + .../molecule/rockylinux9/molecule.yml | 50 + .../molecule/rockylinux9/prepare.yml | 12 + .../molecule/ubuntu2204/molecule.yml | 50 + .../molecule/ubuntu2204/prepare.yml | 7 + omero/roles/ome.omero_server/tasks/main.yml | 16 + .../tasks/omero-configfiles.yml | 19 + .../ome.omero_server/tasks/omero-datadir.yml | 56 + .../ome.omero_server/tasks/omero-install.yml | 248 ++++ .../ome.omero_server/tasks/omero-systemd.yml | 25 + .../ome.omero_server/tasks/omero-user.yml | 31 + .../ome.omero_server/tasks/pre-tasks.yml | 30 + .../templates/00-omero-server-omero.j2 | 29 + .../ome.omero_server/templates/bin-omero.j2 | 22 + .../omero-server-config-update-sh.j2 | 9 + .../systemd-system-omero-server-service.j2 | 36 + .../.github/workflows/molecule.yml | 62 + omero/roles/ome.omero_user/.gitignore | 1 + omero/roles/ome.omero_user/LICENSE.md | 22 + omero/roles/ome.omero_user/README.md | 84 ++ omero/roles/ome.omero_user/defaults/main.yml | 17 + .../ome.omero_user/meta/.galaxy_install_info | 2 + omero/roles/ome.omero_user/meta/main.yml | 19 + .../molecule/default/molecule.yml | 36 + .../molecule/default/playbook.yml | 5 + .../molecule/default/tests/test_default.py | 14 + omero/roles/ome.omero_user/tasks/groups.yml | 39 + omero/roles/ome.omero_user/tasks/main.yml | 14 + .../ome.omero_user/tasks/reset-password.yml | 34 + .../tasks/reset-root-password.yml | 29 + omero/roles/ome.omero_user/tasks/users.yml | 42 + omero/roles/ome.omero_user/tests/inventory | 1 + omero/roles/ome.omero_user/tests/test.yml | 5 + .../.github/workflows/molecule.yml | 62 + omero/roles/ome.omero_web/.gitignore | 3 + omero/roles/ome.omero_web/CHANGES.md | 33 + omero/roles/ome.omero_web/LICENSE.md | 22 + omero/roles/ome.omero_web/README.md | 132 ++ omero/roles/ome.omero_web/defaults/main.yml | 139 +++ omero/roles/ome.omero_web/handlers/main.yml | 22 + .../ome.omero_web/meta/.galaxy_install_info | 2 + omero/roles/ome.omero_web/meta/main.yml | 17 + .../roles/ome.omero_web/meta/requirements.yml | 8 + .../molecule/active-rockylinux9/molecule.yml | 41 + .../molecule/active-ubuntu2204/molecule.yml | 43 + .../molecule/active-ubuntu2204/prepare.yml | 19 + .../molecule/inactive/molecule.yml | 41 + .../molecule/inactive/tests/test_default.py | 1 + .../molecule/resources/playbook.yml | 93 ++ .../molecule/resources/requirements.yml | 8 + .../molecule/resources/tests/test_default.py | 40 + .../molecule/resources/tests/test_nginx.py | 24 + .../molecule/resources/tests/test_sepolicy.py | 11 + .../molecule/resources/tests/test_webapps.py | 109 ++ omero/roles/ome.omero_web/tasks/main.yml | 14 + omero/roles/ome.omero_web/tasks/pre_tasks.yml | 21 + .../ome.omero_web/tasks/web-dependencies.yml | 93 ++ .../ome.omero_web/tasks/web-install-py3.yml | 169 +++ omero/roles/ome.omero_web/tasks/web-nginx.yml | 43 + .../roles/ome.omero_web/tasks/web-systemd.yml | 25 + .../templates/00-omero-web-omero.j2 | 14 + .../ome.omero_web/templates/bin-omero.j2 | 16 + .../ome.omero_web/templates/django.te.j2 | 15 + .../templates/omero-web-apps-omero.j2 | 36 + .../templates/omero-web-config-update-sh.j2 | 9 + .../systemd-system-omero-web-service.j2 | 25 + .../.github/workflows/molecule.yml | 54 + omero/roles/ome.postgresql/.gitignore | 4 + omero/roles/ome.postgresql/CHANGES.md | 35 + omero/roles/ome.postgresql/LICENSE.md | 22 + omero/roles/ome.postgresql/README.md | 112 ++ omero/roles/ome.postgresql/defaults/main.yml | 64 + omero/roles/ome.postgresql/handlers/main.yml | 8 + .../ome.postgresql/meta/.galaxy_install_info | 2 + omero/roles/ome.postgresql/meta/main.yml | 17 + .../ome.postgresql/meta/requirements.yml | 2 + .../molecule/resources/playbook.yml | 71 ++ .../molecule/resources/requirements.yml | 2 + .../molecule/resources/tests/test_default.py | 188 +++ .../resources/tests/test_extra_options.py | 34 + .../molecule/resources/tests/utils.py | 3 + .../molecule/rockylinux9/molecule.yml | 90 ++ .../molecule/rockylinux9/prepare.yml | 11 + .../molecule/ubuntu2204/molecule.yml | 80 ++ .../molecule/ubuntu2204/prepare.yml | 7 + .../roles/ome.postgresql/tasks/databases.yml | 113 ++ omero/roles/ome.postgresql/tasks/debian.yml | 31 + .../roles/ome.postgresql/tasks/initialise.yml | 52 + omero/roles/ome.postgresql/tasks/main.yml | 29 + omero/roles/ome.postgresql/tasks/redhat.yml | 50 + .../ome.postgresql/templates/pg_hba-conf.j2 | 11 + .../templates/postgresql-conf-10-ubuntu.j2 | 673 ++++++++++ .../templates/postgresql-conf.j2 | 654 ++++++++++ .../.github/workflows/molecule.yml | 55 + omero/roles/ome.postgresql_backup/LICENSE.md | 22 + omero/roles/ome.postgresql_backup/README.md | 51 + .../ome.postgresql_backup/defaults/main.yml | 11 + .../meta/.galaxy_install_info | 2 + .../roles/ome.postgresql_backup/meta/main.yml | 14 + .../molecule/default/molecule.yml | 36 + .../molecule/default/playbook.yml | 24 + .../molecule/default/requirements.yml | 3 + .../molecule/default/tests/test_compress.py | 28 + .../molecule/default/tests/test_default.py | 27 + .../ome.postgresql_backup/tasks/main.yml | 17 + .../templates/etc-crond-postgresql-backup.j2 | 17 + .../.github/workflows/molecule.yml | 62 + omero/roles/ome.postgresql_client/.gitignore | 4 + omero/roles/ome.postgresql_client/LICENSE.md | 22 + omero/roles/ome.postgresql_client/README.md | 37 + .../ome.postgresql_client/defaults/main.yml | 8 + .../meta/.galaxy_install_info | 2 + .../roles/ome.postgresql_client/meta/main.yml | 17 + .../molecule/resources/playbook.yml | 5 + .../molecule/resources/tests/test_default.py | 12 + .../resources/tests/test_exactversion.py | 10 + .../molecule/rockylinux9/molecule.yml | 44 + .../molecule/ubuntu2204/molecule.yml | 43 + .../ome.postgresql_client/tasks/debian.yml | 28 + .../ome.postgresql_client/tasks/main.yml | 9 + .../ome.postgresql_client/tasks/redhat.yml | 44 + .../templates/pg_hba-conf.j2 | 11 + .../templates/postgresql-conf-10-ubuntu.j2 | 673 ++++++++++ .../templates/postgresql-conf.j2 | 654 ++++++++++ .../roles/ome.postgresql_client/vars/main.yml | 26 + .../.github/workflows/molecule.yml | 55 + omero/roles/ome.python3_virtualenv/.gitignore | 2 + omero/roles/ome.python3_virtualenv/LICENSE.md | 22 + omero/roles/ome.python3_virtualenv/README.md | 24 + .../files/ome-python3-virtualenv.sh | 19 + .../meta/.galaxy_install_info | 2 + .../ome.python3_virtualenv/meta/main.yml | 19 + .../molecule/default/Dockerfile.j2 | 12 + .../molecule/default/molecule.yml | 35 + .../molecule/resources/playbook.yml | 24 + .../molecule/resources/tests/test_default.py | 18 + .../ome.python3_virtualenv/tasks/debian.yml | 13 + .../ome.python3_virtualenv/tasks/main.yml | 14 + .../ome.python3_virtualenv/tasks/redhat.yml | 11 + .../ome.redis/.github/workflows/molecule.yml | 55 + omero/roles/ome.redis/.gitignore | 1 + omero/roles/ome.redis/LICENSE.md | 22 + omero/roles/ome.redis/README.md | 20 + omero/roles/ome.redis/handlers/main.yml | 8 + .../roles/ome.redis/meta/.galaxy_install_info | 2 + omero/roles/ome.redis/meta/main.yml | 19 + .../ome.redis/molecule/default/molecule.yml | 36 + .../ome.redis/molecule/default/playbook.yml | 6 + .../molecule/default/tests/test_default.py | 15 + omero/roles/ome.redis/tasks/main.yml | 51 + .../.github/workflows/molecule.yml | 62 + omero/roles/ome.selinux_utils/.gitignore | 1 + omero/roles/ome.selinux_utils/LICENSE.md | 22 + omero/roles/ome.selinux_utils/README.md | 32 + .../meta/.galaxy_install_info | 2 + omero/roles/ome.selinux_utils/meta/main.yml | 16 + .../molecule/default/molecule.yml | 25 + .../molecule/default/playbook.yml | 5 + .../molecule/default/tests/test_default.py | 22 + omero/roles/ome.selinux_utils/tasks/main.yml | 27 + .../.github/workflows/molecule.yml | 63 + omero/roles/ome.ssl_certificate/.gitignore | 1 + omero/roles/ome.ssl_certificate/LICENSE.md | 22 + omero/roles/ome.ssl_certificate/README.md | 69 + .../ome.ssl_certificate/defaults/main.yml | 39 + .../ome.ssl_certificate/handlers/main.yml | 7 + .../meta/.galaxy_install_info | 2 + omero/roles/ome.ssl_certificate/meta/main.yml | 19 + .../molecule/default/converge.yml | 15 + .../molecule/default/intermediate.pem | 11 + .../molecule/default/molecule.yml | 25 + .../molecule/default/tests/test_default.py | 18 + .../default/tests/test_intermediate.py | 41 + .../roles/ome.ssl_certificate/tasks/main.yml | 116 ++ .../.github/workflows/molecule.yml | 55 + .../roles/ome.versioncontrol_utils/.gitignore | 2 + .../roles/ome.versioncontrol_utils/LICENSE.md | 22 + .../roles/ome.versioncontrol_utils/README.md | 12 + .../meta/.galaxy_install_info | 2 + .../ome.versioncontrol_utils/meta/main.yml | 16 + .../molecule/default/molecule.yml | 27 + .../molecule/default/playbook.yml | 5 + .../molecule/default/tests/test_default.py | 10 + .../ome.versioncontrol_utils/tasks/main.yml | 18 + 366 files changed, 13923 insertions(+) create mode 100644 omero/roles/iptables_raw/.github/workflows/molecule.yml create mode 100644 omero/roles/iptables_raw/LICENSE.md create mode 100644 omero/roles/iptables_raw/README.md create mode 100644 omero/roles/iptables_raw/library/iptables_raw_25.py create mode 100644 omero/roles/iptables_raw/meta/.galaxy_install_info create mode 100644 omero/roles/iptables_raw/meta/main.yml create mode 100644 omero/roles/iptables_raw/molecule/default/molecule.yml create mode 100644 omero/roles/iptables_raw/molecule/default/playbook.yml create mode 100644 omero/roles/iptables_raw/molecule/default/tests/test_default.py create mode 100644 omero/roles/iptables_raw/tasks/main.yml create mode 100644 omero/roles/nfs_mount/.gitignore create mode 100644 omero/roles/nfs_mount/.travis.yml create mode 100644 omero/roles/nfs_mount/README.md create mode 100644 omero/roles/nfs_mount/defaults/main.yml create mode 100644 omero/roles/nfs_mount/licence.txt create mode 100644 omero/roles/nfs_mount/meta/.galaxy_install_info create mode 100644 omero/roles/nfs_mount/meta/main.yml create mode 100644 omero/roles/nfs_mount/molecule/default/molecule.yml create mode 100644 omero/roles/nfs_mount/molecule/default/playbook.yml create mode 100644 omero/roles/nfs_mount/molecule/default/yaml-lint.yml create mode 100644 omero/roles/nfs_mount/tasks/main.yml create mode 100644 omero/roles/nfs_mount/vars/Debian.yml create mode 100644 omero/roles/nfs_mount/vars/RedHat.yml create mode 100644 omero/roles/nfs_share/.gitignore create mode 100644 omero/roles/nfs_share/.travis.yml create mode 100644 omero/roles/nfs_share/README.md create mode 100644 omero/roles/nfs_share/defaults/main.yml create mode 100644 omero/roles/nfs_share/handlers/main.yml create mode 100644 omero/roles/nfs_share/meta/.galaxy_install_info create mode 100644 omero/roles/nfs_share/meta/main.yml create mode 100644 omero/roles/nfs_share/tasks/main.yml create mode 100644 omero/roles/nfs_share/templates/exports.j2 create mode 100644 omero/roles/nfs_share/tests/inventory create mode 100644 omero/roles/nfs_share/tests/test.yml create mode 100644 omero/roles/ome.basedeps/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.basedeps/.gitignore create mode 100644 omero/roles/ome.basedeps/LICENSE.md create mode 100644 omero/roles/ome.basedeps/README.md create mode 100644 omero/roles/ome.basedeps/meta/.galaxy_install_info create mode 100644 omero/roles/ome.basedeps/meta/main.yml create mode 100644 omero/roles/ome.basedeps/molecule/default/converge.yml create mode 100644 omero/roles/ome.basedeps/molecule/default/molecule.yml create mode 100644 omero/roles/ome.basedeps/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.basedeps/tasks/main.yml create mode 100644 omero/roles/ome.basedeps/vars/main.yml create mode 100644 omero/roles/ome.cli_utils/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.cli_utils/.gitignore create mode 100644 omero/roles/ome.cli_utils/LICENSE.md create mode 100644 omero/roles/ome.cli_utils/README.md create mode 100644 omero/roles/ome.cli_utils/meta/.galaxy_install_info create mode 100644 omero/roles/ome.cli_utils/meta/main.yml create mode 100644 omero/roles/ome.cli_utils/meta/requirements.yml create mode 100644 omero/roles/ome.cli_utils/molecule/default/molecule.yml create mode 100644 omero/roles/ome.cli_utils/molecule/default/playbook.yml create mode 100644 omero/roles/ome.cli_utils/molecule/default/requirements.yml create mode 100644 omero/roles/ome.cli_utils/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.cli_utils/tasks/main.yml create mode 100644 omero/roles/ome.cli_utils/tests/inventory create mode 100644 omero/roles/ome.cli_utils/tests/test.yml create mode 100644 omero/roles/ome.cli_utils/tests/test_default.py create mode 100644 omero/roles/ome.deploy_archive/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.deploy_archive/.gitignore create mode 100644 omero/roles/ome.deploy_archive/LICENSE.md create mode 100644 omero/roles/ome.deploy_archive/README.md create mode 100644 omero/roles/ome.deploy_archive/defaults/main.yml create mode 100644 omero/roles/ome.deploy_archive/meta/.galaxy_install_info create mode 100644 omero/roles/ome.deploy_archive/meta/main.yml create mode 100644 omero/roles/ome.deploy_archive/molecule/default/molecule.yml create mode 100644 omero/roles/ome.deploy_archive/molecule/default/playbook.yml create mode 100644 omero/roles/ome.deploy_archive/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.deploy_archive/tasks/main.yml create mode 100644 omero/roles/ome.docker/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.docker/.gitignore create mode 100644 omero/roles/ome.docker/CHANGES.md create mode 100644 omero/roles/ome.docker/LICENSE.md create mode 100644 omero/roles/ome.docker/README.md create mode 100644 omero/roles/ome.docker/defaults/main.yml create mode 100644 omero/roles/ome.docker/handlers/main.yml create mode 100644 omero/roles/ome.docker/meta/.galaxy_install_info create mode 100644 omero/roles/ome.docker/meta/main.yml create mode 100644 omero/roles/ome.docker/meta/requirements.yml create mode 100644 omero/roles/ome.docker/molecule/default/molecule.yml create mode 100644 omero/roles/ome.docker/molecule/default/playbook.yml create mode 100644 omero/roles/ome.docker/molecule/default/requirements.yml create mode 100644 omero/roles/ome.docker/molecule/default/tests/test_docker-inactive.py create mode 100644 omero/roles/ome.docker/molecule/default/tests/test_docker.py create mode 100644 omero/roles/ome.docker/tasks/main.yml create mode 100644 omero/roles/ome.docker/tasks/pre_tasks.yml create mode 100644 omero/roles/ome.docker/templates/etc-docker-daemon-json.j2 create mode 100644 omero/roles/ome.ice/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.ice/.gitignore create mode 100644 omero/roles/ome.ice/LICENSE.md create mode 100644 omero/roles/ome.ice/README.md create mode 100644 omero/roles/ome.ice/defaults/main.yml create mode 100644 omero/roles/ome.ice/meta/.galaxy_install_info create mode 100644 omero/roles/ome.ice/meta/main.yml create mode 100644 omero/roles/ome.ice/meta/requirements.yml create mode 100644 omero/roles/ome.ice/molecule/ice36-ubuntu2204/molecule.yml create mode 100644 omero/roles/ome.ice/molecule/ice36all/molecule.yml create mode 100644 omero/roles/ome.ice/molecule/ice36all/tests/test_default.py create mode 100644 omero/roles/ome.ice/molecule/ice36minimal/molecule.yml create mode 100644 omero/roles/ome.ice/molecule/ice36minimal/tests/test_default.py create mode 100644 omero/roles/ome.ice/molecule/resources/playbook.yml create mode 100755 omero/roles/ome.ice/molecule/resources/requirements.yml create mode 100644 omero/roles/ome.ice/molecule/resources/tests-built/test_default.py create mode 100644 omero/roles/ome.ice/tasks/debian.yml create mode 100644 omero/roles/ome.ice/tasks/main.yml create mode 100644 omero/roles/ome.ice/tasks/pre_tasks.yml create mode 100644 omero/roles/ome.ice/tasks/redhat9.yml create mode 100644 omero/roles/ome.java/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.java/.gitignore create mode 100644 omero/roles/ome.java/LICENSE.md create mode 100644 omero/roles/ome.java/README.md create mode 100644 omero/roles/ome.java/defaults/main.yml create mode 100644 omero/roles/ome.java/meta/.galaxy_install_info create mode 100644 omero/roles/ome.java/meta/main.yml create mode 100644 omero/roles/ome.java/molecule/resources/playbook.yml create mode 100644 omero/roles/ome.java/molecule/resources/tests/test_jdk.py create mode 100644 omero/roles/ome.java/molecule/resources/tests/test_jdk11.py create mode 100644 omero/roles/ome.java/molecule/resources/tests/test_jre.py create mode 100644 omero/roles/ome.java/molecule/resources/tests/test_jre11.py create mode 100644 omero/roles/ome.java/molecule/rockylinux-9/molecule.yml create mode 100644 omero/roles/ome.java/molecule/ubuntu-2204/molecule.yml create mode 100644 omero/roles/ome.java/tasks/debian.yml create mode 100644 omero/roles/ome.java/tasks/main.yml create mode 100644 omero/roles/ome.java/tasks/redhat.yml create mode 100644 omero/roles/ome.java/vars/main.yml create mode 100644 omero/roles/ome.lvm_partition/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.lvm_partition/.gitignore create mode 100644 omero/roles/ome.lvm_partition/LICENSE.md create mode 100644 omero/roles/ome.lvm_partition/README.md create mode 100644 omero/roles/ome.lvm_partition/defaults/main.yml create mode 100644 omero/roles/ome.lvm_partition/meta/.galaxy_install_info create mode 100644 omero/roles/ome.lvm_partition/meta/main.yml create mode 100644 omero/roles/ome.lvm_partition/molecule/default/molecule.yml create mode 100644 omero/roles/ome.lvm_partition/molecule/default/playbook.yml create mode 100644 omero/roles/ome.lvm_partition/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.lvm_partition/tasks/main.yml create mode 100644 omero/roles/ome.lvm_partition/tests/inventory create mode 100644 omero/roles/ome.lvm_partition/tests/test.yml create mode 100644 omero/roles/ome.nginx/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.nginx/.gitignore create mode 100644 omero/roles/ome.nginx/LICENSE.md create mode 100644 omero/roles/ome.nginx/README.md create mode 100644 omero/roles/ome.nginx/defaults/main.yml create mode 100644 omero/roles/ome.nginx/files/nginx-mainline.repo create mode 100644 omero/roles/ome.nginx/handlers/main.yml create mode 100644 omero/roles/ome.nginx/meta/.galaxy_install_info create mode 100644 omero/roles/ome.nginx/meta/main.yml create mode 100644 omero/roles/ome.nginx/molecule/resources/playbook.yml create mode 100644 omero/roles/ome.nginx/molecule/rockylinux9/molecule.yml create mode 100644 omero/roles/ome.nginx/molecule/rockylinux9/tests/test_default.py create mode 100755 omero/roles/ome.nginx/tasks/debian.yaml create mode 100644 omero/roles/ome.nginx/tasks/main.yml create mode 100644 omero/roles/ome.nginx/tasks/redhat.yaml create mode 100644 omero/roles/ome.nginx/templates/logrotated-nginx.j2 create mode 100644 omero/roles/ome.omero_common/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.omero_common/.gitignore create mode 100644 omero/roles/ome.omero_common/LICENSE.md create mode 100644 omero/roles/ome.omero_common/README.md create mode 100644 omero/roles/ome.omero_common/defaults/main.yml create mode 100644 omero/roles/ome.omero_common/handlers/main.yml create mode 100644 omero/roles/ome.omero_common/meta/.galaxy_install_info create mode 100644 omero/roles/ome.omero_common/meta/main.yml create mode 100644 omero/roles/ome.omero_common/molecule/default/molecule.yml create mode 100644 omero/roles/ome.omero_common/molecule/default/playbook.yml create mode 100644 omero/roles/ome.omero_common/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.omero_common/tasks/main.yml create mode 100644 omero/roles/ome.omero_server/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.omero_server/.gitignore create mode 100644 omero/roles/ome.omero_server/CHANGES.md create mode 100644 omero/roles/ome.omero_server/LICENSE.md create mode 100644 omero/roles/ome.omero_server/README.md create mode 100644 omero/roles/ome.omero_server/defaults/main.yml create mode 100644 omero/roles/ome.omero_server/handlers/main.yml create mode 100644 omero/roles/ome.omero_server/meta/.galaxy_install_info create mode 100644 omero/roles/ome.omero_server/meta/main.yml create mode 100644 omero/roles/ome.omero_server/meta/requirements.yml create mode 100644 omero/roles/ome.omero_server/molecule/resources/playbook.yml create mode 100644 omero/roles/ome.omero_server/molecule/resources/requirements.yml create mode 100644 omero/roles/ome.omero_server/molecule/resources/tests/test_default.py create mode 100644 omero/roles/ome.omero_server/molecule/resources/tests/test_python3.py create mode 100644 omero/roles/ome.omero_server/molecule/resources/upgrade-omero.yml create mode 100644 omero/roles/ome.omero_server/molecule/rockylinux9/molecule.yml create mode 100644 omero/roles/ome.omero_server/molecule/rockylinux9/prepare.yml create mode 100644 omero/roles/ome.omero_server/molecule/ubuntu2204/molecule.yml create mode 100644 omero/roles/ome.omero_server/molecule/ubuntu2204/prepare.yml create mode 100644 omero/roles/ome.omero_server/tasks/main.yml create mode 100644 omero/roles/ome.omero_server/tasks/omero-configfiles.yml create mode 100644 omero/roles/ome.omero_server/tasks/omero-datadir.yml create mode 100644 omero/roles/ome.omero_server/tasks/omero-install.yml create mode 100644 omero/roles/ome.omero_server/tasks/omero-systemd.yml create mode 100644 omero/roles/ome.omero_server/tasks/omero-user.yml create mode 100644 omero/roles/ome.omero_server/tasks/pre-tasks.yml create mode 100644 omero/roles/ome.omero_server/templates/00-omero-server-omero.j2 create mode 100644 omero/roles/ome.omero_server/templates/bin-omero.j2 create mode 100644 omero/roles/ome.omero_server/templates/omero-server-config-update-sh.j2 create mode 100644 omero/roles/ome.omero_server/templates/systemd-system-omero-server-service.j2 create mode 100644 omero/roles/ome.omero_user/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.omero_user/.gitignore create mode 100644 omero/roles/ome.omero_user/LICENSE.md create mode 100644 omero/roles/ome.omero_user/README.md create mode 100644 omero/roles/ome.omero_user/defaults/main.yml create mode 100644 omero/roles/ome.omero_user/meta/.galaxy_install_info create mode 100644 omero/roles/ome.omero_user/meta/main.yml create mode 100644 omero/roles/ome.omero_user/molecule/default/molecule.yml create mode 100644 omero/roles/ome.omero_user/molecule/default/playbook.yml create mode 100644 omero/roles/ome.omero_user/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.omero_user/tasks/groups.yml create mode 100644 omero/roles/ome.omero_user/tasks/main.yml create mode 100644 omero/roles/ome.omero_user/tasks/reset-password.yml create mode 100644 omero/roles/ome.omero_user/tasks/reset-root-password.yml create mode 100644 omero/roles/ome.omero_user/tasks/users.yml create mode 100644 omero/roles/ome.omero_user/tests/inventory create mode 100644 omero/roles/ome.omero_user/tests/test.yml create mode 100644 omero/roles/ome.omero_web/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.omero_web/.gitignore create mode 100644 omero/roles/ome.omero_web/CHANGES.md create mode 100644 omero/roles/ome.omero_web/LICENSE.md create mode 100644 omero/roles/ome.omero_web/README.md create mode 100644 omero/roles/ome.omero_web/defaults/main.yml create mode 100644 omero/roles/ome.omero_web/handlers/main.yml create mode 100644 omero/roles/ome.omero_web/meta/.galaxy_install_info create mode 100644 omero/roles/ome.omero_web/meta/main.yml create mode 100644 omero/roles/ome.omero_web/meta/requirements.yml create mode 100755 omero/roles/ome.omero_web/molecule/active-rockylinux9/molecule.yml create mode 100755 omero/roles/ome.omero_web/molecule/active-ubuntu2204/molecule.yml create mode 100644 omero/roles/ome.omero_web/molecule/active-ubuntu2204/prepare.yml create mode 100644 omero/roles/ome.omero_web/molecule/inactive/molecule.yml create mode 120000 omero/roles/ome.omero_web/molecule/inactive/tests/test_default.py create mode 100644 omero/roles/ome.omero_web/molecule/resources/playbook.yml create mode 100644 omero/roles/ome.omero_web/molecule/resources/requirements.yml create mode 100644 omero/roles/ome.omero_web/molecule/resources/tests/test_default.py create mode 100644 omero/roles/ome.omero_web/molecule/resources/tests/test_nginx.py create mode 100644 omero/roles/ome.omero_web/molecule/resources/tests/test_sepolicy.py create mode 100644 omero/roles/ome.omero_web/molecule/resources/tests/test_webapps.py create mode 100644 omero/roles/ome.omero_web/tasks/main.yml create mode 100644 omero/roles/ome.omero_web/tasks/pre_tasks.yml create mode 100755 omero/roles/ome.omero_web/tasks/web-dependencies.yml create mode 100644 omero/roles/ome.omero_web/tasks/web-install-py3.yml create mode 100644 omero/roles/ome.omero_web/tasks/web-nginx.yml create mode 100644 omero/roles/ome.omero_web/tasks/web-systemd.yml create mode 100644 omero/roles/ome.omero_web/templates/00-omero-web-omero.j2 create mode 100644 omero/roles/ome.omero_web/templates/bin-omero.j2 create mode 100755 omero/roles/ome.omero_web/templates/django.te.j2 create mode 100644 omero/roles/ome.omero_web/templates/omero-web-apps-omero.j2 create mode 100644 omero/roles/ome.omero_web/templates/omero-web-config-update-sh.j2 create mode 100644 omero/roles/ome.omero_web/templates/systemd-system-omero-web-service.j2 create mode 100644 omero/roles/ome.postgresql/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.postgresql/.gitignore create mode 100644 omero/roles/ome.postgresql/CHANGES.md create mode 100644 omero/roles/ome.postgresql/LICENSE.md create mode 100644 omero/roles/ome.postgresql/README.md create mode 100644 omero/roles/ome.postgresql/defaults/main.yml create mode 100644 omero/roles/ome.postgresql/handlers/main.yml create mode 100644 omero/roles/ome.postgresql/meta/.galaxy_install_info create mode 100644 omero/roles/ome.postgresql/meta/main.yml create mode 100644 omero/roles/ome.postgresql/meta/requirements.yml create mode 100644 omero/roles/ome.postgresql/molecule/resources/playbook.yml create mode 100644 omero/roles/ome.postgresql/molecule/resources/requirements.yml create mode 100644 omero/roles/ome.postgresql/molecule/resources/tests/test_default.py create mode 100644 omero/roles/ome.postgresql/molecule/resources/tests/test_extra_options.py create mode 100644 omero/roles/ome.postgresql/molecule/resources/tests/utils.py create mode 100644 omero/roles/ome.postgresql/molecule/rockylinux9/molecule.yml create mode 100644 omero/roles/ome.postgresql/molecule/rockylinux9/prepare.yml create mode 100644 omero/roles/ome.postgresql/molecule/ubuntu2204/molecule.yml create mode 100644 omero/roles/ome.postgresql/molecule/ubuntu2204/prepare.yml create mode 100644 omero/roles/ome.postgresql/tasks/databases.yml create mode 100644 omero/roles/ome.postgresql/tasks/debian.yml create mode 100644 omero/roles/ome.postgresql/tasks/initialise.yml create mode 100644 omero/roles/ome.postgresql/tasks/main.yml create mode 100644 omero/roles/ome.postgresql/tasks/redhat.yml create mode 100644 omero/roles/ome.postgresql/templates/pg_hba-conf.j2 create mode 100644 omero/roles/ome.postgresql/templates/postgresql-conf-10-ubuntu.j2 create mode 100644 omero/roles/ome.postgresql/templates/postgresql-conf.j2 create mode 100644 omero/roles/ome.postgresql_backup/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.postgresql_backup/LICENSE.md create mode 100644 omero/roles/ome.postgresql_backup/README.md create mode 100644 omero/roles/ome.postgresql_backup/defaults/main.yml create mode 100644 omero/roles/ome.postgresql_backup/meta/.galaxy_install_info create mode 100644 omero/roles/ome.postgresql_backup/meta/main.yml create mode 100644 omero/roles/ome.postgresql_backup/molecule/default/molecule.yml create mode 100644 omero/roles/ome.postgresql_backup/molecule/default/playbook.yml create mode 100644 omero/roles/ome.postgresql_backup/molecule/default/requirements.yml create mode 100644 omero/roles/ome.postgresql_backup/molecule/default/tests/test_compress.py create mode 100644 omero/roles/ome.postgresql_backup/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.postgresql_backup/tasks/main.yml create mode 100644 omero/roles/ome.postgresql_backup/templates/etc-crond-postgresql-backup.j2 create mode 100644 omero/roles/ome.postgresql_client/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.postgresql_client/.gitignore create mode 100644 omero/roles/ome.postgresql_client/LICENSE.md create mode 100644 omero/roles/ome.postgresql_client/README.md create mode 100644 omero/roles/ome.postgresql_client/defaults/main.yml create mode 100644 omero/roles/ome.postgresql_client/meta/.galaxy_install_info create mode 100644 omero/roles/ome.postgresql_client/meta/main.yml create mode 100644 omero/roles/ome.postgresql_client/molecule/resources/playbook.yml create mode 100644 omero/roles/ome.postgresql_client/molecule/resources/tests/test_default.py create mode 100644 omero/roles/ome.postgresql_client/molecule/resources/tests/test_exactversion.py create mode 100644 omero/roles/ome.postgresql_client/molecule/rockylinux9/molecule.yml create mode 100644 omero/roles/ome.postgresql_client/molecule/ubuntu2204/molecule.yml create mode 100644 omero/roles/ome.postgresql_client/tasks/debian.yml create mode 100644 omero/roles/ome.postgresql_client/tasks/main.yml create mode 100644 omero/roles/ome.postgresql_client/tasks/redhat.yml create mode 100644 omero/roles/ome.postgresql_client/templates/pg_hba-conf.j2 create mode 100644 omero/roles/ome.postgresql_client/templates/postgresql-conf-10-ubuntu.j2 create mode 100644 omero/roles/ome.postgresql_client/templates/postgresql-conf.j2 create mode 100644 omero/roles/ome.postgresql_client/vars/main.yml create mode 100644 omero/roles/ome.python3_virtualenv/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.python3_virtualenv/.gitignore create mode 100644 omero/roles/ome.python3_virtualenv/LICENSE.md create mode 100644 omero/roles/ome.python3_virtualenv/README.md create mode 100644 omero/roles/ome.python3_virtualenv/files/ome-python3-virtualenv.sh create mode 100644 omero/roles/ome.python3_virtualenv/meta/.galaxy_install_info create mode 100644 omero/roles/ome.python3_virtualenv/meta/main.yml create mode 100644 omero/roles/ome.python3_virtualenv/molecule/default/Dockerfile.j2 create mode 100644 omero/roles/ome.python3_virtualenv/molecule/default/molecule.yml create mode 100644 omero/roles/ome.python3_virtualenv/molecule/resources/playbook.yml create mode 100644 omero/roles/ome.python3_virtualenv/molecule/resources/tests/test_default.py create mode 100644 omero/roles/ome.python3_virtualenv/tasks/debian.yml create mode 100644 omero/roles/ome.python3_virtualenv/tasks/main.yml create mode 100644 omero/roles/ome.python3_virtualenv/tasks/redhat.yml create mode 100644 omero/roles/ome.redis/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.redis/.gitignore create mode 100644 omero/roles/ome.redis/LICENSE.md create mode 100644 omero/roles/ome.redis/README.md create mode 100644 omero/roles/ome.redis/handlers/main.yml create mode 100644 omero/roles/ome.redis/meta/.galaxy_install_info create mode 100644 omero/roles/ome.redis/meta/main.yml create mode 100644 omero/roles/ome.redis/molecule/default/molecule.yml create mode 100644 omero/roles/ome.redis/molecule/default/playbook.yml create mode 100644 omero/roles/ome.redis/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.redis/tasks/main.yml create mode 100644 omero/roles/ome.selinux_utils/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.selinux_utils/.gitignore create mode 100644 omero/roles/ome.selinux_utils/LICENSE.md create mode 100644 omero/roles/ome.selinux_utils/README.md create mode 100644 omero/roles/ome.selinux_utils/meta/.galaxy_install_info create mode 100644 omero/roles/ome.selinux_utils/meta/main.yml create mode 100644 omero/roles/ome.selinux_utils/molecule/default/molecule.yml create mode 100644 omero/roles/ome.selinux_utils/molecule/default/playbook.yml create mode 100644 omero/roles/ome.selinux_utils/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.selinux_utils/tasks/main.yml create mode 100644 omero/roles/ome.ssl_certificate/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.ssl_certificate/.gitignore create mode 100644 omero/roles/ome.ssl_certificate/LICENSE.md create mode 100644 omero/roles/ome.ssl_certificate/README.md create mode 100644 omero/roles/ome.ssl_certificate/defaults/main.yml create mode 100644 omero/roles/ome.ssl_certificate/handlers/main.yml create mode 100644 omero/roles/ome.ssl_certificate/meta/.galaxy_install_info create mode 100644 omero/roles/ome.ssl_certificate/meta/main.yml create mode 100644 omero/roles/ome.ssl_certificate/molecule/default/converge.yml create mode 100644 omero/roles/ome.ssl_certificate/molecule/default/intermediate.pem create mode 100644 omero/roles/ome.ssl_certificate/molecule/default/molecule.yml create mode 100644 omero/roles/ome.ssl_certificate/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.ssl_certificate/molecule/default/tests/test_intermediate.py create mode 100644 omero/roles/ome.ssl_certificate/tasks/main.yml create mode 100644 omero/roles/ome.versioncontrol_utils/.github/workflows/molecule.yml create mode 100644 omero/roles/ome.versioncontrol_utils/.gitignore create mode 100644 omero/roles/ome.versioncontrol_utils/LICENSE.md create mode 100644 omero/roles/ome.versioncontrol_utils/README.md create mode 100644 omero/roles/ome.versioncontrol_utils/meta/.galaxy_install_info create mode 100644 omero/roles/ome.versioncontrol_utils/meta/main.yml create mode 100644 omero/roles/ome.versioncontrol_utils/molecule/default/molecule.yml create mode 100644 omero/roles/ome.versioncontrol_utils/molecule/default/playbook.yml create mode 100644 omero/roles/ome.versioncontrol_utils/molecule/default/tests/test_default.py create mode 100644 omero/roles/ome.versioncontrol_utils/tasks/main.yml diff --git a/omero/roles/iptables_raw/.github/workflows/molecule.yml b/omero/roles/iptables_raw/.github/workflows/molecule.yml new file mode 100644 index 00000000..0f92a0cb --- /dev/null +++ b/omero/roles/iptables_raw/.github/workflows/molecule.yml @@ -0,0 +1,59 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-20.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} + + +# notifications: +# webhooks: https://galaxy.ansible.com/api/v1/notifications/ diff --git a/omero/roles/iptables_raw/LICENSE.md b/omero/roles/iptables_raw/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/iptables_raw/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/iptables_raw/README.md b/omero/roles/iptables_raw/README.md new file mode 100644 index 00000000..12710939 --- /dev/null +++ b/omero/roles/iptables_raw/README.md @@ -0,0 +1,68 @@ +Iptables Raw +============ + +[![Actions Status](https://github.com/ome/ansible-role-iptables-raw/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-iptables-raw/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-iptables_raw-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/iptables_raw/) + +Import the Iptables Raw library and make it available as a task. +Ensure iptables is active. + +See these links for full documentation on the `iptables_raw` module: +- https://nordeus.com/blog/engineering/managing-iptables-with-ansible-the-easy-way/ +- https://github.com/Nordeus/ansible_iptables_raw +- https://github.com/ansible/ansible/pull/21054 + + +Parameters +---------- + +Optional: +- `iptables_raw_disable_firewalld`: Disable the firewalld service (if installed and enabled it will conflict), default `True` + + +Development +----------- +The [`library/iptables_raw.py`](library/iptables_raw.py) version is https://github.com/Nordeus/ansible_iptables_raw/tree/34672590224f393016ad086f82054319108e67ad (2018-02-18) with the following change to prevent ansible-lint/flake8 failing: + +```diff +diff --git a/library/iptables_raw.py b/library/iptables_raw.py +index 71dfc0d..978a6c7 100644 +--- a/library/iptables_raw.py ++++ b/library/iptables_raw.py +@@ -344,7 +344,7 @@ class Iptables: + def _is_debian(self): + return os.path.isfile('/etc/debian_version') + +- # If /etc/arch-release exist, this means this is an ArchLinux OS ++ # If /etc/arch-release exist, this means this is an ArchLinux OS + def _is_arch_linux(self): + return os.path.isfile('/etc/arch-release') + +``` + + +Example Playbook +---------------- + + - hosts: localhost + roles: + - role: ome.iptables-raw + + tasks: + # Block all incoming connections apart from ssh + - ome.iptables_raw: + name: test_rules + keep_unmanaged: no + rules: | + -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT + -A INPUT -j REJECT + -A FORWARD -j REJECT + -A OUTPUT -j ACCEPT + state: present + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/iptables_raw/library/iptables_raw_25.py b/omero/roles/iptables_raw/library/iptables_raw_25.py new file mode 100644 index 00000000..0162e5b2 --- /dev/null +++ b/omero/roles/iptables_raw/library/iptables_raw_25.py @@ -0,0 +1,1107 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +""" +(c) 2016, Strahinja Kustudic +(c) 2016, Damir Markovic + +This file is part of Ansible + +Ansible is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Ansible is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Ansible. If not, see . +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import json + +import time +import fcntl +import re +import shlex +import os +import tempfile + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} + +DOCUMENTATION = ''' +--- +module: iptables_raw +short_description: Manage iptables rules +version_added: "2.5" +description: + - Add/remove iptables rules while keeping state. +options: + backup: + description: + - Create a backup of the iptables state file before overwriting it. + required: false + choices: ["yes", "no"] + default: "no" + ipversion: + description: + - Target the IP version this rule is for. + required: false + default: "4" + choices: ["4", "6"] + keep_unmanaged: + description: + - If set to C(yes) keeps active iptables (unmanaged) rules for the target + C(table) and gives them C(weight=90). This means these rules will be + ordered after most of the rules, since default priority is 40, so they + shouldn't be able to block any allow rules. If set to C(no) deletes all + rules which are not set by this module. + - "WARNING: Be very careful when running C(keep_unmanaged=no) for the + first time, since if you don't specify correct rules, you can block + yourself out of the managed host." + required: false + choices: ["yes", "no"] + default: "yes" + name: + description: + - Name that will be used as an identifier for these rules. It can contain + alphanumeric characters, underscore, hyphen, dot, or a space; has to be + UNIQUE for a specified C(table). You can also pass C(name=*) with + C(state=absent) to flush all rules in the selected table, or even all + tables with C(table=*). + required: true + rules: + description: + - The rules that we want to add. Accepts multiline values. + - "Note: You can only use C(-A)/C(--append), C(-N)/C(--new-chain), and + C(-P)/C(--policy) to specify rules." + required: false + state: + description: + - The state this rules fragment should be in. + choices: ["present", "absent"] + required: false + default: present + table: + description: + - The table this rule applies to. You can specify C(table=*) only with + with C(name=*) and C(state=absent) to flush all rules in all tables. + choices: ["filter", "nat", "mangle", "raw", "security", "*"] + required: false + default: filter + weight: + description: + - Determines the order of the rules. Lower C(weight) means higher + priority. Supported range is C(0 - 99) + choices: ["0 - 99"] + required: false + default: 40 +notes: + - Requires C(iptables) package. Debian-based distributions additionally + require C(iptables-persistent). + - "Depending on the distribution, iptables rules are saved in different + locations, so that they can be loaded on boot. Red Hat distributions (RHEL, + CentOS, etc): C(/etc/sysconfig/iptables) and C(/etc/sysconfig/ip6tables); + Debian distributions (Debian, Ubuntu, etc): C(/etc/iptables/rules.v4) and + C(/etc/iptables/rules.v6); other distributions: C(/etc/sysconfig/iptables) + and C(/etc/sysconfig/ip6tables)." + - This module saves state in C(/etc/ansible-iptables) directory, so don't + modify this directory! +author: + - "Strahinja Kustudic (@kustodian)" + - "Damir Markovic (@damirda)" +''' + +EXAMPLES = ''' +# Allow all IPv4 traffic coming in on port 80 (http) +- iptables_raw: + name: allow_tcp_80 + rules: '-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT' + +# Set default rules with weight 10 and disregard all unmanaged rules +- iptables_raw: + name: default_rules + weight: 10 + keep_unmanaged: no + rules: | + -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT + -A INPUT -i lo -j ACCEPT + -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT + -P INPUT DROP + -P FORWARD DROP + -P OUTPUT ACCEPT + +# Allow all IPv6 traffic coming in on port 443 (https) with weight 50 +- iptables_raw: + ipversion: 6 + weight: 50 + name: allow_tcp_443 + rules: '-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT' + +# Remove the above rule +- iptables_raw: + state: absent + ipversion: 6 + name: allow_tcp_443 + +# Define rules with a custom chain +- iptables_raw: + name: custom1_rules + rules: | + -N CUSTOM1 + -A CUSTOM1 -s 192.168.0.0/24 -j ACCEPT + +# Reset all IPv4 iptables rules in all tables and allow all traffic +- iptables_raw: + name: '*' + table: '*' + state: absent +''' + +RETURN = ''' +state: + description: state of the rules + returned: success + type: string + sample: present +name: + description: name of the rules + returned: success + type: string + sample: open_tcp_80 +weight: + description: weight of the rules + returned: success + type: int + sample: 40 +ipversion: + description: IP version of iptables used + returned: success + type: int + sample: 6 +rules: + description: passed rules + returned: success + type: string + sample: "-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT" +table: + description: iptables table used + returned: success + type: string + sample: filter +backup: + description: if the iptables file should backed up + returned: success + type: boolean + sample: False +keep_unmanaged: + description: if it should keep unmanaged rules + returned: success + type: boolean + sample: True +''' + +try: + from collections import defaultdict +except ImportError: + # This is a workaround for Python 2.4 which doesn't have defaultdict. + class defaultdict(dict): + def __init__(self, default_factory, *args, **kwargs): + super(defaultdict, self).__init__(*args, **kwargs) + self.default_factory = default_factory + + def __getitem__(self, key): + try: + return super(defaultdict, self).__getitem__(key) + except KeyError: + return self.__missing__(key) + + def __missing__(self, key): + try: + self[key] = self.default_factory() + except TypeError: + raise KeyError("Missing key %s" % (key, )) + else: + return self[key] + + +# Genereates a diff dictionary from an old and new table dump. +def generate_diff(dump_old, dump_new): + diff = dict() + if dump_old != dump_new: + diff['before'] = dump_old + diff['after'] = dump_new + return diff + + +def compare_dictionaries(dict1, dict2): + if dict1 is None or dict2 is None: + return False + if not (isinstance(dict1, dict) and isinstance(dict2, dict)): + return False + shared_keys = set(dict2.keys()) & set(dict2.keys()) + if not (len(shared_keys) == len(dict1.keys()) and len(shared_keys) == len(dict2.keys())): # noqa + return False + dicts_are_equal = True + for key in dict1.keys(): + if isinstance(dict1[key], dict): + dicts_are_equal = dicts_are_equal and compare_dictionaries(dict1[key], dict2[key]) # noqa + else: + dicts_are_equal = dicts_are_equal and (dict1[key] == dict2[key]) + if not dicts_are_equal: + break + return dicts_are_equal + + +class Iptables: + + # Default chains for each table + DEFAULT_CHAINS = { + 'filter': ['INPUT', 'FORWARD', 'OUTPUT'], + 'raw': ['PREROUTING', 'OUTPUT'], + 'nat': ['PREROUTING', 'INPUT', 'OUTPUT', 'POSTROUTING'], + 'mangle': ['PREROUTING', 'INPUT', 'FORWARD', 'OUTPUT', 'POSTROUTING'], + 'security': ['INPUT', 'FORWARD', 'OUTPUT'] + } + + # List of tables + TABLES = list(DEFAULT_CHAINS.copy().keys()) + + # Directory which will store the state file. + STATE_DIR = '/etc/ansible-iptables' + + # Key used for unmanaged rules + UNMANAGED_RULES_KEY_NAME = '$unmanaged_rules$' + + # Only allow alphanumeric characters, underscore, hyphen, dots, + # or a space for + # now. We don't want to have problems while parsing comments using regular + # expressions. + RULE_NAME_ALLOWED_CHARS = 'a-zA-Z0-9_ .-' + + module = None + + def __init__(self, module, ipversion): + # Create directory for json files. + if not os.path.exists(self.STATE_DIR): + os.makedirs(self.STATE_DIR) + if Iptables.module is None: + Iptables.module = module + self.state_save_path = self._get_state_save_path(ipversion) + self.system_save_path = self._get_system_save_path(ipversion) + self.state_dict = self._read_state_file() + self.bins = self._get_bins(ipversion) + self.iptables_names_file = self._get_iptables_names_file(ipversion) + # Check if we have a required iptables version. + self._check_compatibility() + # Save active iptables rules for all tables, so that we don't + # need to fetch them every time using 'iptables-save' command. + self._active_rules = {} + self._refresh_active_rules(table='*') + + def __eq__(self, other): + return (isinstance(other, self.__class__) and compare_dictionaries(other.state_dict, self.state_dict)) # noqa + + def __ne__(self, other): + return not self.__eq__(other) + + def _get_bins(self, ipversion): + if ipversion == '4': + return {'iptables': Iptables.module.get_bin_path('iptables'), + 'iptables-save': Iptables.module.get_bin_path('iptables-save'), # noqa + 'iptables-restore': Iptables.module.get_bin_path('iptables-restore')} # noqa + else: + return {'iptables': Iptables.module.get_bin_path('ip6tables'), + 'iptables-save': Iptables.module.get_bin_path('ip6tables-save'), # noqa + 'iptables-restore': Iptables.module.get_bin_path('ip6tables-restore')} # noqa + + def _get_iptables_names_file(self, ipversion): + if ipversion == '4': + return '/proc/net/ip_tables_names' + else: + return '/proc/net/ip6_tables_names' + + # Return a list of active iptables tables + def _get_list_of_active_tables(self): + if os.path.isfile(self.iptables_names_file): + table_names = open(self.iptables_names_file, 'r').read() + return table_names.splitlines() + else: + return [] + + # If /etc/debian_version exist, this means this is a + # debian based OS (Ubuntu, Mint, etc...) + def _is_debian(self): + return os.path.isfile('/etc/debian_version') + + # If /etc/arch-release exist, this means this is an ArchLinux OS + def _is_arch_linux(self): + return os.path.isfile('/etc/arch-release') + + # If /etc/gentoo-release exist, this means this is Gentoo + def _is_gentoo(self): + return os.path.isfile('/etc/gentoo-release') + + # Get the iptables system save path. + # Supports RHEL/CentOS '/etc/sysconfig/' location. + # Supports Debian/Ubuntu/Mint, '/etc/iptables/' location. + # Supports Gentoo, '/var/lib/iptables/' location. + def _get_system_save_path(self, ipversion): + # distro detection, path setting should be added + if self._is_debian(): + # Check if iptables-persistent packages is installed + if not os.path.isdir('/etc/iptables'): + Iptables.module.fail_json(msg="This module requires 'iptables-persistent' package!") # noqa + if ipversion == '4': + return '/etc/iptables/rules.v4' + else: + return '/etc/iptables/rules.v6' + elif self._is_arch_linux(): + if ipversion == '4': + return '/etc/iptables/iptables.rules' + else: + return '/etc/iptables/ip6tables.rules' + elif self._is_gentoo(): + if ipversion == '4': + return '/var/lib/iptables/rules-save' + else: + return '/var/lib/ip6tables/rules-save' + else: + if ipversion == '4': + return '/etc/sysconfig/iptables' + else: + return '/etc/sysconfig/ip6tables' + + # Return path to json state file. + def _get_state_save_path(self, ipversion): + if ipversion == '4': + return self.STATE_DIR + '/iptables.json' + else: + return self.STATE_DIR + '/ip6tables.json' + + # Checks if iptables is installed and if we have a correct version. + def _check_compatibility(self): + from distutils.version import StrictVersion + cmd = [self.bins['iptables'], '--version'] + rc, stdout, stderr = Iptables.module.run_command(cmd, check_rc=False) + if rc == 0: + result = re.search(r'^ip6tables\s+v(\d+\.\d+)\.\d+$', stdout) + if result: + version = result.group(1) + # CentOS 5 ip6tables (v1.3.x) doesn't support comments, + # which means it cannot be used with this module. + if StrictVersion(version) < StrictVersion('1.4'): + Iptables.module.fail_json(msg="This module isn't compatible with ip6tables versions older than 1.4.x") # noqa + else: + Iptables.module.fail_json(msg="Could not fetch iptables version! Is iptables installed?") # noqa + + # Read rules from the json state file and return a dict. + def _read_state_file(self): + json_str = '{}' + if os.path.isfile(self.state_save_path): + try: + json_str = open(self.state_save_path, 'r').read() + except: # noqa + Iptables.module.fail_json(msg="Could not read the state file '%s'!" % self.state_save_path) # noqa + try: + read_dict = defaultdict(lambda: dict(dump='', rules_dict={}), json.loads(json_str)) # noqa + except: # noqa + Iptables.module.fail_json(msg="Could not parse the state file '%s'! Please manually delete it to continue." % self.state_save_path) # noqa + return read_dict + + # Checks if a table exists in the state_dict. + def _has_table(self, tbl): + return tbl in self.state_dict + + # Deletes table from the state_dict. + def _delete_table(self, tbl): + if self._has_table(tbl): + del self.state_dict[tbl] + + # Acquires lock or exits after wait_for_seconds if it cannot be acquired. + def acquire_lock_or_exit(self, wait_for_seconds=10): + lock_file = self.STATE_DIR + '/.iptables.lock' + i = 0 + f = open(lock_file, 'w+') + while i < wait_for_seconds: + try: + fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) + return + except IOError: + i += 1 + time.sleep(1) + Iptables.module.fail_json(msg="Could not acquire lock to " + "continue execution! " + "Probably another instance " + "of this module is running.") + + # Check if a table has anything to flush + # (to check all tables pass table='*'). + def table_needs_flush(self, table): + needs_flush = False + if table == '*': + for tbl in Iptables.TABLES: + # If the table exists or if it needs + # to be flushed that means will make changes. + if self._has_table(tbl) or self._single_table_needs_flush(tbl): # noqa + needs_flush = True + break + # Only flush the specified table + else: + if self._has_table(table) or self._single_table_needs_flush(table): # noqa + needs_flush = True + return needs_flush + + # Check if a passed table needs to be flushed. + def _single_table_needs_flush(self, table): + needs_flush = False + active_rules = self._get_active_rules(table) + if active_rules: + policies = self._filter_default_chain_policies(active_rules, table) # noqa + chains = self._filter_custom_chains(active_rules, table) + rules = self._filter_rules(active_rules, table) + # Go over default policies and check if they are all ACCEPT. + for line in policies.splitlines(): + if not re.search(r'\bACCEPT\b', line): + needs_flush = True + break + # If there is at least one rule or custom chain, + # that means we need flush. + if len(chains) > 0 or len(rules) > 0: + needs_flush = True + return needs_flush + + # Returns a copy of the rules dict of a passed table. + def _get_table_rules_dict(self, table): + return self.state_dict[table]['rules_dict'].copy() + + # Returns saved table dump. + def get_saved_table_dump(self, table): + return self.state_dict[table]['dump'] + + # Sets saved table dump. + def _set_saved_table_dump(self, table, dump): + self.state_dict[table]['dump'] = dump + + # Updates saved table dump from the active rules. + def refresh_saved_table_dump(self, table): + active_rules = self._get_active_rules(table) + self._set_saved_table_dump(table, active_rules) + + # Sets active rules of the passed table. + def _set_active_rules(self, table, rules): + self._active_rules[table] = rules + + # Return active rules of the passed table. + def _get_active_rules(self, table, clean=True): + active_rules = '' + if table == '*': + all_rules = [] + for tbl in Iptables.TABLES: + if tbl in self._active_rules: + all_rules.append(self._active_rules[tbl]) + active_rules = '\n'.join(all_rules) + else: + active_rules = self._active_rules[table] + if clean: + return self._clean_save_dump(active_rules) + else: + return active_rules + + # Refresh active rules of a table ('*' for all tables). + def _refresh_active_rules(self, table): + if table == '*': + for tbl in Iptables.TABLES: + self._set_active_rules(tbl, self._get_system_active_rules(tbl)) # noqa + else: + self._set_active_rules(table, self._get_system_active_rules(table)) # noqa + + # Get iptables-save dump of active rules of + # one or all tables (pass '*') and return it as a string. + def _get_system_active_rules(self, table): + active_tables = self._get_list_of_active_tables() + if table == '*': + cmd = [self.bins['iptables-save']] + # If there are no active tables, that means there are no rules + if not active_tables: + return "" + else: + cmd = [self.bins['iptables-save'], '-t', table] + # If the table is not active, that means it has no rules + if table not in active_tables: + return "" + rc, stdout, stderr = Iptables.module.run_command(cmd, check_rc=True) + return stdout + + # Splits a rule into tokens + def _split_rule_into_tokens(self, rule): + try: + return shlex.split(rule, comments=True) + except: # noqa + msg = "Could not parse the iptables rule:\n%s" % rule + Iptables.module.fail_json(msg=msg) + + # Removes comment lines and empty lines from rules. + @staticmethod + def clean_up_rules(rules): + cleaned_rules = [] + for line in rules.splitlines(): + # Remove lines with comments and empty lines. + if not (Iptables.is_comment(line) or Iptables.is_empty_line(line)): # noqa + cleaned_rules.append(line) + return '\n'.join(cleaned_rules) + + # Checks if the line is a custom chain in specific iptables table. + @staticmethod + def is_custom_chain(line, table): + default_chains = Iptables.DEFAULT_CHAINS[table] + if re.match(r'\s*(:|(-N|--new-chain)\s+)[^\s]+', line) \ + and not re.match(r'\s*(:|(-N|--new-chain)\s+)\b(' + '|'.join(default_chains) + r')\b', line): # noqa + return True + else: + return False + + # Checks if the line is a default chain of an iptables table. + @staticmethod + def is_default_chain(line, table): + default_chains = Iptables.DEFAULT_CHAINS[table] + if re.match(r'\s*(:|(-P|--policy)\s+)\b(' + '|'.join(default_chains) + r')\b\s+(ACCEPT|DROP)', line): # noqa + return True + else: + return False + + # Checks if a line is an iptables rule. + @staticmethod + def is_rule(line): + # We should only allow adding rules with '-A/--append', + # since others don't make any sense. + if re.match(r'\s*(-A|--append)\s+[^\s]+', line): + return True + else: + return False + + # Checks if a line starts with '#'. + @staticmethod + def is_comment(line): + if re.match(r'\s*#', line): + return True + else: + return False + + # Checks if a line is empty. + @staticmethod + def is_empty_line(line): + if re.match(r'^$', line.strip()): + return True + else: + return False + + # Return name of custom chain from the rule. + def _get_custom_chain_name(self, line, table): + if Iptables.is_custom_chain(line, table): + return re.match(r'\s*(:|(-N|--new-chain)\s+)([^\s]+)', line).group(3) # noqa + else: + return '' + + # Return name of default chain from the rule. + def _get_default_chain_name(self, line, table): + if Iptables.is_default_chain(line, table): + return re.match(r'\s*(:|(-N|--new-chain)\s+)([^\s]+)', line).group(3) # noqa + else: + return '' + + # Return target of the default chain from the rule. + def _get_default_chain_target(self, line, table): + if Iptables.is_default_chain(line, table): + return re.match(r'\s*(:|(-N|--new-chain)\s+)([^\s]+)\s+([A-Z]+)', line).group(4) # noqa + else: + return '' + + # Removes duplicate custom chains from the table rules. + def _remove_duplicate_custom_chains(self, rules, table): + all_rules = [] + custom_chain_names = [] + for line in rules.splitlines(): + # Extract custom chains. + if Iptables.is_custom_chain(line, table): + chain_name = self._get_custom_chain_name(line, table) + if chain_name not in custom_chain_names: + custom_chain_names.append(chain_name) + all_rules.append(line) + else: + all_rules.append(line) + return '\n'.join(all_rules) + + # Returns current iptables-save dump cleaned + # from comments and packet/byte counters. + def _clean_save_dump(self, simple_rules): + cleaned_dump = [] + for line in simple_rules.splitlines(): + # Ignore comments. + if Iptables.is_comment(line): + continue + # Reset counters for chains (begin with ':'), + # for easier comparing later on. + if re.match(r'\s*:', line): + cleaned_dump.append(re.sub(r'\[([0-9]+):([0-9]+)\]', '[0:0]', line)) # noqa + else: + cleaned_dump.append(line) + cleaned_dump.append('\n') + return '\n'.join(cleaned_dump) + + # Returns lines with default chain policies. + def _filter_default_chain_policies(self, rules, table): + chains = [] + for line in rules.splitlines(): + if Iptables.is_default_chain(line, table): + chains.append(line) + return '\n'.join(chains) + + # Returns lines with iptables rules from an iptables-save table dump + # (removes chain policies, custom chains, comments and everything else). + # By default returns all rules, if 'only_unmanged=True' + # returns rules which are not managed by Ansible. + def _filter_rules(self, rules, table, only_unmanaged=False): + filtered_rules = [] + for line in rules.splitlines(): + if Iptables.is_rule(line): + if only_unmanaged: + tokens = self._split_rule_into_tokens(line) + # We need to check if a rule has a comment + # which starts with 'ansible[name]' + if '--comment' in tokens: + comment_index = tokens.index('--comment') + 1 + if comment_index < len(tokens): + # Fetch the comment + comment = tokens[comment_index] + # Skip the rule if the comment + # starts with 'ansible[name]' + if not re.match(r'ansible\[[' + Iptables.RULE_NAME_ALLOWED_CHARS + r']+\]', comment): # noqa + filtered_rules.append(line) + else: + # Fail if there is no comment after + # the --comment parameter + msg = "Iptables rule is missing a comment after the '--comment' parameter:\n%s" % line # noqa + Iptables.module.fail_json(msg=msg) + # If it doesn't have comment, this means + # it is not managed by Ansible and we should append it. + else: + filtered_rules.append(line) + else: + filtered_rules.append(line) + return '\n'.join(filtered_rules) + + # Same as _filter_rules(), but returns custom chains + def _filter_custom_chains(self, rules, table, only_unmanaged=False): + filtered_chains = [] + # Get list of managed custom chains, + # which is needed to detect unmanaged custom chains + managed_custom_chains_list = self._get_custom_chains_list(table) + for line in rules.splitlines(): + if Iptables.is_custom_chain(line, table): + if only_unmanaged: + # The chain is not managed by this module + # if it's not in the list of managed custom chains. + chain_name = self._get_custom_chain_name(line, table) + if chain_name not in managed_custom_chains_list: + filtered_chains.append(line) + else: + filtered_chains.append(line) + return '\n'.join(filtered_chains) + + # Returns list of custom chains of a table. + def _get_custom_chains_list(self, table): + custom_chains_list = [] + for key, value in self._get_table_rules_dict(table).items(): + # Ignore UNMANAGED_RULES_KEY_NAME key, since + # we only want managed custom chains. + if key != Iptables.UNMANAGED_RULES_KEY_NAME: + for line in value['rules'].splitlines(): + if Iptables.is_custom_chain(line, table): + chain_name = self._get_custom_chain_name(line, table) + if chain_name not in custom_chains_list: + custom_chains_list.append(chain_name) + return custom_chains_list + + # Prepends 'ansible[name]: ' to iptables rule '--comment' argument, + # or adds 'ansible[name]' as a comment if there is no comment. + def _prepend_ansible_comment(self, rules, name): + commented_lines = [] + for line in rules.splitlines(): + # Extract rules only since we cannot + # add comments to custom chains. + if Iptables.is_rule(line): + tokens = self._split_rule_into_tokens(line) + if '--comment' in tokens: + # If there is a comment parameter, + # we need to prepand 'ansible[name]: '. + comment_index = tokens.index('--comment') + 1 + if comment_index < len(tokens): + # We need to remove double quotes + # from comments, since there + # is an incompatiblity with older iptables versions + comment_text = tokens[comment_index].replace('"', '') + tokens[comment_index] = 'ansible[' + name + ']: ' + comment_text # noqa + else: + # Fail if there is no comment + # after the --comment parameter + msg = "Iptables rule is missing a comment after the '--comment' parameter:\n%s" % line # noqa + Iptables.module.fail_json(msg=msg) + else: + # If comment doesn't exist, we + # add a comment 'ansible[name]' + tokens += ['-m', 'comment', '--comment', 'ansible[' + name + ']'] # noqa + # Escape and quote tokens in case they have spaces + tokens = [self._escape_and_quote_string(x) for x in tokens] + commented_lines.append(" ".join(tokens)) + # Otherwise it's a chain, and we should just return it. + else: + commented_lines.append(line) + return '\n'.join(commented_lines) + + # Double quote a string if it contains a space and escape double quotes. + def _escape_and_quote_string(self, s): + escaped = s.replace('"', r'\"') + if re.search(r'\s', escaped): + return '"' + escaped + '"' + else: + return escaped + + # Add table rule to the state_dict. + def add_table_rule(self, table, name, weight, rules, prepend_ansible_comment=True): # noqa + self._fail_on_bad_rules(rules, table) + if prepend_ansible_comment: + self.state_dict[table]['rules_dict'][name] = {'weight': weight, 'rules': self._prepend_ansible_comment(rules, name)} # noqa + else: + self.state_dict[table]['rules_dict'][name] = {'weight': weight, 'rules': rules} # noqa + + # Remove table rule from the state_dict. + def remove_table_rule(self, table, name): + if name in self.state_dict[table]['rules_dict']: + del self.state_dict[table]['rules_dict'][name] + + # TODO: Add sorting of rules so that diffs in check_ + # mode look nicer and easier to follow. + # Sorting would be done from top to bottom like this: + # * default chain policies + # * custom chains + # * rules + # + # Converts rules from a state_dict to an iptables-save readable format. + def get_table_rules(self, table): + generated_rules = '' + # We first add a header e.g. '*filter'. + generated_rules += '*' + table + '\n' + rules_list = [] + custom_chains_list = [] + default_chain_policies = [] + dict_rules = self._get_table_rules_dict(table) + # Return list of rule names sorted by ('weight', 'rules') tuple. + for rule_name in sorted(dict_rules, key=lambda x: (dict_rules[x]['weight'], dict_rules[x]['rules'])): # noqa + rules = dict_rules[rule_name]['rules'] + # Fail if some of the rules are bad + self._fail_on_bad_rules(rules, table) + rules_list.append(self._filter_rules(rules, table)) + custom_chains_list.append(self._filter_custom_chains(rules, table)) # noqa + default_chain_policies.append(self._filter_default_chain_policies(rules, table)) # noqa + # Clean up empty strings from these two lists. + rules_list = list(filter(None, rules_list)) + custom_chains_list = list(filter(None, custom_chains_list)) + default_chain_policies = list(filter(None, default_chain_policies)) + if default_chain_policies: + # Since iptables-restore applies + # the last chain policy it reads, we + # have to reverse the order of chain + # policies so that those with + # the lowest weight (higher priority) are read last. + generated_rules += '\n'.join(reversed(default_chain_policies)) + '\n' # noqa + if custom_chains_list: + # We remove duplicate custom chains so that iptables-restore + # doesn't fail because of that. + generated_rules += self._remove_duplicate_custom_chains('\n'.join(sorted(custom_chains_list)), table) + '\n' # noqa + if rules_list: + generated_rules += '\n'.join(rules_list) + '\n' + generated_rules += 'COMMIT\n' + return generated_rules + + # Sets unmanaged rules for the passed table in the state_dict. + def _set_unmanaged_rules(self, table, rules): + self.add_table_rule(table, Iptables.UNMANAGED_RULES_KEY_NAME, 90, rules, prepend_ansible_comment=False) # noqa + + # Clears unmanaged rules of a table. + def clear_unmanaged_rules(self, table): + self._set_unmanaged_rules(table, '') + + # Updates unmanaged rules of a table from the active rules. + def refresh_unmanaged_rules(self, table): + # Get active iptables rules and clean them up. + active_rules = self._get_active_rules(table) + unmanaged_chains_and_rules = [] + unmanaged_chains_and_rules.append(self._filter_custom_chains(active_rules, table, only_unmanaged=True)) # noqa + unmanaged_chains_and_rules.append(self._filter_rules(active_rules, table, only_unmanaged=True)) # noqa + # Clean items which are empty strings + unmanaged_chains_and_rules = list(filter(None, unmanaged_chains_and_rules)) # noqa + self._set_unmanaged_rules(table, '\n'.join(unmanaged_chains_and_rules)) # noqa + + # Check if there are bad lines in the specified rules. + def _fail_on_bad_rules(self, rules, table): + for line in rules.splitlines(): + tokens = self._split_rule_into_tokens(line) + if '-t' in tokens or '--table' in tokens: + msg = ("Iptables rules cannot contain '-t/--table' parameter. " # noqa + "You should use the 'table' parameter of the module to set rules " # noqa + "for a specific table.") + Iptables.module.fail_json(msg=msg) + # Fail if the parameter --comment doesn't have a comment after + if '--comment' in tokens and len(tokens) <= tokens.index('--comment') + 1: # noqa + msg = "Iptables rule is missing a comment after the '--comment' parameter:\n%s" % line # noqa + Iptables.module.fail_json(msg=msg) + if not (Iptables.is_rule(line) or + Iptables.is_custom_chain(line, table) or + Iptables.is_default_chain(line, table) or + Iptables.is_comment(line)): + msg = ("Bad iptables rule '%s'! You can only use -A/--append, -N/--new-chain " # noqa + "and -P/--policy to specify rules." % line) + Iptables.module.fail_json(msg=msg) + + # Write rules to dest path. + def _write_rules_to_file(self, rules, dest): + tmp_path = self._write_to_temp_file(rules) + Iptables.module.atomic_move(tmp_path, dest) + + # Write text to a temp file and return path to that file. + def _write_to_temp_file(self, text): + fd, path = tempfile.mkstemp() + Iptables.module.add_cleanup_file(path) # add file for cleanup later + tmp = os.fdopen(fd, 'w') + tmp.write(text) + tmp.close() + return path + + # + # Public and private methods which make changes on the system + # are named 'system_*' and '_system_*', respectively. + # + + # Flush all rules in a passed table. + def _system_flush_single_table_rules(self, table): + # Set all default chain policies to ACCEPT. + for chain in Iptables.DEFAULT_CHAINS[table]: + cmd = [self.bins['iptables'], '-t', table, '-P', chain, 'ACCEPT'] + Iptables.module.run_command(cmd, check_rc=True) + # Then flush all rules. + cmd = [self.bins['iptables'], '-t', table, '-F'] + Iptables.module.run_command(cmd, check_rc=True) + # And delete custom chains. + cmd = [self.bins['iptables'], '-t', table, '-X'] + Iptables.module.run_command(cmd, check_rc=True) + # Update active rules in the object. + self._refresh_active_rules(table) + + # Save active iptables rules to the system path. + def _system_save_active(self, backup=False): + # Backup if needed + if backup: + Iptables.module.backup_local(self.system_save_path) + # Get iptables-save dump of all tables + all_active_rules = self._get_active_rules(table='*', clean=False) + # Move iptables-save dump of all tables to the iptables_save_path + self._write_rules_to_file(all_active_rules, self.system_save_path) + + # Apply table dict rules to the system. + def system_apply_table_rules(self, table, test=False): + dump_path = self._write_to_temp_file(self.get_table_rules(table)) + if test: + cmd = [self.bins['iptables-restore'], '-t', dump_path] + else: + cmd = [self.bins['iptables-restore'], dump_path] + rc, stdout, stderr = Iptables.module.run_command(cmd, check_rc=False) + if rc != 0: + if test: + dump_contents_file = open(dump_path, 'r') + dump_contents = dump_contents_file.read() + dump_contents_file.close() + msg = "There is a problem with the iptables rules:" \ + + '\n\nError message:\n' \ + + stderr \ + + '\nGenerated rules:\n#######\n' \ + + dump_contents + '#####' + else: + msg = "Could not load iptables rules:\n\n" + stderr + Iptables.module.fail_json(msg=msg) + self._refresh_active_rules(table) + + # Flush one or all tables (to flush all tables pass table='*'). + def system_flush_table_rules(self, table): + if table == '*': + for tbl in Iptables.TABLES: + self._delete_table(tbl) + if self._single_table_needs_flush(tbl): + self._system_flush_single_table_rules(tbl) + # Only flush the specified table. + else: + self._delete_table(table) + if self._single_table_needs_flush(table): + self._system_flush_single_table_rules(table) + + # Saves state file and system iptables rules. + def system_save(self, backup=False): + self._system_save_active(backup=backup) + rules = json.dumps(self.state_dict, sort_keys=True, indent=4, separators=(',', ': ')) # noqa + self._write_rules_to_file(rules, self.state_save_path) + + +def main(): + + module = AnsibleModule( + argument_spec=dict( + ipversion=dict(required=False, choices=["4", "6"], type='str', default="4"), # noqa + state=dict(required=False, choices=['present', 'absent'], default='present', type='str'), # noqa + weight=dict(required=False, type='int', default=40), + name=dict(required=True, type='str'), + table=dict(required=False, choices=Iptables.TABLES + ['*'], default="filter", type='str'), # noqa + rules=dict(required=False, type='str', default=""), + backup=dict(required=False, type='bool', default=False), + keep_unmanaged=dict(required=False, type='bool', default=True), + ), + supports_check_mode=True, + ) + + check_mode = module.check_mode + changed = False + ipversion = module.params['ipversion'] + state = module.params['state'] + weight = module.params['weight'] + name = module.params['name'] + table = module.params['table'] + rules = module.params['rules'] + backup = module.params['backup'] + keep_unmanaged = module.params['keep_unmanaged'] + + kw = dict(state=state, name=name, rules=rules, weight=weight, ipversion=ipversion, # noqa + table=table, backup=backup, keep_unmanaged=keep_unmanaged) + + iptables = Iptables(module, ipversion) + + # Acquire lock so that only one instance of this object can exist. + # Fail if the lock cannot be acquired within 10 seconds. + iptables.acquire_lock_or_exit(wait_for_seconds=10) + + # Clean up rules of comments and empty lines. + rules = Iptables.clean_up_rules(rules) + + # Check additional parameter requirements + if state == 'present' and name == '*': + module.fail_json(msg="Parameter 'name' can only be '*' if 'state=absent'") # noqa + if state == 'present' and table == '*': + module.fail_json(msg="Parameter 'table' can only be '*' if 'name=*' and 'state=absent'") # noqa + if state == 'present' and not name: + module.fail_json(msg="Parameter 'name' cannot be empty") + if state == 'present' and not re.match('^[' + Iptables.RULE_NAME_ALLOWED_CHARS + ']+$', name): # noqa + module.fail_json(msg="Parameter 'name' not valid! It can only contain alphanumeric characters, " # noqa + "underscore, hyphen, or a space, got: '%s'" % name) # noqa + if weight < 0 or weight > 99: + module.fail_json(msg="Parameter 'weight' can be 0-99, got: %d" % weight) # noqa + if state == 'present' and rules == '': + module.fail_json(msg="Parameter 'rules' cannot be empty when 'state=present'") # noqa + + # Flush rules of one or all tables + if state == 'absent' and name == '*': + # Check if table(s) need to be flushed + if iptables.table_needs_flush(table): + changed = True + if not check_mode: + # Flush table(s) + iptables.system_flush_table_rules(table) + # Save state and system iptables rules + iptables.system_save(backup=backup) + # Exit since there is nothing else to do + kw['changed'] = changed + module.exit_json(**kw) + + # Initialize new iptables object which will store new rules + iptables_new = Iptables(module, ipversion) + + if state == 'present': + iptables_new.add_table_rule(table, name, weight, rules) + else: + iptables_new.remove_table_rule(table, name) + + if keep_unmanaged: + iptables_new.refresh_unmanaged_rules(table) + else: + iptables_new.clear_unmanaged_rules(table) + + # Refresh saved table dump with active iptables rules + iptables_new.refresh_saved_table_dump(table) + + # Check if there are changes in iptables, and if yes load new rules + if iptables != iptables_new: + + changed = True + + # Test generated rules + iptables_new.system_apply_table_rules(table, test=True) + + if check_mode: + # Create a predicted diff for check_mode. + # Diff will be created from rules generated + # from the state dictionary. + if hasattr(module, '_diff') and module._diff: + # Update unmanaged rules in the old + # object so the generated diff + # from the rules dictionaries is more accurate. + iptables.refresh_unmanaged_rules(table) + # Generate table rules from rules dictionaries. + table_rules_old = iptables.get_table_rules(table) + table_rules_new = iptables_new.get_table_rules(table) + # If rules generated from dicts are not equal + # we generate a diff from them. + if table_rules_old != table_rules_new: + kw['diff'] = generate_diff(table_rules_old, table_rules_new) # noqa + else: + # TODO: Update this comment to be better. + kw['diff'] = {'prepared': "System rules were not changed (e.g. rule " # noqa + "weight changed, redundant rule, etc)"} # noqa + else: + # We need to fetch active table dump before we apply new rules + # since we will need them to generate a diff. + table_active_rules = iptables_new.get_saved_table_dump(table) + + # Apply generated rules. + iptables_new.system_apply_table_rules(table) + + # Refresh saved table dump with active iptables rules. + iptables_new.refresh_saved_table_dump(table) + + # Save state and system iptables rules. + iptables_new.system_save(backup=backup) + + # Generate a diff. + if hasattr(module, '_diff') and module._diff: + table_active_rules_new = iptables_new.get_saved_table_dump(table) # noqa + if table_active_rules != table_active_rules_new: + kw['diff'] = generate_diff(table_active_rules, table_active_rules_new) # noqa + else: + # TODO: Update this comment to be better. + kw['diff'] = {'prepared': "System rules were not changed (e.g. rule " # noqa + "weight changed, redundant rule, etc)"} # noqa + + kw['changed'] = changed + module.exit_json(**kw) + + +if __name__ == '__main__': + main() diff --git a/omero/roles/iptables_raw/meta/.galaxy_install_info b/omero/roles/iptables_raw/meta/.galaxy_install_info new file mode 100644 index 00000000..c4e5fc53 --- /dev/null +++ b/omero/roles/iptables_raw/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:59 2024 +version: 0.4.0 diff --git a/omero/roles/iptables_raw/meta/main.yml b/omero/roles/iptables_raw/meta/main.yml new file mode 100644 index 00000000..50bd4bdf --- /dev/null +++ b/omero/roles/iptables_raw/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Import iptables_raw library + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.6 + platforms: + - name: EL + versions: + - 9 + namespace: ome + role_name: iptables_raw + galaxy_tags: [] + +dependencies: [] diff --git a/omero/roles/iptables_raw/molecule/default/molecule.yml b/omero/roles/iptables_raw/molecule/default/molecule.yml new file mode 100644 index 00000000..bcbb4fec --- /dev/null +++ b/omero/roles/iptables_raw/molecule/default/molecule.yml @@ -0,0 +1,26 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: iptables-raw + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint +verifier: + name: testinfra diff --git a/omero/roles/iptables_raw/molecule/default/playbook.yml b/omero/roles/iptables_raw/molecule/default/playbook.yml new file mode 100644 index 00000000..b60fad35 --- /dev/null +++ b/omero/roles/iptables_raw/molecule/default/playbook.yml @@ -0,0 +1,27 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.iptables_raw + + tasks: + # - allow established/related inbound/outbound + # - allow ssh inbound + # - block http outbound + # - allow all other outbound + - name: Create iptables test rules + iptables_raw_25: + name: test_rules + keep_unmanaged: false + rules: | + -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT + -A OUTPUT -p tcp -m tcp --dport 80 -j REJECT + -A INPUT -j REJECT + -A FORWARD -j REJECT + -A OUTPUT -j ACCEPT + state: present + +# TODO: For a full test we should reboot and check the iptables rules +# are still active diff --git a/omero/roles/iptables_raw/molecule/default/tests/test_default.py b/omero/roles/iptables_raw/molecule/default/tests/test_default.py new file mode 100644 index 00000000..fab4ad0f --- /dev/null +++ b/omero/roles/iptables_raw/molecule/default/tests/test_default.py @@ -0,0 +1,26 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE'] +).get_hosts('all') + + +def test_hosts_file(host): + f = host.file('/etc/hosts') + + assert f.exists + assert f.user == 'root' + assert f.group == 'root' + + +def test_http_block(host): + out = host.run('curl -f -I http://www.openmicroscopy.org') + assert out.rc == 7 + assert 'Connection refused' in out.stderr + + +def test_https_allow(host): + out = host.check_output('curl -f -I https://www.openmicroscopy.org') + assert 'HTTP/2 200' in out diff --git a/omero/roles/iptables_raw/tasks/main.yml b/omero/roles/iptables_raw/tasks/main.yml new file mode 100644 index 00000000..22bbf64b --- /dev/null +++ b/omero/roles/iptables_raw/tasks/main.yml @@ -0,0 +1,32 @@ +--- +# tasks file for iptables-raw + +- name: iptables-raw | install iptables services + become: true + ansible.builtin.dnf: + update_cache: true + name: iptables-services + state: present + +- name: iptables-raw | get list of services + become: true + service_facts: + +- name: iptables-raw | disable firewalld + become: true + service: + name: firewalld + state: stopped + enabled: false + when: >- + (iptables_raw_disable_firewalld | default(True)) and ( + ('firewalld' in ansible_facts.services) or + ('firewalld.service' in ansible_facts.services) + ) + +- name: iptables-raw | enable iptables + become: true + service: + name: iptables + state: started + enabled: true diff --git a/omero/roles/nfs_mount/.gitignore b/omero/roles/nfs_mount/.gitignore new file mode 100644 index 00000000..a52f8697 --- /dev/null +++ b/omero/roles/nfs_mount/.gitignore @@ -0,0 +1,175 @@ +# Created by https://www.gitignore.io/api/linux,macos,python,ansible +# Edit at https://www.gitignore.io/?templates=linux,macos,python,ansible + +### Ansible ### +*.retry + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don’t work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# End of https://www.gitignore.io/api/linux,macos,python,ansible diff --git a/omero/roles/nfs_mount/.travis.yml b/omero/roles/nfs_mount/.travis.yml new file mode 100644 index 00000000..07a3a207 --- /dev/null +++ b/omero/roles/nfs_mount/.travis.yml @@ -0,0 +1,35 @@ +--- +language: python +services: docker + +env: + global: + - ROLE_NAME: nfs-mount + matrix: + - MOLECULE_DISTRO: centos7 + - MOLECULE_DISTRO: centos8 + - MOLECULE_DISTRO: ubuntu1604 + - MOLECULE_DISTRO: ubuntu1804 + - MOLECULE_DISTRO: debian9 + - MOLECULE_DISTRO: debian10 + +install: + # Install test dependencies. + - pip install molecule docker testinfra ansible-lint flake8 yamllint + +before_script: + # Use actual Ansible Galaxy role name for the project directory. + - cd ../ + - mv ansible-$ROLE_NAME $ROLE_NAME + - cd $ROLE_NAME + +script: + - molecule --version + - ansible --version + - molecule test + +notifications: + webhooks: + urls: + - "https://galaxy.ansible.com/api/v1/notifications/" + on_success: change diff --git a/omero/roles/nfs_mount/README.md b/omero/roles/nfs_mount/README.md new file mode 100644 index 00000000..ef5f418e --- /dev/null +++ b/omero/roles/nfs_mount/README.md @@ -0,0 +1,38 @@ +NFS Mount +========= + +Manage NFS mounts. + +Role Variables +-------------- + +- `nfs_version`: NFS version to use (default: nfs) +- `nfs_mount_opts`: Default NFS mount options (default: defaults) +- `nfs_share_mounts`: List of dictionaries of NFS shares: + - `path`: mount-point + - `mount`: nfs server path + - `opts`: mount options (optional) + - `nfs_version`: NFS version to use (optional; default to {{ nfs_version }}) + +Example Playbook +---------------- + +```yaml +- hosts: localhost + roles: + - role: nfs-mount + nfs_share_mounts: + - path: /mnt/remote + location: nfs.example.org:/data + nfs_version: nfs + - path: /mnt/readonly + location: nfs.example.org:/read-only + opts: "{{ nfs_mount_opts }},ro" + nfs_version: nfs4 +``` + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk +sonic@justereseau.ca diff --git a/omero/roles/nfs_mount/defaults/main.yml b/omero/roles/nfs_mount/defaults/main.yml new file mode 100644 index 00000000..6f447574 --- /dev/null +++ b/omero/roles/nfs_mount/defaults/main.yml @@ -0,0 +1,11 @@ +--- +# defaults file for roles/nfs-mount + +# List of NFS shares +nfs_share_mounts: [] + +# Default NFS4 mount options +nfs_mount_opts: defaults + +# Default NFS version (nfs for v3) +nfs_version: nfs diff --git a/omero/roles/nfs_mount/licence.txt b/omero/roles/nfs_mount/licence.txt new file mode 100644 index 00000000..1fe1f85c --- /dev/null +++ b/omero/roles/nfs_mount/licence.txt @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2020 Lucas Maurice (Sonic) + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/omero/roles/nfs_mount/meta/.galaxy_install_info b/omero/roles/nfs_mount/meta/.galaxy_install_info new file mode 100644 index 00000000..cac2b511 --- /dev/null +++ b/omero/roles/nfs_mount/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:57 2024 +version: 2.0.0 diff --git a/omero/roles/nfs_mount/meta/main.yml b/omero/roles/nfs_mount/meta/main.yml new file mode 100644 index 00000000..a33ddc59 --- /dev/null +++ b/omero/roles/nfs_mount/meta/main.yml @@ -0,0 +1,33 @@ +--- +galaxy_info: + role_name: nfs-mount + + author: Lucas Maurice (Sonic) + description: Manage NFS mounts + company: Justereseau + + license: WTFPL + + min_ansible_version: 2.9 + + platforms: + - name: EL + versions: + - 7 + - 8 + - name: Debian + versions: + - 9 + - 10 + - name: Ubuntu + versions: + - 16.04 + - 18.04 + + galaxy_tags: + - nfs + - share + - nfs3 + - nfs4 + +dependencies: [] diff --git a/omero/roles/nfs_mount/molecule/default/molecule.yml b/omero/roles/nfs_mount/molecule/default/molecule.yml new file mode 100644 index 00000000..fa4175bb --- /dev/null +++ b/omero/roles/nfs_mount/molecule/default/molecule.yml @@ -0,0 +1,36 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint --config-file molecule/default/yaml-lint.yml . + ansible-lint + flake8 +platforms: + - name: instance + image: "geerlingguy/docker-${MOLECULE_DISTRO:-debian10}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true +provisioner: + name: ansible + lint: ansible-lint + playbooks: + converge: playbook.yml +scenario: + name: default + test_sequence: + - lint + - destroy + - create + - syntax + - converge + - idempotence + - verify + - destroy +verifier: + name: testinfra + lint: flake8 diff --git a/omero/roles/nfs_mount/molecule/default/playbook.yml b/omero/roles/nfs_mount/molecule/default/playbook.yml new file mode 100644 index 00000000..1bcdda94 --- /dev/null +++ b/omero/roles/nfs_mount/molecule/default/playbook.yml @@ -0,0 +1,18 @@ +--- +- name: Converge + hosts: all + become: true + + vars: + pip_executable: pip + pip_install_packages: + - docker-compose + - docker + + pre_tasks: + - name: Update apt cache. + apt: update_cache=yes + when: ansible_os_family == 'Debian' + + roles: + - nfs-mount diff --git a/omero/roles/nfs_mount/molecule/default/yaml-lint.yml b/omero/roles/nfs_mount/molecule/default/yaml-lint.yml new file mode 100644 index 00000000..db22c42e --- /dev/null +++ b/omero/roles/nfs_mount/molecule/default/yaml-lint.yml @@ -0,0 +1,6 @@ +--- +extends: default +rules: + line-length: + max: 160 + level: warning diff --git a/omero/roles/nfs_mount/tasks/main.yml b/omero/roles/nfs_mount/tasks/main.yml new file mode 100644 index 00000000..2edde34e --- /dev/null +++ b/omero/roles/nfs_mount/tasks/main.yml @@ -0,0 +1,23 @@ +--- +- name: Include family related vars + include_vars: "{{ ansible_os_family }}.yml" + +- name: Install NFS mount utility + become: true + package: + name: "{{ nfs_package }}" + state: present + +# Do not create mountpoint using file, the mount module will create it +# automatically. This avoids problems where the module tries to change +# permissions on an existing directory + +- name: Mount NFS share + become: true + mount: + fstype: "{{ item.nfs_version | default(nfs_version) }}" + name: "{{ item.path }}" + opts: "{{ item.opts | default(nfs_mount_opts) }}" + src: "{{ item.location }}" + state: mounted + with_items: "{{ nfs_share_mounts }}" diff --git a/omero/roles/nfs_mount/vars/Debian.yml b/omero/roles/nfs_mount/vars/Debian.yml new file mode 100644 index 00000000..bfa5146f --- /dev/null +++ b/omero/roles/nfs_mount/vars/Debian.yml @@ -0,0 +1,2 @@ +--- +nfs_package: nfs-common diff --git a/omero/roles/nfs_mount/vars/RedHat.yml b/omero/roles/nfs_mount/vars/RedHat.yml new file mode 100644 index 00000000..6b6897ac --- /dev/null +++ b/omero/roles/nfs_mount/vars/RedHat.yml @@ -0,0 +1,2 @@ +--- +nfs_package: nfs-utils diff --git a/omero/roles/nfs_share/.gitignore b/omero/roles/nfs_share/.gitignore new file mode 100644 index 00000000..b6261c93 --- /dev/null +++ b/omero/roles/nfs_share/.gitignore @@ -0,0 +1 @@ +.*~ diff --git a/omero/roles/nfs_share/.travis.yml b/omero/roles/nfs_share/.travis.yml new file mode 100644 index 00000000..49e7e1c5 --- /dev/null +++ b/omero/roles/nfs_share/.travis.yml @@ -0,0 +1,29 @@ +--- +language: python +python: "2.7" + +# Use the new container infrastructure +sudo: false + +# Install ansible +addons: + apt: + packages: + - python-pip + +install: + # Install ansible + - pip install ansible + + # Check ansible version + - ansible --version + + # Create ansible.cfg with correct roles_path + - printf '[defaults]\nroles_path=../' >ansible.cfg + +script: + # Basic role syntax check + - ansible-playbook tests/test.yml -i tests/inventory --syntax-check + +notifications: + webhooks: https://galaxy.ansible.com/api/v1/notifications/ diff --git a/omero/roles/nfs_share/README.md b/omero/roles/nfs_share/README.md new file mode 100644 index 00000000..c4b50b00 --- /dev/null +++ b/omero/roles/nfs_share/README.md @@ -0,0 +1,39 @@ +NFS Share +========= + +Manage NFS file shares (no authentication). + +Note if SELinux is enabled you may need modify the configure of the the shared directories (not handled by this role). + + +Role Variables +-------------- + +`nfs_shares`: A dictionary of lists of hosts and options `{/exported/directory: [{ host: host-pattern, options: options (optional) }, ...] }` + +Note the default NFS share options in this role (`ro,all_squash`) are slightly more restrictive than the original NFS defaults. + + +Example Playbook +---------------- + + - hosts: localhost + roles: + - role: nfs-share + nfs_shares: + # Allow access from *.example.org with default options + /srv/share1: + - host: "*.example.org" + + # Allow read-write access from two subnets, squash all except root + /srv/share2: + - host: 192.168.1.0/25 + options: rw,root_squash + - host: 172.16.0.0/20 + options: rw,root_squash + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/nfs_share/defaults/main.yml b/omero/roles/nfs_share/defaults/main.yml new file mode 100644 index 00000000..30117f1f --- /dev/null +++ b/omero/roles/nfs_share/defaults/main.yml @@ -0,0 +1,5 @@ +--- +# defaults file for roles/nfs-share + +# A dictionary of shares, see README.md +nfs_shares: {} diff --git a/omero/roles/nfs_share/handlers/main.yml b/omero/roles/nfs_share/handlers/main.yml new file mode 100644 index 00000000..fff52ad1 --- /dev/null +++ b/omero/roles/nfs_share/handlers/main.yml @@ -0,0 +1,6 @@ +--- +# Handlers for nfs-share + +- name: refresh nfs + become: yes + command: exportfs -ar diff --git a/omero/roles/nfs_share/meta/.galaxy_install_info b/omero/roles/nfs_share/meta/.galaxy_install_info new file mode 100644 index 00000000..c5dfece1 --- /dev/null +++ b/omero/roles/nfs_share/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:58 2024 +version: 1.0.0 diff --git a/omero/roles/nfs_share/meta/main.yml b/omero/roles/nfs_share/meta/main.yml new file mode 100644 index 00000000..5f69087a --- /dev/null +++ b/omero/roles/nfs_share/meta/main.yml @@ -0,0 +1,13 @@ +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Manage NFS file shares + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.1 + platforms: + - name: EL + versions: + - 7 + galaxy_tags: [] + +dependencies: [] diff --git a/omero/roles/nfs_share/tasks/main.yml b/omero/roles/nfs_share/tasks/main.yml new file mode 100644 index 00000000..7fa740a4 --- /dev/null +++ b/omero/roles/nfs_share/tasks/main.yml @@ -0,0 +1,24 @@ +--- +# tasks file for roles/nfs-share + +- name: system packages | nfs server + become: yes + yum: + name: nfs-utils + state: present + +- name: nfs server | configure shares + become: yes + template: + backup: yes + dest: /etc/exports + src: exports.j2 + notify: + - refresh nfs + +- name: nfs server | enable nfs + become: yes + service: + enabled: yes + name: nfs-server + state: started diff --git a/omero/roles/nfs_share/templates/exports.j2 b/omero/roles/nfs_share/templates/exports.j2 new file mode 100644 index 00000000..55ef0cb9 --- /dev/null +++ b/omero/roles/nfs_share/templates/exports.j2 @@ -0,0 +1,3 @@ +{% for key, value in nfs_shares.iteritems() %} +{{ key }} {% for access in value %} {{ access.host }}({{ access.options | default("ro,all_squash") }}) {% endfor %} +{% endfor %} diff --git a/omero/roles/nfs_share/tests/inventory b/omero/roles/nfs_share/tests/inventory new file mode 100644 index 00000000..2fbb50c4 --- /dev/null +++ b/omero/roles/nfs_share/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/omero/roles/nfs_share/tests/test.yml b/omero/roles/nfs_share/tests/test.yml new file mode 100644 index 00000000..99c212a6 --- /dev/null +++ b/omero/roles/nfs_share/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - role: ansible-role-nfs-share diff --git a/omero/roles/ome.basedeps/.github/workflows/molecule.yml b/omero/roles/ome.basedeps/.github/workflows/molecule.yml new file mode 100644 index 00000000..e55180a9 --- /dev/null +++ b/omero/roles/ome.basedeps/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v3 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: ansible-actions/ansible-galaxy-action@v1.2.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + galaxy_version: ${{ github.ref_name }} diff --git a/omero/roles/ome.basedeps/.gitignore b/omero/roles/ome.basedeps/.gitignore new file mode 100644 index 00000000..d35ab669 --- /dev/null +++ b/omero/roles/ome.basedeps/.gitignore @@ -0,0 +1,2 @@ +.*~ +*.pyc diff --git a/omero/roles/ome.basedeps/LICENSE.md b/omero/roles/ome.basedeps/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.basedeps/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.basedeps/README.md b/omero/roles/ome.basedeps/README.md new file mode 100644 index 00000000..e45a3a0d --- /dev/null +++ b/omero/roles/ome.basedeps/README.md @@ -0,0 +1,28 @@ +Base Dependencies +================= + +[![Actions Status](https://github.com/ome/ansible-role-basedeps/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-basedeps/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-basedeps-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/basedeps/) + +Base dependencies for most servers. + +These dependencies should be suitable for installation on a minimal production server. + +Example Playbook +---------------- + + - hosts: servers + roles: + - { role: ome.basedeps } + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk + + +License +------- + +BSD diff --git a/omero/roles/ome.basedeps/meta/.galaxy_install_info b/omero/roles/ome.basedeps/meta/.galaxy_install_info new file mode 100644 index 00000000..982fcdc9 --- /dev/null +++ b/omero/roles/ome.basedeps/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:40 2024 +version: 1.3.2 diff --git a/omero/roles/ome.basedeps/meta/main.yml b/omero/roles/ome.basedeps/meta/main.yml new file mode 100644 index 00000000..cb7e055e --- /dev/null +++ b/omero/roles/ome.basedeps/meta/main.yml @@ -0,0 +1,19 @@ +--- +galaxy_info: + role_name: basedeps + namespace: ome + author: ome-devel@lists.openmicroscopy.org.uk + description: Base dependencies for most servers. + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.1 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + galaxy_tags: + - cloud + - system diff --git a/omero/roles/ome.basedeps/molecule/default/converge.yml b/omero/roles/ome.basedeps/molecule/default/converge.yml new file mode 100644 index 00000000..f8b1b048 --- /dev/null +++ b/omero/roles/ome.basedeps/molecule/default/converge.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.basedeps diff --git a/omero/roles/ome.basedeps/molecule/default/molecule.yml b/omero/roles/ome.basedeps/molecule/default/molecule.yml new file mode 100644 index 00000000..1ff011fa --- /dev/null +++ b/omero/roles/ome.basedeps/molecule/default/molecule.yml @@ -0,0 +1,22 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: rockylinux-9 + image: rockylinux:9 + - name: ubuntu-2204 + image: ubuntu:22.04 +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.basedeps/molecule/default/tests/test_default.py b/omero/roles/ome.basedeps/molecule/default/tests/test_default.py new file mode 100644 index 00000000..420559a9 --- /dev/null +++ b/omero/roles/ome.basedeps/molecule/default/tests/test_default.py @@ -0,0 +1,15 @@ +import os + +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("all") + + +@pytest.mark.parametrize( + "package", ["curl", "patch", "rsync", "tar", "unzip", "wget", "zip"] +) +def test_command(host, package): + assert host.exists(package) diff --git a/omero/roles/ome.basedeps/tasks/main.yml b/omero/roles/ome.basedeps/tasks/main.yml new file mode 100644 index 00000000..8d14cfc3 --- /dev/null +++ b/omero/roles/ome.basedeps/tasks/main.yml @@ -0,0 +1,32 @@ +--- +# tasks file for roles/basedeps +- name: Import a key for epel + ansible.builtin.rpm_key: + state: present + key: https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-9 + when: ansible_os_family == 'RedHat' + +- name: epel | setup dnf repository + become: true + ansible.builtin.dnf: + update_cache: true + name: + https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm + state: present + when: ansible_os_family == 'RedHat' + +# use separate yum/apt tasks because package only installs one item at a time +- name: system packages | basic system utils (rockylinux) + become: true + ansible.builtin.dnf: + name: "{{ basedeps_packages.redhat }}" + state: present + when: ansible_os_family == 'RedHat' + +- name: system packages | basic system utils (ubuntu) + become: true + ansible.builtin.apt: + update_cache: true + name: "{{ basedeps_packages.debian }}" + state: present + when: ansible_os_family == 'Debian' diff --git a/omero/roles/ome.basedeps/vars/main.yml b/omero/roles/ome.basedeps/vars/main.yml new file mode 100644 index 00000000..bac93125 --- /dev/null +++ b/omero/roles/ome.basedeps/vars/main.yml @@ -0,0 +1,19 @@ +--- + + +basedeps_packages: + redhat: + - patch + - rsync + - tar + - unzip + - wget + - zip + debian: + - curl + - patch + - rsync + - tar + - unzip + - wget + - zip diff --git a/omero/roles/ome.cli_utils/.github/workflows/molecule.yml b/omero/roles/ome.cli_utils/.github/workflows/molecule.yml new file mode 100644 index 00000000..f1ea4c82 --- /dev/null +++ b/omero/roles/ome.cli_utils/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: ansible-actions/ansible-galaxy-action@v1.2.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + galaxy_version: ${{ github.ref_name }} diff --git a/omero/roles/ome.cli_utils/.gitignore b/omero/roles/ome.cli_utils/.gitignore new file mode 100644 index 00000000..b6261c93 --- /dev/null +++ b/omero/roles/ome.cli_utils/.gitignore @@ -0,0 +1 @@ +.*~ diff --git a/omero/roles/ome.cli_utils/LICENSE.md b/omero/roles/ome.cli_utils/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.cli_utils/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.cli_utils/README.md b/omero/roles/ome.cli_utils/README.md new file mode 100644 index 00000000..e9b6f945 --- /dev/null +++ b/omero/roles/ome.cli_utils/README.md @@ -0,0 +1,21 @@ +CLI utils +========= + +[![Actions Status](https://github.com/ome/ansible-role-cli-utils/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-cli-utils/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-cli_utils-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/cli_utils/) + +Useful command-line utilities for administering a server. + +This is intended for utilities that are generally useful but are not strictly necessary for a production server. + + +Dependencies +------------ + +Depends on the `ome.basedeps` role. + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.cli_utils/meta/.galaxy_install_info b/omero/roles/ome.cli_utils/meta/.galaxy_install_info new file mode 100644 index 00000000..2ed0dd04 --- /dev/null +++ b/omero/roles/ome.cli_utils/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:34:00 2024 +version: 1.2.5 diff --git a/omero/roles/ome.cli_utils/meta/main.yml b/omero/roles/ome.cli_utils/meta/main.yml new file mode 100644 index 00000000..67d36bb9 --- /dev/null +++ b/omero/roles/ome.cli_utils/meta/main.yml @@ -0,0 +1,14 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Useful command-line utilities for administering a server + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + namespace: ome + role_name: cli_utils + galaxy_tags: [] diff --git a/omero/roles/ome.cli_utils/meta/requirements.yml b/omero/roles/ome.cli_utils/meta/requirements.yml new file mode 100644 index 00000000..1d87f749 --- /dev/null +++ b/omero/roles/ome.cli_utils/meta/requirements.yml @@ -0,0 +1,2 @@ +--- +- src: ome.basedeps diff --git a/omero/roles/ome.cli_utils/molecule/default/molecule.yml b/omero/roles/ome.cli_utils/molecule/default/molecule.yml new file mode 100644 index 00000000..93ad4166 --- /dev/null +++ b/omero/roles/ome.cli_utils/molecule/default/molecule.yml @@ -0,0 +1,20 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: instance + image: rockylinux:9 +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.cli_utils/molecule/default/playbook.yml b/omero/roles/ome.cli_utils/molecule/default/playbook.yml new file mode 100644 index 00000000..c627ecba --- /dev/null +++ b/omero/roles/ome.cli_utils/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.cli_utils diff --git a/omero/roles/ome.cli_utils/molecule/default/requirements.yml b/omero/roles/ome.cli_utils/molecule/default/requirements.yml new file mode 100644 index 00000000..9312f4cc --- /dev/null +++ b/omero/roles/ome.cli_utils/molecule/default/requirements.yml @@ -0,0 +1,2 @@ +--- +- role: ome.basedeps \ No newline at end of file diff --git a/omero/roles/ome.cli_utils/molecule/default/tests/test_default.py b/omero/roles/ome.cli_utils/molecule/default/tests/test_default.py new file mode 100644 index 00000000..7ab61fe5 --- /dev/null +++ b/omero/roles/ome.cli_utils/molecule/default/tests/test_default.py @@ -0,0 +1,11 @@ +import os +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +@pytest.mark.parametrize("package", ["bzip2", "screen", "tmux", "zsh"]) +def test_analysis_packages(host, package): + assert host.package(package).is_installed diff --git a/omero/roles/ome.cli_utils/tasks/main.yml b/omero/roles/ome.cli_utils/tasks/main.yml new file mode 100644 index 00000000..4a08818e --- /dev/null +++ b/omero/roles/ome.cli_utils/tasks/main.yml @@ -0,0 +1,28 @@ +--- +# tasks file for roles/cli-utils + +- name: Import a key for epel + become: true + ansible.builtin.rpm_key: + state: present + key: https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-9 + +- name: epel | setup dnf repository + become: true + ansible.builtin.dnf: + update_cache: true + name: + https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm + state: present + +- name: system packages | cli user utils + become: true + ansible.builtin.dnf: + update_cache: true + name: + - bzip2 + - screen + - tmux + - zsh + state: present + when: ansible_os_family == 'RedHat' diff --git a/omero/roles/ome.cli_utils/tests/inventory b/omero/roles/ome.cli_utils/tests/inventory new file mode 100644 index 00000000..2fbb50c4 --- /dev/null +++ b/omero/roles/ome.cli_utils/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/omero/roles/ome.cli_utils/tests/test.yml b/omero/roles/ome.cli_utils/tests/test.yml new file mode 100644 index 00000000..c1902f6d --- /dev/null +++ b/omero/roles/ome.cli_utils/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - role: ome.cli_utils diff --git a/omero/roles/ome.cli_utils/tests/test_default.py b/omero/roles/ome.cli_utils/tests/test_default.py new file mode 100644 index 00000000..2cf53164 --- /dev/null +++ b/omero/roles/ome.cli_utils/tests/test_default.py @@ -0,0 +1,11 @@ +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + '.molecule/ansible_inventory').get_hosts('all') + + +def test_analysis_packages(Package): + assert Package('bzip2') + assert Package('zsh') + assert Package('screen') + assert Package('tmux') diff --git a/omero/roles/ome.deploy_archive/.github/workflows/molecule.yml b/omero/roles/ome.deploy_archive/.github/workflows/molecule.yml new file mode 100644 index 00000000..1bde8477 --- /dev/null +++ b/omero/roles/ome.deploy_archive/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} diff --git a/omero/roles/ome.deploy_archive/.gitignore b/omero/roles/ome.deploy_archive/.gitignore new file mode 100644 index 00000000..d35ab669 --- /dev/null +++ b/omero/roles/ome.deploy_archive/.gitignore @@ -0,0 +1,2 @@ +.*~ +*.pyc diff --git a/omero/roles/ome.deploy_archive/LICENSE.md b/omero/roles/ome.deploy_archive/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.deploy_archive/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.deploy_archive/README.md b/omero/roles/ome.deploy_archive/README.md new file mode 100644 index 00000000..a62b0d55 --- /dev/null +++ b/omero/roles/ome.deploy_archive/README.md @@ -0,0 +1,43 @@ +Deploy Archive +============== + +[![Actions Status](https://github.com/ome/ansible-role-deploy-archive/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-deploy-archive/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-deploy_archive-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/deploy_archive/) + +Deploys an archive. +Downloads, extracts and optionally creates a symlink. + + +Prerequisites +------------- + +This role does not install tools such as `unzip` or `bzip` that may be required for extracting archives. + +This role does not set `become: yes` on tasks. If you do not include this in your playbook you must ensure the Ansible user has write permissions on the destination directory. + + +Role Variables +-------------- + +Required: +- `deploy_archive_dest_dir`: The destination directory, will be automatically created +- `deploy_archive_src_url`: URL to the archive + +Optional: +- `deploy_archive_sha256`: SHA256 checksum, ignored if empty +- `deploy_archive_filename`: Name of the downloaded file, default is the basename of the URL path. +- `deploy_archive_symlink`: Absolute path of a symlink to the unarchived deployment, ignored if empty +- `deploy_archive_internal_root`: Target of the symlink within the destination directory +- `deploy_archive_notifies`: List of handlers to notify if the downloaded archive changes + + +Example playbook +---------------- + +See [`playbook.yml`](molecule/default/playbook.yml) + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.deploy_archive/defaults/main.yml b/omero/roles/ome.deploy_archive/defaults/main.yml new file mode 100644 index 00000000..51d416f1 --- /dev/null +++ b/omero/roles/ome.deploy_archive/defaults/main.yml @@ -0,0 +1,18 @@ +--- +# defaults for deploy-archive + +# Destination directory for the archive, required +# deploy_archive_dest_dir: +# URL to the archive, required +# deploy_archive_src_url: + +# SHA256 checksum, ignored if empty +deploy_archive_sha256: "" +# Name of the downloaded file, default is the basename of the URL path +deploy_archive_filename: "{{ deploy_archive_src_url | basename }}" +# Absolute path of a symlink to the unarchived deployment, ignored if empty +deploy_archive_symlink: "" +# Target of the symlink within the archive, default empty (top level directory) +deploy_archive_internal_root: "" +# List of handlers to notify if the downlaoded archive changes, default empty +deploy_archive_notifies: [] diff --git a/omero/roles/ome.deploy_archive/meta/.galaxy_install_info b/omero/roles/ome.deploy_archive/meta/.galaxy_install_info new file mode 100644 index 00000000..47f9239b --- /dev/null +++ b/omero/roles/ome.deploy_archive/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:47 2024 +version: 0.2.0 diff --git a/omero/roles/ome.deploy_archive/meta/main.yml b/omero/roles/ome.deploy_archive/meta/main.yml new file mode 100644 index 00000000..fdb47bd0 --- /dev/null +++ b/omero/roles/ome.deploy_archive/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: deploy_archive + author: ome-devel@lists.openmicroscopy.org.uk + description: Download and deploy an archive + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.4 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + galaxy_tags: [] diff --git a/omero/roles/ome.deploy_archive/molecule/default/molecule.yml b/omero/roles/ome.deploy_archive/molecule/default/molecule.yml new file mode 100644 index 00000000..ae2df164 --- /dev/null +++ b/omero/roles/ome.deploy_archive/molecule/default/molecule.yml @@ -0,0 +1,22 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: deploy-archive-r9 + image: rockylinux:9 + - name: deploy-archive-u2204 + image: ubuntu:22.04 +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.deploy_archive/molecule/default/playbook.yml b/omero/roles/ome.deploy_archive/molecule/default/playbook.yml new file mode 100644 index 00000000..586c490a --- /dev/null +++ b/omero/roles/ome.deploy_archive/molecule/default/playbook.yml @@ -0,0 +1,25 @@ +--- +- name: Converge + hosts: all + become: true + pre_tasks: + - name: Install unzip + package: + update_cache: true + name: unzip + state: present + roles: + - role: ome.deploy_archive + deploy_archive_dest_dir: /opt/deploy-archive-test + deploy_archive_src_url: > + https://github.com/IDR/idr.openmicroscopy.org/archive/IDR-0.5.0.zip + deploy_archive_sha256: > + c71033292a19f305f2372730733b18a4149ac4fbe23165a2156e4680883bab8b + deploy_archive_symlink: /opt/idr-web-src + deploy_archive_internal_root: idr.openmicroscopy.org-IDR-0.5.0 + deploy_archive_notifies: + - deploy-archive test handler + + handlers: + - name: deploy-archive test handler + shell: echo triggered >> /opt/deploy-archive-test/handler-triggered diff --git a/omero/roles/ome.deploy_archive/molecule/default/tests/test_default.py b/omero/roles/ome.deploy_archive/molecule/default/tests/test_default.py new file mode 100644 index 00000000..898dad0b --- /dev/null +++ b/omero/roles/ome.deploy_archive/molecule/default/tests/test_default.py @@ -0,0 +1,32 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_dir(host): + f = host.file('/opt/deploy-archive-test/idr.openmicroscopy.org-IDR-0.5.0') + assert f.exists + assert f.is_directory + + +def test_file(host): + f = host.file( + '/opt/deploy-archive-test/idr.openmicroscopy.org-IDR-0.5.0/index.html') + assert f.exists + assert f.is_file + + +def test_symlink(host): + f = host.file('/opt/idr-web-src') + assert f.exists + assert f.is_symlink + assert f.linked_to == ( + '/opt/deploy-archive-test/idr.openmicroscopy.org-IDR-0.5.0') + + +def test_handler_trigger_once(host): + f = host.file('/opt/deploy-archive-test/handler-triggered') + assert f.content.strip() == b'triggered' diff --git a/omero/roles/ome.deploy_archive/tasks/main.yml b/omero/roles/ome.deploy_archive/tasks/main.yml new file mode 100644 index 00000000..7410151b --- /dev/null +++ b/omero/roles/ome.deploy_archive/tasks/main.yml @@ -0,0 +1,43 @@ +--- +# tasks file for deploy-archive + +- name: deploy archive | create directory + file: + path: "{{ deploy_archive_dest_dir }}" + state: directory + serole: _default + setype: _default + seuser: _default + mode: 0755 + +- name: deploy archive | download + get_url: + url: "{{ deploy_archive_src_url }}" + checksum: >- + {{ (deploy_archive_sha256 | length > 0) | + ternary('sha256:' + deploy_archive_sha256, omit) }} + dest: "{{ deploy_archive_dest_dir }}/{{ deploy_archive_filename }}" + +- name: deploy archive | unarchive + unarchive: + src: "{{ deploy_archive_dest_dir }}/{{ deploy_archive_filename }}" + dest: "{{ deploy_archive_dest_dir }}" + group: root + owner: root + remote_src: true + +- name: deploy archive | create symlink parent directory + file: + path: "{{ deploy_archive_symlink | dirname }}" + state: directory + mode: 0755 + when: deploy_archive_symlink | dirname | length > 0 + +- name: deploy archive | symlink + file: + path: "{{ deploy_archive_symlink }}" + src: "{{ deploy_archive_dest_dir }}/{{ deploy_archive_internal_root }}" + force: true + state: link + when: deploy_archive_symlink | length > 0 + notify: "{{ deploy_archive_notifies }}" diff --git a/omero/roles/ome.docker/.github/workflows/molecule.yml b/omero/roles/ome.docker/.github/workflows/molecule.yml new file mode 100644 index 00000000..2a8b703c --- /dev/null +++ b/omero/roles/ome.docker/.github/workflows/molecule.yml @@ -0,0 +1,56 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: ansible-actions/ansible-galaxy-action@v1.2.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + galaxy_version: ${{ github.ref_name }} diff --git a/omero/roles/ome.docker/.gitignore b/omero/roles/ome.docker/.gitignore new file mode 100644 index 00000000..3d8d5649 --- /dev/null +++ b/omero/roles/ome.docker/.gitignore @@ -0,0 +1,2 @@ +.*~ +*.pyc \ No newline at end of file diff --git a/omero/roles/ome.docker/CHANGES.md b/omero/roles/ome.docker/CHANGES.md new file mode 100644 index 00000000..b027b9bb --- /dev/null +++ b/omero/roles/ome.docker/CHANGES.md @@ -0,0 +1,13 @@ +# Changes in Version 3 + +## Summary of breaking changes +- Removed support for installing distribution docker +- Removed `docker_install_upstream` parameter + + +# Changes in Version 2 + +## Summary of breaking changes +- Switched to Docker Community Edition (uses overlay as the default storage driver). +- Use `/etc/docker/daemon.json` for configuration instead of modifying the package's systemd service. +- Removed `docker_repo_version` parameter. diff --git a/omero/roles/ome.docker/LICENSE.md b/omero/roles/ome.docker/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.docker/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.docker/README.md b/omero/roles/ome.docker/README.md new file mode 100644 index 00000000..cdce12a2 --- /dev/null +++ b/omero/roles/ome.docker/README.md @@ -0,0 +1,114 @@ +Docker +====== + +[![Actions Status](https://github.com/ome/ansible-role-docker/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-docker/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-docker-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/docker/) + +Setup Docker, provides options for using an advanced storage or networking configuration. +Installs the latest official upstream Docker (Community Edition). + +This role should work with RedHat Enterprise Linux 7, but [this is not supported by Docker](https://docs.docker.com/install/linux/docker-ee/rhel/). + +If you want the distribution supplied Docker package do not use this role. + + +Role Variables +-------------- + +Optional variables: +- `docker_version`: Install a particular version of docker, e.g. `17.12.1.ce-1.el7.centos`, default current +- `docker_groupmembers`: A list of users who will be added to the `docker` system group, allows docker to be run without sudo +- `docker_use_ipv4_nic_mtu`: Force Docker to use the MTU set by the main IPV4 interface. This may be necessary on virtualised hosts, see comment in `defaults/main.yml`. +- `docker_additional_options`: Dictionary of additional Docker configuration options. +- `docker_use_custom_storage`: If `True` use a custom storage configuration, default `False` +- `docker_use_custom_network`: If `True` use a custom network configuration, default `False` +- `docker_systemd_setup`: Set this to False to disable automatic systemd configuration, default `False`. + You may wish to use this when building virtualisation images. +- `docker_repo_force_releasever`: The repo config uses the `$releasever` variables. On some systems this may not work, if necessary you can forcibly override it by setting this variable. + + +### Custom storage + +If `docker_use_custom_storage` is `True` thin-pool logical volumes will be created for Docker, and a separate logical volume will be created for the Docker volume (`/var/lib/docker`). + +- `docker_basefs`: Filesystem to use for the Docker containers (default xfs) +- `docker_lvfilesystem`: Filesystem for the Docker volume (default xfs) +- `docker_lvopts`: Additional arguments to be used when creating logical volumes + +The following variables must be defined when using custom storage: + +- `docker_vgname`: LVM volume group for the logical volumes +- `docker_poolsize`: Size of the Docker thin-pool partition +- `docker_metadatasize`: Size of the Docker thin-pool metadata partition (try 1% of the poolsize) +- `docker_volumesize`: Size of the Docker volume + +If `docker_use_custom_storage` is `False` you may wish to mount `/var/lib/docker` on a separate partition or volume before applying this role. + + +### Custom networking + +If `docker_use_custom_network` is `True` a custom network bridge will be used, this must be created outside of this role. +The following variables must be defined: + +- `docker_bridge_name`: The name of a custom network bridge for docker +- `docker_bridge_ips`: The custom IP range that docker should use for allocating IPs + + +Dependencies +------------ + +Depends on lvm-partition. + + +Development +----------- + +This role is partially tested by Travis-CI, which requires running Docker-in-Docker. +When testing changes you should therefore run a full test using molecule with the Vagrant driver as part of any review: + + molecule test --driver vagrant + + +Example Playbook +---------------- + +Simple example (uses default storage overlay driver): + + - hosts: localhost + roles: + - role: ome.docker + +Example using the default storage driver, with a dedicated logical volume for docker: + + - hosts: localhost + roles: + - role: ome.lvm_partition + lvm_lvname: var_lib_docker + lvm_lvmount: /var/lib/docker + lvm_lvsize: 100g + lvm_lvfilesystem: ext4 + - role: ome.docker + +Advanced example using custom storage and listening on external port 4243 (insecure). +The LVM volume group `VolGroup00` must already exist: + + - hosts: localhost + roles: + - role: ome.docker + docker_use_ipv4_nic_mtu: True + docker_use_custom_storage: True + docker_vgname: VolGroup00 + docker_poolsize: 10g + docker_metadatasize: 100m + docker_volumesize: 5g + docker_groupmembers: [centos] + docker_additional_options: + hosts: + - tcp://0.0.0.0:4243 + - unix:///var/run/docker.sock + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.docker/defaults/main.yml b/omero/roles/ome.docker/defaults/main.yml new file mode 100644 index 00000000..c37425ee --- /dev/null +++ b/omero/roles/ome.docker/defaults/main.yml @@ -0,0 +1,48 @@ +--- +# defaults file for roles/docker + +# Docker version to be installed +docker_version: '' + +# Set to True if using a custom storage configuration +docker_use_custom_storage: false + +# Set to True if using a custom network configuration +docker_use_custom_network: false + +# Filesystem to use for the Docker containers +docker_basefs: xfs + +# Filesystem for the Docker volume +docker_lvfilesystem: xfs + +# Docker 1.10+ attempts to find the MTU using Path MTU Discovery, but may +# fail. This can be a problem on virtualised docker hosts. Set to True to +# use the MTU from the `ansible_default_ipv4` variable. +# - https://github.com/docker/docker/issues/22028 +# - https://github.com/docker/docker/issues/12565 +# TODO: Add an option to explicitly set the MTU in case auto-detection fails +docker_use_ipv4_nic_mtu: false + +# Dictionary of additional docker options +docker_additional_options: {} + +# Users who can run docker +docker_groupmembers: [] + +# Setup systemd services +docker_systemd_setup: true + +# Override the releasever in the yum repo configuration +docker_repo_force_releasever: '$releasever' + + +###################################################################### +# Expert users only! +###################################################################### + +# Use a custom storage driver +docker_storage_driver: '' + +# Enable debug mode on server +docker_debug: false diff --git a/omero/roles/ome.docker/handlers/main.yml b/omero/roles/ome.docker/handlers/main.yml new file mode 100644 index 00000000..cabd7321 --- /dev/null +++ b/omero/roles/ome.docker/handlers/main.yml @@ -0,0 +1,9 @@ +--- +# Handlers for docker + +- name: restart docker + become: true + service: + name: docker + state: restarted + when: docker_systemd_setup diff --git a/omero/roles/ome.docker/meta/.galaxy_install_info b/omero/roles/ome.docker/meta/.galaxy_install_info new file mode 100644 index 00000000..87b960bd --- /dev/null +++ b/omero/roles/ome.docker/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:34:01 2024 +version: 3.2.2 diff --git a/omero/roles/ome.docker/meta/main.yml b/omero/roles/ome.docker/meta/main.yml new file mode 100644 index 00000000..2adaf5dc --- /dev/null +++ b/omero/roles/ome.docker/meta/main.yml @@ -0,0 +1,14 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Install upstream Docker + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + role_name: docker + namespace: ome + galaxy_tags: [] diff --git a/omero/roles/ome.docker/meta/requirements.yml b/omero/roles/ome.docker/meta/requirements.yml new file mode 100644 index 00000000..2d40150a --- /dev/null +++ b/omero/roles/ome.docker/meta/requirements.yml @@ -0,0 +1,2 @@ +--- +- src: ome.lvm_partition diff --git a/omero/roles/ome.docker/molecule/default/molecule.yml b/omero/roles/ome.docker/molecule/default/molecule.yml new file mode 100644 index 00000000..83f5e3ef --- /dev/null +++ b/omero/roles/ome.docker/molecule/default/molecule.yml @@ -0,0 +1,50 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + # For mysterious reasons naming something "docker" with the current + # ome-ansible-molecule versions fails + - name: xdockerx + image: eniocarboni/docker-rockylinux-systemd:9 + privileged: true + command: /sbin/init + groups: + - docker-hosts + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + - name: docker-inactive + image: rockylinux:9 + groups: + - docker-hosts + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup +provisioner: + name: ansible + lint: + name: ansible-lint + inventory: + group_vars: + docker-hosts: + # This should allow docker-in-docker to work + docker_storage_driver: vfs + host_vars: + xdockerx: + docker_use_ipv4_nic_mtu: true + # Latest version 17.12.1.ce-1.el7.centos has a bug that prevents + # testing on travis: https://github.com/docker/for-linux/issues/219 + #docker_version: 17.09.1.ce-1.el7.centos + docker-inactive: + docker_systemd_setup: false +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.docker/molecule/default/playbook.yml b/omero/roles/ome.docker/molecule/default/playbook.yml new file mode 100644 index 00000000..47fe44a9 --- /dev/null +++ b/omero/roles/ome.docker/molecule/default/playbook.yml @@ -0,0 +1,16 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.docker + docker_additional_options: + hosts: + - tcp://127.0.0.1:4243 + - unix:///var/run/docker.sock + + tasks: + - name: create unprivileged user + become: true + user: + name: test + state: present diff --git a/omero/roles/ome.docker/molecule/default/requirements.yml b/omero/roles/ome.docker/molecule/default/requirements.yml new file mode 100644 index 00000000..1bf542aa --- /dev/null +++ b/omero/roles/ome.docker/molecule/default/requirements.yml @@ -0,0 +1,3 @@ +--- + +- src: ome.lvm_partition diff --git a/omero/roles/ome.docker/molecule/default/tests/test_docker-inactive.py b/omero/roles/ome.docker/molecule/default/tests/test_docker-inactive.py new file mode 100644 index 00000000..d76d5fb7 --- /dev/null +++ b/omero/roles/ome.docker/molecule/default/tests/test_docker-inactive.py @@ -0,0 +1,13 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('docker-inactive') + + +def test_docker_installed(host): + with host.sudo(): + cmd = host.command('docker info') + assert cmd.rc == 1 + assert 'ERROR: Cannot connect to the Docker daemon' in cmd.stdout diff --git a/omero/roles/ome.docker/molecule/default/tests/test_docker.py b/omero/roles/ome.docker/molecule/default/tests/test_docker.py new file mode 100644 index 00000000..3c677cd0 --- /dev/null +++ b/omero/roles/ome.docker/molecule/default/tests/test_docker.py @@ -0,0 +1,40 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('xdockerx') + + +def test_service_running_and_enabled(host): + assert host.service('docker').is_running + assert host.service('docker').is_enabled + + +def test_docker_info(host): + with host.sudo(): + host.command.check_output('docker info') + + +def test_docker_socket_unprivileged(host): + with host.sudo('test'): + r = host.command('docker info') + assert r.rc > 0 + assert 'permission denied' in r.stdout + + +def test_docker_tcp_unprivileged(host): + with host.sudo('test'): + host.command.check_output( + 'DOCKER_HOST=tcp://127.0.0.1:4243 docker info') + + +def test_docker_run(host): + with host.sudo(): + out = host.command.check_output('docker run busybox id') + assert out == 'uid=0(root) gid=0(root) groups=0(root),10(wheel)' + + +def test_docker_package(host): + assert host.package('docker-ce').is_installed + assert not host.package('docker').is_installed diff --git a/omero/roles/ome.docker/tasks/main.yml b/omero/roles/ome.docker/tasks/main.yml new file mode 100644 index 00000000..6dc5c31b --- /dev/null +++ b/omero/roles/ome.docker/tasks/main.yml @@ -0,0 +1,83 @@ +--- +# Setup a Docker node +- ansible.builtin.import_tasks: pre_tasks.yml + +- name: docker | Import a key for docker + become: true + ansible.builtin.rpm_key: + state: present + key: https://download.docker.com/linux/centos/gpg + +- name: docker | setup dnf repository + become: true + ansible.builtin.dnf: + update_cache: true + name: + - https://download.docker.com/linux/centos/9/x86_64/stable/Packages/containerd.io-1.6.24-3.1.el9.x86_64.rpm + - https://download.docker.com/linux/centos/9/x86_64/stable/Packages/docker-ce-20.10.24-3.el9.x86_64.rpm + - https://download.docker.com/linux/centos/9/x86_64/stable/Packages/docker-ce-cli-20.10.24-3.el9.x86_64.rpm + - https://download.docker.com/linux/centos/9/x86_64/stable/Packages/docker-scan-plugin-0.23.0-3.el9.x86_64.rpm + - https://download.docker.com/linux/centos/9/x86_64/stable/Packages/docker-ce-rootless-extras-24.0.7-1.el9.x86_64.rpm + state: present + +- name: docker | install docker + become: true + ansible.builtin.yum: + update_cache: true + name: + - docker-ce + state: present + +- name: docker | setup lvm docker-pool + become: true + lvol: + vg: "{{ docker_vgname }}" + lv: docker-pool + size: "{{ docker_poolsize }}" + opts: > + {{ docker_lvopts | default(None) }} --thin --poolmetadatasize + {{ docker_metadatasize }} + when: docker_use_custom_storage + +- name: docker | configuration directory + become: true + file: + path: /etc/docker + state: directory + mode: 0755 + +# https://docs.docker.com/engine/reference/commandline/dockerd/#linux-configuration-file +- name: docker | configure docker options + become: true + template: + src: etc-docker-daemon-json.j2 + dest: /etc/docker/daemon.json + backup: true + mode: 0644 + notify: + - restart docker + +# change service file to remove _H options from service file to be able to use daemon.json +- name: docker | remove options from service + become: true + ansible.builtin.replace: + path: /usr/lib/systemd/system/docker.service + regexp: ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock + replace: ExecStart=/usr/bin/dockerd + +- name: docker | enable + become: true + ansible.builtin.service: + name: docker + state: started + enabled: true + # ignore_errors: true + when: docker_systemd_setup + +- name: docker | group members + become: true + ansible.builtin.user: + name: "{{ item }}" + groups: docker + append: true + with_items: "{{ docker_groupmembers }}" diff --git a/omero/roles/ome.docker/tasks/pre_tasks.yml b/omero/roles/ome.docker/tasks/pre_tasks.yml new file mode 100644 index 00000000..1c38b289 --- /dev/null +++ b/omero/roles/ome.docker/tasks/pre_tasks.yml @@ -0,0 +1,13 @@ +--- + +- name: Set up partition + ansible.builtin.include_role: + name: ome.lvm_partition + vars: + lvm_vgname: "{{ docker_vgname }}" + lvm_lvname: docker-volume + lvm_lvmount: /var/lib/docker + lvm_lvsize: "{{ docker_volumesize }}" + lvm_lvfilesystem: "{{ docker_lvfilesystem }}" + lvm_lvopts: "{{ docker_lvopts | default(None) }}" + when: docker_use_custom_storage diff --git a/omero/roles/ome.docker/templates/etc-docker-daemon-json.j2 b/omero/roles/ome.docker/templates/etc-docker-daemon-json.j2 new file mode 100644 index 00000000..6ee32576 --- /dev/null +++ b/omero/roles/ome.docker/templates/etc-docker-daemon-json.j2 @@ -0,0 +1,27 @@ +{ +{% if docker_use_custom_storage %} + "storage-driver": "devicemapper", + "storage-opts": [ + "dm.fs={{ docker_basefs }}", + "dm.thinpooldev=/dev/mapper/{{ docker_vgname }}-docker--pool" + ], +{% endif %} +{% if docker_storage_driver | length > 0 %} + "storage-driver": "{{ docker_storage_driver }}", +{% endif %} + +{% if docker_use_custom_network %} + "bridge": "{{ docker_bridge_name }}", + "fixed-cidr": "{{ docker_bridge_ips }}", +{% endif %} + +{% if docker_use_ipv4_nic_mtu %} + "mtu": {{ ansible_default_ipv4.mtu }}, +{% endif %} + +{% for key in docker_additional_options %} + "{{ key }}": {{ docker_additional_options[key] | to_json }}, +{% endfor %} + + "debug": {{ docker_debug | bool | to_json }} +} diff --git a/omero/roles/ome.ice/.github/workflows/molecule.yml b/omero/roles/ome.ice/.github/workflows/molecule.yml new file mode 100644 index 00000000..f1ea4c82 --- /dev/null +++ b/omero/roles/ome.ice/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: ansible-actions/ansible-galaxy-action@v1.2.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + galaxy_version: ${{ github.ref_name }} diff --git a/omero/roles/ome.ice/.gitignore b/omero/roles/ome.ice/.gitignore new file mode 100644 index 00000000..d35ab669 --- /dev/null +++ b/omero/roles/ome.ice/.gitignore @@ -0,0 +1,2 @@ +.*~ +*.pyc diff --git a/omero/roles/ome.ice/LICENSE.md b/omero/roles/ome.ice/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.ice/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.ice/README.md b/omero/roles/ome.ice/README.md new file mode 100644 index 00000000..74f6a4b0 --- /dev/null +++ b/omero/roles/ome.ice/README.md @@ -0,0 +1,39 @@ +Role Name +========= + +[![Actions Status](https://github.com/ome/ansible-role-ice/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-ice/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-ice-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/ice/) + +Install Zeroc Ice. + +On Ubuntu this only installs the Ice binaries and required libraries under `/opt/ice/bin` (note this is a symlink). + + +Role Variables +-------------- + +Optional (expert users only): +- `ice_install_devel`: Install Ice development packages, default `True` +- `ice_install_python`: Install Ice Python globally, default `True`, ignored on Ubuntu and CentOS 8 (always `False`) +- `ice_python_wheel`: URL to a python wheel package to be installed, ignored on Ubuntu and CentOS 8. + You can use this to provide a precompiled ice-py package for 3.6 as an alternative to automatically compiling from the source package. +- `ice_binaries_symlink_dest`: Symlink the Ice binaries required by OMERO into this directory e.g. `/usr/local/bin` (Ubuntu and CentOS 8 only, must exist, if empty don't create symlinks) + + +Notes +----- +Note that 3.6 requires ice-python to be installed using pip, and will result in the installation of several development tools and libraries unless `ice_python_wheel` is provided. + + +Example Playbook +---------------- + + - hosts: localhost + roles: + - role: ome.ice + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.ice/defaults/main.yml b/omero/roles/ome.ice/defaults/main.yml new file mode 100644 index 00000000..7aed77d1 --- /dev/null +++ b/omero/roles/ome.ice/defaults/main.yml @@ -0,0 +1,22 @@ +--- +# defaults file for ice + +ice_install_devel: true +ice_install_python: true +ice_python_wheel: '' + +# Symlink the main ice binaries into this directory +ice_binaries_symlink_dest: '' + + +###################################################################### +# Expert users only! +###################################################################### + +ice_zeroc_ice_ubuntu2204_version: '20221004' +ice_zeroc_ice_ubuntu2204_sha256: >- + 05e5148f7df0dfc6f06ee2e4445419f95d5b19e4fc8c99660d93af13fb14e709 + +ice_zeroc_ice_rockylinux9_version: '20231130' +ice_zeroc_ice_rockylinux9_sha256: >- + 9da10544e46dc95197e670dda4df18200d80991c404b2a2692d635ab59896c5d diff --git a/omero/roles/ome.ice/meta/.galaxy_install_info b/omero/roles/ome.ice/meta/.galaxy_install_info new file mode 100644 index 00000000..71fb6383 --- /dev/null +++ b/omero/roles/ome.ice/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:44 2024 +version: 4.4.4 diff --git a/omero/roles/ome.ice/meta/main.yml b/omero/roles/ome.ice/meta/main.yml new file mode 100644 index 00000000..73d5b8f4 --- /dev/null +++ b/omero/roles/ome.ice/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: ZeroC Ice including Python + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + role_name: ice + galaxy_tags: [] diff --git a/omero/roles/ome.ice/meta/requirements.yml b/omero/roles/ome.ice/meta/requirements.yml new file mode 100644 index 00000000..e47c05a3 --- /dev/null +++ b/omero/roles/ome.ice/meta/requirements.yml @@ -0,0 +1,4 @@ +--- +- src: ome.deploy_archive +- src: ome.basedeps +- src: ome.java diff --git a/omero/roles/ome.ice/molecule/ice36-ubuntu2204/molecule.yml b/omero/roles/ome.ice/molecule/ice36-ubuntu2204/molecule.yml new file mode 100644 index 00000000..c47e650e --- /dev/null +++ b/omero/roles/ome.ice/molecule/ice36-ubuntu2204/molecule.yml @@ -0,0 +1,32 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: ice36-ubuntu2204 + image: ubuntu:22.04 +provisioner: + name: ansible + lint: + name: ansible-lint + playbooks: + converge: ../resources/playbook.yml + inventory: + host_vars: + ice36-ubuntu2204: + ice_install_devel: false + ice_binaries_symlink_dest: /usr/local/bin +scenario: + name: ice36-ubuntu2204 + converge_sequence: + - converge +verifier: + name: testinfra + directory: ../resources/tests-built/ diff --git a/omero/roles/ome.ice/molecule/ice36all/molecule.yml b/omero/roles/ome.ice/molecule/ice36all/molecule.yml new file mode 100644 index 00000000..88387525 --- /dev/null +++ b/omero/roles/ome.ice/molecule/ice36all/molecule.yml @@ -0,0 +1,28 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: ice36all + image: rockylinux:9 +provisioner: + name: ansible + lint: + name: ansible-lint + playbooks: + converge: ../resources/playbook.yml + inventory: + host_vars: + ice36all: + ice_binaries_symlink_dest: /usr/local/bin +scenario: + name: ice36all +verifier: + name: testinfra diff --git a/omero/roles/ome.ice/molecule/ice36all/tests/test_default.py b/omero/roles/ome.ice/molecule/ice36all/tests/test_default.py new file mode 100644 index 00000000..9cc1a128 --- /dev/null +++ b/omero/roles/ome.ice/molecule/ice36all/tests/test_default.py @@ -0,0 +1,22 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_ice_version(host): + assert host.exists('icegridnode') + c = host.run('icegridnode --version') + assert c.rc == 0 + assert c.stderr.startswith('3.6.') + + +def test_icepy_version(host): + c = host.run('python -c "import Ice; print (Ice.stringVersion())"') + assert c.stdout.startswith('3.6.') + + +def test_ice_devel(host): + assert not host.package('ice-all-devel').is_installed diff --git a/omero/roles/ome.ice/molecule/ice36minimal/molecule.yml b/omero/roles/ome.ice/molecule/ice36minimal/molecule.yml new file mode 100644 index 00000000..6ee2792e --- /dev/null +++ b/omero/roles/ome.ice/molecule/ice36minimal/molecule.yml @@ -0,0 +1,30 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: ice36minimal + image: rockylinux:9 +provisioner: + name: ansible + lint: + name: ansible-lint + playbooks: + converge: ../resources/playbook.yml + inventory: + host_vars: + ice36minimal: + ice_install_devel: false + ice_install_python: false + ice_binaries_symlink_dest: /usr/local/bin +scenario: + name: ice36minimal +verifier: + name: testinfra diff --git a/omero/roles/ome.ice/molecule/ice36minimal/tests/test_default.py b/omero/roles/ome.ice/molecule/ice36minimal/tests/test_default.py new file mode 100644 index 00000000..a324a8df --- /dev/null +++ b/omero/roles/ome.ice/molecule/ice36minimal/tests/test_default.py @@ -0,0 +1,23 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_ice_version(host): + assert host.exists('icegridnode') + c = host.run('icegridnode --version') + assert c.rc == 0 + assert c.stderr.startswith('3.6.') + + +def test_icepy_version(host): + c = host.run('python -c "import Ice"') + assert c.rc == 1 + assert "No module named \'Ice\'" in c.stderr + + +def test_ice_devel(host): + assert not host.package('ice-all-devel').is_installed diff --git a/omero/roles/ome.ice/molecule/resources/playbook.yml b/omero/roles/ome.ice/molecule/resources/playbook.yml new file mode 100644 index 00000000..f7fd5655 --- /dev/null +++ b/omero/roles/ome.ice/molecule/resources/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.ice diff --git a/omero/roles/ome.ice/molecule/resources/requirements.yml b/omero/roles/ome.ice/molecule/resources/requirements.yml new file mode 100755 index 00000000..e47c05a3 --- /dev/null +++ b/omero/roles/ome.ice/molecule/resources/requirements.yml @@ -0,0 +1,4 @@ +--- +- src: ome.deploy_archive +- src: ome.basedeps +- src: ome.java diff --git a/omero/roles/ome.ice/molecule/resources/tests-built/test_default.py b/omero/roles/ome.ice/molecule/resources/tests-built/test_default.py new file mode 100644 index 00000000..892c5121 --- /dev/null +++ b/omero/roles/ome.ice/molecule/resources/tests-built/test_default.py @@ -0,0 +1,19 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +@pytest.mark.parametrize('binary', [ + 'glacier2router', + 'icegridadmin', + 'icegridnode', +]) +def test_ice_version(host, binary): + assert host.exists('icegridnode') + c = host.run('icegridnode --version') + assert c.rc == 0 + assert c.stderr.startswith('3.6.5') diff --git a/omero/roles/ome.ice/tasks/debian.yml b/omero/roles/ome.ice/tasks/debian.yml new file mode 100644 index 00000000..d4ec1c24 --- /dev/null +++ b/omero/roles/ome.ice/tasks/debian.yml @@ -0,0 +1,15 @@ +--- +# tasks file for roles/ice + +# Note download is handled by the ome.deploy_archive dependency + +- name: zeroc ice | dependencies + become: true + ansible.builtin.apt: + update_cache: true + name: + - libdb5.3 + - libdb5.3++ + - libexpat1 + - libmcpp0 + - openssl diff --git a/omero/roles/ome.ice/tasks/main.yml b/omero/roles/ome.ice/tasks/main.yml new file mode 100644 index 00000000..9d4d40a4 --- /dev/null +++ b/omero/roles/ome.ice/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- import_tasks: pre_tasks.yml + +- import_tasks: redhat9.yml + when: >- + (ansible_os_family | lower == 'redhat') and + (ansible_distribution_major_version == '9') + +- import_tasks: debian.yml + when: ansible_os_family | lower == 'debian' + +- name: zeroc ice | Display all variables/facts known for a host + ansible.builtin.debug: + msg: System {{ inventory_hostname }} has {{ ice_binaries_symlink_dest }} + + +- name: zeroc ice | symlink binaries + become: true + file: + force: true + path: "{{ ice_binaries_symlink_dest }}/{{ item }}" + src: /opt/ice/bin/{{ item }} + state: link + when: 'ice_binaries_symlink_dest | length > 0' + with_items: + - glacier2router + - icegridadmin + - icegridnode diff --git a/omero/roles/ome.ice/tasks/pre_tasks.yml b/omero/roles/ome.ice/tasks/pre_tasks.yml new file mode 100644 index 00000000..254c83c3 --- /dev/null +++ b/omero/roles/ome.ice/tasks/pre_tasks.yml @@ -0,0 +1,51 @@ +--- + +- name: zeroc ice | Include ome.basedeps role + include_role: + name: ome.basedeps + when: >- + (ansible_os_family | lower == 'redhat') and + (ansible_distribution_major_version == '9') + +- name: zeroc ice | Include ome.java + include_role: + name: ome.java + when: >- + (ansible_os_family | lower == 'redhat') and + (ansible_distribution_major_version == '9') + + +- name: zeroc ice | Include ome.jadeploy_archiveva debian + include_role: + name: ome.deploy_archive + vars: + ansible_become: yes + deploy_archive_dest_dir: /opt + deploy_archive_src_url: "https://github.com/\ + glencoesoftware/zeroc-ice-ubuntu2204-x86_64/releases/\ + download/{{ ice_zeroc_ice_ubuntu2204_version }}/Ice-3.6.5-ubuntu2204-x86_64.tar.gz" + deploy_archive_sha256: "{{ ice_zeroc_ice_ubuntu2204_sha256 }}" + deploy_archive_symlink: /opt/ice + deploy_archive_internal_root: >- + Ice-3.6.5 + when: >- + (ansible_os_family | lower == 'debian') and + (ansible_distribution_major_version == '22') + + +- name: zeroc ice | Include ome.jadeploy_archiveva redhat + include_role: + name: ome.deploy_archive + vars: + ansible_become: yes + deploy_archive_dest_dir: /opt + deploy_archive_src_url: "https://github.com/\ +glencoesoftware/zeroc-ice-rhel9-x86_64/releases/\ +download/{{ ice_zeroc_ice_rockylinux9_version }}/Ice-3.6.5-rhel9-x86_64.tar.gz" + deploy_archive_sha256: "{{ ice_zeroc_ice_rockylinux9_sha256 }}" + deploy_archive_symlink: /opt/ice + deploy_archive_internal_root: >- + Ice-3.6.5 + when: >- + (ansible_os_family | lower == 'redhat') and + (ansible_distribution_major_version == '9') diff --git a/omero/roles/ome.ice/tasks/redhat9.yml b/omero/roles/ome.ice/tasks/redhat9.yml new file mode 100644 index 00000000..56cecbec --- /dev/null +++ b/omero/roles/ome.ice/tasks/redhat9.yml @@ -0,0 +1,100 @@ +--- +# tasks file for roles/ice + + + +#- name: zeroc ice | set-enabled crb +# become: true +# ansible.builtin.command: dnf config-manager --set-enabled crb +# state: present + +- name : zeroc ice | check rocky.repo file + stat: + path: /etc/yum.repos.d/rocky.repo + register: rockyrepo_name + +- name: zeroc ice | install config-manager in rocky + become: true + ansible.builtin.dnf: + update_cache: true + name: + - 'dnf-command(config-manager)' + state: present + when: rockyrepo_name.stat.exists + +- name: zeroc ice | Enable crp repo in rocky + become: true + ansible.builtin.replace: + path: /etc/yum.repos.d/rocky.repo + # create: false + regexp: enabled=0 + replace: enabled=1 + # state: present + when: rockyrepo_name.stat.exists + +- name: zeroc ice | Add CRB repository for RHEL + become: true + ansible.builtin.command: + subscription-manager repos --enable codeready-builder-for-rhel-9-x86_64-rpms + when: ansible_os_family == 'RedHat' and not rockyrepo_name.stat.exists + +- name: zeroc ice | install libdb + become: true + ansible.builtin.dnf: + update_cache: true + name: + - libdb-cxx + state: present + +# - name: zeroc ice | command echo lib64 +# ansible.builtin.command: echo /opt/ice-3.6.5/lib64 > /etc/ld.so.conf.d/ice-x86_64.conf +# become: true + +# - name: zeroc ice | command ldconfig +# ansible.builtin.command: ldconfig +# become: true + +- name: zero ice | install python + become: true + ansible.builtin.dnf: + update_cache: true + name: python + state: present + +- name: zeroc ice | install ice pip dependencies + become: true + ansible.builtin.dnf: + update_cache: true + name: + - gcc + - gcc-c++ + - libdb-utils + - bzip2-devel + - expat-devel + - openssl-devel + - python-devel + - python-pip + state: present + when: ice_install_python and (ice_python_wheel | length < 1) + +- name: zeroc ice | pip install packages + become: true + pip: + name: + - "zeroc-ice>=3.6,<3.7" + state: present + when: ice_install_python and (ice_python_wheel | length < 1) + +- name: zeroc ice | install python-pip for wheel + become: true + yum: + name: python-pip + state: present + when: ice_install_python and (ice_python_wheel | length >= 1) + +- name: zeroc ice | install ice wheel package + become: true + pip: + name: "{{ ice_python_wheel }}" + state: present + when: ice_install_python and (ice_python_wheel | length >= 1) diff --git a/omero/roles/ome.java/.github/workflows/molecule.yml b/omero/roles/ome.java/.github/workflows/molecule.yml new file mode 100644 index 00000000..2b19bf44 --- /dev/null +++ b/omero/roles/ome.java/.github/workflows/molecule.yml @@ -0,0 +1,58 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-20.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-20.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} + +# notifications: +# webhooks: https://galaxy.ansible.com/api/v1/notifications/ diff --git a/omero/roles/ome.java/.gitignore b/omero/roles/ome.java/.gitignore new file mode 100644 index 00000000..0bf56261 --- /dev/null +++ b/omero/roles/ome.java/.gitignore @@ -0,0 +1,2 @@ +.*~ +__pycache__ diff --git a/omero/roles/ome.java/LICENSE.md b/omero/roles/ome.java/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.java/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.java/README.md b/omero/roles/ome.java/README.md new file mode 100644 index 00000000..dea4e7ac --- /dev/null +++ b/omero/roles/ome.java/README.md @@ -0,0 +1,35 @@ +Java +==== + +[![Actions Status](https://github.com/ome/ansible-role-java/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-java/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-java-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/java/) + +Install Java JREs and optionally JDKs. + + +Role Variables +-------------- + +Optional variables: +- `java_versions`: A list of Java versions to install, default `["8"]`, + versions other than `"8"` and `"11"` may work but are not supported +- `java_jdk_install`: If `True` install JDKs corresponding to the JRE versions, default `False` + + +Example Playbook +---------------- + + - hosts: servers + roles: + - { role: ome.java } + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk + +License +------- + +BSD diff --git a/omero/roles/ome.java/defaults/main.yml b/omero/roles/ome.java/defaults/main.yml new file mode 100644 index 00000000..44083277 --- /dev/null +++ b/omero/roles/ome.java/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# defaults file for roles/java + +# List of Java versions to install +java_versions: + - "8" + +# Install JDKs corresponding to JREs? +java_jdk_install: false diff --git a/omero/roles/ome.java/meta/.galaxy_install_info b/omero/roles/ome.java/meta/.galaxy_install_info new file mode 100644 index 00000000..17229187 --- /dev/null +++ b/omero/roles/ome.java/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:42 2024 +version: 2.2.0 diff --git a/omero/roles/ome.java/meta/main.yml b/omero/roles/ome.java/meta/main.yml new file mode 100644 index 00000000..6d21b103 --- /dev/null +++ b/omero/roles/ome.java/meta/main.yml @@ -0,0 +1,21 @@ +--- +galaxy_info: + role_name: java + author: ome-devel@lists.openmicroscopy.org.uk + description: Install Java JREs and optionally JDKs. + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.4 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + galaxy_tags: + - system + - java + - jdk + - openjdk diff --git a/omero/roles/ome.java/molecule/resources/playbook.yml b/omero/roles/ome.java/molecule/resources/playbook.yml new file mode 100644 index 00000000..20520b93 --- /dev/null +++ b/omero/roles/ome.java/molecule/resources/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.java diff --git a/omero/roles/ome.java/molecule/resources/tests/test_jdk.py b/omero/roles/ome.java/molecule/resources/tests/test_jdk.py new file mode 100644 index 00000000..a24268b5 --- /dev/null +++ b/omero/roles/ome.java/molecule/resources/tests/test_jdk.py @@ -0,0 +1,20 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('java-jdk') + + +def test_jre_version(host): + assert host.exists('java') + c = host.run('java -version') + assert c.rc == 0 + assert c.stderr.startswith('openjdk version "1.8.0') + + +def test_jdk_version(host): + assert host.exists('javac') + c = host.run('javac -version') + assert c.rc == 0 + assert c.stderr.startswith('javac 1.8.0') diff --git a/omero/roles/ome.java/molecule/resources/tests/test_jdk11.py b/omero/roles/ome.java/molecule/resources/tests/test_jdk11.py new file mode 100644 index 00000000..25232734 --- /dev/null +++ b/omero/roles/ome.java/molecule/resources/tests/test_jdk11.py @@ -0,0 +1,21 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('java-jdk11') + + +def test_jre_version(host): + assert host.exists('java') + c = host.run('java -version') + assert c.rc == 0 + assert c.stderr.startswith('openjdk version "11.0') + + +def test_jdk_version(host): + assert host.exists('javac') + c = host.run('javac -version') + assert c.rc == 0 + # Output has changed from stderr to stdout for javac 11 only + assert c.stdout.startswith('javac 11.0') diff --git a/omero/roles/ome.java/molecule/resources/tests/test_jre.py b/omero/roles/ome.java/molecule/resources/tests/test_jre.py new file mode 100644 index 00000000..2148a183 --- /dev/null +++ b/omero/roles/ome.java/molecule/resources/tests/test_jre.py @@ -0,0 +1,17 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('java-jre') + + +def test_jre_version(host): + assert host.exists('java') + c = host.run('java -version') + assert c.rc == 0 + assert c.stderr.startswith('openjdk version "1.8.0') + + +def test_jdk_version(host): + assert not host.exists('javac') diff --git a/omero/roles/ome.java/molecule/resources/tests/test_jre11.py b/omero/roles/ome.java/molecule/resources/tests/test_jre11.py new file mode 100644 index 00000000..c47ed7bb --- /dev/null +++ b/omero/roles/ome.java/molecule/resources/tests/test_jre11.py @@ -0,0 +1,17 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('java-jre11') + + +def test_jre_version(host): + assert host.exists('java') + c = host.run('java -version') + assert c.rc == 0 + assert c.stderr.startswith('openjdk version "11.0.') + + +def test_jdk_version(host): + assert not host.exists('javac') diff --git a/omero/roles/ome.java/molecule/rockylinux-9/molecule.yml b/omero/roles/ome.java/molecule/rockylinux-9/molecule.yml new file mode 100644 index 00000000..a14d3885 --- /dev/null +++ b/omero/roles/ome.java/molecule/rockylinux-9/molecule.yml @@ -0,0 +1,41 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: java-jre + image: rockylinux:9 + - name: java-jdk + image: rockylinux:9 + - name: java-jre11 + image: rockylinux:9 + - name: java-jdk11 + image: rockylinux:9 +provisioner: + name: ansible + playbooks: + converge: ../resources/playbook.yml + lint: + name: ansible-lint + inventory: + host_vars: + java-jdk: + java_jdk_install: true + java-jre11: + java_versions: + - "11" + java-jdk11: + java_versions: + - "11" + java_jdk_install: true + +scenario: + name: rockylinux-9 +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.java/molecule/ubuntu-2204/molecule.yml b/omero/roles/ome.java/molecule/ubuntu-2204/molecule.yml new file mode 100644 index 00000000..86e0571b --- /dev/null +++ b/omero/roles/ome.java/molecule/ubuntu-2204/molecule.yml @@ -0,0 +1,41 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: java-jre + image: ubuntu:22.04 + - name: java-jdk + image: ubuntu:22.04 + - name: java-jre11 + image: ubuntu:22.04 + - name: java-jdk11 + image: ubuntu:22.04 +provisioner: + name: ansible + playbooks: + converge: ../resources/playbook.yml + lint: + name: ansible-lint + inventory: + host_vars: + java-jdk: + java_jdk_install: true + java-jre11: + java_versions: + - "11" + java-jdk11: + java_versions: + - "11" + java_jdk_install: true + +scenario: + name: ubuntu-2204 +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.java/tasks/debian.yml b/omero/roles/ome.java/tasks/debian.yml new file mode 100644 index 00000000..8b06c3d4 --- /dev/null +++ b/omero/roles/ome.java/tasks/debian.yml @@ -0,0 +1,22 @@ +--- +# tasks file for roles/java + +- name: system packages | install java jre (ubuntu) + become: true + ansible.builtin.apt: + update_cache: true + name: >- + openjdk-{{ java_backwards_compatibility_version.debian[item] | + default(item) }}-jre + state: present + with_items: "{{ java_versions }}" + +- name: system packages | install java jdk (ubuntu) + become: true + ansible.builtin.apt: + name: >- + openjdk-{{ java_backwards_compatibility_version.debian[item] | + default(item) }}-jdk + state: present + when: java_jdk_install + with_items: "{{ java_versions }}" diff --git a/omero/roles/ome.java/tasks/main.yml b/omero/roles/ome.java/tasks/main.yml new file mode 100644 index 00000000..87b3f77a --- /dev/null +++ b/omero/roles/ome.java/tasks/main.yml @@ -0,0 +1,24 @@ +--- +# tasks file for roles/java + +- name: java | manage legacy java version + block: + + - name: java | warn about old java_jre_versions variables + ansible.builtin.fail: + msg: java_jre_versions variable is deprecated, use java_versions instead + ignore_errors: true + + - name: java | set java_versions from old java_jre_versions variables + ansible.builtin.set_fact: + java_versions: "{{ java_jre_versions }}" + + when: java_jre_versions is defined + +- name: java | import tasks for redhat OS family + ansible.builtin.import_tasks: redhat.yml + when: ansible_os_family | lower == 'redhat' + +- name: java | import tasks for debian OS family + ansible.builtin.import_tasks: debian.yml + when: ansible_os_family | lower == 'debian' diff --git a/omero/roles/ome.java/tasks/redhat.yml b/omero/roles/ome.java/tasks/redhat.yml new file mode 100644 index 00000000..474a1e4c --- /dev/null +++ b/omero/roles/ome.java/tasks/redhat.yml @@ -0,0 +1,21 @@ +--- +# tasks file for roles/java + +- name: system packages | install java jre (rockylinux) + become: true + ansible.builtin.dnf: + name: >- + java-{{ java_backwards_compatibility_version.redhat[item] | + default(item) }}-openjdk + state: present + with_items: "{{ java_versions }}" + +- name: system packages | install java jdk (rockylinux) + become: true + ansible.builtin.dnf: + name: >- + java-{{ java_backwards_compatibility_version.redhat[item] | + default(item) }}-openjdk-devel + state: present + when: java_jdk_install + with_items: "{{ java_versions }}" diff --git a/omero/roles/ome.java/vars/main.yml b/omero/roles/ome.java/vars/main.yml new file mode 100644 index 00000000..1263fcc8 --- /dev/null +++ b/omero/roles/ome.java/vars/main.yml @@ -0,0 +1,8 @@ +--- +# internal vars, may be changed at any point + +java_backwards_compatibility_version: + debian: + 1.8.0: "8" + redhat: + "8": "1.8.0" diff --git a/omero/roles/ome.lvm_partition/.github/workflows/molecule.yml b/omero/roles/ome.lvm_partition/.github/workflows/molecule.yml new file mode 100644 index 00000000..1bde8477 --- /dev/null +++ b/omero/roles/ome.lvm_partition/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} diff --git a/omero/roles/ome.lvm_partition/.gitignore b/omero/roles/ome.lvm_partition/.gitignore new file mode 100644 index 00000000..b6261c93 --- /dev/null +++ b/omero/roles/ome.lvm_partition/.gitignore @@ -0,0 +1 @@ +.*~ diff --git a/omero/roles/ome.lvm_partition/LICENSE.md b/omero/roles/ome.lvm_partition/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.lvm_partition/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.lvm_partition/README.md b/omero/roles/ome.lvm_partition/README.md new file mode 100644 index 00000000..42c4a8e0 --- /dev/null +++ b/omero/roles/ome.lvm_partition/README.md @@ -0,0 +1,30 @@ +LVM Partition +============= + +[![Actions Status](https://github.com/ome/ansible-role-lvm-partition/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-lvm-partition/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-lvm_partition-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/lvm_partition/) + +Additional LVM logical volumes to be created and mounted. + +Existing LVs will be resized. + +Role Variables +-------------- + +These variables must be defined (defaults aren't provided): + +- `lvm_vgname`: LVM volume group for the logical volume +- `lvm_lvname`: Logical volume name, use `[A-Aa-z0-9]+` to avoid problems +- `lvm_lvmount`: Where the partition should be mounted +- `lvm_lvsize`: Size of the partition +- `lvm_lvfilesystem`: filesystem for partitions which need to be formatted + +Optional variables: + +- `lvm_shrink`: Shrink if current size is higher than size requested (default: True) +- `lvm_lvopts`: Logical volume creation options (default: None) + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.lvm_partition/defaults/main.yml b/omero/roles/ome.lvm_partition/defaults/main.yml new file mode 100644 index 00000000..2222885d --- /dev/null +++ b/omero/roles/ome.lvm_partition/defaults/main.yml @@ -0,0 +1,4 @@ +--- +# defaults file for roles/lvm-partitions + +lvm_lvopts: diff --git a/omero/roles/ome.lvm_partition/meta/.galaxy_install_info b/omero/roles/ome.lvm_partition/meta/.galaxy_install_info new file mode 100644 index 00000000..5df6d224 --- /dev/null +++ b/omero/roles/ome.lvm_partition/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:34:05 2024 +version: 1.2.0 diff --git a/omero/roles/ome.lvm_partition/meta/main.yml b/omero/roles/ome.lvm_partition/meta/main.yml new file mode 100644 index 00000000..56497673 --- /dev/null +++ b/omero/roles/ome.lvm_partition/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Create a formatted LVM volume + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.2 + platforms: + - name: EL + versions: + - 9 + role_name: lvm_partition + namespace: ome + galaxy_tags: ['lvm', 'system'] + +dependencies: [] diff --git a/omero/roles/ome.lvm_partition/molecule/default/molecule.yml b/omero/roles/ome.lvm_partition/molecule/default/molecule.yml new file mode 100644 index 00000000..0ceebfa1 --- /dev/null +++ b/omero/roles/ome.lvm_partition/molecule/default/molecule.yml @@ -0,0 +1,24 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: instance + image: rockylinux:9 +provisioner: + name: ansible + lint: + name: ansible-lint +verifier: + name: testinfra +scenario: + test_sequence: + - lint + - dependency + - cleanup + - syntax diff --git a/omero/roles/ome.lvm_partition/molecule/default/playbook.yml b/omero/roles/ome.lvm_partition/molecule/default/playbook.yml new file mode 100644 index 00000000..7b9de325 --- /dev/null +++ b/omero/roles/ome.lvm_partition/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.lvm_partition diff --git a/omero/roles/ome.lvm_partition/molecule/default/tests/test_default.py b/omero/roles/ome.lvm_partition/molecule/default/tests/test_default.py new file mode 100644 index 00000000..9e0e1890 --- /dev/null +++ b/omero/roles/ome.lvm_partition/molecule/default/tests/test_default.py @@ -0,0 +1,15 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE'] +).get_hosts('all') + + +def test_hosts_file(host): + f = host.file('/etc/hosts') + + assert f.exists + assert f.user == 'root' + assert f.group == 'root' diff --git a/omero/roles/ome.lvm_partition/tasks/main.yml b/omero/roles/ome.lvm_partition/tasks/main.yml new file mode 100644 index 00000000..4a231d69 --- /dev/null +++ b/omero/roles/ome.lvm_partition/tasks/main.yml @@ -0,0 +1,28 @@ +--- +# Setup LVM partition + +- name: storage | create logical volume + become: true + lvol: + vg: "{{ lvm_vgname }}" + lv: "{{ lvm_lvname }}" + size: "{{ lvm_lvsize }}" + shrink: "{{ lvm_shrink | default(True) }}" + opts: "{{ lvm_lvopts | default(None) }}" + +- name: storage | filesystem + become: true + filesystem: + fstype: "{{ lvm_lvfilesystem }}" + dev: /dev/{{ lvm_vgname }}/{{ lvm_lvname }} + resizefs: true + +- name: storage | mount + become: true + mount: + name: "{{ lvm_lvmount }}" + src: /dev/{{ lvm_vgname }}/{{ lvm_lvname }} + dump: "1" + passno: "2" + fstype: "{{ lvm_lvfilesystem }}" + state: mounted diff --git a/omero/roles/ome.lvm_partition/tests/inventory b/omero/roles/ome.lvm_partition/tests/inventory new file mode 100644 index 00000000..2fbb50c4 --- /dev/null +++ b/omero/roles/ome.lvm_partition/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/omero/roles/ome.lvm_partition/tests/test.yml b/omero/roles/ome.lvm_partition/tests/test.yml new file mode 100644 index 00000000..6f1a9df8 --- /dev/null +++ b/omero/roles/ome.lvm_partition/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - role: ome.lvm_partition diff --git a/omero/roles/ome.nginx/.github/workflows/molecule.yml b/omero/roles/ome.nginx/.github/workflows/molecule.yml new file mode 100644 index 00000000..77ad5981 --- /dev/null +++ b/omero/roles/ome.nginx/.github/workflows/molecule.yml @@ -0,0 +1,56 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: ansible-actions/ansible-galaxy-action@v1.2.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + galaxy_version: ${{ github.ref_name }} + diff --git a/omero/roles/ome.nginx/.gitignore b/omero/roles/ome.nginx/.gitignore new file mode 100644 index 00000000..3d8d5649 --- /dev/null +++ b/omero/roles/ome.nginx/.gitignore @@ -0,0 +1,2 @@ +.*~ +*.pyc \ No newline at end of file diff --git a/omero/roles/ome.nginx/LICENSE.md b/omero/roles/ome.nginx/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.nginx/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.nginx/README.md b/omero/roles/ome.nginx/README.md new file mode 100644 index 00000000..446ae983 --- /dev/null +++ b/omero/roles/ome.nginx/README.md @@ -0,0 +1,30 @@ +Nginx +===== + +[![Actions Status](https://github.com/ome/ansible-role-nginx/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-nginx/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-nginx-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/nginx/) + +Install upstream Nginx. + +TODO: Add configuration options. + + +Role Variables +-------------- + +- `nginx_keep_default_configs`: If `true` keep the default site configuration files in `nginx/conf.d`, default `false` (disable them) +- `nginx_stable_repo`: If `false` use the mainline instead of stable repo, default `true` +- `nginx_version`: The packaged version of Nginx, optional, available versions depends on `nginx_stable_repo`. Not supported on Ubuntu. +- `nginx_systemd_setup`: Start/restart nginx using systemd, default `true` +, if you want to manage Nginx yourself set this to `false` + +Log rotation: + +- `nginx_logrotate_interval`: Rotate log files at this interval, default `daily` +- `nginx_logrotate_backlog_size`: Number of backlog files to keep, default `366` + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.nginx/defaults/main.yml b/omero/roles/ome.nginx/defaults/main.yml new file mode 100644 index 00000000..e5a11d8b --- /dev/null +++ b/omero/roles/ome.nginx/defaults/main.yml @@ -0,0 +1,20 @@ +--- +# defaults file for roles/nginx + +# Not supported on Ubuntu +nginx_version: '' + +# Rotate log files at this interval +nginx_logrotate_interval: daily + +# Number of backlog files to keep +nginx_logrotate_backlog_size: 366 + +# Use stable or mainline? +nginx_stable_repo: true + +# Keep default configurations under /etc/nginx +nginx_keep_default_configs: false + +# Start/restart nginx using systemd +nginx_systemd_setup: true diff --git a/omero/roles/ome.nginx/files/nginx-mainline.repo b/omero/roles/ome.nginx/files/nginx-mainline.repo new file mode 100644 index 00000000..9b8af3b0 --- /dev/null +++ b/omero/roles/ome.nginx/files/nginx-mainline.repo @@ -0,0 +1,5 @@ +[nginx] +name=nginx repo +baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ +gpgcheck=0 +enabled=1 diff --git a/omero/roles/ome.nginx/handlers/main.yml b/omero/roles/ome.nginx/handlers/main.yml new file mode 100644 index 00000000..2867ac9c --- /dev/null +++ b/omero/roles/ome.nginx/handlers/main.yml @@ -0,0 +1,9 @@ +--- +# Handler for nginx + +- name: restart nginx + become: true + service: + name: nginx + state: restarted + when: nginx_systemd_setup diff --git a/omero/roles/ome.nginx/meta/.galaxy_install_info b/omero/roles/ome.nginx/meta/.galaxy_install_info new file mode 100644 index 00000000..4532a6ec --- /dev/null +++ b/omero/roles/ome.nginx/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:51 2024 +version: 2.2.1 diff --git a/omero/roles/ome.nginx/meta/main.yml b/omero/roles/ome.nginx/meta/main.yml new file mode 100644 index 00000000..b2c02857 --- /dev/null +++ b/omero/roles/ome.nginx/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Install upstream Nginx + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.6 + platforms: + - name: EL + versions: + - 9 + namespace: ome + role_name: nginx + galaxy_tags: ['nginx'] + +dependencies: [] diff --git a/omero/roles/ome.nginx/molecule/resources/playbook.yml b/omero/roles/ome.nginx/molecule/resources/playbook.yml new file mode 100644 index 00000000..178201f2 --- /dev/null +++ b/omero/roles/ome.nginx/molecule/resources/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.nginx diff --git a/omero/roles/ome.nginx/molecule/rockylinux9/molecule.yml b/omero/roles/ome.nginx/molecule/rockylinux9/molecule.yml new file mode 100644 index 00000000..d4bf3216 --- /dev/null +++ b/omero/roles/ome.nginx/molecule/rockylinux9/molecule.yml @@ -0,0 +1,59 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: nginx-default + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: nginx-custom + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: nginx-disabled + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + playbooks: + converge: ../resources/playbook.yml + # prepare: prepare.yml + lint: + name: ansible-lint + inventory: + host_vars: + nginx-custom: + nginx_keep_default_configs: true + nginx_stable_repo: false + # Current mainline is 1.15.9 + nginx_version: 1.20.2 + nginx_logrotate_interval: weekly + nginx_logrotate_backlog_size: 5 + nginx-disabled: + nginx_systemd_setup: false +scenario: + name: rockylinux9 +verifier: + name: testinfra diff --git a/omero/roles/ome.nginx/molecule/rockylinux9/tests/test_default.py b/omero/roles/ome.nginx/molecule/rockylinux9/tests/test_default.py new file mode 100644 index 00000000..34d6e0f9 --- /dev/null +++ b/omero/roles/ome.nginx/molecule/rockylinux9/tests/test_default.py @@ -0,0 +1,56 @@ +import os +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_package(host): + assert host.package('nginx').is_installed + + +def test_service(host): + hostname = host.backend.get_hostname() + service = host.service('nginx') + if hostname == 'nginx-disabled': + assert not service.is_running + else: + assert service.is_running + + +@pytest.mark.parametrize("configfile", ["example_ssl.conf", "default.conf"]) +def test_configuration(host, configfile): + c = host.file('/etc/nginx/conf.d/%s' % configfile) + hostname = host.backend.get_hostname() + if hostname != 'nginx-custom': + assert (c.content_string == + "# This file is intentionally blank (Ansible)") + + +def test_logrotate(host): + log = host.file("/etc/logrotate.d/nginx") + hostname = host.backend.get_hostname() + if hostname != 'nginx-custom': + assert log.contains("daily") + assert log.contains("rotate 366") + else: + assert log.contains("weekly") + assert log.contains("rotate 5") + + +def test_version(host): + hostname = host.backend.get_hostname() + r = host.run('nginx -v') + assert r.rc == 0 + ver = r.stderr.strip() + if hostname == 'nginx-custom': + assert ver == ('nginx version: nginx/1.20.2') + else: + assert ver.startswith('nginx version: nginx/1.24.0') + + +def test_nginx_configuration(host): + c = host.file('/etc/nginx/nginx.conf') + assert 'http {' in c.content_string + assert 'server {' not in c.content_string diff --git a/omero/roles/ome.nginx/tasks/debian.yaml b/omero/roles/ome.nginx/tasks/debian.yaml new file mode 100755 index 00000000..91a9b7cd --- /dev/null +++ b/omero/roles/ome.nginx/tasks/debian.yaml @@ -0,0 +1,26 @@ +--- +# - name: system packages | add nginx apt key +# become: true +# ansible.builtin.apt_key: +# keyring: /usr/share/keyrings/nginx-archive-keyring.gpg +# url: https://nginx.org/keys/nginx_signing.key +# id: ABF5BD827BD9BF62 + + +# - name: system packages | Add nginx stable repository into sources list +# ansible.builtin.apt_repository: +# repo: "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu jammy nginx" +# state: present + +- name: system packages | install nginx + become: true + ansible.builtin.apt: + update_cache: true + name: nginx + state: present + +- name: nginx | remove default config + become: true + file: + path: /etc/nginx/sites-enabled/default + state: absent diff --git a/omero/roles/ome.nginx/tasks/main.yml b/omero/roles/ome.nginx/tasks/main.yml new file mode 100644 index 00000000..80b7a129 --- /dev/null +++ b/omero/roles/ome.nginx/tasks/main.yml @@ -0,0 +1,23 @@ +--- +# tasks file for roles/nginx + +- import_tasks: redhat.yaml + when: ansible_os_family | lower == 'redhat' + +- import_tasks: debian.yaml + when: ansible_os_family | lower == 'debian' + +- name: nginx | running + become: true + service: + name: nginx + state: started + when: nginx_systemd_setup + +- name: nginx | configure logrotate + become: true + template: + backup: false + dest: /etc/logrotate.d/nginx + src: logrotated-nginx.j2 + mode: 0644 diff --git a/omero/roles/ome.nginx/tasks/redhat.yaml b/omero/roles/ome.nginx/tasks/redhat.yaml new file mode 100644 index 00000000..b42d0313 --- /dev/null +++ b/omero/roles/ome.nginx/tasks/redhat.yaml @@ -0,0 +1,45 @@ +--- +- name: Import a key for nginx + become: true + ansible.builtin.rpm_key: + state: present + key: https://nginx.org/keys/nginx_signing.key + +- name: system packages | setup upstream nginx stable repo + become: true + ansible.builtin.dnf: + update_cache: true + name: "https://nginx.org/packages/centos/9/x86_64/RPMS/nginx-1.24.0-1.el9.ngx.x86_64.rpm" + state: present + when: not nginx_version + +- name: system packages | setup upstream nginx stable repo + become: true + ansible.builtin.dnf: + update_cache: true + name: "https://nginx.org/packages/centos/9/x86_64/RPMS/nginx-{{ nginx_version }}-1.el9.ngx.x86_64.rpm" + state: present + when: nginx_version + +- name: system packages | install nginx + become: true + ansible.builtin.dnf: + update_cache: true + name: >- + nginx + state: present + +# example_ssl.conf is in some distro versions but not upstream, disable it +# just in case +- name: nginx | remove default config + become: true + copy: + content: "# This file is intentionally blank (Ansible)" + dest: /etc/nginx/conf.d/{{ item }} + mode: 0644 + with_items: + - example_ssl.conf + - default.conf + when: not (nginx_keep_default_configs | default(False)) + notify: + - restart nginx diff --git a/omero/roles/ome.nginx/templates/logrotated-nginx.j2 b/omero/roles/ome.nginx/templates/logrotated-nginx.j2 new file mode 100644 index 00000000..335224da --- /dev/null +++ b/omero/roles/ome.nginx/templates/logrotated-nginx.j2 @@ -0,0 +1,19 @@ +# Managed by Ansible +/var/log/nginx/*.log { + {{ nginx_logrotate_interval }} + missingok + rotate {{ nginx_logrotate_backlog_size }} + compress + delaycompress + notifempty + create 640 nginx adm + sharedscripts + postrotate +{% if ansible_os_family == 'RedHat' %} + [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` +{% endif %} +{% if ansible_os_family == 'Debian' %} + invoke-rc.d nginx rotate >/dev/null 2>&1 +{% endif %} + endscript +} diff --git a/omero/roles/ome.omero_common/.github/workflows/molecule.yml b/omero/roles/ome.omero_common/.github/workflows/molecule.yml new file mode 100644 index 00000000..e279a58c --- /dev/null +++ b/omero/roles/ome.omero_common/.github/workflows/molecule.yml @@ -0,0 +1,56 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-20.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-20.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-20.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} diff --git a/omero/roles/ome.omero_common/.gitignore b/omero/roles/ome.omero_common/.gitignore new file mode 100644 index 00000000..dba1d4d9 --- /dev/null +++ b/omero/roles/ome.omero_common/.gitignore @@ -0,0 +1,3 @@ +.*~ +*.pyc +.molecule diff --git a/omero/roles/ome.omero_common/LICENSE.md b/omero/roles/ome.omero_common/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.omero_common/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.omero_common/README.md b/omero/roles/ome.omero_common/README.md new file mode 100644 index 00000000..1b533322 --- /dev/null +++ b/omero/roles/ome.omero_common/README.md @@ -0,0 +1,40 @@ +OMERO Common +============ + +[![Actions Status](https://github.com/ome/ansible-role-omero-common/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-omero-common/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-omero_common-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/omero_common/) + +Common variables and handlers for other OMERO application Ansible roles. + + +Role Variables +-------------- + +All variables are optional. +You should use the defaults unless you have a good reason not to. +- `omero_common_basedir`: The parent directory for OMERO applications. + + +Handlers +-------- + +This role includes standalone handlers which can be use to restart `omero-server` and `omero-web` without depending on the corresponding Ansible roles. +This may be useful when modifying the configuration of OMERO after installation. + +If you know that the component you wish to restart is installed you can notify: +- `restart omero-server` +- `restart omero-web` +- `restart nginx` + +If the component may or may not be installed you can notify: +- `restart omero-server if installed` +- `restart omero-web if installed` +- `restart nginx if installed` + +Note that in the latter case the installation check is done when this role is run, not when the handlers are run, so there is a potential race condition. + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.omero_common/defaults/main.yml b/omero/roles/ome.omero_common/defaults/main.yml new file mode 100644 index 00000000..59ea5fce --- /dev/null +++ b/omero/roles/ome.omero_common/defaults/main.yml @@ -0,0 +1,4 @@ +--- +# defaults for omero-common + +omero_common_basedir: /opt/omero diff --git a/omero/roles/ome.omero_common/handlers/main.yml b/omero/roles/ome.omero_common/handlers/main.yml new file mode 100644 index 00000000..0e0b6e58 --- /dev/null +++ b/omero/roles/ome.omero_common/handlers/main.yml @@ -0,0 +1,50 @@ +--- +# Handlers for omero-common + +# The conditional means you can safely notify this on non-systemd servers +- name: reload systemd + become: true + command: systemctl daemon-reload + when: ansible_service_mgr == 'systemd' + tags: + # [ANSIBLE0006] systemctl used in place of systemd module + - skip_ansible_lint + +- name: restart omero-server + become: true + service: + name: omero-server + state: restarted + +- name: restart omero-web + become: true + service: + name: omero-web + state: restarted + +- name: restart nginx + become: true + service: + name: nginx + state: restarted + +- name: restart omero-server if installed + become: true + service: + name: omero-server + state: restarted + when: _omero_common_services_installed.results.0.stat.exists + +- name: restart omero-web if installed + become: true + service: + name: omero-web + state: restarted + when: _omero_common_services_installed.results.1.stat.exists + +- name: restart nginx if installed + become: true + service: + name: nginx + state: restarted + when: _omero_common_services_installed.results.2.stat.exists diff --git a/omero/roles/ome.omero_common/meta/.galaxy_install_info b/omero/roles/ome.omero_common/meta/.galaxy_install_info new file mode 100644 index 00000000..a5c11846 --- /dev/null +++ b/omero/roles/ome.omero_common/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:39 2024 +version: 0.4.0 diff --git a/omero/roles/ome.omero_common/meta/main.yml b/omero/roles/ome.omero_common/meta/main.yml new file mode 100644 index 00000000..dd077968 --- /dev/null +++ b/omero/roles/ome.omero_common/meta/main.yml @@ -0,0 +1,19 @@ +--- +galaxy_info: + role_name: omero_common + author: ome-devel@lists.openmicroscopy.org.uk + description: Common variables and tasks for OMERO applications + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.2 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - Jammy + namespace: ome + galaxy_tags: [] + +dependencies: [] diff --git a/omero/roles/ome.omero_common/molecule/default/molecule.yml b/omero/roles/ome.omero_common/molecule/default/molecule.yml new file mode 100644 index 00000000..9840d2a5 --- /dev/null +++ b/omero/roles/ome.omero_common/molecule/default/molecule.yml @@ -0,0 +1,26 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: rockylinux + image: rockylinux:9 + - name: ubuntu-22.04 + image: ubuntu:22.04 + - name: ubuntu-systemd-22.04 + image: eniocarboni/docker-ubuntu-systemd:22.04 + - name: rockylinux-systemd-22.04 + image: eniocarboni/docker-rockylinux-systemd:9 +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.omero_common/molecule/default/playbook.yml b/omero/roles/ome.omero_common/molecule/default/playbook.yml new file mode 100644 index 00000000..c15f7644 --- /dev/null +++ b/omero/roles/ome.omero_common/molecule/default/playbook.yml @@ -0,0 +1,35 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.omero_common + + tasks: + + - name: test reload systemd handler + file: + path: /etc/systemd/system + state: directory + mode: 0755 + notify: + - reload systemd + + # Should be a noop + - name: test restart handler without omero-server + file: + path: /etc/systemd/notify-omero-server-handler + state: directory + mode: 0755 + notify: + - restart omero-server if installed + + post_tasks: + - name: Check omero-common service variable + assert: + that: + # omero-server + - not _omero_common_services_installed.results.0.stat.exists + # omero-web + - not _omero_common_services_installed.results.1.stat.exists + # nginx + - not _omero_common_services_installed.results.2.stat.exists diff --git a/omero/roles/ome.omero_common/molecule/default/tests/test_default.py b/omero/roles/ome.omero_common/molecule/default/tests/test_default.py new file mode 100644 index 00000000..188281ea --- /dev/null +++ b/omero/roles/ome.omero_common/molecule/default/tests/test_default.py @@ -0,0 +1,13 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_directory(host): + d = host.file('/opt/omero') + assert d.is_directory + assert d.user == 'root' + assert d.group == 'root' diff --git a/omero/roles/ome.omero_common/tasks/main.yml b/omero/roles/ome.omero_common/tasks/main.yml new file mode 100644 index 00000000..69da8c02 --- /dev/null +++ b/omero/roles/ome.omero_common/tasks/main.yml @@ -0,0 +1,21 @@ +--- +# tasks for omero-common + +- name: omero-common | create parent directory + become: true + file: + path: "{{ omero_common_basedir }}" + state: directory + mode: 0755 + +# This lets us make handlers conditional on existence of the service +- name: omero-common | check if services installed + stat: + path: "{{ item }}" + check_mode: false + register: _omero_common_services_installed + with_items: + # Order must match the indicies in handlers + - /etc/systemd/system/omero-server.service + - /etc/systemd/system/omero-web.service + - /usr/lib/systemd/system/nginx.service diff --git a/omero/roles/ome.omero_server/.github/workflows/molecule.yml b/omero/roles/ome.omero_server/.github/workflows/molecule.yml new file mode 100644 index 00000000..543b1e7f --- /dev/null +++ b/omero/roles/ome.omero_server/.github/workflows/molecule.yml @@ -0,0 +1,62 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Read the role name + id: role-name + run: | + name=$(grep 'role_name' meta/main.yml | sed -r 's/^[^:]*:(.*)$/\1/' | tr -d '[:space:]') # noqa + echo "rolename=$name" >> "$GITHUB_OUTPUT" + - name: Publish to Galaxy + uses: ome/action-ansible-galaxy-publish@main + with: + galaxy-api-key: ${{ secrets.GALAXY_API_KEY }} + galaxy-version: ${{ github.ref_name }} + role-name: ${{ steps.role-name.outputs.rolename }} diff --git a/omero/roles/ome.omero_server/.gitignore b/omero/roles/ome.omero_server/.gitignore new file mode 100644 index 00000000..dba1d4d9 --- /dev/null +++ b/omero/roles/ome.omero_server/.gitignore @@ -0,0 +1,3 @@ +.*~ +*.pyc +.molecule diff --git a/omero/roles/ome.omero_server/CHANGES.md b/omero/roles/ome.omero_server/CHANGES.md new file mode 100644 index 00000000..39f57c97 --- /dev/null +++ b/omero/roles/ome.omero_server/CHANGES.md @@ -0,0 +1,106 @@ +# Changes in Version 6 + +## Summary of breaking changes + +- Install self-signed certificates by default + +# Changes in Version 5 + +## Summary of breaking changes + +- Remove support for CentOS 7 and Ubuntu 20.04 +- Add support for RHEL/RockyLinux 9 and Ubuntu 202.04 + +# Changes in Version 4 + +## Summary of breaking changes + +- Python 2 support is now dropped +- `omero_server_python_requirements_ice_package` is now a nested dictionary + to support multiple versions per distribution + +## Removed variables + +- `omero_server_python3`: the role only installs the server with Python 3 +- `omero_server_virtualenv`: a virtual environment is created unconditionally +- `omero_server_systemd_require_network` + +# Changes in Version 3 + +## Summary of breaking changes +- Default to installing and running under Python 3.6. + Set `omero_server_python3: false` to use Python 2.7. +- The server always uses a virtualenv `/opt/omero/server/venv3` and does not include system-site-packages. + +## Removed variables +- `omero_server_ice_version`: This is now an internal variable and must always be `3.6`. + + +# Changes in Version 2 + +## Summary of breaking changes +- All variables are prefixed with `omero_server`. +- OMERO.web has been moved to an independent role `omero-web`, it is no longer setup by this role. +- The OMERO data directory creation logic is simplified. +- Some configuration variables and handlers have been moved to a dependent role `omero-common`. +- `omego` is in a dependent role. +- The `omero` system user is renamed `omero-server` and has a minimal home directory `/opt/omero/server`. +- The `omero` systemd service is renamed to `omero-server`. +- Systemd is setup by default. +- If you disable systemd setup OMERO.server is not automatically started. +- PostgreSQL server is not installed by this role (the clients are still installed). +- The database is not backed-up by default since you probably want the backup to go to a custom path (set `omero_server_database_backupdir`). +- Manual configuration changes are not copied when the server is upgraded. +- Configuration should be done using a conf.d style directory. +- This role requires Ansible 2.2. + +## Removed variables +- `omero_datadir_create`: OMERO data directories are always created and the top-level owner/group/permissions reset +- `omero_db_create`: A PostgreSQL database must be setup independently of this role +- `omero_omego_venv`: Replaced by `omero_server_omego` which is the path to the executable +- `omero_prestart_file`: Replaced by a config directory +- `omero_reinstall_on_error`: Never implemented +- `omero_selinux_setup`: Only used by the OMERO.web tasks +- `omero_serverdir`: Same as `omero_server_basedir` +- `omero_systemd_restart`: The systemd restart policy is now always `no` +- `omero_web_install`: OMERO.web is no longer managed by this role + +## Renamed variables +- `omero_basedir`: `omero_server_basedir` + +- `omero_database_backupdir`: `omero_server_database_backupdir` + +- `omero_datadir_managedrepo_mode`: `omero_server_datadir_managedrepo_mode` +- `omero_datadir`: `omero_server_datadir` +- `omero_datadir_chown`: `omero_server_datadir_chown` +- `omero_datadir_managedrepo`: `omero_server_datadir_managedrepo` +- `omero_datadir_mode`: `omero_server_datadir_mode` + +- `omero_dbhost`: `omero_server_dbhost` +- `omero_dbuser`: `omero_server_dbuser` +- `omero_dbname`: `omero_server_dbname` +- `omero_dbpassword`: `omero_server_dbpassword` + +- `omero_omego_additional_args`: `omero_server_omego_additional_args` +- `omero_omego_verbosity`: `omero_server_omego_verbosity` + +- `omero_release`: `omero_server_release` + +- `omero_rootpassword`: `omero_server_rootpassword` + +- `omero_system_uid`: `omero_server_system_uid` +- `omero_system_user`: `omero_server_system_user` +- `omero_system_umask`: `omero_server_system_umask` +- `omero_system_managedrepo_group`: `omero_server_system_managedrepo_group` + +- `omero_systemd_setup`: `omero_server_systemd_setup` +- `omero_server_limit_nofile`: `omero_server_systemd_limit_nofile` + +- `omero_server_config`: `omero_server_config_set` + +- `omero_upgrade`: `omero_server_upgrade` + + + +## Handlers +- Handlers that are intended to be used outside this role have been moved to the `omero-common` role so they can be used in other playbooks and roles without depending on this role. diff --git a/omero/roles/ome.omero_server/LICENSE.md b/omero/roles/ome.omero_server/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.omero_server/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.omero_server/README.md b/omero/roles/ome.omero_server/README.md new file mode 100644 index 00000000..bd682672 --- /dev/null +++ b/omero/roles/ome.omero_server/README.md @@ -0,0 +1,119 @@ +OMERO Server +============ + +[![Actions Status](https://github.com/ome/ansible-role-omero-server/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-omero-server/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-omero_server-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/omero_server/) + +Installs and configures OMERO.server. + +**Warning:** Only supports Python 3. +See [`CHANGES.md`](./CHANGES.md) for details. + + +Dependencies +------------ + +A PostgreSQL server is required. + + + +Role Variables +-------------- + +All variables are optional, see `defaults/main.yml` for the full list + +OMERO.server version. +- `omero_server_release`: The OMERO release, e.g. `5.6.0`. + The default is `present` which will install the latest server if no server is installed, but will not modify an existing server. + Use `latest` to automatically upgrade when a new version is released. + +Database connection parameters and initialisation. +- `omero_server_dbhost`: Database host +- `omero_server_dbuser`: Database user +- `omero_server_dbname`: Database name +- `omero_server_dbpassword`: Database password +- `omero_server_rootpassword`: OMERO root password, default `omero`. + This is only used when initialising a new database. + +OMERO.server configuration. +- `omero_server_config_set`: A dictionary of `config-key: value` which will be used for the initial OMERO.server configuration, default empty. + `value` can be a string, or an object (list, dictionary) that will be automatically converted to quoted JSON. + Note configuration can also be done pre/post installation using the `server/config` conf.d style directory. + +OMERO system user, group, permissions, and data directory. +You may need to change these for in-place imports. +- `omero_server_system_user`: OMERO.server system user, default `omero-server`. +- `omero_server_system_user_manage`: Create or update the OMERO.server system user if necessary, default `True`. +- `omero_server_system_uid`: OMERO system user ID (default automatic) +- `omero_server_system_umask`: OMERO system user umask, may need to be changed for in-place imports +- `omero_server_system_managedrepo_group`: OMERO system group for the `ManagedRepository` +- `omero_server_datadir_mode`: Permissions for OMERO data directories apart from `ManagedRepository` +- `omero_server_datadir_managedrepo_mode`: Permissions for OMERO `ManagedRepository` +- `omero_server_datadir`: OMERO data directory, default `/OMERO` +- `omero_server_datadir_managedrepo`: OMERO ManagedRepository directory +- `omero_server_selfsigned_certificates`: Generate self-signed certificates instead of using anonymous ciphers, default `True`, use this if your system does not support insecure ciphers + +OMERO.server systemd configuration. +- `omero_server_systemd_setup`: Create and start the `omero-server` systemd service, default `True` +- `omero_server_systemd_limit_nofile`: Systemd limit for number of open files (default ignore) +- `omero_server_systemd_after`: A list of strings with additional service names to appear in systemd unit file "After" statements. Default empty/none. +- `omero_server_systemd_requires`: A list of strings with additional service names to appear in systemd unit file "Requires" statements. Default empty/none. +- `omero_server_systemd_environment`: Dictionary of additional environment variables. + +Python virtualenv +- `omero_server_python_addons`: List of additional Python packages to be installed into virtualenv. + Alternatively you can install packages into `/opt/omero/server/venv3` independently from this role. + +Backups +- `omero_server_database_backupdir`: Dump the OMERO database to this directory before upgrading, default empty (disabled) + + +Configuring OMERO.server +------------------------ + +This role regenerates the OMERO configuration file using the configuration files and helper script in `/opt/omero/server/config`. +`omero_server_config_set` can be used for simple configurations, for anything more complex consider creating one or more configuration files under: `/opt/omero/server/config/` with the extension `.omero`. + +Manual configuration changes (`omero config ...`) will be lost following a restart of `omero-server` with systemd, you can disable this by setting `omero_server_always_reset_config: false`. +Manual configuration changes will never be copied during an upgrade. + +See https://github.com/ome/design/issues/70 for a proposal to add support for a conf.d style directory directly into OMERO. + + +Example Playbooks +----------------- + + # Install the latest release, including PostgreSQL on the same server + - hosts: localhost + roles: + + - role: ome.postgresql + postgresql_version: "13" + postgresql_databases: + - name: omero + owner: omero + postgresql_users: + - user: omero + password: omero + databases: [omero] + + - role: ome.omero_server + + + # Install or upgrade to a particular version, with an external database + - hosts: localhost + roles: + - ome.omero_server + omero_server_release: 5.6.0 + omero_server_dbhost: postgres.example.org + omero_server_dbuser: db_user + omero_server_dbname: db_name + omero_server_dbpassword: db_password + # Version required for the psql client + postgresql_version: "13" + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.omero_server/defaults/main.yml b/omero/roles/ome.omero_server/defaults/main.yml new file mode 100644 index 00000000..abc66e30 --- /dev/null +++ b/omero/roles/ome.omero_server/defaults/main.yml @@ -0,0 +1,195 @@ +--- +# defaults for omero-server + +omero_server_release: present + +# OMERO database connection parameters +omero_server_dbhost: localhost +omero_server_dbuser: omero +omero_server_dbname: omero +omero_server_dbpassword: omero + +# OMERO root password +omero_server_rootpassword: omero + +# Dictionary of additional OMERO configuration options +omero_server_config_set: {} + +# OMERO system user +omero_server_system_user: omero-server +omero_server_system_user_manage: true + +# OMERO system user ID (If not defined one is chosen automatically) +# omero_server_system_uid: + +# OMERO system user umask +omero_server_system_umask: "0002" + +# system group for the ManagedRepository +omero_server_system_managedrepo_group: omero + +# OMERO data directory +omero_server_datadir: /OMERO + +# OMERO ManagedRepository directory +omero_server_datadir_managedrepo: "{{ omero_server_datadir }}/ManagedRepository" + +# Permissions for OMERO data directories apart from ManagedRepository +omero_server_datadir_mode: "u=rwX,g=rX,o=rX" + +# Permissions for OMERO ManagedRepository +omero_server_datadir_managedrepo_mode: "u=rwX,g=srwX,o=rX" + +# Setup systemd services +omero_server_systemd_setup: true + +# Change the systemd limit for number of open files (default ignore) +omero_server_systemd_limit_nofile: + + +# Services which OMERO server needs to be running before it can start, +# such as remote storage. +omero_server_systemd_after: [] + +# Services which OMERO server needs to be concurrently running. +omero_server_systemd_requires: [] + +# Dictionary of additional environment variables +omero_server_systemd_environment: {} + +# List of additional Python packages to be installed into virtualenv +omero_server_python_addons: [] + +# If non-empty dump the OMERO database to this directory before upgrading +omero_server_database_backupdir: "" + +# If true disable anonymous ciphers and use self-signed certificates +omero_server_selfsigned_certificates: true + + +###################################################################### +# Expert users only! +###################################################################### + +omero_server_ice_version: "3.6" + +omero_server_python_requirements_ice_package: + RedHat: + 9: "https://github.com/glencoesoftware/zeroc-ice-py-rhel9-x86_64/releases/download/\ + 20230830/zeroc_ice-3.6.5-cp39-cp39-linux_x86_64.whl" + Debian: + 22: "https://github.com/glencoesoftware/zeroc-ice-py-ubuntu2204-x86_64/releases/download/\ + 20221004/zeroc_ice-3.6.5-cp310-cp310-linux_x86_64.whl" + + +# TODO: sort this out +# ? pip install omero-server-dependencies=={{omero_server_release}} +# ? get_url https://downloads.openmicroscopy.org/omero/ +# {{omero_server_release}}/artifacts/ +# OMERO.server-{{omero_server_release}}.requirements.txt +# List of Python3 packages to install +# _omero_* are temporary overrides pending a final release +# Can't leave this unset because pip won't install the Python 3 pre-releases +_omero_py_version: '>=5.6.0' +_omero_dropbox_version: '>=5.6.1' +omero_server_python_requirements: + - omego==0.7.0 + # TODO: make the use of our non-standard wheel optional + - "{{ omero_server_python_requirements_ice_package[ansible_os_family][ + ansible_distribution_major_version | int ] | + default('zeroc-ice')}}" + - "omero-py{{ _omero_py_version | default('') }}" + - "omero-dropbox{{ _omero_dropbox_version | default('') }}" + # TODO: keep or ditch ipython? It's a big dependency and mostly useful for + # clients + # - ipython + - jinja2 + # Includes optional dependencies: always installed but activation may be + # optional + - omero-server + +# Path to virtualenv +omero_server_virtualenv_basedir: "{{ omero_server_basedir + '/venv3' }}" + +# OMERODIR +omero_server_omerodir: "{{ omero_server_basedir }}/{{ omero_server_symlink }}" + +# How to run omero +omero_server_omero_command: "{{ omero_server_omerodir }}/bin/omero" + +# Config update command +omero_server_config_update: >- + {{ + omero_server_omero_command + ' load --glob ' + omero_server_basedir + + '/config/*.omero' + }} + +# Need to set OMERODIR when omego runs omero +omero_server_omego_environment: "{{ {'OMERODIR': omero_server_omerodir} }}" + +# Recursively set the owner on the OMERO data directory, use if the directory +# has been copied with an incorrect owner +omero_server_datadir_chown: false + +# OMERO BioFormatsCache directory +omero_server_datadir_bioformatscache: >- + {{ omero_server_datadir }}/BioFormatsCache + +# DEVELOPMENT: If True clear the existing configuration before regenerating +omero_server_always_reset_config: true + +# DEVELOPMENT: Automatically start systemd omero +omero_server_systemd_start: true + +# DEVELOPMENT: Automatically init/upgrade and configure the OMERO database +omero_server_database_manage: true + +# DEVELOPMENT: Automatically create and configure OMERO data directories +omero_server_datadir_manage: true + +# Base directory for the server installation +omero_server_basedir: "{{ omero_common_basedir }}/server" + +# Symlink to the currently installed OMERO.server +omero_server_symlink: OMERO.server + +# Path of omego +omero_server_omego: "{{ omero_server_virtualenv_basedir + '/bin/omego' }}" + +# Control verbosity of omego +omero_server_omego_verbosity: "-qq" + +# Additional omego aguments passed to upgrade or install +omero_server_omego_additional_args: "" + +# If True and server is already installed then upgrade to the version in +# omero_server_release, otherwise don't upgrade an existing server. +# This should not be needed if version are correctly compared. +omero_server_upgrade: true + +# DEVELOPMENT: Operator for comparing current-version against +# omero_server_release, e.g. '!='. Default is to upgrade when +# current-version < omero_server_release +omero_server_checkupgrade_comparator: '<' + + +# _omero_server_new_version is set in tasks/omero-install.yml +# We can't just use omero_server_release because if it is "present" +# it needs to be substituted with a value that omego will accept +omero_server_omego_options: > + --release {{ _omero_server_new_version }} + --sym {{ omero_server_symlink }} + --ice {{ omero_server_ice_version }} + --no-start + --no-web + --ignoreconfig + --omerocli {{ omero_server_virtualenv_basedir + '/bin/omero' }} + {{ omero_server_omego_verbosity }} + {{ omero_server_omego_additional_args }} + +omero_server_omego_db_options: > + --dbhost {{ omero_server_dbhost | quote }} + --dbuser {{ omero_server_dbuser | quote }} + --dbname {{ omero_server_dbname | quote }} + --dbpass {{ omero_server_dbpassword | quote }} + {{ omero_server_database_manage | ternary('--managedb', '') }} diff --git a/omero/roles/ome.omero_server/handlers/main.yml b/omero/roles/ome.omero_server/handlers/main.yml new file mode 100644 index 00000000..e740b169 --- /dev/null +++ b/omero/roles/ome.omero_server/handlers/main.yml @@ -0,0 +1,17 @@ +--- +# handlers for omero-server +# Don't use omero-common handlers because systemd might be disabled. +# This also avoids problems with ordering of handlers: +# http://stackoverflow.com/a/35130254 + +- name: omero-server rewrite omero-server configuration + become: true + become_user: "{{ omero_server_system_user }}" + command: "{{ omero_server_config_update }}" + +- name: omero-server restart omero-server + become: true + service: + name: omero-server + state: restarted + when: omero_server_systemd_setup and omero_server_systemd_start diff --git a/omero/roles/ome.omero_server/meta/.galaxy_install_info b/omero/roles/ome.omero_server/meta/.galaxy_install_info new file mode 100644 index 00000000..cd303ee8 --- /dev/null +++ b/omero/roles/ome.omero_server/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:48 2024 +version: 6.1.0 diff --git a/omero/roles/ome.omero_server/meta/main.yml b/omero/roles/ome.omero_server/meta/main.yml new file mode 100644 index 00000000..a490e5d2 --- /dev/null +++ b/omero/roles/ome.omero_server/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Install and configure OMERO.server, and optionally PostgreSQL + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + role_name: omero_server + galaxy_tags: ['omero', 'server'] diff --git a/omero/roles/ome.omero_server/meta/requirements.yml b/omero/roles/ome.omero_server/meta/requirements.yml new file mode 100644 index 00000000..233eba49 --- /dev/null +++ b/omero/roles/ome.omero_server/meta/requirements.yml @@ -0,0 +1,7 @@ +--- +- src: ome.omero_common +- src: ome.basedeps +- src: ome.java +- src: ome.python3_virtualenv +- src: ome.ice +- src: ome.postgresql_client diff --git a/omero/roles/ome.omero_server/molecule/resources/playbook.yml b/omero/roles/ome.omero_server/molecule/resources/playbook.yml new file mode 100644 index 00000000..c50ea741 --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/resources/playbook.yml @@ -0,0 +1,61 @@ +--- + +- name: Converge + hosts: all + + roles: + + - role: ome.postgresql + postgresql_databases: + - name: omero + owner: omero + postgresql_users: + - user: omero + password: omero + databases: [omero] + + - role: ansible-role-omero-server + omero_server_system_managedrepo_group: importer + omero_server_config_set: + Ice.IPv6: "0" + omero.client.ui.tree.type_order: + - screen + - plate + - project + - dataset + omero_server_release: latest + omero_server_python_addons: + - omero-upload + + tasks: + + - name: additional config file + copy: + content: > + config set omero.policy.binary_access -- "-read,-write,-image,-plate" + dest: /opt/omero/server/config/molecule-additional-config.omero + mode: 0644 + notify: + - restart omero-server + + +- name: Additional tasks for setting up tests + hosts: all + tasks: + + - name: create import user + user: + name: data-importer + group: importer + + - name: create data directory + file: + path: /data/import + state: directory + mode: 0755 + + - name: create fake image + copy: + content: '' + dest: /data/import/test.fake + mode: 0644 diff --git a/omero/roles/ome.omero_server/molecule/resources/requirements.yml b/omero/roles/ome.omero_server/molecule/resources/requirements.yml new file mode 100644 index 00000000..2643cc7a --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/resources/requirements.yml @@ -0,0 +1,8 @@ +--- +- src: ome.omero_common +- src: ome.basedeps +- src: ome.java +- src: ome.python3_virtualenv +- src: ome.ice +- src: ome.postgresql +- src: ome.postgresql_client diff --git a/omero/roles/ome.omero_server/molecule/resources/tests/test_default.py b/omero/roles/ome.omero_server/molecule/resources/tests/test_default.py new file mode 100644 index 00000000..b1a5507c --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/resources/tests/test_default.py @@ -0,0 +1,76 @@ +import os +import pytest +import testinfra.utils.ansible_runner +from time import time + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + +# Ubuntu sudo doesn't set HOME so it tries to write to /root +ENV = 'OMERO_USERDIR=/home/data-importer/omero-{}'.format(time()) +OMERO = '/opt/omero/server/OMERO.server/bin/omero' +OMERO_LOGIN = '-C -s localhost -u root -w omero' + + +def test_service_running_and_enabled(host): + assert host.service('omero-server').is_running + assert host.service('omero-server').is_enabled + + +def test_omero_root_login(host): + with host.sudo('data-importer'): + host.check_output('%s %s login %s' % (ENV, OMERO, OMERO_LOGIN)) + + +@pytest.mark.parametrize("key,value", [ + ('omero.data.dir', '/OMERO'), + ('omero.client.ui.tree.type_order', + '["screen", "plate", "project", "dataset"]'), + ('omero.policy.binary_access', '-read,-write,-image,-plate'), +]) +def test_omero_server_config(host, key, value): + with host.sudo('omero-server'): + cfg = host.check_output('%s %s config get %s' % (ENV, OMERO, key)) + assert cfg == value + + +def test_omero_datadir(host): + d = host.file('/OMERO') + assert d.is_directory + assert d.user == 'omero-server' + assert d.group == 'root' + assert d.mode == 0o755 + + +def test_omero_managedrepo(host): + d = host.file('/OMERO/ManagedRepository') + assert d.is_directory + assert d.user == 'omero-server' + assert d.group == 'importer' + assert d.mode == 0o2775 + + +def test_inplace_import(host): + fake_file = '/data/import/test.fake' + with host.sudo('data-importer'): + outimport = host.check_output( + '%s %s %s import --skip=upgrade --transfer=ln_s %s' % + (ENV, OMERO, OMERO_LOGIN, fake_file)) + + imageid = int(outimport.split(':', 1)[1]) + assert imageid + + query = ('SELECT concat(ofile.path, ofile.name) ' + 'FROM FilesetEntry AS fse ' + 'JOIN fse.fileset AS fileset ' + 'JOIN fse.originalFile AS ofile ' + 'JOIN fileset.images AS image ' + 'WHERE image.id = %d' % imageid) + with host.sudo('data-importer'): + outhql = host.check_output( + '%s %s %s hql -q --style plain "%s"' % + (ENV, OMERO, OMERO_LOGIN, query)) + + f = host.file('/OMERO/ManagedRepository/%s' % outhql.split(',', 1)[1]) + assert f.is_symlink + assert f.linked_to == fake_file diff --git a/omero/roles/ome.omero_server/molecule/resources/tests/test_python3.py b/omero/roles/ome.omero_server/molecule/resources/tests/test_python3.py new file mode 100644 index 00000000..9019c43c --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/resources/tests/test_python3.py @@ -0,0 +1,50 @@ +import os +import re +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('omero-py3') + +OMERO = '/opt/omero/server/OMERO.server/bin/omero' +# Need to match 5.6.dev2 +# VERSION_PATTERN = re.compile('(\d+)\.(\d+)\.(\d+)-ice36-') +VERSION_PATTERN = re.compile(r'(\d+)\.(\d+)\.(\w+)') + + +def test_omero_version(host): + with host.sudo('data-importer'): + ver = host.check_output("%s version" % OMERO) + m = VERSION_PATTERN.match(ver) + assert m is not None + assert int(m.group(1)) >= 5 + assert int(m.group(2)) >= 6 + + +def test_postgres_version(host): + ver = host.check_output("psql --version") + assert ver.startswith('psql (PostgreSQL) 13') + + +def test_additional_python(host): + piplist = host.check_output("/opt/omero/server/venv3/bin/pip list") + assert "omero-upload" in piplist + + +def test_running_in_venv(host): + # host.process may use `ps -Aww -o ...` which truncates some fields + # https://github.com/philpep/testinfra/blob/3.2.0/testinfra/modules/process.py#L127-L148 + count = 0 + for line in host.check_output('ps -Aww -o pid,comm,user').splitlines()[1:]: + pid, command, user = line.split() + if command == 'python' and user == 'omero-server': + try: + f = host.file('/proc/%s/environ' % pid) + env = dict(item.split('=', 1) for item in + f.content_string.split('\0') if item) + assert env.get('PATH').startswith( + '/opt/omero/server/venv3/bin:') + count += 1 + except RuntimeError: + # Might be a transient unrelated process + pass + assert count > 1 diff --git a/omero/roles/ome.omero_server/molecule/resources/upgrade-omero.yml b/omero/roles/ome.omero_server/molecule/resources/upgrade-omero.yml new file mode 100644 index 00000000..135a1996 --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/resources/upgrade-omero.yml @@ -0,0 +1,53 @@ +--- +# omero_server_release is defined in molecule.yml host_vars so: +# - omero-server-newdep: latest: upgraded +# - omero-server-olddep: present: unchanged at 5.2 +- name: Upgrade OMERO if required + hosts: all + roles: + + - role: ansible-role-omero-server + omero_server_system_managedrepo_group: importer + omero_server_config_set: + Ice.IPv6: "0" + omero.client.ui.tree.type_order: + - screen + - plate + - project + - dataset + omero_server_python3: false + + +- name: Additional tasks for setting up tests + hosts: all + tasks: + + - name: create import user + user: + name: data-importer + group: importer + + - name: create data directory + file: + path: /data/import + state: directory + mode: 0755 + + - name: create fake image + copy: + content: '' + dest: /data/import/test.fake + mode: 0644 + + +# testinfra Sudo doesn't use the `-i` flag, so the working directory needs +# to be accessible +- hosts: vagrant-hosts + tasks: + - name: make vagrant home accessible + file: + owner: vagrant + group: vagrant + mode: "0711" + path: /home/vagrant + state: directory diff --git a/omero/roles/ome.omero_server/molecule/rockylinux9/molecule.yml b/omero/roles/ome.omero_server/molecule/rockylinux9/molecule.yml new file mode 100644 index 00000000..6ff2efd0 --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/rockylinux9/molecule.yml @@ -0,0 +1,50 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: omero-server-rockylinux9 + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - docker-hosts + - omero-py3 +provisioner: + name: ansible + lint: + name: ansible-lint + # To test the upgrade process without breaking the idempotence check + # - install omero during the prepare step which is only run once + # - attempt to upgrade in the converge step + options: + v: true + diff: true + # tags: [x] + playbooks: + # TODO: Use shared test playbooks + converge: ../resources/playbook.yml + inventory: + host_vars: + omero-server-rockylinux9: + postgresql_version: "13" + omero_server_selfsigned_certificates: true +scenario: + name: rockylinux9 + converge_sequence: + - converge + +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.omero_server/molecule/rockylinux9/prepare.yml b/omero/roles/ome.omero_server/molecule/rockylinux9/prepare.yml new file mode 100644 index 00000000..dc498ace --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/rockylinux9/prepare.yml @@ -0,0 +1,12 @@ +--- + +- name: Prepare all + hosts: all + tasks: + - name: Upgrade ca-certificates + ansible.builtin.dnf: + update_cache: true + pkg: + - ca-certificates + - procps + state: latest diff --git a/omero/roles/ome.omero_server/molecule/ubuntu2204/molecule.yml b/omero/roles/ome.omero_server/molecule/ubuntu2204/molecule.yml new file mode 100644 index 00000000..80cefd79 --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/ubuntu2204/molecule.yml @@ -0,0 +1,50 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: omero-server-ubuntu2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - docker-hosts + - omero-py3 +provisioner: + name: ansible + lint: + name: ansible-lint + # To test the upgrade process without breaking the idempotence check + # - install omero during the prepare step which is only run once + # - attempt to upgrade in the converge step + options: + v: true + diff: true + # tags: [x] + playbooks: + # TODO: Use shared test playbooks + converge: ../resources/playbook.yml + inventory: + host_vars: + omero-server-ubuntu2204: + postgresql_version: "13" + ansible_python_interpreter: /usr/bin/python3 + omero_server_selfsigned_certificates: true +scenario: + name: ubuntu2204 + converge_sequence: + - converge + +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.omero_server/molecule/ubuntu2204/prepare.yml b/omero/roles/ome.omero_server/molecule/ubuntu2204/prepare.yml new file mode 100644 index 00000000..6397a7f0 --- /dev/null +++ b/omero/roles/ome.omero_server/molecule/ubuntu2204/prepare.yml @@ -0,0 +1,7 @@ +--- + +- name: Prepare all + hosts: all + tasks: + - ansible.builtin.apt: + update_cache: true diff --git a/omero/roles/ome.omero_server/tasks/main.yml b/omero/roles/ome.omero_server/tasks/main.yml new file mode 100644 index 00000000..c32c8d09 --- /dev/null +++ b/omero/roles/ome.omero_server/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks for omero-server + +- include: pre-tasks.yml + +- include: omero-user.yml + +- include: omero-datadir.yml + when: omero_server_datadir_manage + +- include: omero-configfiles.yml + +- include: omero-install.yml + +- include: omero-systemd.yml + when: omero_server_systemd_setup diff --git a/omero/roles/ome.omero_server/tasks/omero-configfiles.yml b/omero/roles/ome.omero_server/tasks/omero-configfiles.yml new file mode 100644 index 00000000..da226fe2 --- /dev/null +++ b/omero/roles/ome.omero_server/tasks/omero-configfiles.yml @@ -0,0 +1,19 @@ +--- +# OMERO template configuration files + +- name: omero server | remove old configuration script + become: true + file: + path: "{{ omero_server_basedir }}/config/omero-server-config-update.sh" + state: absent + +- name: omero server | configuration 00-omero-server.omero + become: true + template: + dest: "{{ omero_server_basedir }}/config/00-omero-server.omero" + force: true + src: 00-omero-server-omero.j2 + mode: 0644 + notify: + - omero-server rewrite omero-server configuration + - omero-server restart omero-server diff --git a/omero/roles/ome.omero_server/tasks/omero-datadir.yml b/omero/roles/ome.omero_server/tasks/omero-datadir.yml new file mode 100644 index 00000000..25f5a191 --- /dev/null +++ b/omero/roles/ome.omero_server/tasks/omero-datadir.yml @@ -0,0 +1,56 @@ +--- +# OMERO data directories + +- name: omero server | create omero datadir base directory + become: true + file: + owner: "{{ omero_server_system_user }}" + mode: "{{ omero_server_datadir_mode }}" + path: "{{ omero_server_datadir }}" + recurse: false + state: directory + +- name: omero server | create omero datadir subdirectories + become: true + file: + owner: "{{ omero_server_system_user }}" + mode: "{{ omero_server_datadir_mode }}" + path: "{{ omero_server_datadir }}/{{ item }}" + recurse: "{{ omero_server_datadir_chown }}" + state: directory + with_items: + - Files + - Thumbnails + - DropBox + - FullText + - Pixels + +- name: omero server | create omero BioFormatsCache + become: true + file: + owner: "{{ omero_server_system_user }}" + mode: "{{ omero_server_datadir_mode }}" + path: "{{ omero_server_datadir_bioformatscache }}" + recurse: "{{ omero_server_datadir_chown }}" + state: directory + +- name: omero server | create omero BioFormatsCache symlink + become: true + file: + src: "{{ omero_server_datadir_bioformatscache }}" + path: "{{ omero_server_datadir }}/BioFormatsCache" + state: link + force: true + when: >- + omero_server_datadir_bioformatscache != + (omero_server_datadir + "/BioFormatsCache") + +- name: omero server | create omero ManagedRepository + become: true + file: + owner: "{{ omero_server_system_user }}" + group: "{{ omero_server_system_managedrepo_group }}" + mode: "{{ omero_server_datadir_managedrepo_mode }}" + path: "{{ omero_server_datadir_managedrepo }}" + recurse: "{{ omero_server_datadir_chown }}" + state: directory diff --git a/omero/roles/ome.omero_server/tasks/omero-install.yml b/omero/roles/ome.omero_server/tasks/omero-install.yml new file mode 100644 index 00000000..f31d29cf --- /dev/null +++ b/omero/roles/ome.omero_server/tasks/omero-install.yml @@ -0,0 +1,248 @@ +--- +# install/upgrade OMERO.server + +- name: omero server | is server symlink present + become: true + stat: + path: "{{ omero_server_basedir }}/{{ omero_server_symlink }}" + register: omero_server_symlink_st + +- name: omero server | is virtualenv present + become: true + stat: + path: "{{ omero_server_virtualenv_basedir }}" + register: omero_server_venv_st + +# Is there an existing OMERO.server that uses the requested virtualenv? +- name: omero server | does omero server match requested virtualenv + set_fact: + _omero_server_matches_virtualenv: >- + {{ + omero_server_symlink_st.stat.exists and + omero_server_venv_st.stat.exists + }} + +# Previously this used the output of 'omero version' +# Python modules are now decoupled so get the version from the folder name +- name: omero server | get server version + set_fact: + omero_server_version: >- + {{ + omero_server_symlink_st.stat.lnk_target | basename | + regex_replace('OMERO.server-(.+)-ice3.+', '\1') + }} + when: _omero_server_matches_virtualenv + +- name: omero server | check omero version could be obtained + assert: + msg: >- + OMERO.server found but unable to get version, + you may have a corrupt installation + that: >- + not _omero_server_matches_virtualenv or + (omero_server_version | default('') | length > 0) + +# TODO: If server was started by systemd but stopped directly you may end up +# with a hanging process + +# Check whether an upgrade is available since `omego upgrade` always +# restarts the server +- name: omero server | get latest downloads url + uri: + url: https://downloads.openmicroscopy.org/latest/omero + method: HEAD + register: _omero_server_downloads_latest + check_mode: false + +# omego supports --release "latest" but not "present" +# It's easiest to lookup a concrete version and use this for all omego +# operations instead +- name: omero server | get latest version + set_fact: + _omero_server_new_version: "{{ + (omero_server_release in ('latest', 'present')) | ternary( + _omero_server_downloads_latest.url.strip('/').split('/')[-1], + omero_server_release + ) + }}" + +- block: + - name: omero server | checkupgrade + set_fact: + # If _omero_server_new_version does not begin with a number assume + # it's a custom build, always upgrade + # If we're switching from a non-venv to a venv treat it as an upgrade + _omero_server_update_needed: >- + {{ + not _omero_server_matches_virtualenv or + not (_omero_server_new_version | regex_search('^[0-9]')) or + ( + (omero_server_version | default('') | length > 0) and + (omero_server_version != _omero_server_new_version) and + (omero_server_version is version( + _omero_server_new_version, + omero_server_checkupgrade_comparator)) + ) + }} + rescue: + # For example, comparing 5.6.dev2 with 5.6.0-m1 leads to + # '<' not supported between instances of 'str' and 'int' + # Assume this is a dev or pre-release and upgrade + # Ansible will exit 0 but show a failed task in the summary + + - debug: + msg: >- + Error comparing current version + ({{ omero_server_version | default('') }}) + and new version + ({{ _omero_server_new_version }}), upgrading + + - name: omero server | checkupgrade failed + set_fact: + _omero_server_update_needed: true + +- debug: + msg: >- + Upgrade needed: {{ omero_server_version | default('UNKNOWN') }} -> + {{ omero_server_release }} + when: _omero_server_update_needed + +# If the OMERO.server symlink doesn't exist don't upgrade, this is a new +# installation +- name: omero server | set upgrade flag + set_fact: + _omero_server_execute_upgrade: "{{ + omero_server_upgrade and + _omero_server_update_needed and + (omero_server_release != 'present') and + omero_server_symlink_st.stat.exists + }}" + + +# TODO: figure out dependencies +- name: omero server | setup virtualenv3 + become: true + pip: + name: "pip>=21" + state: present + virtualenv: "{{ omero_server_virtualenv_basedir }}" + virtualenv_command: /usr/local/bin/ome-python3-virtualenv + +- name: omero server | install requirements + become: true + pip: + name: "{{ omero_server_python_requirements + omero_server_python_addons }}" + state: present + virtualenv: "{{ omero_server_virtualenv_basedir }}" + virtualenv_command: /usr/local/bin/ome-python3-virtualenv + notify: + - omero-server rewrite omero-server configuration + - omero-server restart omero-server + +- name: omero server | install omero + become: true + become_user: "{{ omero_server_system_user }}" + command: > + {{ omero_server_omego }} + install + {{ omero_server_omego_options }} + {{ omero_server_omego_db_options }} + --rootpass {{ omero_server_rootpassword | quote }} + args: + chdir: "{{ omero_server_basedir }}" + creates: "{{ omero_server_basedir }}/{{ omero_server_symlink }}" + environment: "{{ omero_server_omego_environment }}" + notify: + - omero-server rewrite omero-server configuration + - omero-server restart omero-server + +# Backup database + +- name: omero server | create omero backup directory + become: true + file: + mode: 0700 + owner: "{{ omero_server_system_user }}" + path: "{{ omero_server_database_backupdir }}" + state: directory + when: >- + (omero_server_database_backupdir | length > 0) and + _omero_server_execute_upgrade + +- name: omero server | backup database + become: true + become_user: "{{ omero_server_system_user }}" + command: > + {{ omero_server_omego }} + db dump + {{ omero_server_omego_db_options }} + --serverdir {{ omero_server_basedir }}/{{ omero_server_symlink }} + args: + chdir: "{{ omero_server_database_backupdir }}" + environment: "{{ omero_server_omego_environment }}" + when: >- + (omero_server_database_backupdir | length > 0) and + _omero_server_execute_upgrade + +# Upgrade +- name: omero server | upgrade + become: true + become_user: "{{ omero_server_system_user }}" + command: > + {{ omero_server_omego }} + install --upgrade + {{ omero_server_omego_options }} + {{ omero_server_omego_db_options }} + args: + chdir: "{{ omero_server_basedir }}" + environment: "{{ omero_server_omego_environment }}" + when: _omero_server_execute_upgrade + notify: + - omero-server rewrite omero-server configuration + - omero-server restart omero-server + +- name: omero server | delete OMERO.server/lib/python + become: true + file: + path: "{{ omero_server_omerodir }}/lib/python" + state: absent + +# Remembering to set OMERODIR everywhere is prone to error +- name: omero server | create bin directory for wrapper + become: true + file: + path: "{{ omero_server_omerodir }}/bin/" + state: directory + mode: 0555 + +- name: omero server | create omero server wrapper + become: true + template: + dest: "{{ omero_server_omero_command }}" + src: bin-omero.j2 + mode: 0555 + notify: + - omero-server rewrite omero-server configuration + - omero-server restart omero-server + +- name: system packages | install openssl + become: true + package: + name: openssl + state: present + +- name: server package | install redhat blosc + become: true + ansible.builtin.dnf: + update_cache: true + name: blosc + state: present + when: ansible_os_family | lower == 'redhat' + +- name: server package | install debian blosc + become: true + ansible.builtin.apt: + update_cache: true + name: libblosc1 + state: present + when: ansible_os_family | lower == 'debian' diff --git a/omero/roles/ome.omero_server/tasks/omero-systemd.yml b/omero/roles/ome.omero_server/tasks/omero-systemd.yml new file mode 100644 index 00000000..a3e0977e --- /dev/null +++ b/omero/roles/ome.omero_server/tasks/omero-systemd.yml @@ -0,0 +1,25 @@ +--- +# Setup systemd files + +- name: omero server | systemd service + become: true + template: + dest: /etc/systemd/system/omero-server.service + force: true + src: systemd-system-omero-server-service.j2 + mode: 0644 + notify: + - reload systemd + - omero-server restart omero-server + +# Flush handlers to ensure systemd is reloaded +- name: omero server | flush systemd handlers + meta: flush_handlers + +- name: omero server | enable and start server systemd + become: true + service: + enabled: true + name: omero-server.service + state: started + when: omero_server_systemd_start diff --git a/omero/roles/ome.omero_server/tasks/omero-user.yml b/omero/roles/ome.omero_server/tasks/omero-user.yml new file mode 100644 index 00000000..9f87f332 --- /dev/null +++ b/omero/roles/ome.omero_server/tasks/omero-user.yml @@ -0,0 +1,31 @@ +--- +# omero system user + +- name: omero server | create system user + become: true + user: + name: "{{ omero_server_system_user }}" + home: "{{ omero_server_basedir }}" + createhome: false + state: present + system: true + uid: "{{ omero_server_system_uid | default(omit) }}" + when: omero_server_system_user_manage + +# TODO: Ideally everything should be read-only apart from the var directory +- name: omero server | create omero directories + become: true + file: + path: "{{ item }}" + state: directory + owner: "{{ omero_server_system_user }}" + mode: 0755 + with_items: + - "{{ omero_server_basedir }}" + - "{{ omero_server_basedir }}/config" + +- name: omero server | create managedrepo system group + become: true + group: + name: "{{ omero_server_system_managedrepo_group }}" + state: present diff --git a/omero/roles/ome.omero_server/tasks/pre-tasks.yml b/omero/roles/ome.omero_server/tasks/pre-tasks.yml new file mode 100644 index 00000000..0011741d --- /dev/null +++ b/omero/roles/ome.omero_server/tasks/pre-tasks.yml @@ -0,0 +1,30 @@ +--- +# omero_common must be imported to prevent +# undeclared variable failure +- name: omero server | Import ome.omero_common role + import_role: + name: ome.omero_common + +- name: omero server | Include ome.basedeps role + include_role: + name: ome.basedeps + +- name: omero server | Include ome.java + include_role: + name: ome.java + +- name: omero server | Include ome.python3_virtualenv + include_role: + name: ome.python3_virtualenv + +- name: omero server | Include ome.ice role + include_role: + name: ome.ice + vars: + ice_version: "{{ omero_server_ice_version }}" + ice_install_devel: false + ice_install_python: false + +- name: omero server | Include ome.postgresql_client + include_role: + name: ome.postgresql_client diff --git a/omero/roles/ome.omero_server/templates/00-omero-server-omero.j2 b/omero/roles/ome.omero_server/templates/00-omero-server-omero.j2 new file mode 100644 index 00000000..60970e5d --- /dev/null +++ b/omero/roles/ome.omero_server/templates/00-omero-server-omero.j2 @@ -0,0 +1,29 @@ +# {{ ansible_managed }} + +{% if omero_server_always_reset_config %} +config drop default +{% endif %} + +{% if omero_server_database_manage %} +config set omero.db.host {{ omero_server_dbhost | quote }} +config set omero.db.user {{ omero_server_dbuser | quote }} +config set omero.db.name {{ omero_server_dbname | quote }} +config set omero.db.pass {{ omero_server_dbpassword | quote }} +{% endif %} + +{% if omero_server_datadir_manage %} +config set omero.data.dir {{ omero_server_datadir | quote }} +{% endif %} + +# Additional custom options +{% for key in (omero_server_config_set | sort) %} +config set -- {{ key | quote }} {{ + ((omero_server_config_set[key] | string) == omero_server_config_set[key]) | + ternary(omero_server_config_set[key], omero_server_config_set[key] | to_json) | + quote +}} +{% endfor %} + +{% if omero_server_selfsigned_certificates %} +certificates -v +{% endif %} diff --git a/omero/roles/ome.omero_server/templates/bin-omero.j2 b/omero/roles/ome.omero_server/templates/bin-omero.j2 new file mode 100644 index 00000000..91bf2dfa --- /dev/null +++ b/omero/roles/ome.omero_server/templates/bin-omero.j2 @@ -0,0 +1,22 @@ +#!{{ omero_server_virtualenv_basedir }}/bin/python + +import os +from subprocess import run +import sys + +if not os.getenv('OMERODIR'): + os.environ['OMERODIR'] = '{{ omero_server_omerodir }}' + +paths = os.getenv('PATH', '').split(os.pathsep) +venv_bin = '{{ omero_server_virtualenv_basedir }}/bin' +ice_bin = '/opt/ice/bin' + +if os.path.isdir(ice_bin) and ice_bin not in paths: + paths.insert(0, ice_bin) +if venv_bin not in paths: + paths.insert(0, venv_bin) + +os.environ['PATH'] = os.pathsep.join(paths) + +p = run(['{{ omero_server_virtualenv_basedir }}/bin/omero'] + sys.argv[1:]) +sys.exit(p.returncode) diff --git a/omero/roles/ome.omero_server/templates/omero-server-config-update-sh.j2 b/omero/roles/ome.omero_server/templates/omero-server-config-update-sh.j2 new file mode 100644 index 00000000..85fba976 --- /dev/null +++ b/omero/roles/ome.omero_server/templates/omero-server-config-update-sh.j2 @@ -0,0 +1,9 @@ +#!/bin/sh +# {{ ansible_managed }} +# Regenerate the omero-server configuration: + +set -e + +for f in {{ omero_server_basedir }}/config/*.omero; do + {{ omero_server_omero_command }} load "$f" +done diff --git a/omero/roles/ome.omero_server/templates/systemd-system-omero-server-service.j2 b/omero/roles/ome.omero_server/templates/systemd-system-omero-server-service.j2 new file mode 100644 index 00000000..78e49b52 --- /dev/null +++ b/omero/roles/ome.omero_server/templates/systemd-system-omero-server-service.j2 @@ -0,0 +1,36 @@ +[Unit] +Description=OMERO.server +# Requires: forces the dependency to be started +# After: ensures this service starts after the dependency, but only if the +# dependency is also started (PostgreSQL may be on a different server) +After=postgresql-11.service +After=postgresql-12.service +After=postgresql-13.service +After=postgresql-14.service +After=network.service +{% for value in omero_server_systemd_after %}After={{ value }} +{% endfor %} +{% for value in omero_server_systemd_requires %}Requires={{ value }} +{% endfor %} + +[Service] +User={{ omero_server_system_user }} +UMask={{ omero_server_system_umask }} +Type=forking +PIDFile={{ omero_server_omerodir }}/var/master/master.pid +Restart=no +RestartSec=10 +# Allow up to 5 min for start/stop +TimeoutSec=300 +{% for name in (omero_server_systemd_environment | sort) %} +Environment={{ name }}={{ omero_server_systemd_environment[name] | quote }} +{% endfor %} +ExecStartPre={{ omero_server_config_update }} +ExecStart={{ omero_server_omero_command }} admin start +ExecStop={{ omero_server_omero_command }} admin stop +{% if omero_server_systemd_limit_nofile %} +LimitNOFILE={{ omero_server_systemd_limit_nofile }} +{% endif %} + +[Install] +WantedBy=multi-user.target diff --git a/omero/roles/ome.omero_user/.github/workflows/molecule.yml b/omero/roles/ome.omero_user/.github/workflows/molecule.yml new file mode 100644 index 00000000..ed869c6f --- /dev/null +++ b/omero/roles/ome.omero_user/.github/workflows/molecule.yml @@ -0,0 +1,62 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-20.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Read the role name + id: role-name + run: | + name=$(grep 'role_name' meta/main.yml | sed -r 's/^[^:]*:(.*)$/\1/' | tr -d '[:space:]') + echo "rolename=$name" >> "$GITHUB_OUTPUT" + - name: Publish to Galaxy + uses: ome/action-ansible-galaxy-publish@main + with: + galaxy-api-key: ${{ secrets.GALAXY_API_KEY }} + galaxy-version: ${{ github.ref_name }} + role-name: ${{ steps.role-name.outputs.rolename }} diff --git a/omero/roles/ome.omero_user/.gitignore b/omero/roles/ome.omero_user/.gitignore new file mode 100644 index 00000000..b6261c93 --- /dev/null +++ b/omero/roles/ome.omero_user/.gitignore @@ -0,0 +1 @@ +.*~ diff --git a/omero/roles/ome.omero_user/LICENSE.md b/omero/roles/ome.omero_user/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.omero_user/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.omero_user/README.md b/omero/roles/ome.omero_user/README.md new file mode 100644 index 00000000..6b418231 --- /dev/null +++ b/omero/roles/ome.omero_user/README.md @@ -0,0 +1,84 @@ +OMERO user +========== + +[![Actions Status](https://github.com/ome/ansible-role-omero-user/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-omero-user/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-omero_user-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/omero_user/) + +Create OMERO user accounts and groups. +This will not modify existing users or groups, apart from the user password if `force` is set. + + +Dependencies +------------ + +Assumes the `ome.omero_server` role is installed with defaults, if not you will have to set most of the role variables below. + +This requires features present in OMERO 5.X. + + +Role Variables +-------------- + +All variables are optional, see `defaults/main.yml` + +Create OMERO user accounts and groups: +- `omero_user_bin_omero`: The full path to `bin/omero` application, default `/opt/omero/server/OMERO.server/bin/omero` +- `omero_user_system`: Run the `omero` CLI as this user, default `omero` (must not be `root`) +- `omero_user_admin_user`: Login to OMERO as this admin user, default `root` +- `omero_user_admin_pass`: Password for `omero_user_admin_user` + +- `omero_user_create`: List of dictionaries of OMERO users to create with fields: + - `login`: OMERO user-name + - `firstname`: First name + - `lastname`: Last name + - `password`: Password + - `groups`: String containing group arguments (see `bin/omero user add --help`), this must be quoted if the group-names contain spaces or other special characters + - `force`: Forcibly reset password, default `False` (requires direct database access) +- `omero_user_reset_root_password`: The new OMERO `root` password (requires direct database access) +- `omero_group_create`: List of dictionaries of OMERO groups to create with fields: + - `name`: Group name + - `type`: Group type + +Database connection parameters (required if forcibly resetting OMERO user passwords): +- `omero_user_dbhost`: Database host +- `omero_user_dbuser`: Database user +- `omero_user_dbname`: Database name +- `omero_user_dbpassword`: Database password + + +Example +------- + +Create the user account `public` and group `demo` if it doesn't exist + + - hosts: omero-servers + roles: + - ome.omero_user + vars: + - omero_group_create: + - name: demo + type: read-only + - omero_user_create: + - login: public + firstname: public + lastname: user + password: public + groups: "--group-name demo" + +Reset the OMERO `root` password: + + - hosts: omero-servers + roles: + - ome.omero_user + vars: + - omero_user_reset_root_password: "omero root password" + #- omero_user_dbhost: localhost + #- omero_user_dbuser: omero + #- omero_user_dbname: omero + #- omero_user_dbpassword: omero + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.omero_user/defaults/main.yml b/omero/roles/ome.omero_user/defaults/main.yml new file mode 100644 index 00000000..3aa7026d --- /dev/null +++ b/omero/roles/ome.omero_user/defaults/main.yml @@ -0,0 +1,17 @@ +--- +# defaults file for roles/omero-user + +omero_user_bin_omero: /opt/omero/server/OMERO.server/bin/omero +omero_user_system: omero +omero_user_admin_user: root +omero_user_admin_pass: omero + +omero_user_create: [] +omero_group_create: [] + +omero_user_reset_root_password: '' + +omero_user_dbhost: localhost +omero_user_dbuser: omero +omero_user_dbname: omero +omero_user_dbpassword: omero diff --git a/omero/roles/ome.omero_user/meta/.galaxy_install_info b/omero/roles/ome.omero_user/meta/.galaxy_install_info new file mode 100644 index 00000000..4f8f9305 --- /dev/null +++ b/omero/roles/ome.omero_user/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:34:03 2024 +version: 0.4.0 diff --git a/omero/roles/ome.omero_user/meta/main.yml b/omero/roles/ome.omero_user/meta/main.yml new file mode 100644 index 00000000..c6e7eccc --- /dev/null +++ b/omero/roles/ome.omero_user/meta/main.yml @@ -0,0 +1,19 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Create OMERO user accounts and groups + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + role_name: omero_user + galaxy_tags: [] + +dependencies: [] diff --git a/omero/roles/ome.omero_user/molecule/default/molecule.yml b/omero/roles/ome.omero_user/molecule/default/molecule.yml new file mode 100644 index 00000000..59be675b --- /dev/null +++ b/omero/roles/ome.omero_user/molecule/default/molecule.yml @@ -0,0 +1,36 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: rockylinux-9 + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: ubuntu-2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.omero_user/molecule/default/playbook.yml b/omero/roles/ome.omero_user/molecule/default/playbook.yml new file mode 100644 index 00000000..0c0afafc --- /dev/null +++ b/omero/roles/ome.omero_user/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.omero_user diff --git a/omero/roles/ome.omero_user/molecule/default/tests/test_default.py b/omero/roles/ome.omero_user/molecule/default/tests/test_default.py new file mode 100644 index 00000000..eedd64a1 --- /dev/null +++ b/omero/roles/ome.omero_user/molecule/default/tests/test_default.py @@ -0,0 +1,14 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_hosts_file(host): + f = host.file('/etc/hosts') + + assert f.exists + assert f.user == 'root' + assert f.group == 'root' diff --git a/omero/roles/ome.omero_user/tasks/groups.yml b/omero/roles/ome.omero_user/tasks/groups.yml new file mode 100644 index 00000000..184e32f7 --- /dev/null +++ b/omero/roles/ome.omero_user/tasks/groups.yml @@ -0,0 +1,39 @@ +--- +# tasks file for roles/omero-user + +# Always run including in check mode +- name: omero user | current group list + become: true + become_user: "{{ omero_user_system }}" + command: > + {{ omero_user_bin_omero }} group -C + -s localhost + -u {{ omero_user_admin_user }} + -w {{ omero_user_admin_pass | quote }} + list + -q + --style json + register: groupcmd + check_mode: false + changed_when: false + +- name: omero user | set group list var + set_fact: + omero_group_list: "{{ groupcmd.stdout | from_json }}" + +- name: omero user | create group + become: true + become_user: "{{ omero_user_system }}" + command: > + {{ omero_user_bin_omero }} group -C + -s localhost + -u {{ omero_user_admin_user }} + -w {{ omero_user_admin_pass | quote }} + add + {{ item.name | quote }} + --type {{ item.type }} + when: > + (omero_group_list | selectattr('name', 'equalto', item.name) | + list | length) < 1 + with_items: + - "{{ omero_group_create }}" diff --git a/omero/roles/ome.omero_user/tasks/main.yml b/omero/roles/ome.omero_user/tasks/main.yml new file mode 100644 index 00000000..a956c04d --- /dev/null +++ b/omero/roles/ome.omero_user/tasks/main.yml @@ -0,0 +1,14 @@ +--- +# tasks file for roles/omero-user + +- include: reset-root-password.yml + when: "omero_user_reset_root_password | length > 0" + +- include: groups.yml + when: "omero_group_create | length > 0" + +- include: users.yml + when: "omero_user_create | length > 0" + +- include: reset-password.yml + when: "omero_user_create | length > 0" diff --git a/omero/roles/ome.omero_user/tasks/reset-password.yml b/omero/roles/ome.omero_user/tasks/reset-password.yml new file mode 100644 index 00000000..e4f4d1a4 --- /dev/null +++ b/omero/roles/ome.omero_user/tasks/reset-password.yml @@ -0,0 +1,34 @@ +--- +# tasks file for roles/omero-user + +# If user isn't in `omero_user_list` then skip, since user should be newly +# created and therefore shouldn't need a password reset +- name: omero user | get password update command + become: true + become_user: "{{ omero_user_system }}" + command: > + {{ omero_user_bin_omero }} db password + --user-id + {{ (omero_user_list | + selectattr('login', 'equalto', item.login) | first).id }} + {{ item.password | quote }} + when: > + ((omero_user_list | selectattr('login', 'equalto', item.login) | + list | length ) > 0) and + (item.force | default(False)) + with_items: + - "{{ omero_user_create }}" + register: pwdupdate + +- name: omero user | force reset omero password + command: > + psql + -h {{ omero_user_dbhost }} + -U {{ omero_user_dbuser }} + -d {{ omero_user_dbname }} + -w -c + {{ item.stdout | quote }} + when: "item is changed" + with_items: "{{ pwdupdate.results }}" + environment: + PGPASSWORD: "{{ omero_user_dbpassword }}" diff --git a/omero/roles/ome.omero_user/tasks/reset-root-password.yml b/omero/roles/ome.omero_user/tasks/reset-root-password.yml new file mode 100644 index 00000000..421b3a21 --- /dev/null +++ b/omero/roles/ome.omero_user/tasks/reset-root-password.yml @@ -0,0 +1,29 @@ +--- +# tasks file for roles/omero-user + +# Forcibly reset OMERO root password +- name: omero user | get root password update command + become: true + become_user: "{{ omero_user_system }}" + command: > + {{ omero_user_bin_omero }} db password + --user-id 0 + {{ omero_user_reset_root_password | quote }} + register: rootpwdupdate + # TODO: Is there a way to make this idempotent? + tags: + - skip_ansible_lint + +# WARNING: this will always run +- name: omero user | force reset omero root password + command: > + psql + -h {{ omero_user_dbhost }} + -U {{ omero_user_dbuser }} + -d {{ omero_user_dbname }} + -w -c + {{ rootpwdupdate.stdout | quote }} + environment: + PGPASSWORD: "{{ omero_user_dbpassword }}" + # This conditional ensures this task won't fail in check-mode + when: "rootpwdupdate is changed" diff --git a/omero/roles/ome.omero_user/tasks/users.yml b/omero/roles/ome.omero_user/tasks/users.yml new file mode 100644 index 00000000..f68be8d4 --- /dev/null +++ b/omero/roles/ome.omero_user/tasks/users.yml @@ -0,0 +1,42 @@ +--- +# tasks file for roles/omero-user + +# Always run including in check mode +- name: omero user | current user list + become: true + become_user: "{{ omero_user_system }}" + command: > + {{ omero_user_bin_omero }} user -C + -s localhost + -u {{ omero_user_admin_user }} + -w {{ omero_user_admin_pass | quote }} + list + -q + --style json + register: usercmd + check_mode: false + changed_when: false + +- name: omero user | set user list var + set_fact: + omero_user_list: "{{ usercmd.stdout | from_json }}" + +- name: omero user | create user + become: true + become_user: "{{ omero_user_system }}" + command: > + {{ omero_user_bin_omero }} user -C + -s localhost + -u {{ omero_user_admin_user }} + -w {{ omero_user_admin_pass | quote }} + add + {{ item.login | quote }} + {{ item.firstname | quote }} + {{ item.lastname | quote }} + --userpassword {{ item.password | quote }} + {{ item.groups }} + when: > + (omero_user_list | selectattr('login', 'equalto', item.login) | + list | length) < 1 + with_items: + - "{{ omero_user_create }}" diff --git a/omero/roles/ome.omero_user/tests/inventory b/omero/roles/ome.omero_user/tests/inventory new file mode 100644 index 00000000..2fbb50c4 --- /dev/null +++ b/omero/roles/ome.omero_user/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/omero/roles/ome.omero_user/tests/test.yml b/omero/roles/ome.omero_user/tests/test.yml new file mode 100644 index 00000000..096bd853 --- /dev/null +++ b/omero/roles/ome.omero_user/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - role: ome.omero_user diff --git a/omero/roles/ome.omero_web/.github/workflows/molecule.yml b/omero/roles/ome.omero_web/.github/workflows/molecule.yml new file mode 100644 index 00000000..c3ac276b --- /dev/null +++ b/omero/roles/ome.omero_web/.github/workflows/molecule.yml @@ -0,0 +1,62 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Read the role name + id: role-name + run: | + name=$(grep 'role_name' meta/main.yml | sed -r 's/^[^:]*:(.*)$/\1/' | tr -d '[:space:]') # noqa + echo "rolename=$name" >> "$GITHUB_OUTPUT" + - name: Publish to Galaxy + uses: ome/action-ansible-galaxy-publish@main + with: + galaxy-api-key: ${{ secrets.GALAXY_API_KEY }} + galaxy-version: ${{ github.ref_name }} + role-name: ${{ steps.role-name.outputs.rolename }} diff --git a/omero/roles/ome.omero_web/.gitignore b/omero/roles/ome.omero_web/.gitignore new file mode 100644 index 00000000..dba1d4d9 --- /dev/null +++ b/omero/roles/ome.omero_web/.gitignore @@ -0,0 +1,3 @@ +.*~ +*.pyc +.molecule diff --git a/omero/roles/ome.omero_web/CHANGES.md b/omero/roles/ome.omero_web/CHANGES.md new file mode 100644 index 00000000..f4d5fbc6 --- /dev/null +++ b/omero/roles/ome.omero_web/CHANGES.md @@ -0,0 +1,33 @@ +# Changes in Version 4 + +## Summary of breaking changes + +- Python 2 support is now dropped +- `omero_web_python_requirements_ice_package` is now a nested dictionary to + support multiple versions per distribution + +## Removed variables + +- `omero_web_python3`: the role only installs OMERO.web with Python 3 + +# Changes in Version 3 + +## Summary of breaking changes +- Default to installing and running under Python 3.6. + Set `omero_web_python3: false` to use Python 2.7. +- `/opt/omero/web/OMERO.web/` is a directory not a symlink. +- The virtualenv path is `/opt/omero/web/venv3` and does not include system-site-packages. +- Home directory of `omero_web_system_user` is changed from `/opt/omero/web` to `/opt/omero/web/OMERO.web/var`. + This increases security by restricting the directories that are writeable by `omero_web_system_user`. +- The [omero-web-apps](https://galaxy.ansible.com/ome/omero_web_apps) role has been merged into this role. +- `omero_web_release` does not support `latest`, only `present` and full versions. + +## Removed variables +- `omero_web_ice_version`: This is now an internal variable and must always be `3.6`. + + +# Changes in Version 2 + +## Removed variables +- `omero_web_upgrade`: This variable is now an internal variable. + Upgrades are automatically executed depending on the value of `omero_web_release` which can be set to `present`, `latest` or a fixed version. diff --git a/omero/roles/ome.omero_web/LICENSE.md b/omero/roles/ome.omero_web/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.omero_web/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.omero_web/README.md b/omero/roles/ome.omero_web/README.md new file mode 100644 index 00000000..7e6bb484 --- /dev/null +++ b/omero/roles/ome.omero_web/README.md @@ -0,0 +1,132 @@ +OMERO Web +========= + +[![Actions Status](https://github.com/ome/ansible-role-omero-web/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-omero-web/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-omero_web-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/omero_web/) + +Installs and configures OMERO.web and Nginx. +Uses a conf.d style configuration directory for managing the OMERO.web configuration. + +**Warning:** Python 2 support is dropped. +See [`CHANGES.md`](./CHANGES.md) for details. + + +Role Variables +-------------- + +All variables are optional, see `defaults/main.yml` for the full list + +OMERO.web version and installation. +- `omero_web_release`: The OMERO.web release, e.g. `5.9.1`. + The default is `present` which will install the latest version if web is not already installed, but will not modify an existing web. + Use `latest` to automatically upgrade when a new version is released. +- `omero_web_system_user`: OMERO.web system user, default `omero-web`. +- `omero_web_system_uid`: OMERO.web system user ID (default automatic) + +OMERO.web configuration. +- `omero_web_config_set`: A dictionary of `config-key: value` which will be used for the initial OMERO.web configuration, default empty. + `value` can be a string, or an object (list, dictionary) that will be automatically converted to quoted JSON. + Note configuration can also be done pre/post installation using the `web/config` conf.d style directory. +- `omero_web_setup_nginx`: Install and configure Nginx, default `True`. + +OMERO.web systemd configuration +- `omero_web_systemd_setup`: Create and start the `omero-web` systemd service, default `True` +- `omero_web_systemd_limit_nofile`: Systemd limit for number of open files (default ignore) +- `omero_web_systemd_after`: A list of strings with additional service names to appear in systemd unit file "After" statements. Default empty/none. +- `omero_web_systemd_requires`: A list of strings with additional service names to appear in systemd unit file "Requires" statements. Default empty/none. + +Python 3 only parameters. +- `omero_web_python_addons`: List of additional Python packages to be installed into virtualenv + +The [omero-web-apps](https://galaxy.ansible.com/ome/omero_web_apps) role has been merged into this role for Python 3 deployments. +All variables are optional: +- `omero_web_apps_names`: List of web application names to be appended to `omero.web.apps` +- `omero_web_apps_packages`: List of pip installable packages +- `omero_web_apps_top_links`: Lists of top link dictionaries to be appended to `omero.web.ui.top_links`, of the form: + - `label`: Label + - `link`: URL or a dict + - `attrs`: Dictionary of attributes (optional) +- `omero_web_apps_ui_metadata_panes`: Items to be appended to `omero.web.ui.metadata_panes` +- `omero_web_apps_config_append`: Dictionary of other key-[list of values] pairs to be appended (multiple values can be appended to the same key) +- `omero_web_apps_config_set`: Dictionary of other key-value pairs to be set +- `omero_web_apps_config_name`: The basename of the configuration file (`web/config/{{ omero_web_apps_config_name }}.omero`) + + + +Unstable features +----------------- + +Variables : +- `omero_web_systemd_start`: Automatically enable and start/restart systemd omero-web service, default `True`. + This is intended for use in server images where installation may be separate from configuration and execution. +- `omero_web_always_reset_config`: Clear the existing configuration before regenerating, default `True`. + +It should be safe to use this role to deploy OMERO.web inside a standard `centos:7` Docker container without systemd (`omero_web_systemd_setup: False`). + + + +Configuring OMERO.web +--------------------- + +This role regenerates the OMERO.web configuration file using the configuration files and helper script in `/opt/omero/web/config`. +`omero_web_config_set` can be used for simple configurations, for anything more complex consider creating one or more configuration files under: `/opt/omero/web/config/` with the extension `.omero`. + +Manual configuration changes (`omero config ...`) will be lost following a restart of `omero-web` with systemd, you can disable this by setting `omero_web_always_reset_config: False`. +Manual configuration changes will never be copied during an upgrade. + +See https://github.com/ome/design/issues/70 for a proposal to add support for a conf.d style directory directly into OMERO. + + +Example Playbooks +----------------- + +OMERO.web with the default backend server, `localhost:4064`: + + - hosts: localhost + roles: + - role: ome.omero_web + +OMERO.web with a custom configuration using `omero_web_config_set`: + + - hosts: localhost + roles: + - role: ome.omero_web + omero_web_config_set: + omero.web.server_list: + - [omero.example.org, 4064, omero-example] + omero.web.public.enabled: True + omero.web.public.server_id: 1 + omero.web.public.user: public + omero.web.public.password: secret-password + +OMERO.web with the redis session engine + + hosts: localhost + roles: + - role: ome.omero_web + omero_web_setup_redis_session: true + omero_web_config_set: + "omero.web.caches": + "default": + "BACKEND": "django_redis.cache.RedisCache" + "LOCATION": "redis://127.0.0.1:6379/0" + "omero.web.session_engine": "django.contrib.sessions.backends.cache" + +OMERO.web with a custom configuration using a configuration file `web-custom-config.omero`: + + - hosts: localhost + roles: + - role: ome.omero_web + tasks: + - copy: + content: > + config set omero.web.server_list '[["omero.example.org", 4064, "omero-example"]' + dest: /opt/omero/web/config/web-custom-config.omero + notify: + - restart omero-web + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.omero_web/defaults/main.yml b/omero/roles/ome.omero_web/defaults/main.yml new file mode 100644 index 00000000..b3e3340c --- /dev/null +++ b/omero/roles/ome.omero_web/defaults/main.yml @@ -0,0 +1,139 @@ +--- +# defaults for omero-web + +omero_web_release: present + +# OMERO.web system user +omero_web_system_user: omero-web + +# OMERO.web system user ID (If not defined one is chosen automatically) +# omero_web_system_uid: + +# Setup systemd services +omero_web_systemd_setup: true + +# Change the systemd limit for number of open files (default ignore) +omero_web_systemd_limit_nofile: + +# Services which OMERO web needs to be running before it can start, such as +# remote storage. +omero_web_systemd_after: [] + +# Services which OMERO web needs to be concurrently running. +omero_web_systemd_requires: [] + +# Configuration key-values to be set +omero_web_config_set: {} + +# Install and configure Nginx +omero_web_setup_nginx: true + +# Install required package to deploy redis session engine +omero_web_setup_redis_session: false + +# List of additional Python packages to be installed into virtualenv +omero_web_python_addons: [] + + +###################################################################### +# defaults from the old omero-web-apps +###################################################################### + +# The pip installable package +omero_web_apps_packages: [] + +# The name of the web application, used for configuration +omero_web_apps_names: [] + +# Top links +omero_web_apps_top_links: [] + +# UI metadata panes +omero_web_apps_ui_metadata_panes: [] + +# Other list value properties (dict, append) +omero_web_apps_config_append: {} + +# Other key value properties (dict, set) +omero_web_apps_config_set: {} + +# The basename of the configuration file +omero_web_apps_config_name: omero-web-apps + + +###################################################################### +# Expert users only! +###################################################################### + +omero_web_ice_version: "3.6" + +omero_web_python_requirements_ice_package: + RedHat: + 9: "https://github.com/glencoesoftware/zeroc-ice-py-rhel9-x86_64/releases/download/\ + 20230830/zeroc_ice-3.6.5-cp39-cp39-linux_x86_64.whl" + Debian: + 22: "https://github.com/glencoesoftware/zeroc-ice-py-ubuntu2204-x86_64/releases/download/\ + 20221004/zeroc_ice-3.6.5-cp310-cp310-linux_x86_64.whl" + +# List of python3 packages to install +omero_web_python_requirements: + # TODO: make the use of our non-standard wheel optional + - "{{ omero_web_python_requirements_ice_package[ansible_os_family][ + ansible_distribution_major_version | int ] | + default('zeroc-ice')}}" + # Let omero-web bring this in + # - omero-py=={{ _omero_py_version | default('5.6.dev4') }} + - "omero-web{{ (omero_web_release == 'present') | + ternary('', '==' + omero_web_release) }}" + - redis + +# Path to virtualenv +omero_web_virtualenv_basedir: "{{ omero_web_basedir + '/venv3' }}" + +# OMERODIR +omero_web_omerodir: "{{ omero_web_basedir }}/{{ omero_web_symlink }}" + +# How to run omero +omero_web_omero_command: "{{ omero_web_omerodir + '/bin/omero' }}" + +# Config update command +omero_web_config_update: >- + {{ + omero_web_omero_command + ' load --glob ' + omero_web_basedir + + '/config/*.omero' + }} + +# DEVELOPMENT: If True clear the existing configuration before regenerating +omero_web_always_reset_config: true + +# DEVELOPMENT: Automatically start systemd omero-web +omero_web_systemd_start: true + +# Base directory for the web installation +omero_web_basedir: "{{ omero_common_basedir }}/web" + +# Symlink to the currently installed OMERO.web +omero_web_symlink: OMERO.web + +# Path of omego +omero_web_omego: "{{ omero_common_basedir }}/omego/bin/omego" + +# Additional omego aguments passed to upgrade or install +omero_web_omego_additional_args: "" + +# If True and web is already installed then upgrade to the version in +# omero_web_release, otherwise don't upgrade an existing web. +# This should not be needed if versions are correctly compared. +omero_web_upgrade: true + +# DEVELOPMENT: Operator for comparing current-version against +# omero_web_release, e.g. '!='. Default is to upgrade when +# current-version < omero_web_release +omero_web_checkupgrade_comparator: '<' + +omero_web_omego_options: > + --release {{ _omero_web_new_version }} + --sym {{ omero_web_symlink }} + --ice {{ omero_web_ice_version }} + -qq + {{ omero_web_omego_additional_args }} diff --git a/omero/roles/ome.omero_web/handlers/main.yml b/omero/roles/ome.omero_web/handlers/main.yml new file mode 100644 index 00000000..0afe19de --- /dev/null +++ b/omero/roles/ome.omero_web/handlers/main.yml @@ -0,0 +1,22 @@ +--- +# handlers for omero-web +# Don't use omero-common handlers because systemd might be disabled. +# This also avoids problems with ordering of handlers: +# http://stackoverflow.com/a/35130254 + +- name: omero-web rewrite omero-web configuration + become: true + become_user: "{{ omero_web_system_user }}" + command: "{{ omero_web_config_update }}" + +- name: omero-web restart omero-web + become: true + service: + name: omero-web + state: restarted + when: omero_web_systemd_setup and omero_web_systemd_start + +- name: omero-web Reload SELinux + become: true + command: load_policy + when: selinux_enabled diff --git a/omero/roles/ome.omero_web/meta/.galaxy_install_info b/omero/roles/ome.omero_web/meta/.galaxy_install_info new file mode 100644 index 00000000..50b5f512 --- /dev/null +++ b/omero/roles/ome.omero_web/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:50 2024 +version: 5.1.1 diff --git a/omero/roles/ome.omero_web/meta/main.yml b/omero/roles/ome.omero_web/meta/main.yml new file mode 100644 index 00000000..37b9b2bb --- /dev/null +++ b/omero/roles/ome.omero_web/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Install and configure OMERO.web + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + role_name: omero_web + namespace: ome + galaxy_tags: [] diff --git a/omero/roles/ome.omero_web/meta/requirements.yml b/omero/roles/ome.omero_web/meta/requirements.yml new file mode 100644 index 00000000..ae5e6709 --- /dev/null +++ b/omero/roles/ome.omero_web/meta/requirements.yml @@ -0,0 +1,8 @@ +--- + +- src: ome.omero_common +- src: ome.nginx +- src: ome.python3_virtualenv +- src: ome.selinux_utils +- src: ome.redis +- src: ome.basedeps diff --git a/omero/roles/ome.omero_web/molecule/active-rockylinux9/molecule.yml b/omero/roles/ome.omero_web/molecule/active-rockylinux9/molecule.yml new file mode 100755 index 00000000..df5902a2 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/active-rockylinux9/molecule.yml @@ -0,0 +1,41 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: omero-web-active-rockylinux9 + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint + playbooks: + converge: ../resources/playbook.yml + inventory: + host_vars: + omero-web-active-rockylinux9: + options: + v: true + diff: true +scenario: + name: active-rockylinux9 + converge_sequence: + - converge +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.omero_web/molecule/active-ubuntu2204/molecule.yml b/omero/roles/ome.omero_web/molecule/active-ubuntu2204/molecule.yml new file mode 100755 index 00000000..945f4817 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/active-ubuntu2204/molecule.yml @@ -0,0 +1,43 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: omero-web-active-ubuntu2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + +provisioner: + name: ansible + lint: + name: ansible-lint + playbooks: + # TODO: Install curl in basedeps instead + prepare: prepare.yml + converge: ../resources/playbook.yml + inventory: + host_vars: + omero-web-active-ubuntu2204: + options: + v: true + diff: true +scenario: + name: active-ubuntu2204 + converge_sequence: + - converge +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.omero_web/molecule/active-ubuntu2204/prepare.yml b/omero/roles/ome.omero_web/molecule/active-ubuntu2204/prepare.yml new file mode 100644 index 00000000..412fb7aa --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/active-ubuntu2204/prepare.yml @@ -0,0 +1,19 @@ +--- +# Curl isn't installed, needed for tests + +- name: Prepare + hosts: all + + tasks: + - name: Install packages + become: true + ansible.builtin.apt: + update_cache: true + name: + - curl + - gnupg + - ca-certificates + - python3 + - sudo + - bash + state: present diff --git a/omero/roles/ome.omero_web/molecule/inactive/molecule.yml b/omero/roles/ome.omero_web/molecule/inactive/molecule.yml new file mode 100644 index 00000000..e7ea9983 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/inactive/molecule.yml @@ -0,0 +1,41 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: omero-web-inactive + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint + playbooks: + converge: ../resources/playbook.yml + inventory: + host_vars: + omero-web-inactive: + # This tests a hypothetical instance where systemd is inactive but might + # be activated in future + # It also tests this role can be used to install omero.web on a system + # that will never have systemd, e.g. a simple docker container + omero_web_systemd_start: false + omero_web_setup_nginx: false + omero_web_release: present +scenario: + name: inactive +verifier: + name: testinfra diff --git a/omero/roles/ome.omero_web/molecule/inactive/tests/test_default.py b/omero/roles/ome.omero_web/molecule/inactive/tests/test_default.py new file mode 120000 index 00000000..f4a3648e --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/inactive/tests/test_default.py @@ -0,0 +1 @@ +../../resources/tests/test_default.py \ No newline at end of file diff --git a/omero/roles/ome.omero_web/molecule/resources/playbook.yml b/omero/roles/ome.omero_web/molecule/resources/playbook.yml new file mode 100644 index 00000000..30028288 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/resources/playbook.yml @@ -0,0 +1,93 @@ +--- +# - name: Converge +# hosts: all + +# pre_tasks: +# # To test the upgrade process without breaking the idempotence check +# # we need to add a flag so the first omero-web installation is +# # only run once +# - name: check whether omero-web has been installed at least once +# stat: +# path: /opt/omero/web/OMERO.web +# register: molecule_test_omero_web_installed_1 + +# roles: + +# - role: ansible-role-omero-web +# omero_web_config_set: +# omero.web.server_list: +# - [localhost, 12345, molecule-test] +# omero_web_release: "5.3" +# when: not molecule_test_omero_web_installed_1.stat.exists + +# tasks: +# - name: get omero-web version +# become: true +# become_user: omero-web +# command: /opt/omero/web/OMERO.web/bin/omero version +# register: molecule_test_omero_web_version +# changed_when: false + +# - name: check version +# assert: +# that: molecule_test_omero_web_version.stdout.startswith('5.3.') +# when: not molecule_test_omero_web_installed_1.stat.exists + +# vars: +# ice_python_wheel: "https://github.com/ome/zeroc-ice-py-centos7/releases/\ +# download/0.1.0/zeroc_ice-3.6.4-cp27-cp27mu-linux_x86_64.whl" + + +# Attempt to upgrade +# omero_web_release is defined in molecule.yml host_vars so: +# - omero-web: latest: upgraded +# - omero-web-inactive: present: unchanged at 5.3 +- name: Converge upgrade + hosts: all + roles: + - role: ome.omero_web + omero_web_config_set: + omero.web.server_list: + - [localhost, 12345, molecule-test] + + omero_web_apps_packages: + - omero-mapr + omero_web_apps_names: + - omero_mapr + omero_web_apps_top_links: + - label: OMERO + link: + viewname: webindex + query_string: {experimenter: -1} + attrs: + title: Image Data Repository + - label: Genes + link: + viewname: maprindex_gene + query_string: {experimenter: -1} + attrs: + title: Genes browser + omero_web_apps_config_append: + omero.web.mapr.config: + - menu: "gene" + config: + default: + - "Gene Symbol" + all: + - "Gene Symbol" + - "Gene Identifier" + ns: + - "openmicroscopy.org/mapr/gene" + label: "Gene" + case_sensitive: true + - menu: "genesupplementary" + config: + default: [] + all: [] + ns: + - "openmicroscopy.org/mapr/gene/supplementary" + label: "Gene supplementary" + omero_web_apps_config_set: + example.string: example value + example.boolean: true + example.integer: 2 diff --git a/omero/roles/ome.omero_web/molecule/resources/requirements.yml b/omero/roles/ome.omero_web/molecule/resources/requirements.yml new file mode 100644 index 00000000..ae5e6709 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/resources/requirements.yml @@ -0,0 +1,8 @@ +--- + +- src: ome.omero_common +- src: ome.nginx +- src: ome.python3_virtualenv +- src: ome.selinux_utils +- src: ome.redis +- src: ome.basedeps diff --git a/omero/roles/ome.omero_web/molecule/resources/tests/test_default.py b/omero/roles/ome.omero_web/molecule/resources/tests/test_default.py new file mode 100644 index 00000000..0a6ae562 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/resources/tests/test_default.py @@ -0,0 +1,40 @@ +import os +import re + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +OMERO = '/opt/omero/web/OMERO.web/bin/omero' +# Need to match 5.6.dev2 +# VERSION_PATTERN = re.compile('(\d+)\.(\d+)\.(\d+)-ice36-') +VERSION_PATTERN = re.compile(r'(\d+)\.(\d+)\.(\w+)') + + +def test_omero_web_config(host): + with host.sudo('omero-web'): + cfg = host.check_output("%s config get omero.web.server_list" % OMERO) + assert cfg == '[["localhost", 12345, "molecule-test"]]' + + with host.sudo('omero-web'): + keys = host.check_output("%s config keys" % OMERO) + assert sorted(keys.split()) == [ + 'example.boolean', + 'example.integer', + 'example.string', + 'omero.web.apps', + 'omero.web.mapr.config', + 'omero.web.server_list', + 'omero.web.ui.top_links', + ] + + +def test_omero_version(host): + with host.sudo('omero-web'): + ver = host.check_output("%s version" % OMERO) + m = VERSION_PATTERN.match(ver) + assert m is not None + assert int(m.group(1)) >= 5 + assert int(m.group(2)) > 3 diff --git a/omero/roles/ome.omero_web/molecule/resources/tests/test_nginx.py b/omero/roles/ome.omero_web/molecule/resources/tests/test_nginx.py new file mode 100644 index 00000000..36df8b53 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/resources/tests/test_nginx.py @@ -0,0 +1,24 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +@pytest.mark.parametrize("name", ["omero-web", "nginx"]) +def test_services_running_and_enabled(host, name): + service = host.service(name) + assert service.is_running + assert service.is_enabled + + +def test_nginx_gateway(host): + out = host.check_output('curl -L localhost') + assert 'OMERO.web - Login' in out + + +def test_omero_web_config_applied(host): + out = host.check_output('curl -L localhost') + assert 'molecule-test:12345' in out diff --git a/omero/roles/ome.omero_web/molecule/resources/tests/test_sepolicy.py b/omero/roles/ome.omero_web/molecule/resources/tests/test_sepolicy.py new file mode 100644 index 00000000..6eb56f93 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/resources/tests/test_sepolicy.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('all') + + +def test_selinux_custom_policy(host): + out = host.check_output('semodule -l') + assert 'django' in out diff --git a/omero/roles/ome.omero_web/molecule/resources/tests/test_webapps.py b/omero/roles/ome.omero_web/molecule/resources/tests/test_webapps.py new file mode 100644 index 00000000..8cc9fef2 --- /dev/null +++ b/omero/roles/ome.omero_web/molecule/resources/tests/test_webapps.py @@ -0,0 +1,109 @@ +import os +import json +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + +OMERO = '/opt/omero/web/OMERO.web/bin/omero' + + +def assert_jcfg(host, key, value, isjson): + with host.sudo('omero-web'): + cfg = host.check_output("%s config get %s", OMERO, key) + if isjson: + cfg = json.loads(cfg) + assert cfg == value + + +@pytest.mark.parametrize("key,value", [ + ('example.string', 'example value'), +]) +# ('example.boolean', True), +# ('example.integer', 2), +def test_example_config(host, key, value): + assert_jcfg(host, key, value, False) + + +def test_omero_web_apps(host): + assert_jcfg(host, 'omero.web.apps', ["omero_mapr"], True) + + +def test_omero_web_mapr_config(host): + expected = [ + { + "menu": "gene", "config": { + "default": ["Gene Symbol"], + "case_sensitive": True, + "all": ["Gene Symbol", "Gene Identifier"], + "ns": ["openmicroscopy.org/mapr/gene"], + "label": "Gene" + } + }, + { + "menu": "genesupplementary", + "config": { + "default": [], + "all": [], + "ns": ["openmicroscopy.org/mapr/gene/supplementary"], + "label": "Gene supplementary" + } + } + ] + assert_jcfg(host, 'omero.web.mapr.config', expected, True) + + +def test_omero_web_ui_toplinks(host): + expected = [ + [ + "Data", + "webindex", + {"title": "Browse Data via Projects, Tags etc"} + ], + [ + "History", + "history", + {"title": "History"} + ], + [ + "Help", + "https://help.openmicroscopy.org/", + {"target": "new", "title": "Open OMERO user guide in a new tab"} + ], + [ + "OMERO", + { + "query_string": {"experimenter": -1}, + "viewname": "webindex" + }, + {"title": "Image Data Repository"} + ], + [ + "Genes", + { + "query_string": {"experimenter": -1}, + "viewname": "maprindex_gene" + }, + {"title": "Genes browser"} + ] + ] + assert_jcfg(host, 'omero.web.ui.top_links', expected, True) + + +def test_mapr_config(host): + config = { + 'gene': { + 'all': ['Gene Symbol', 'Gene Identifier'], + 'case_sensitive': True, + 'default': ['Gene Symbol'], + 'label': 'Gene', + 'ns': ['openmicroscopy.org/mapr/gene']}, + 'genesupplementary': { + 'all': [], + 'default': [], + 'label': 'Gene supplementary', + 'ns': ['openmicroscopy.org/mapr/gene/supplementary']} + } + out = host.check_output('curl -L http://localhost/mapr/api/config/') + assert json.loads(out) == config diff --git a/omero/roles/ome.omero_web/tasks/main.yml b/omero/roles/ome.omero_web/tasks/main.yml new file mode 100644 index 00000000..59ef76d6 --- /dev/null +++ b/omero/roles/ome.omero_web/tasks/main.yml @@ -0,0 +1,14 @@ +--- +# tasks for omero-web +- +- include: pre_tasks.yml + +- include: web-dependencies.yml + +- include: web-install-py3.yml + +- include: web-systemd.yml + when: omero_web_systemd_setup + +- include: web-nginx.yml + when: omero_web_setup_nginx diff --git a/omero/roles/ome.omero_web/tasks/pre_tasks.yml b/omero/roles/ome.omero_web/tasks/pre_tasks.yml new file mode 100644 index 00000000..3f95743d --- /dev/null +++ b/omero/roles/ome.omero_web/tasks/pre_tasks.yml @@ -0,0 +1,21 @@ +--- + +- ansible.builtin.import_role: + name: ome.omero_common + +- name: omero-web | Include ome.selinux_utils + ansible.builtin.include_role: + name: ome.selinux_utils + +- name: omero-web | Include ome.python3_virtualenv role + ansible.builtin.include_role: + name: ome.python3_virtualenv + +- name: omero-web | Include ome.nginx role + ansible.builtin.include_role: + name: ome.nginx + when: omero_web_setup_nginx + +- name: omero-web | Include ome.basedeps role + ansible.builtin.include_role: + name: ome.basedeps diff --git a/omero/roles/ome.omero_web/tasks/web-dependencies.yml b/omero/roles/ome.omero_web/tasks/web-dependencies.yml new file mode 100755 index 00000000..53323d2d --- /dev/null +++ b/omero/roles/ome.omero_web/tasks/web-dependencies.yml @@ -0,0 +1,93 @@ +--- +# selinux +- name: omero web | selinux booleans + become: true + seboolean: + name: "{{ item }}" + state: true + persistent: true + with_items: + - httpd_read_user_content + - httpd_enable_homedirs + - httpd_can_network_relay + when: selinux_enabled + +# Alternatively set httpd_can_network_connect=yes to allow all ports +- name: omero web | selinux ports + become: true + seport: + ports: "4080" + proto: tcp + setype: http_port_t + state: present + when: selinux_enabled + +- name: omero web | register pp file + stat: + path: /tmp/django.pp + register: pp_file_name + +- name: omero web | copy te file + become: true + template: + dest: /tmp/django.te + force: true + src: django.te.j2 + mode: 0644 + +- name: omero web | install checkpolicy + become: true + ansible.builtin.dnf: + update_cache: true + name: + - checkpolicy + - policycoreutils + - ipa-selinux + # - selinux-policy-targeted + state: present + when: ansible_os_family | lower == 'redhat' + +- name: omero web | install checkpolicy for ubuntu + become: true + ansible.builtin.apt: + update_cache: true + name: + - checkpolicy + - policycoreutils + - semodule-utils + - selinux-basics + state: present + when: ansible_os_family | lower != 'redhat' + +- name: omero web | Compile into a policy module + become: true + command: "checkmodule -M -m -o /tmp/django.mod /tmp/django.te" + args: + creates: /tmp/django.mod + when: not pp_file_name.stat.exists + +- name: omero web | register mod file + stat: + path: /tmp/django.mod + register: mod_file_name + +- name: omero web | Package the policy module + become: true + command: "semodule_package -o /tmp/django.pp -m /tmp/django.mod" + args: + creates: /tmp/mypolicy.pp + + when: not pp_file_name.stat.exists + +- name: omero web | Load the policy module + become: true + command: "semodule -i /tmp/django.pp" + notify: + - omero-web Reload SELinux + when: mod_file_name.stat.exists + +- name: omero web | delete mod file + become: true + ansible.builtin.file: + path: /tmp/django.mod + state: absent diff --git a/omero/roles/ome.omero_web/tasks/web-install-py3.yml b/omero/roles/ome.omero_web/tasks/web-install-py3.yml new file mode 100644 index 00000000..d3b05558 --- /dev/null +++ b/omero/roles/ome.omero_web/tasks/web-install-py3.yml @@ -0,0 +1,169 @@ +--- +# install OMERO.web + +# TODO: allow version to be specified, handle latest/present etc +# E.g. get version info from https://pypi.org/pypi/omero-web/json +# and parse using +# https://stackoverflow.com/questions/54025894/how-to-sort-version-numbers-in-ansible + +- name: omero web | display omero_common_basedir value + debug: + msg: "default: {{ omero_common_basedir }}" + +- name: omero web | is web symlink present + become: true + stat: + path: "{{ omero_web_omerodir }}" + register: omero_web_symlink_st + +# Symlink ⇒ Old Python 2 installation: stop OMERO before doing anything else +- name: omero web | stop omero web + become: true + service: + name: omero-web + state: stopped + when: omero_web_symlink_st.stat.exists and omero_web_symlink_st.stat.islnk + +- name: omero web | remove symlink + become: true + file: + path: "{{ omero_web_omerodir }}" + state: absent + when: omero_web_symlink_st.stat.exists and omero_web_symlink_st.stat.islnk + +- name: omero web | create OMERODIR readonly + become: true + file: + path: "{{ item }}" + state: directory + mode: 0755 + with_items: + - "{{ omero_web_basedir }}" + - "{{ omero_web_basedir }}/config" + - "{{ omero_web_omerodir }}" + - "{{ omero_web_omerodir }}/bin" + +# omero-web system user +# TODO: Check is home directory location be modified for an upgrade? +- name: omero web | create system user + become: true + user: + name: "{{ omero_web_system_user }}" + home: "{{ omero_web_omerodir }}/var" + createhome: false + state: present + system: true + uid: "{{ omero_web_system_uid | default(omit) }}" + +- name: omero web | create OMERODIR writeable + become: true + file: + path: "{{ omero_web_omerodir }}{{ item }}" + state: directory + owner: "{{ omero_web_system_user }}" + mode: 0755 + with_items: + - /etc/grid + - /var + +- name: omero web | remove old configuration script + become: true + file: + path: "{{ omero_web_basedir }}/config/omero-web-config-update.sh" + state: absent + +- name: omero web | configuration 00-omero-web.omero + become: true + template: + dest: "{{ omero_web_basedir }}/config/00-omero-web.omero" + force: true + src: 00-omero-web-omero.j2 + mode: 0644 + notify: + - omero-web rewrite omero-web configuration + - omero-web restart omero-web + +- name: omero web | add application web configuration + become: true + template: + dest: "{{ omero_web_basedir }}/config/\ + {{ omero_web_apps_config_name }}.omero" + force: true + src: omero-web-apps-omero.j2 + mode: 0644 + notify: + - omero-web rewrite omero-web configuration + - omero-web restart omero-web + +- name: omero web | setup virtualenv3 + become: true + pip: + name: "pip>=21" + state: present + virtualenv: "{{ omero_web_virtualenv_basedir }}" + virtualenv_command: /usr/local/bin/ome-python3-virtualenv + +- name: omero web | install tzdata + become: true + pip: + name: tzdata + state: present + virtualenv: "{{ omero_web_virtualenv_basedir }}" + virtualenv_command: /usr/local/bin/ome-python3-virtualenv + notify: + - omero-web rewrite omero-web configuration + - omero-web restart omero-web + +- name: omero web | install django_redis + become: true + pip: + name: django_redis + state: present + virtualenv: "{{ omero_web_virtualenv_basedir }}" + virtualenv_command: /usr/local/bin/ome-python3-virtualenv + notify: + - omero-web rewrite omero-web configuration + - omero-web restart omero-web + when: omero_web_setup_redis_session + +# TODO: figure out dependencies, use omero-web version +# Install/upgrade OMERO.web after the configuration files are updated +# This should mean that if OMERO.web fails to start due to a configuration +# error it will be updated before a restart +- name: omero web | install requirements + become: true + pip: + name: >- + {{ + omero_web_python_requirements + + omero_web_python_addons + + omero_web_apps_packages + }} + state: present + virtualenv: "{{ omero_web_virtualenv_basedir }}" + virtualenv_command: /usr/local/bin/ome-python3-virtualenv + notify: + - omero-web rewrite omero-web configuration + - omero-web restart omero-web + +# Remembering to set OMERODIR everywhere is prone to error +- name: omero web | create omero web wrapper + become: true + template: + dest: "{{ omero_web_omero_command }}" + src: bin-omero.j2 + mode: 0555 + notify: + - omero-web rewrite omero-web configuration + - omero-web restart omero-web + +- name: omero web | selinux restorecon + become: true + command: >- + /usr/sbin/restorecon -R -v + {{ ansible_check_mode | ternary('-n', '') }} + {{ omero_web_basedir }}/OMERO.web + register: result + check_mode: false + changed_when: result.stdout | length > 0 + when: selinux_enabled diff --git a/omero/roles/ome.omero_web/tasks/web-nginx.yml b/omero/roles/ome.omero_web/tasks/web-nginx.yml new file mode 100644 index 00000000..698ce050 --- /dev/null +++ b/omero/roles/ome.omero_web/tasks/web-nginx.yml @@ -0,0 +1,43 @@ +--- +# setup nginx + +# Flush handlers to ensure configuration is reloaded +- name: omero web | flush systemd handlers + meta: flush_handlers + +- block: + + - name: omero web | generate nginx config + become: true + become_user: "{{ omero_web_system_user }}" + command: "{{ omero_web_omero_command }} web config nginx" + register: _omero_web_config_nginx + # This should be safe to always run since nothing is written + # The subsequent copy task will handle changed/unchanged + changed_when: false + check_mode: false + + - name: omero web | write nginx config + become: true + copy: + content: "{{ _omero_web_config_nginx.stdout }}" + dest: /etc/nginx/conf.d/omero-web.conf + mode: 0644 + notify: restart nginx + + +- name: omero web | nginx remove system defaults + become: true + replace: + backup: true + dest: /etc/nginx/nginx.conf + regexp: '80\s*default_server\s*;' + replace: '80; # default_server;' + notify: restart nginx + +- name: omero web | enable nginx + become: true + service: + enabled: true + name: nginx + state: started diff --git a/omero/roles/ome.omero_web/tasks/web-systemd.yml b/omero/roles/ome.omero_web/tasks/web-systemd.yml new file mode 100644 index 00000000..01e3674f --- /dev/null +++ b/omero/roles/ome.omero_web/tasks/web-systemd.yml @@ -0,0 +1,25 @@ +--- +# Setup systemd files + +- name: omero web | systemd service + become: true + template: + dest: /etc/systemd/system/omero-web.service + force: true + src: systemd-system-omero-web-service.j2 + mode: 0644 + notify: + - reload systemd + - omero-web restart omero-web + +# Flush handlers to ensure systemd is reloaded +- name: omero web | flush systemd handlers + meta: flush_handlers + +- name: omero web | enable and start web systemd + become: true + service: + enabled: true + name: omero-web.service + state: started + when: omero_web_systemd_start diff --git a/omero/roles/ome.omero_web/templates/00-omero-web-omero.j2 b/omero/roles/ome.omero_web/templates/00-omero-web-omero.j2 new file mode 100644 index 00000000..0a66d811 --- /dev/null +++ b/omero/roles/ome.omero_web/templates/00-omero-web-omero.j2 @@ -0,0 +1,14 @@ +# {{ ansible_managed }} + +{% if omero_web_always_reset_config %} +config drop default +{% endif %} + +# Additional custom options +{% for key in (omero_web_config_set | sort) %} +config set -- {{ key | quote }} {{ + ((omero_web_config_set[key] | string) == omero_web_config_set[key]) | + ternary(omero_web_config_set[key], omero_web_config_set[key] | to_json) | + quote +}} +{% endfor %} diff --git a/omero/roles/ome.omero_web/templates/bin-omero.j2 b/omero/roles/ome.omero_web/templates/bin-omero.j2 new file mode 100644 index 00000000..7db480de --- /dev/null +++ b/omero/roles/ome.omero_web/templates/bin-omero.j2 @@ -0,0 +1,16 @@ +#!{{ omero_web_virtualenv_basedir }}/bin/python + +import os +from subprocess import run +import sys + +if not os.getenv('OMERODIR'): + os.environ['OMERODIR'] = '{{ omero_web_omerodir }}' + +current_path = os.getenv('PATH', '') +venv_bin = '{{ omero_web_virtualenv_basedir }}/bin' +if not current_path.startswith(venv_bin + os.pathsep): + os.environ['PATH'] = '{}{}{}'.format(venv_bin, os.pathsep, current_path) + +p = run(['{{ omero_web_virtualenv_basedir }}/bin/omero'] + sys.argv[1:]) +sys.exit(p.returncode) diff --git a/omero/roles/ome.omero_web/templates/django.te.j2 b/omero/roles/ome.omero_web/templates/django.te.j2 new file mode 100755 index 00000000..698aa146 --- /dev/null +++ b/omero/roles/ome.omero_web/templates/django.te.j2 @@ -0,0 +1,15 @@ + +module django 1.0; + +require { + type var_t; + type httpd_t; + type init_t; + class file { getattr ioctl open read }; +} + +#============= httpd_t ============== +allow httpd_t var_t:file { getattr open read }; + +#============= init_t ============== +allow init_t var_t:file { ioctl open read }; diff --git a/omero/roles/ome.omero_web/templates/omero-web-apps-omero.j2 b/omero/roles/ome.omero_web/templates/omero-web-apps-omero.j2 new file mode 100644 index 00000000..d408f0d2 --- /dev/null +++ b/omero/roles/ome.omero_web/templates/omero-web-apps-omero.j2 @@ -0,0 +1,36 @@ +# {{ ansible_managed }} + +# add application +{% for item in omero_web_apps_names %} +config append -- omero.web.apps {{ item | to_json | quote }} +{% endfor %} + +# add top links +{% for item in omero_web_apps_top_links %} +{% if 'attrs' in item %} +config append -- omero.web.ui.top_links {{ [item.label, item.link, item.attrs] | to_json | quote }} +{% else %} +config append -- omero.web.ui.top_links {{ [item.label, item.link] | to_json | quote }} +{% endif %} +{% endfor %} + +# ui metadata panes +{% for item in omero_web_apps_ui_metadata_panes %} +config append -- omero.web.ui.metadata_panes {{ item | to_json | quote }} +{% endfor %} + +# Other list value properties (append) +{% for key in omero_web_apps_config_append %} +{% for value in omero_web_apps_config_append[key] %} +config append -- {{ key | quote }} {{ value | to_json | quote }} +{% endfor %} +{% endfor %} + +# Other key value properties (set) +{% for key in omero_web_apps_config_set %} +config set -- {{ key | quote }} {{ + ((omero_web_apps_config_set[key] | string) == omero_web_apps_config_set[key]) | + ternary(omero_web_apps_config_set[key], omero_web_apps_config_set[key] | to_json) | + quote +}} +{% endfor %} diff --git a/omero/roles/ome.omero_web/templates/omero-web-config-update-sh.j2 b/omero/roles/ome.omero_web/templates/omero-web-config-update-sh.j2 new file mode 100644 index 00000000..b82e2e59 --- /dev/null +++ b/omero/roles/ome.omero_web/templates/omero-web-config-update-sh.j2 @@ -0,0 +1,9 @@ +#!/bin/sh +# {{ ansible_managed }} +# Regenerate the omero-web configuration + +set -e + +for f in {{ omero_web_basedir }}/config/*.omero; do + {{ omero_web_omero_command }} load "$f" +done diff --git a/omero/roles/ome.omero_web/templates/systemd-system-omero-web-service.j2 b/omero/roles/ome.omero_web/templates/systemd-system-omero-web-service.j2 new file mode 100644 index 00000000..4a2656f8 --- /dev/null +++ b/omero/roles/ome.omero_web/templates/systemd-system-omero-web-service.j2 @@ -0,0 +1,25 @@ +[Unit] +Description=OMERO.web +# Not mandatory, Nginx may be running on a different server +#Requires=nginx.service +After=network.service +{% for value in omero_web_systemd_after %}After={{ value }} +{% endfor %} +{% for value in omero_web_systemd_requires %}Requires={{ value }} +{% endfor %} + +[Service] +User={{ omero_web_system_user }} +Type=forking +PIDFile={{ omero_web_omerodir }}/var/django.pid +Restart=no +RestartSec=10 +ExecStartPre={{ omero_web_config_update }} +ExecStart={{ omero_web_omero_command }} web start +ExecStop={{ omero_web_omero_command }} web stop +{% if omero_web_systemd_limit_nofile %} +LimitNOFILE={{ omero_web_systemd_limit_nofile }} +{% endif %} + +[Install] +WantedBy=multi-user.target diff --git a/omero/roles/ome.postgresql/.github/workflows/molecule.yml b/omero/roles/ome.postgresql/.github/workflows/molecule.yml new file mode 100644 index 00000000..1fa548c2 --- /dev/null +++ b/omero/roles/ome.postgresql/.github/workflows/molecule.yml @@ -0,0 +1,54 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v3 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: pip install "ansible<8" ansible-lint flake8 \ + "molecule<5" molecule-plugins[docker] pytest-testinfra \ + "ansible-compat<4" + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: ansible-actions/ansible-galaxy-action@v1.2.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + galaxy_version: ${{ github.ref_name }} diff --git a/omero/roles/ome.postgresql/.gitignore b/omero/roles/ome.postgresql/.gitignore new file mode 100644 index 00000000..97752ea8 --- /dev/null +++ b/omero/roles/ome.postgresql/.gitignore @@ -0,0 +1,4 @@ +.*~ +*.pyc +.molecule +.vagrant diff --git a/omero/roles/ome.postgresql/CHANGES.md b/omero/roles/ome.postgresql/CHANGES.md new file mode 100644 index 00000000..5de3cdc0 --- /dev/null +++ b/omero/roles/ome.postgresql/CHANGES.md @@ -0,0 +1,35 @@ +# Changes in Version 5 + +## Summary of breaking changes + +- PostgreSQL 11 is no longer supported by this role. +- PostgreSQL 9.5 is no longer supported by this role. +- `postgresql_install_server` is removed, the server is always configured, use `ome.postgresql_client` to install just the client. +- `postgresql_install_extensions` is removed, extension packages are always installed. + + +# Changes in Version 4 + +## Summary of breaking changes + +- `postgresql_version` is now a required variable. The previous default of "9.4" is no longer supported. + + See [README.md](README.md) for full documentation + +# Changes in Version 3 + +## Summary of breaking changes + +- `postgresql.conf` is templated instead of making in-line modifications to the distribution configuration +- `CONNECT` and `public` schema `USAGE` privileges are explicitly granted to database users +- `postgresql_users_databases` has been replaced by two variables which are both required + - `postgresql_databases`: The databases to be created + - `postgresql_users`: The users to be created, and the databases they have access to + + See [README.md](README.md) for full documentation + + +# Changes in Version 2 + +## Summary of breaking changes +- PostgreSQL 9.3 is no longer supported diff --git a/omero/roles/ome.postgresql/LICENSE.md b/omero/roles/ome.postgresql/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.postgresql/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.postgresql/README.md b/omero/roles/ome.postgresql/README.md new file mode 100644 index 00000000..4ec4136d --- /dev/null +++ b/omero/roles/ome.postgresql/README.md @@ -0,0 +1,112 @@ +Postgresql +========== + +[![Actions Status](https://github.com/ome/ansible-role-postgresql/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-postgresql/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-postgresql-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/postgresql/) + +Install upstream PostgreSQL server. + +Optionally creates users and databases. +If you wish to use your distribution's packages then do not use this role. +This role revokes default `PUBLIC` privileges from database and `public` schema for all supported versions of PostgreSQL. +This is to be inline with the breaking change made in PostgreSQL 15. + +Role Variables +-------------- + +Defaults: `defaults/main.yml` + +- `postgresql_version`: The PostgreSQL major version: `12`, `13`, `14`, `15`, `16` +- `postgresql_package_version`: The PostgreSQL full version, leave this empty to use the latest minor release from `postgresql_version`, ignored on Ubuntu +- `postgresql_dist_redhat` or `postgresql_dist_debian`: Object that define configuration attributes for PostgreSQL on each specific OS, these variables allow to change the interaction between variables defined at [ome.postgresql](https://galaxy.ansible.com/ome/postgresql) and [ome.postgresql_client](https://github.com/ome/ansible-role-postgresql-client) + +The following parameters will be ignored if `postgresql_install_server: False`: +- `postgresql_databases`: List of dictionaries of databases. + Items should be of the form: + - `name`: Database name + - `owner`: Owner role (optional) + - `lc_collate`: Collation order (LC_COLLATE) to use in the database + - `lc_ctype`: Character classification (LC_CTYPE) to use in the database + - `encoding`: Encoding of the database, default `UTF-8` + - `template`: Template used to create the database +- `postgresql_users`: List of dictionaries of users. + Items should be of the form: + - `user`: Database username + - `password`: Database user password + - `databases`: List of databases that user can connect to, required but can be empty `[]` + - `roles`: Role attribute flags, optional + If you want the user to have restricted access see the section below on Restricted users. +- `postgresql_server_listen`: Listen on these interfaces, default `localhost`, use `'*'` for all +- `postgresql_server_conf`: Dictionary of additional postgresql.conf options +- `postgresql_server_auth_local`: Whether to allow the default postgres local authentication (default `True`) +- `postgresql_server_auth`: List of dictionaries of authorisation parameters, if omitted the default local authentication only will be enabled. Items should be of the form: + - `database`: Name of the database + - `user`: Username + - `address`: Address from which connections will be made + - `method`: Ignore this unless you really know what you are doing +- `postgresql_server_chown_datadir`: If `True` recursively reset the owner and group of the postgres datadir, default `False`, use this when you have an existing datadir with incorrect owner/group + + +Restricted databases +-------------------- + +In general it is not possible to create users with restricted access (e.g. read-only users) until a schema has been populated. +This role removes the default PUBLIC privileges from all databases, then grants: +- `ALL` privileges to the database owner if specified (`postgresql_databases[].owner`) +- `CONNECT` privilege to the database, and `USAGE` privilege on the `public` schema, to databases listed for each user (`postgresql_users[].databases`) + +If you wish to created a restricted user set the `databases` field in `postgresql_users` to `[]`, and use the [Ansible `postgresql_privs`](http://docs.ansible.com/ansible/latest/postgresql_privs_module.html) module to grant access after the database schema has been created. + +An example can be seen in [`playbook.yml`](playbook.yml). + +Limitations +----------- + +The role assumes the PSQL cluster will be installed in the default data directory +of the Linux distribution and this directory is not configurable as of the current +version. + +Example Playbook +---------------- + + # Simple example relying on the default Postgres PUBLIC privileges + # which allow access to all users + - hosts: localhost + roles: + - role: postgresql + postgresql_server_listen: "'*'" + postgresql_server_auth: + - database: publicdb + user: alice + address: 192.168.1.0/24 + postgresql_databases: + - name: publicdb + postgresql_users: + - user: alice + password: alice123 + databases: [] + + + # Advanced example with no default access to databases + # This sets up minimal privileges for `bob`, you will need to configure + # additional privileges yourself + - hosts: localhost + roles: + - postgresql + vars: + - postgresql_databases: + - name: secretdb + owner: alice + - postgresql_users: + - user: alice + password: alice123 + databases: [secretdb] + - user: bob + password: bob123 + databases: [] + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.postgresql/defaults/main.yml b/omero/roles/ome.postgresql/defaults/main.yml new file mode 100644 index 00000000..c3eb0e22 --- /dev/null +++ b/omero/roles/ome.postgresql/defaults/main.yml @@ -0,0 +1,64 @@ +--- +# defaults file for ome.postgresql + +# The PostgreSQL major version, required +# postgresql_version + +# Full package version of postgres, see ome.postgresql_client +postgresql_package_version: '' + +# OS system user to become when become_user: is defined +postgresql_become_user: postgres + +# List of dictionaries of databases +postgresql_databases: [] + +# List of dictionaries of users +postgresql_users: [] + +# Network interfaces to listen on +postgresql_server_listen: localhost + +# Dictionary of additional postgresql.conf options +postgresql_server_conf: {} + +# Whether to enable the default local authentication methods +postgresql_server_auth_local: true + +# List of dictionaries of client authorisation lines +postgresql_server_auth: [] + +# Recursively reset the owner/group of the postgres datadir? +postgresql_server_chown_datadir: false + +###################################################################### +# Internal role variables, do not modify +###################################################################### + +# Attributes are parsed and used to set facts at tasks/redhat.yml. +# Overriding the default values allow to configure future versions of +# PostgreSQL, e.g. different paths according to the version, config, etc. +postgresql_dist_redhat: + bindir: /usr/pgsql-{{ postgresql_version }}/bin + confdir: /var/lib/pgsql/{{ postgresql_version }}/data + conf_postgresql_src: postgresql-conf.j2 + datadir: /var/lib/pgsql/{{ postgresql_version }}/data + basename: postgresql{{ postgresql_version }} + repoid: pgdg{{ postgresql_version }} + setupname: postgresql-{{ postgresql_version }}-setup + service: postgresql-{{ postgresql_version }} + version_suffix: >- + {{ + (postgresql_package_version | length > 0) | + ternary('-' + postgresql_package_version, '') + }} + +# Attributes are parsed and used to set facts at tasks/debian.yml. +# Debian variation, following the same principles of postgresql_dist_redhat +postgresql_dist_debian: + bindir: /usr/lib/postgresql/{{ postgresql_version }}/bin + confdir: /etc/postgresql/{{ postgresql_version }}/main + conf_postgresql_src: postgresql-conf-10-ubuntu.j2 + datadir: /var/lib/postgresql/{{ postgresql_version }}/main + basename: postgresql-{{ postgresql_version }} + service: postgresql diff --git a/omero/roles/ome.postgresql/handlers/main.yml b/omero/roles/ome.postgresql/handlers/main.yml new file mode 100644 index 00000000..0dd0ae3f --- /dev/null +++ b/omero/roles/ome.postgresql/handlers/main.yml @@ -0,0 +1,8 @@ +--- +# Handler for postgresql + +- name: restart postgresql + become: true + service: + name: "{{ postgresql_dist_service }}" + state: restarted diff --git a/omero/roles/ome.postgresql/meta/.galaxy_install_info b/omero/roles/ome.postgresql/meta/.galaxy_install_info new file mode 100644 index 00000000..6e156878 --- /dev/null +++ b/omero/roles/ome.postgresql/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:45 2024 +version: 5.4.0 diff --git a/omero/roles/ome.postgresql/meta/main.yml b/omero/roles/ome.postgresql/meta/main.yml new file mode 100644 index 00000000..5370fb34 --- /dev/null +++ b/omero/roles/ome.postgresql/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Upstream PostgreSQL server + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + role_name: postgresql + galaxy_tags: ['postgresql', 'database'] diff --git a/omero/roles/ome.postgresql/meta/requirements.yml b/omero/roles/ome.postgresql/meta/requirements.yml new file mode 100644 index 00000000..e2a700a1 --- /dev/null +++ b/omero/roles/ome.postgresql/meta/requirements.yml @@ -0,0 +1,2 @@ +--- +- src: ome.postgresql_client diff --git a/omero/roles/ome.postgresql/molecule/resources/playbook.yml b/omero/roles/ome.postgresql/molecule/resources/playbook.yml new file mode 100644 index 00000000..208d4f8c --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/resources/playbook.yml @@ -0,0 +1,71 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.postgresql + postgresql_databases: + - name: publicdb + - name: secretdb + owner: alice + postgresql_users: + - user: alice + password: alice123 + # alice is the owner of secretdb so already has access + databases: [publicdb] + - user: bob + password: bob123 + databases: [publicdb, secretdb] + roles: "CREATEDB,NOSUPERUSER" + - user: charles + password: charles123 + databases: [] + - user: tester + password: tester123 + databases: [] + roles: "SUPERUSER" + +- hosts: all + tasks: + - name: create test tables publicdb + command: > + env PGPASSWORD=tester123 psql -h localhost -U tester publicdb + -c "{{ item }}" + register: result + changed_when: > + (not ('skipping' in result.stderr or '0 0' in result.stdout)) + with_items: + - "create table if not exists regular (text text primary key);" + - > + insert into regular select ('clear text') where not exists + (select text from regular); + + - name: create test tables secretdb + command: >- + env PGPASSWORD=alice123 psql -h localhost -U alice secretdb + -c "{{ item }}" + register: result + changed_when: > + (not ('skipping' in result.stderr or '0 0' in result.stdout)) + with_items: + - "create table if not exists regular (text text primary key);" + - > + insert into regular select ('clear text') where not exists + (select text from regular); + - "create table if not exists password (text text primary key);" + - > + insert into password select ('PRIVATE!') where not exists + (select text from password); + + - name: set privileges on secretdb tables + become: true + become_user: postgres + postgresql_privs: + database: "{{ item }}" + obj: regular + privs: SELECT + roles: bob + state: present + type: table + with_items: + - publicdb + - secretdb diff --git a/omero/roles/ome.postgresql/molecule/resources/requirements.yml b/omero/roles/ome.postgresql/molecule/resources/requirements.yml new file mode 100644 index 00000000..e2a700a1 --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/resources/requirements.yml @@ -0,0 +1,2 @@ +--- +- src: ome.postgresql_client diff --git a/omero/roles/ome.postgresql/molecule/resources/tests/test_default.py b/omero/roles/ome.postgresql/molecule/resources/tests/test_default.py new file mode 100644 index 00000000..35d9a648 --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/resources/tests/test_default.py @@ -0,0 +1,188 @@ +import os +import pytest +import testinfra.utils.ansible_runner +import uuid +from re import match +from utils import get_version + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +# Server + +@pytest.mark.parametrize("name,expected_db", [ + ('publicdb', 'publicdb|{lang}.UTF-8|{lang}.UTF-8'), + ('secretdb', 'secretdb|{lang}.UTF-8|{lang}.UTF-8') +]) +def test_databases(host, name, expected_db): + sql = ("SELECT datname,datcollate,datctype FROM pg_database " + "WHERE datname='%s'" % name) + with host.sudo('postgres'): + out = host.check_output('psql postgres -c "%s" -At' % sql) + + if host.system_info.distribution == 'rocky': + lang = 'en_US' + else: + lang = 'C' + assert out == expected_db.format(lang=lang) + + +def test_server_listen(host): + version = get_version(host) + if host.system_info.distribution == 'rocky': + configfile = '/var/lib/pgsql/{version}/data/postgresql.conf' + else: + configfile = '/etc/postgresql/{version}/main/postgresql.conf' + with host.sudo(): + value = configfile.format(version=version) + f = host.file(value).content_string + + count_listen_addresses = 0 + for line in f.split('\n'): + if match(r'\s*listen_addresses', line): + count_listen_addresses += 1 + listen_addresses = line + assert count_listen_addresses == 1 + + assert listen_addresses == "listen_addresses = localhost" + + +def test_psql_version(host): + ver = get_version(host) + out = host.check_output('psql --version') + assert out.startswith('psql (PostgreSQL) {}.'.format(ver)) + + +# Create + +def createdb(host, db, should_pass, password, name): + try: + host.check_output( + 'env PGPASSWORD=%s createdb -h localhost -U %s "%s"' % + (password, name, db)) + assert should_pass + except Exception: + assert not should_pass + + +@pytest.mark.parametrize("name,password,should_pass", [ + ('tester', 'tester123', True), + ('alice', 'alice123', False), + ('bob', 'bob123', True), + ('charles', 'charles123', False), +]) +def test_create(host, name, password, should_pass): + rnd = str(uuid.uuid4()) + createdb(host, rnd, should_pass, password, name) + + +# Privileges + +def psql(host, database, sql, name): + password = name + '123' + return host.run( + 'env PGPASSWORD=%s psql %s -h localhost -U %s -c "%s" -At' % + (password, database, name, sql)) + + +@pytest.mark.parametrize("name,expected_roles", [ + ('tester', 'tester|t|t|f|f|t|f|-1|********||f||'), + ('alice', 'alice|f|t|f|f|t|f|-1|********||f||'), + ('bob', 'bob|f|t|f|t|t|f|-1|********||f||'), +]) +def test_user_roles(host, name, expected_roles): + sql = "SELECT * FROM pg_roles WHERE rolname='%s'" % name + with host.sudo('postgres'): + out = host.check_output('psql postgres -c "%s" -At' % sql) + # Everything except the UID at the end + assert out.startswith(expected_roles) + + +# Owner and users with SELECT privileges can read +@pytest.mark.parametrize("name,database,table,should_pass", [ + ('tester', 'publicdb', "regular", True), + ('tester', 'secretdb', "regular", True), + ('tester', 'secretdb', "password", True), + + ('alice', 'publicdb', "regular", False), + ('alice', 'secretdb', "regular", True), + ('alice', 'secretdb', "password", True), + + ('bob', 'publicdb', "regular", True), + ('bob', 'secretdb', "regular", True), + ('bob', 'secretdb', "password", False), + + ('charles', 'publicdb', "regular", False), + ('charles', 'secretdb', "regular", False), + ('charles', 'secretdb', "password", False), +]) +def test_select(host, name, database, table, should_pass): + sql = "SELECT * FROM " + table + c = psql(host, database, sql, name) + if should_pass: + assert c.rc == 0 + else: + assert c.rc > 0 + assert 'permission denied' in c.stderr + + +@pytest.mark.parametrize("name,database,should_pass", [ + ('tester', 'publicdb', True), + ('tester', 'secretdb', True), + + ('alice', 'publicdb', False), + ('alice', 'secretdb', True), + + ('bob', 'publicdb', False), + ('bob', 'secretdb', False), + + ('charles', 'publicdb', False), + ('charles', 'secretdb', False), +]) +def test_create_table(host, name, database, should_pass): + rnd = 'table_' + str(uuid.uuid4()).replace('-', '') + sql = "CREATE TABLE %s (text text primary key);" % rnd + c = psql(host, database, sql, name) + if should_pass: + assert c.rc == 0 + assert 'CREATE TABLE' in c.stdout + else: + assert c.rc > 0 + + +@pytest.mark.parametrize("name,database,table,should_pass", [ + ('tester', 'publicdb', "regular", True), + ('tester', 'secretdb', "regular", True), + ('tester', 'secretdb', "password", True), + + ('alice', 'publicdb', "regular", False), + ('alice', 'secretdb', "regular", True), + ('alice', 'secretdb', "password", True), + + ('bob', 'publicdb', "regular", False), + ('bob', 'secretdb', "regular", False), + ('bob', 'secretdb', "password", False), + + ('charles', 'publicdb', "regular", False), + ('charles', 'secretdb', "regular", False), + ('charles', 'secretdb', "password", False), +]) +def test_modify(host, name, database, table, should_pass): + rnd = str(uuid.uuid4()) + + sql = "insert into %s values ('%s')" % (table, rnd) + c = psql(host, database, sql, name) + if should_pass: + assert c.rc == 0 + else: + assert c.rc > 0 + assert 'permission denied' in c.stderr + + sql = "delete from %s" % table + c = psql(host, database, sql, name) + if should_pass: + assert c.rc == 0 + else: + assert c.rc > 0 + assert 'permission denied' in c.stderr diff --git a/omero/roles/ome.postgresql/molecule/resources/tests/test_extra_options.py b/omero/roles/ome.postgresql/molecule/resources/tests/test_extra_options.py new file mode 100644 index 00000000..4e6feb71 --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/resources/tests/test_extra_options.py @@ -0,0 +1,34 @@ +import os +import testinfra.utils.ansible_runner +from datetime import datetime, timedelta +from utils import get_version + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('extra_options') + + +def test_server_additional_config(host): + version = get_version(host) + if host.system_info.distribution == 'rocky': + configfile = '/var/lib/pgsql/{version}/data/postgresql.conf' + else: + configfile = '/etc/postgresql/{version}/main/postgresql.conf' + f = host.file(configfile.format(version=version)).content_string + lines = f.split('\n') + assert "shared_preload_libraries = 'pg_stat_statements'" in lines + assert "log_filename = 'postgresql-%F.log'" in lines + + +def test_server_log_file_name(host): + # Check previous day too in case this is run at midnight + version = get_version(host) + if host.system_info.distribution == 'rocky': + logdir = '/var/lib/pgsql/{version}/data/pg_log' + else: + logdir = '/var/lib/postgresql/{version}/main/pg_log' + date1 = datetime.today() + date0 = date1 - timedelta(days=1) + logdir = logdir.format(version=version) + file1 = '%s/postgresql-%s.log' % (logdir, date1.strftime('%F')) + file0 = '%s/postgresql-%s.log' % (logdir, date0.strftime('%F')) + assert host.file(file1).is_file or host.file(file0).is_file diff --git a/omero/roles/ome.postgresql/molecule/resources/tests/utils.py b/omero/roles/ome.postgresql/molecule/resources/tests/utils.py new file mode 100644 index 00000000..d2368726 --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/resources/tests/utils.py @@ -0,0 +1,3 @@ +def get_version(host): + variables = host.ansible.get_variables() + return variables["postgresql_version"] diff --git a/omero/roles/ome.postgresql/molecule/rockylinux9/molecule.yml b/omero/roles/ome.postgresql/molecule/rockylinux9/molecule.yml new file mode 100644 index 00000000..8334ce49 --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/rockylinux9/molecule.yml @@ -0,0 +1,90 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: postgresql-12-r9 + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: postgresql-13-r9 + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: postgresql-14-r9 + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: postgresql-15-r9 + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: postgresql-16-r9 + image: eniocarboni/docker-rockylinux-systemd:9 + image_version: latest + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint + inventory: + host_vars: + postgresql-12-r9: + postgresql_version: "12" + postgresql-13-r9: + postgresql_version: "13" + postgresql-14-r9: + postgresql_version: "14" + postgresql-15-r9: + postgresql_version: "15" + postgresql-16-r9: + postgresql_version: "16" + group_vars: + extra_options: + postgresql_server_conf: + shared_preload_libraries: "'pg_stat_statements'" + log_filename: "'postgresql-%F.log'" + playbooks: + converge: ../resources/playbook.yml +scenario: + name: rockylinux9 +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.postgresql/molecule/rockylinux9/prepare.yml b/omero/roles/ome.postgresql/molecule/rockylinux9/prepare.yml new file mode 100644 index 00000000..faebe092 --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/rockylinux9/prepare.yml @@ -0,0 +1,11 @@ +--- + +- name: Prepare all + hosts: all + tasks: + - name: Upgrade ca-certificates + ansible.builtin.dnf: + update_cache: true + pkg: + - ca-certificates + state: latest diff --git a/omero/roles/ome.postgresql/molecule/ubuntu2204/molecule.yml b/omero/roles/ome.postgresql/molecule/ubuntu2204/molecule.yml new file mode 100644 index 00000000..89a9e5ed --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/ubuntu2204/molecule.yml @@ -0,0 +1,80 @@ +--- +dependency: + name: galaxy + options: + role-file: molecule/resources/requirements.yml +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: postgresql-12-u2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + - name: postgresql-13-u2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + - name: postgresql-14-u2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + - name: postgresql-15-u2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + - name: postgresql-16-u2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup +provisioner: + name: ansible + lint: + name: ansible-lint + inventory: + host_vars: + postgresql-12-u2204: + postgresql_version: "12" + ansible_python_interpreter: /usr/bin/python3 + postgresql-13-u2204: + postgresql_version: "13" + ansible_python_interpreter: /usr/bin/python3 + postgresql-14-u2204: + postgresql_version: "14" + ansible_python_interpreter: /usr/bin/python3 + postgresql-15-u2204: + postgresql_version: "15" + ansible_python_interpreter: /usr/bin/python3 + postgresql-16-u2204: + postgresql_version: "16" + ansible_python_interpreter: /usr/bin/python3 + group_vars: + extra_options: + postgresql_server_conf: + shared_preload_libraries: "'pg_stat_statements'" + log_filename: "'postgresql-%F.log'" + playbooks: + converge: ../resources/playbook.yml +scenario: + name: ubuntu2204 +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.postgresql/molecule/ubuntu2204/prepare.yml b/omero/roles/ome.postgresql/molecule/ubuntu2204/prepare.yml new file mode 100644 index 00000000..6397a7f0 --- /dev/null +++ b/omero/roles/ome.postgresql/molecule/ubuntu2204/prepare.yml @@ -0,0 +1,7 @@ +--- + +- name: Prepare all + hosts: all + tasks: + - ansible.builtin.apt: + update_cache: true diff --git a/omero/roles/ome.postgresql/tasks/databases.yml b/omero/roles/ome.postgresql/tasks/databases.yml new file mode 100644 index 00000000..eb9a9be9 --- /dev/null +++ b/omero/roles/ome.postgresql/tasks/databases.yml @@ -0,0 +1,113 @@ +--- +# Manage local databases and users +# This only works where the local system `postgres` user has admin rights + +- block: + - name: postgres | create users + postgresql_user: + encrypted: true + name: "{{ item.user }}" + password: "{{ item.password }}" + role_attr_flags: "{{ item.roles | default(omit) }}" + state: present + with_items: + - "{{ postgresql_users }}" + + - name: postgres | create databases + postgresql_db: + name: "{{ item.name }}" + owner: "{{ item.owner | default(omit) }}" + state: present + lc_collate: "{{ item.lc_collate | default(omit) }}" + lc_ctype: "{{ item.lc_ctype | default(omit) }}" + encoding: "{{ item.encoding | default('UTF-8') }}" + template: "{{ item.template | default(omit) }}" + with_items: + - "{{ postgresql_databases }}" + + # Setting privileges is complicated: + # - https://stackoverflow.com/a/39029296 + + # From https://www.postgresql.org/docs/9.6/static/sql-grant.html: + # + # "The key word PUBLIC indicates that the privileges are to be granted to + # all roles, including those that might be created later. PUBLIC can be + # thought of as an implicitly defined group that always includes all roles. + # Any particular role will have the sum of privileges granted directly to + # it, privileges granted to any role it is presently a member of, and + # privileges granted to PUBLIC." + # + # "There is no need to grant privileges to the owner of an object (usually + # the user that created it), as the owner has all privileges by default. + # (The owner could, however, choose to revoke some of their own privileges + # for safety.)" + # + # "PostgreSQL grants default privileges on some types of objects to PUBLIC. + # No privileges are granted to PUBLIC by default on tables, columns, schemas + # or tablespaces. For other types, the default privileges granted to PUBLIC + # are as follows: CONNECT and CREATE TEMP TABLE for databases; EXECUTE + # privilege for functions; and USAGE privilege for languages." + + - name: postgres | revoke default permissions + postgresql_privs: + database: "{{ item.name }}" + privs: ALL + roles: PUBLIC + state: absent + type: database + with_items: + - "{{ postgresql_databases }}" + changed_when: false + + # Revoke the default permissions on the public schema + - name: postgres | revoke default schema permissions + postgresql_privs: + database: "{{ item.name }}" + obj: public + privs: ALL + roles: PUBLIC + state: absent + type: schema + with_items: + - "{{ postgresql_databases }}" + changed_when: false + + # The default public schema is owned by postgres, and since the PUBLIC + # privileges are revoked we must grant them back to the owner + - name: postgres | grant database owner public schema privileges + postgresql_privs: + database: "{{ item.name }}" + obj: public + privs: ALL + roles: "{{ item.owner }}" + state: present + type: schema + when: item.owner is defined + with_items: + - "{{ postgresql_databases }}" + + - name: postgres | grant connect privileges + postgresql_privs: + database: "{{ item.1 }}" + privs: CONNECT + roles: "{{ item.0.user }}" + state: present + type: database + with_subelements: + - "{{ postgresql_users }}" + - databases + + - name: postgres | grant usage privileges on default public schema + postgresql_privs: + database: "{{ item.1 }}" + objs: public + privs: USAGE + roles: "{{ item.0.user }}" + state: present + type: schema + with_subelements: + - "{{ postgresql_users }}" + - databases + + become: true + become_user: "{{ postgresql_become_user }}" diff --git a/omero/roles/ome.postgresql/tasks/debian.yml b/omero/roles/ome.postgresql/tasks/debian.yml new file mode 100644 index 00000000..b980694d --- /dev/null +++ b/omero/roles/ome.postgresql/tasks/debian.yml @@ -0,0 +1,31 @@ +--- +# tasks file for ome.postgresql ubuntu + +- name: postgres | install packages + become: true + ansible.builtin.apt: + update_cache: true + name: >- + {{ postgresql_dist_debian.basename }} + state: present + +- name: postgres | install ansible prerequisites + become: true + ansible.builtin.apt: + update_cache: true + # Needs to match the Ansible interpreter + name: >- + python{{ + ansible_python_version is version('3.0.0', '<') | ternary('', '3') + }}-psycopg2 + state: present + +- name: postgres | set debian dist variables + set_fact: + postgresql_dist_datadir: "{{ postgresql_dist_debian.datadir }}" + postgresql_dist_bindir: "{{ postgresql_dist_debian.bindir }}" + postgresql_dist_confdir: "{{ postgresql_dist_debian.confdir }}" + postgresql_dist_setup: "{{ postgresql_dist_debian.bindir }}/initdb" + postgresql_dist_service: "{{ postgresql_dist_debian.service }}" + postgresql_dist_conf_postgresql_src: >- + {{ postgresql_dist_debian.conf_postgresql_src }} diff --git a/omero/roles/ome.postgresql/tasks/initialise.yml b/omero/roles/ome.postgresql/tasks/initialise.yml new file mode 100644 index 00000000..bfff92bf --- /dev/null +++ b/omero/roles/ome.postgresql/tasks/initialise.yml @@ -0,0 +1,52 @@ +--- +# tasks file for ome.postgresql + +- block: + - name: postgres | set permissions on data directory + file: + owner: postgres + group: postgres + path: "{{ postgresql_dist_datadir }}" + state: directory + mode: 0700 + when: postgresql_server_chown_datadir + + - name: >- + postgres | initialise PostgreSQL cluster (skip if data directory + already exists) + command: "{{ postgresql_dist_setup }}" + args: + creates: "{{ postgresql_dist_datadir }}/PG_VERSION" + + environment: + PGSETUP_INITDB_OPTIONS: >- + --encoding=UTF8 --locale=en_US.UTF-8 --auth-host=md5 + + - name: postgres | postgresql config file + template: + dest: >- + {{ postgresql_dist_confdir }}/postgresql.conf + src: "{{ postgresql_dist_conf_postgresql_src }}" + mode: 0644 + notify: + - restart postgresql + + become_user: "{{ postgresql_become_user }}" + + - name: postgres | configure client authorisation + template: + dest: "{{ postgresql_dist_confdir }}/pg_hba.conf" + src: pg_hba-conf.j2 + mode: 0640 + notify: + - restart postgresql + + become_user: "{{ postgresql_become_user }}" + + - name: postgres | start service + service: + enabled: true + name: "{{ postgresql_dist_service }}" + state: started + + become: true diff --git a/omero/roles/ome.postgresql/tasks/main.yml b/omero/roles/ome.postgresql/tasks/main.yml new file mode 100644 index 00000000..ed0f6761 --- /dev/null +++ b/omero/roles/ome.postgresql/tasks/main.yml @@ -0,0 +1,29 @@ +--- +- name: postgres | Include ome.postgresql_client role + include_role: + name: ome.postgresql_client + +# tasks file for ome.postgresql +- name: postgres | fail if postgresql_users_databases defined + fail: + msg: > + Variable 'postgresql_users_databases' has been replaced by + 'postgresql_databases' and 'postgresql_users' + when: "postgresql_users_databases | default(False)" + +- name: postgres | fail if postgresql_install_server true + fail: + msg: > + Variable 'postgresql_install_server=false' has been replaced by the + 'ome.postgresql_client' role + when: "not (postgresql_install_server | default(True))" + +- import_tasks: redhat.yml + when: ansible_os_family | lower == 'redhat' + +- import_tasks: debian.yml + when: ansible_os_family | lower == 'debian' + +- import_tasks: initialise.yml + +- import_tasks: databases.yml diff --git a/omero/roles/ome.postgresql/tasks/redhat.yml b/omero/roles/ome.postgresql/tasks/redhat.yml new file mode 100644 index 00000000..4f6d9733 --- /dev/null +++ b/omero/roles/ome.postgresql/tasks/redhat.yml @@ -0,0 +1,50 @@ +--- +# tasks file for ome.postgresql rocky + +- name: postgres | install server packages + become: true + ansible.builtin.dnf: + update_cache: true + name: >- + {{ postgresql_dist_redhat.basename }}-server{{ + postgresql_dist_redhat.version_suffix }} + state: present + +- name: postgres | install extension packages + become: true + ansible.builtin.dnf: + update_cache: true + name: >- + {{ postgresql_dist_redhat.basename }}-contrib{{ + postgresql_dist_redhat.version_suffix }} + state: present + +- name: postgres | install ansible prerequisites + become: true + ansible.builtin.dnf: + update_cache: true + # Needs to match the Ansible interpreter + name: >- + python{{ + ansible_python_version is version('3.0.0', '<') | ternary('2', '3') + }}-psycopg2 + state: present + +- name: get langpack for en + become: true + ansible.builtin.dnf: + update_cache: true + name: glibc-langpack-en + state: present + +- name: postgres | set redhat dist variables + set_fact: + postgresql_dist_datadir: "{{ postgresql_dist_redhat.datadir }}" + postgresql_dist_bindir: "{{ postgresql_dist_redhat.bindir }}" + postgresql_dist_confdir: "{{ postgresql_dist_redhat.confdir }}" + postgresql_dist_setup: >- + {{ postgresql_dist_redhat.bindir }}/{{ postgresql_dist_redhat.setupname }} + initdb + postgresql_dist_service: "{{ postgresql_dist_redhat.service }}" + postgresql_dist_conf_postgresql_src: >- + {{ postgresql_dist_redhat.conf_postgresql_src }} diff --git a/omero/roles/ome.postgresql/templates/pg_hba-conf.j2 b/omero/roles/ome.postgresql/templates/pg_hba-conf.j2 new file mode 100644 index 00000000..328c05fe --- /dev/null +++ b/omero/roles/ome.postgresql/templates/pg_hba-conf.j2 @@ -0,0 +1,11 @@ +# PostgreSQL Client Authentication Configuration File (Ansible) +# TYPE DATABASE USER ADDRESS METHOD +{% if postgresql_server_auth_local %} +local all all peer +host all all 127.0.0.1/32 md5 +host all all ::1/128 md5 +{% endif %} + +{% for item in postgresql_server_auth %} +host {{ item.database }} {{ item.user }} {{ item.address }} {{ item.method | default("md5") }} +{% endfor %} diff --git a/omero/roles/ome.postgresql/templates/postgresql-conf-10-ubuntu.j2 b/omero/roles/ome.postgresql/templates/postgresql-conf-10-ubuntu.j2 new file mode 100644 index 00000000..06dc4aaa --- /dev/null +++ b/omero/roles/ome.postgresql/templates/postgresql-conf-10-ubuntu.j2 @@ -0,0 +1,673 @@ +# ----------------------------- +# PostgreSQL configuration file +# ----------------------------- +# +# This file consists of lines of the form: +# +# name = value +# +# (The "=" is optional.) Whitespace may be used. Comments are introduced with +# "#" anywhere on a line. The complete list of parameter names and allowed +# values can be found in the PostgreSQL documentation. +# +# The commented-out settings shown in this file represent the default values. +# Re-commenting a setting is NOT sufficient to revert it to the default value; +# you need to reload the server. +# +# This file is read on server startup and when the server receives a SIGHUP +# signal. If you edit the file on a running system, you have to SIGHUP the +# server for the changes to take effect, run "pg_ctl reload", or execute +# "SELECT pg_reload_conf()". Some parameters, which are marked below, +# require a server shutdown and restart to take effect. +# +# Any parameter can also be given as a command-line option to the server, e.g., +# "postgres -c log_connections=on". Some parameters can be changed at run time +# with the "SET" SQL command. +# +# Memory units: kB = kilobytes Time units: ms = milliseconds +# MB = megabytes s = seconds +# GB = gigabytes min = minutes +# TB = terabytes h = hours +# d = days + + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +# The default values of these variables are driven from the -D command-line +# option or PGDATA environment variable, represented here as ConfigDir. + +data_directory = '/var/lib/postgresql/{{ postgresql_version }}/main' # use data in another directory + # (change requires restart) +hba_file = '/etc/postgresql/{{ postgresql_version }}/main/pg_hba.conf' # host-based authentication file + # (change requires restart) +ident_file = '/etc/postgresql/{{ postgresql_version }}/main/pg_ident.conf' # ident configuration file + # (change requires restart) + +# If external_pid_file is not explicitly set, no extra PID file is written. +external_pid_file = '/var/run/postgresql/{{ postgresql_version }}-main.pid' # write an extra PID file + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +#listen_addresses = 'localhost' # what IP address(es) to listen on; + # comma-separated list of addresses; + # defaults to 'localhost'; use '*' for all + # (change requires restart) +port = 5432 # (change requires restart) +max_connections = 100 # (change requires restart) +#superuser_reserved_connections = 3 # (change requires restart) +unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories + # (change requires restart) +#unix_socket_group = '' # (change requires restart) +#unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +#bonjour = off # advertise server via Bonjour + # (change requires restart) +#bonjour_name = '' # defaults to the computer name + # (change requires restart) + +# - Security and Authentication - + +#authentication_timeout = 1min # 1s-600s +ssl = on +#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers +#ssl_prefer_server_ciphers = on +#ssl_ecdh_curve = 'prime256v1' +#ssl_dh_params_file = '' +ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem' +ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key' +#ssl_ca_file = '' +#ssl_crl_file = '' +#password_encryption = md5 # md5 or scram-sha-256 +#db_user_namespace = off +#row_security = on + +# GSSAPI using Kerberos +#krb_server_keyfile = '' +#krb_caseins_users = off + +# - TCP Keepalives - +# see "man 7 tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default + + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +shared_buffers = 128MB # min 128kB + # (change requires restart) +#huge_pages = try # on, off, or try + # (change requires restart) +#temp_buffers = 8MB # min 800kB +#max_prepared_transactions = 0 # zero disables the feature + # (change requires restart) +# Caution: it is not advisable to set max_prepared_transactions nonzero unless +# you actively intend to use prepared transactions. +#work_mem = 4MB # min 64kB +#maintenance_work_mem = 64MB # min 1MB +#replacement_sort_tuples = 150000 # limits use of replacement selection sort +#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem +#max_stack_depth = 2MB # min 100kB +dynamic_shared_memory_type = posix # the default is the first option + # supported by the operating system: + # posix + # sysv + # windows + # mmap + # use none to disable dynamic shared memory + # (change requires restart) + +# - Disk - + +#temp_file_limit = -1 # limits per-process temp file space + # in kB, or -1 for no limit + +# - Kernel Resource Usage - + +#max_files_per_process = 1000 # min 25 + # (change requires restart) +#shared_preload_libraries = '' # (change requires restart) + +# - Cost-Based Vacuum Delay - + +#vacuum_cost_delay = 0 # 0-100 milliseconds +#vacuum_cost_page_hit = 1 # 0-10000 credits +#vacuum_cost_page_miss = 10 # 0-10000 credits +#vacuum_cost_page_dirty = 20 # 0-10000 credits +#vacuum_cost_limit = 200 # 1-10000 credits + +# - Background Writer - + +#bgwriter_delay = 200ms # 10-10000ms between rounds +#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round +#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round +#bgwriter_flush_after = 512kB # measured in pages, 0 disables + +# - Asynchronous Behavior - + +#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching +#max_worker_processes = 8 # (change requires restart) +#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers +#max_parallel_workers = 8 # maximum number of max_worker_processes that + # can be used in parallel queries +#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate + # (change requires restart) +#backend_flush_after = 0 # measured in pages, 0 disables + + +#------------------------------------------------------------------------------ +# WRITE AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +#wal_level = replica # minimal, replica, or logical + # (change requires restart) +#fsync = on # flush data to disk for crash safety + # (turning this off can cause + # unrecoverable data corruption) +#synchronous_commit = on # synchronization level; + # off, local, remote_write, remote_apply, or on +#wal_sync_method = fsync # the default is the first option + # supported by the operating system: + # open_datasync + # fdatasync (default on Linux) + # fsync + # fsync_writethrough + # open_sync +#full_page_writes = on # recover from partial page writes +#wal_compression = off # enable compression of full-page writes +#wal_log_hints = off # also do full page writes of non-critical updates + # (change requires restart) +#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers + # (change requires restart) +#wal_writer_delay = 200ms # 1-10000 milliseconds +#wal_writer_flush_after = 1MB # measured in pages, 0 disables + +#commit_delay = 0 # range 0-100000, in microseconds +#commit_siblings = 5 # range 1-1000 + +# - Checkpoints - + +#checkpoint_timeout = 5min # range 30s-1d +#max_wal_size = 1GB +#min_wal_size = 80MB +#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 +#checkpoint_flush_after = 256kB # measured in pages, 0 disables +#checkpoint_warning = 30s # 0 disables + +# - Archiving - + +#archive_mode = off # enables archiving; off, on, or always + # (change requires restart) +#archive_command = '' # command to use to archive a logfile segment + # placeholders: %p = path of file to archive + # %f = file name only + # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' +#archive_timeout = 0 # force a logfile segment switch after this + # number of seconds; 0 disables + + +#------------------------------------------------------------------------------ +# REPLICATION +#------------------------------------------------------------------------------ + +# - Sending Server(s) - + +# Set these on the master and on any standby that will send replication data. + +#max_wal_senders = 10 # max number of walsender processes + # (change requires restart) +#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables +#wal_sender_timeout = 60s # in milliseconds; 0 disables + +#max_replication_slots = 10 # max number of replication slots + # (change requires restart) +#track_commit_timestamp = off # collect timestamp of transaction commit + # (change requires restart) + +# - Master Server - + +# These settings are ignored on a standby server. + +#synchronous_standby_names = '' # standby servers that provide sync rep + # method to choose sync standbys, number of sync standbys, + # and comma-separated list of application_name + # from standby(s); '*' = all +#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed + +# - Standby Servers - + +# These settings are ignored on a master server. + +#hot_standby = on # "off" disallows queries during recovery + # (change requires restart) +#max_standby_archive_delay = 30s # max delay before canceling queries + # when reading WAL from archive; + # -1 allows indefinite delay +#max_standby_streaming_delay = 30s # max delay before canceling queries + # when reading streaming WAL; + # -1 allows indefinite delay +#wal_receiver_status_interval = 10s # send replies at least this often + # 0 disables +#hot_standby_feedback = off # send info from standby to prevent + # query conflicts +#wal_receiver_timeout = 60s # time that receiver waits for + # communication from master + # in milliseconds; 0 disables +#wal_retrieve_retry_interval = 5s # time to wait before retrying to + # retrieve WAL after a failed attempt + +# - Subscribers - + +# These settings are ignored on a publisher. + +#max_logical_replication_workers = 4 # taken from max_worker_processes + # (change requires restart) +#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers + + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Method Configuration - + +#enable_bitmapscan = on +#enable_hashagg = on +#enable_hashjoin = on +#enable_indexscan = on +#enable_indexonlyscan = on +#enable_material = on +#enable_mergejoin = on +#enable_nestloop = on +#enable_seqscan = on +#enable_sort = on +#enable_tidscan = on + +# - Planner Cost Constants - + +#seq_page_cost = 1.0 # measured on an arbitrary scale +#random_page_cost = 4.0 # same scale as above +#cpu_tuple_cost = 0.01 # same scale as above +#cpu_index_tuple_cost = 0.005 # same scale as above +#cpu_operator_cost = 0.0025 # same scale as above +#parallel_tuple_cost = 0.1 # same scale as above +#parallel_setup_cost = 1000.0 # same scale as above +#min_parallel_table_scan_size = 8MB +#min_parallel_index_scan_size = 512kB +#effective_cache_size = 4GB + +# - Genetic Query Optimizer - + +#geqo = on +#geqo_threshold = 12 +#geqo_effort = 5 # range 1-10 +#geqo_pool_size = 0 # selects default based on effort +#geqo_generations = 0 # selects default based on effort +#geqo_selection_bias = 2.0 # range 1.5-2.0 +#geqo_seed = 0.0 # range 0.0-1.0 + +# - Other Planner Options - + +#default_statistics_target = 100 # range 1-10000 +#constraint_exclusion = partition # on, off, or partition +#cursor_tuple_fraction = 0.1 # range 0.0-1.0 +#from_collapse_limit = 8 +#join_collapse_limit = 8 # 1 disables collapsing of explicit + # JOIN clauses +#force_parallel_mode = off + + +#------------------------------------------------------------------------------ +# ERROR REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - Where to Log - + +log_destination = 'stderr' # Valid values are combinations of + # stderr, csvlog, syslog, and eventlog, + # depending on platform. csvlog + # requires logging_collector to be on. + +# This is used when logging to stderr: +logging_collector = on # Enable capturing of stderr and csvlog + # into log files. Required to be on for + # csvlogs. + # (change requires restart) + +# These are only used if logging_collector is on: +log_directory = 'pg_log' # directory where log files are written, + # can be absolute or relative to PGDATA +log_filename = 'postgresql-%a.log' # log file name pattern, + # can include strftime() escapes +#log_file_mode = 0600 # creation mode for log files, + # begin with 0 to use octal notation +log_truncate_on_rotation = on # If on, an existing log file with the + # same name as the new log file will be + # truncated rather than appended to. + # But such truncation only occurs on + # time-driven rotation, not on restarts + # or size-driven rotation. Default is + # off, meaning append to existing files + # in all cases. +log_rotation_age = 1d # Automatic rotation of logfiles will + # happen after that time. 0 disables. +log_rotation_size = 0 # Automatic rotation of logfiles will + # happen after that much log output. + # 0 disables. + +# These are relevant when logging to syslog: +#syslog_facility = 'LOCAL0' +#syslog_ident = 'postgres' +#syslog_sequence_numbers = on +#syslog_split_messages = on + +# This is only relevant when logging to eventlog (win32): +# (change requires restart) +#event_source = 'PostgreSQL' + +# - When to Log - + +#client_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # log + # notice + # warning + # error + +#log_min_messages = warning # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic + +#log_min_error_statement = error # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic (effectively off) + +#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements + # and their durations, > 0 logs only + # statements running at least this number + # of milliseconds + + +# - What to Log - + +#debug_print_parse = off +#debug_print_rewritten = off +#debug_print_plan = off +#debug_pretty_print = on +#log_checkpoints = off +#log_connections = off +#log_disconnections = off +#log_duration = off +#log_error_verbosity = default # terse, default, or verbose messages +#log_hostname = off +log_line_prefix = '%m [%p] %q%u@%d ' # special values: + # %a = application name + # %u = user name + # %d = database name + # %r = remote host and port + # %h = remote host + # %p = process ID + # %t = timestamp without milliseconds + # %m = timestamp with milliseconds + # %n = timestamp with milliseconds (as a Unix epoch) + # %i = command tag + # %e = SQL state + # %c = session ID + # %l = session line number + # %s = session start timestamp + # %v = virtual transaction ID + # %x = transaction ID (0 if none) + # %q = stop here in non-session + # processes + # %% = '%' + # e.g. '<%u%%%d> ' +#log_lock_waits = off # log lock waits >= deadlock_timeout +#log_statement = 'none' # none, ddl, mod, all +#log_replication_commands = off +#log_temp_files = -1 # log temporary files equal or larger + # than the specified size in kilobytes; + # -1 disables, 0 logs all temp files +log_timezone = 'Etc/UTC' + + +# - Process Title - + +cluster_name = '{{ postgresql_version }}/main' # added to process titles if nonempty + # (change requires restart) +#update_process_title = on + + +#------------------------------------------------------------------------------ +# RUNTIME STATISTICS +#------------------------------------------------------------------------------ + +# - Query/Index Statistics Collector - + +#track_activities = on +#track_counts = on +#track_io_timing = off +#track_functions = none # none, pl, all +#track_activity_query_size = 1024 # (change requires restart) +{% if postgresql_version < '15' %}stats_temp_directory = '/var/run/postgresql/{{ postgresql_version }}-main.pg_stat_tmp'{% endif %} + + +# - Statistics Monitoring - + +#log_parser_stats = off +#log_planner_stats = off +#log_executor_stats = off +#log_statement_stats = off + + +#------------------------------------------------------------------------------ +# AUTOVACUUM PARAMETERS +#------------------------------------------------------------------------------ + +#autovacuum = on # Enable autovacuum subprocess? 'on' + # requires track_counts to also be on. +#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and + # their durations, > 0 logs only + # actions running at least this number + # of milliseconds. +#autovacuum_max_workers = 3 # max number of autovacuum subprocesses + # (change requires restart) +#autovacuum_naptime = 1min # time between autovacuum runs +#autovacuum_vacuum_threshold = 50 # min number of row updates before + # vacuum +#autovacuum_analyze_threshold = 50 # min number of row updates before + # analyze +#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze +#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum + # (change requires restart) +#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age + # before forced vacuum + # (change requires restart) +#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for + # autovacuum, in milliseconds; + # -1 means use vacuum_cost_delay +#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for + # autovacuum, -1 means use + # vacuum_cost_limit + + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Statement Behavior - + +#search_path = '"$user", public' # schema names +#default_tablespace = '' # a tablespace name, '' uses the default +#temp_tablespaces = '' # a list of tablespace names, '' uses + # only default tablespace +#check_function_bodies = on +#default_transaction_isolation = 'read committed' +#default_transaction_read_only = off +#default_transaction_deferrable = off +#session_replication_role = 'origin' +#statement_timeout = 0 # in milliseconds, 0 is disabled +#lock_timeout = 0 # in milliseconds, 0 is disabled +#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#vacuum_freeze_min_age = 50000000 +#vacuum_freeze_table_age = 150000000 +#vacuum_multixact_freeze_min_age = 5000000 +#vacuum_multixact_freeze_table_age = 150000000 +#bytea_output = 'hex' # hex, escape +#xmlbinary = 'base64' +#xmloption = 'content' +#gin_fuzzy_search_limit = 0 +#gin_pending_list_limit = 4MB + +# - Locale and Formatting - + +datestyle = 'iso, mdy' +#intervalstyle = 'postgres' +timezone = 'Etc/UTC' +#timezone_abbreviations = 'Default' # Select the set of available time zone + # abbreviations. Currently, there are + # Default + # Australia (historical usage) + # India + # You can create your own file in + # share/timezonesets/. +#extra_float_digits = 0 # min -15, max 3 +#client_encoding = sql_ascii # actually, defaults to database + # encoding + +# These settings are initialized by initdb, but they can be changed. +lc_messages = 'C.UTF-8' # locale for system error message + # strings +lc_monetary = 'C.UTF-8' # locale for monetary formatting +lc_numeric = 'C.UTF-8' # locale for number formatting +lc_time = 'C.UTF-8' # locale for time formatting + +# default configuration for text search +default_text_search_config = 'pg_catalog.english' + +# - Other Defaults - + +#dynamic_library_path = '$libdir' +#local_preload_libraries = '' +#session_preload_libraries = '' + + +#------------------------------------------------------------------------------ +# LOCK MANAGEMENT +#------------------------------------------------------------------------------ + +#deadlock_timeout = 1s +#max_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_relation = -2 # negative values mean + # (max_pred_locks_per_transaction + # / -max_pred_locks_per_relation) - 1 +#max_pred_locks_per_page = 2 # min 0 + + +#------------------------------------------------------------------------------ +# VERSION/PLATFORM COMPATIBILITY +#------------------------------------------------------------------------------ + +# - Previous PostgreSQL Versions - + +#array_nulls = on +#backslash_quote = safe_encoding # on, off, or safe_encoding +#default_with_oids = off +#escape_string_warning = on +#lo_compat_privileges = off +#operator_precedence_warning = off +#quote_all_identifiers = off +#standard_conforming_strings = on +#synchronize_seqscans = on + +# - Other Platforms and Clients - + +#transform_null_equals = off + + +#------------------------------------------------------------------------------ +# ERROR HANDLING +#------------------------------------------------------------------------------ + +#exit_on_error = off # terminate session on any error? +#restart_after_crash = on # reinitialize after backend crash? +#data_sync_retry = off # retry or panic on failure to fsync + # data? + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONFIG FILE INCLUDES +#------------------------------------------------------------------------------ + +# These options allow settings to be loaded from files other than the +# default postgresql.conf. Note that these are directives, not variable +# assignments, so they can usefully be given more than once. + +include_dir = 'conf.d' # include files ending in '.conf' from + # a directory, e.g., 'conf.d' +#include_if_exists = '...' # include file only if it exists +#include = '...' # include file + + +#------------------------------------------------------------------------------ +# CUSTOMIZED OPTIONS +#------------------------------------------------------------------------------ + +# Add settings for extensions here + + +#------------------------------------------------------------------------------ +# ANSIBLE OPTIONS +#------------------------------------------------------------------------------ + +listen_addresses = {{ postgresql_server_listen }} + +{% for option in (postgresql_server_conf | sort) %} +{{ option }} = {{ postgresql_server_conf[option] }} +{% endfor %} diff --git a/omero/roles/ome.postgresql/templates/postgresql-conf.j2 b/omero/roles/ome.postgresql/templates/postgresql-conf.j2 new file mode 100644 index 00000000..0f1193d6 --- /dev/null +++ b/omero/roles/ome.postgresql/templates/postgresql-conf.j2 @@ -0,0 +1,654 @@ +# {{ ansible_managed }} + +# ----------------------------- +# PostgreSQL configuration file +# ----------------------------- +# +# This file consists of lines of the form: +# +# name = value +# +# (The "=" is optional.) Whitespace may be used. Comments are introduced with +# "#" anywhere on a line. The complete list of parameter names and allowed +# values can be found in the PostgreSQL documentation. +# +# The commented-out settings shown in this file represent the default values. +# Re-commenting a setting is NOT sufficient to revert it to the default value; +# you need to reload the server. +# +# This file is read on server startup and when the server receives a SIGHUP +# signal. If you edit the file on a running system, you have to SIGHUP the +# server for the changes to take effect, or use "pg_ctl reload". Some +# parameters, which are marked below, require a server shutdown and restart to +# take effect. +# +# Any parameter can also be given as a command-line option to the server, e.g., +# "postgres -c log_connections=on". Some parameters can be changed at run time +# with the "SET" SQL command. +# +# Memory units: kB = kilobytes Time units: ms = milliseconds +# MB = megabytes s = seconds +# GB = gigabytes min = minutes +# TB = terabytes h = hours +# d = days + + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +# The default values of these variables are driven from the -D command-line +# option or PGDATA environment variable, represented here as ConfigDir. + +#data_directory = 'ConfigDir' # use data in another directory + # (change requires restart) +#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file + # (change requires restart) +#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file + # (change requires restart) + +# If external_pid_file is not explicitly set, no extra PID file is written. +#external_pid_file = '' # write an extra PID file + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +#listen_addresses = 'localhost' # what IP address(es) to listen on; + # comma-separated list of addresses; + # defaults to 'localhost'; use '*' for all + # (change requires restart) +#port = 5432 # (change requires restart) +max_connections = 100 # (change requires restart) +#superuser_reserved_connections = 3 # (change requires restart) +#unix_socket_directories = '/var/run/postgresql, /tmp' # comma-separated list of directories + # (change requires restart) +#unix_socket_group = '' # (change requires restart) +#unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +#bonjour = off # advertise server via Bonjour + # (change requires restart) +#bonjour_name = '' # defaults to the computer name + # (change requires restart) + +# - Security and Authentication - + +#authentication_timeout = 1min # 1s-600s +#ssl = off # (change requires restart) +#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers + # (change requires restart) +#ssl_prefer_server_ciphers = on # (change requires restart) +#ssl_ecdh_curve = 'prime256v1' # (change requires restart) +#ssl_cert_file = 'server.crt' # (change requires restart) +#ssl_key_file = 'server.key' # (change requires restart) +#ssl_ca_file = '' # (change requires restart) +#ssl_crl_file = '' # (change requires restart) +#password_encryption = on +#db_user_namespace = off +#row_security = on + +# GSSAPI using Kerberos +#krb_server_keyfile = '' +#krb_caseins_users = off + +# - TCP Keepalives - +# see "man 7 tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default + + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +shared_buffers = 128MB # min 128kB + # (change requires restart) +#huge_pages = try # on, off, or try + # (change requires restart) +#temp_buffers = 8MB # min 800kB +#max_prepared_transactions = 0 # zero disables the feature + # (change requires restart) +# Caution: it is not advisable to set max_prepared_transactions nonzero unless +# you actively intend to use prepared transactions. +#work_mem = 4MB # min 64kB +#maintenance_work_mem = 64MB # min 1MB +#replacement_sort_tuples = 150000 # limits use of replacement selection sort +#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem +#max_stack_depth = 2MB # min 100kB +dynamic_shared_memory_type = posix # the default is the first option + # supported by the operating system: + # posix + # sysv + # windows + # mmap + # use none to disable dynamic shared memory + +# - Disk - + +#temp_file_limit = -1 # limits per-process temp file space + # in kB, or -1 for no limit + +# - Kernel Resource Usage - + +#max_files_per_process = 1000 # min 25 + # (change requires restart) +#shared_preload_libraries = '' # (change requires restart) + +# - Cost-Based Vacuum Delay - + +#vacuum_cost_delay = 0 # 0-100 milliseconds +#vacuum_cost_page_hit = 1 # 0-10000 credits +#vacuum_cost_page_miss = 10 # 0-10000 credits +#vacuum_cost_page_dirty = 20 # 0-10000 credits +#vacuum_cost_limit = 200 # 1-10000 credits + +# - Background Writer - + +#bgwriter_delay = 200ms # 10-10000ms between rounds +#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round +#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round +#bgwriter_flush_after = 512kB # measured in pages, 0 disables + +# - Asynchronous Behavior - + +#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching +#max_worker_processes = 8 # (change requires restart) +#max_parallel_workers_per_gather = 0 # taken from max_worker_processes +#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate + # (change requires restart) +#backend_flush_after = 0 # measured in pages, 0 disables + + +#------------------------------------------------------------------------------ +# WRITE AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +#wal_level = minimal # minimal, replica, or logical + # (change requires restart) +#fsync = on # flush data to disk for crash safety + # (turning this off can cause + # unrecoverable data corruption) +#synchronous_commit = on # synchronization level; + # off, local, remote_write, remote_apply, or on +#wal_sync_method = fsync # the default is the first option + # supported by the operating system: + # open_datasync + # fdatasync (default on Linux) + # fsync + # fsync_writethrough + # open_sync +#full_page_writes = on # recover from partial page writes +#wal_compression = off # enable compression of full-page writes +#wal_log_hints = off # also do full page writes of non-critical updates + # (change requires restart) +#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers + # (change requires restart) +#wal_writer_delay = 200ms # 1-10000 milliseconds +#wal_writer_flush_after = 1MB # measured in pages, 0 disables + +#commit_delay = 0 # range 0-100000, in microseconds +#commit_siblings = 5 # range 1-1000 + +# - Checkpoints - + +#checkpoint_timeout = 5min # range 30s-1d +#max_wal_size = 1GB +#min_wal_size = 80MB +#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 +#checkpoint_flush_after = 256kB # measured in pages, 0 disables +#checkpoint_warning = 30s # 0 disables + +# - Archiving - + +#archive_mode = off # enables archiving; off, on, or always + # (change requires restart) +#archive_command = '' # command to use to archive a logfile segment + # placeholders: %p = path of file to archive + # %f = file name only + # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' +#archive_timeout = 0 # force a logfile segment switch after this + # number of seconds; 0 disables + + +#------------------------------------------------------------------------------ +# REPLICATION +#------------------------------------------------------------------------------ + +# - Sending Server(s) - + +# Set these on the master and on any standby that will send replication data. + +#max_wal_senders = 0 # max number of walsender processes + # (change requires restart) +#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables +#wal_sender_timeout = 60s # in milliseconds; 0 disables + +#max_replication_slots = 0 # max number of replication slots + # (change requires restart) +#track_commit_timestamp = off # collect timestamp of transaction commit + # (change requires restart) + +# - Master Server - + +# These settings are ignored on a standby server. + +#synchronous_standby_names = '' # standby servers that provide sync rep + # number of sync standbys and comma-separated list of application_name + # from standby(s); '*' = all +#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed + +# - Standby Servers - + +# These settings are ignored on a master server. + +#hot_standby = off # "on" allows queries during recovery + # (change requires restart) +#max_standby_archive_delay = 30s # max delay before canceling queries + # when reading WAL from archive; + # -1 allows indefinite delay +#max_standby_streaming_delay = 30s # max delay before canceling queries + # when reading streaming WAL; + # -1 allows indefinite delay +#wal_receiver_status_interval = 10s # send replies at least this often + # 0 disables +#hot_standby_feedback = off # send info from standby to prevent + # query conflicts +#wal_receiver_timeout = 60s # time that receiver waits for + # communication from master + # in milliseconds; 0 disables +#wal_retrieve_retry_interval = 5s # time to wait before retrying to + # retrieve WAL after a failed attempt + + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Method Configuration - + +#enable_bitmapscan = on +#enable_hashagg = on +#enable_hashjoin = on +#enable_indexscan = on +#enable_indexonlyscan = on +#enable_material = on +#enable_mergejoin = on +#enable_nestloop = on +#enable_seqscan = on +#enable_sort = on +#enable_tidscan = on + +# - Planner Cost Constants - + +#seq_page_cost = 1.0 # measured on an arbitrary scale +#random_page_cost = 4.0 # same scale as above +#cpu_tuple_cost = 0.01 # same scale as above +#cpu_index_tuple_cost = 0.005 # same scale as above +#cpu_operator_cost = 0.0025 # same scale as above +#parallel_tuple_cost = 0.1 # same scale as above +#parallel_setup_cost = 1000.0 # same scale as above +#min_parallel_relation_size = 8MB +#effective_cache_size = 4GB + +# - Genetic Query Optimizer - + +#geqo = on +#geqo_threshold = 12 +#geqo_effort = 5 # range 1-10 +#geqo_pool_size = 0 # selects default based on effort +#geqo_generations = 0 # selects default based on effort +#geqo_selection_bias = 2.0 # range 1.5-2.0 +#geqo_seed = 0.0 # range 0.0-1.0 + +# - Other Planner Options - + +#default_statistics_target = 100 # range 1-10000 +#constraint_exclusion = partition # on, off, or partition +#cursor_tuple_fraction = 0.1 # range 0.0-1.0 +#from_collapse_limit = 8 +#join_collapse_limit = 8 # 1 disables collapsing of explicit + # JOIN clauses +#force_parallel_mode = off + + +#------------------------------------------------------------------------------ +# ERROR REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - Where to Log - + +log_destination = 'stderr' # Valid values are combinations of + # stderr, csvlog, syslog, and eventlog, + # depending on platform. csvlog + # requires logging_collector to be on. + +# This is used when logging to stderr: +logging_collector = on # Enable capturing of stderr and csvlog + # into log files. Required to be on for + # csvlogs. + # (change requires restart) + +# These are only used if logging_collector is on: +log_directory = 'pg_log' # directory where log files are written, + # can be absolute or relative to PGDATA +log_filename = 'postgresql-%a.log' # log file name pattern, + # can include strftime() escapes +#log_file_mode = 0600 # creation mode for log files, + # begin with 0 to use octal notation +log_truncate_on_rotation = on # If on, an existing log file with the + # same name as the new log file will be + # truncated rather than appended to. + # But such truncation only occurs on + # time-driven rotation, not on restarts + # or size-driven rotation. Default is + # off, meaning append to existing files + # in all cases. +log_rotation_age = 1d # Automatic rotation of logfiles will + # happen after that time. 0 disables. +log_rotation_size = 0 # Automatic rotation of logfiles will + # happen after that much log output. + # 0 disables. + +# These are relevant when logging to syslog: +#syslog_facility = 'LOCAL0' +#syslog_ident = 'postgres' +#syslog_sequence_numbers = on +#syslog_split_messages = on + +# This is only relevant when logging to eventlog (win32): +#event_source = 'PostgreSQL' + +# - When to Log - + +#client_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # log + # notice + # warning + # error + +#log_min_messages = warning # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic + +#log_min_error_statement = error # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic (effectively off) + +#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements + # and their durations, > 0 logs only + # statements running at least this number + # of milliseconds + + +# - What to Log - + +#debug_print_parse = off +#debug_print_rewritten = off +#debug_print_plan = off +#debug_pretty_print = on +#log_checkpoints = off +#log_connections = off +#log_disconnections = off +#log_duration = off +#log_error_verbosity = default # terse, default, or verbose messages +#log_hostname = off +log_line_prefix = '< %m > ' # special values: + # %a = application name + # %u = user name + # %d = database name + # %r = remote host and port + # %h = remote host + # %p = process ID + # %t = timestamp without milliseconds + # %m = timestamp with milliseconds + # %n = timestamp with milliseconds (as a Unix epoch) + # %i = command tag + # %e = SQL state + # %c = session ID + # %l = session line number + # %s = session start timestamp + # %v = virtual transaction ID + # %x = transaction ID (0 if none) + # %q = stop here in non-session + # processes + # %% = '%' + # e.g. '<%u%%%d> ' +#log_lock_waits = off # log lock waits >= deadlock_timeout +#log_statement = 'none' # none, ddl, mod, all +#log_replication_commands = off +#log_temp_files = -1 # log temporary files equal or larger + # than the specified size in kilobytes; + # -1 disables, 0 logs all temp files +log_timezone = 'UTC' + + +# - Process Title - + +#cluster_name = '' # added to process titles if nonempty + # (change requires restart) +#update_process_title = on + + +#------------------------------------------------------------------------------ +# RUNTIME STATISTICS +#------------------------------------------------------------------------------ + +# - Query/Index Statistics Collector - + +#track_activities = on +#track_counts = on +#track_io_timing = off +#track_functions = none # none, pl, all +#track_activity_query_size = 1024 # (change requires restart) +#stats_temp_directory = 'pg_stat_tmp' + + +# - Statistics Monitoring - + +#log_parser_stats = off +#log_planner_stats = off +#log_executor_stats = off +#log_statement_stats = off + + +#------------------------------------------------------------------------------ +# AUTOVACUUM PARAMETERS +#------------------------------------------------------------------------------ + +#autovacuum = on # Enable autovacuum subprocess? 'on' + # requires track_counts to also be on. +#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and + # their durations, > 0 logs only + # actions running at least this number + # of milliseconds. +#autovacuum_max_workers = 3 # max number of autovacuum subprocesses + # (change requires restart) +#autovacuum_naptime = 1min # time between autovacuum runs +#autovacuum_vacuum_threshold = 50 # min number of row updates before + # vacuum +#autovacuum_analyze_threshold = 50 # min number of row updates before + # analyze +#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze +#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum + # (change requires restart) +#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age + # before forced vacuum + # (change requires restart) +#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for + # autovacuum, in milliseconds; + # -1 means use vacuum_cost_delay +#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for + # autovacuum, -1 means use + # vacuum_cost_limit + + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Statement Behavior - + +#search_path = '"$user", public' # schema names +#default_tablespace = '' # a tablespace name, '' uses the default +#temp_tablespaces = '' # a list of tablespace names, '' uses + # only default tablespace +#check_function_bodies = on +#default_transaction_isolation = 'read committed' +#default_transaction_read_only = off +#default_transaction_deferrable = off +#session_replication_role = 'origin' +#statement_timeout = 0 # in milliseconds, 0 is disabled +#lock_timeout = 0 # in milliseconds, 0 is disabled +#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#vacuum_freeze_min_age = 50000000 +#vacuum_freeze_table_age = 150000000 +#vacuum_multixact_freeze_min_age = 5000000 +#vacuum_multixact_freeze_table_age = 150000000 +#bytea_output = 'hex' # hex, escape +#xmlbinary = 'base64' +#xmloption = 'content' +#gin_fuzzy_search_limit = 0 +#gin_pending_list_limit = 4MB + +# - Locale and Formatting - + +datestyle = 'iso, mdy' +#intervalstyle = 'postgres' +timezone = 'UTC' +#timezone_abbreviations = 'Default' # Select the set of available time zone + # abbreviations. Currently, there are + # Default + # Australia (historical usage) + # India + # You can create your own file in + # share/timezonesets/. +#extra_float_digits = 0 # min -15, max 3 +#client_encoding = sql_ascii # actually, defaults to database + # encoding + +# These settings are initialized by initdb, but they can be changed. +lc_messages = 'en_US.UTF-8' # locale for system error message + # strings +lc_monetary = 'en_US.UTF-8' # locale for monetary formatting +lc_numeric = 'en_US.UTF-8' # locale for number formatting +lc_time = 'en_US.UTF-8' # locale for time formatting + +# default configuration for text search +default_text_search_config = 'pg_catalog.english' + +# - Other Defaults - + +#dynamic_library_path = '$libdir' +#local_preload_libraries = '' +#session_preload_libraries = '' + + +#------------------------------------------------------------------------------ +# LOCK MANAGEMENT +#------------------------------------------------------------------------------ + +#deadlock_timeout = 1s +#max_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_transaction = 64 # min 10 + # (change requires restart) + + +#------------------------------------------------------------------------------ +# VERSION/PLATFORM COMPATIBILITY +#------------------------------------------------------------------------------ + +# - Previous PostgreSQL Versions - + +#array_nulls = on +#backslash_quote = safe_encoding # on, off, or safe_encoding +#default_with_oids = off +#escape_string_warning = on +#lo_compat_privileges = off +#operator_precedence_warning = off +#quote_all_identifiers = off +#sql_inheritance = on +#standard_conforming_strings = on +#synchronize_seqscans = on + +# - Other Platforms and Clients - + +#transform_null_equals = off + + +#------------------------------------------------------------------------------ +# ERROR HANDLING +#------------------------------------------------------------------------------ + +#exit_on_error = off # terminate session on any error? +#restart_after_crash = on # reinitialize after backend crash? + + +#------------------------------------------------------------------------------ +# CONFIG FILE INCLUDES +#------------------------------------------------------------------------------ + +# These options allow settings to be loaded from files other than the +# default postgresql.conf. + +#include_dir = 'conf.d' # include files ending in '.conf' from + # directory 'conf.d' +#include_if_exists = 'exists.conf' # include file only if it exists +#include = 'special.conf' # include file + + +#------------------------------------------------------------------------------ +# CUSTOMIZED OPTIONS +#------------------------------------------------------------------------------ + +# Add settings for extensions here + + +#------------------------------------------------------------------------------ +# ANSIBLE OPTIONS +#------------------------------------------------------------------------------ + +listen_addresses = {{ postgresql_server_listen }} + +{% for option in (postgresql_server_conf | sort) %} +{{ option }} = {{ postgresql_server_conf[option] }} +{% endfor %} diff --git a/omero/roles/ome.postgresql_backup/.github/workflows/molecule.yml b/omero/roles/ome.postgresql_backup/.github/workflows/molecule.yml new file mode 100644 index 00000000..ad1f62a4 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} diff --git a/omero/roles/ome.postgresql_backup/LICENSE.md b/omero/roles/ome.postgresql_backup/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.postgresql_backup/README.md b/omero/roles/ome.postgresql_backup/README.md new file mode 100644 index 00000000..2fa217fe --- /dev/null +++ b/omero/roles/ome.postgresql_backup/README.md @@ -0,0 +1,51 @@ +PostgreSQL Backup +================= + +[![Actions Status](https://github.com/ome/ansible-role-postgresql-backup/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-postgresql-backup/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-postgresql_backup-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/postgresql_backup/) + +Setup a cron job for regular full PostgreSQL database dumps. + +Assumes the local `postgres` has password-less access to all databases (this is the default when installing PostgreSQL server). + + +Dependencies +------------ + +This requires a cron daemon to already be running. +This should be the default on most systems. + + +Role Variables +-------------- + +Required: +- `postgresql_backup_dir`: Save backups in this directory + +Optional: +- `postgresql_backup_filename_format`: A filename containing unix `date` format sequences, default `{{ ansible_hostname }}-%Y%m%d-%H%M%S.pgdump` (or `{{ ansible_hostname }}-%Y%m%d-%H%M%S.pgdump.gz` if `postgresql_backup_compress: true`). + This can be used to automatically overwrite backups on a rolling basis. +- `postgresql_backup_frequency`: This must match one of the standard `/etc/cron.*` directories, typically either `daily` (default), `hourly`, `weekly` or `monthly`. +- `postgresql_backup_minimum_expected_size`: The minimum size in bytes of the backup file. + The cron job will return an error if the file is smaller than this. +- `postgresql_backup_compress`: If `true` compress the output using gzip, default `false`. + + +Example playbook +---------------- + + # This will name the backup file /nfs/backups/HOSTNAME-Mon.pgdump + # where Mon will be replaced by the abbreviated day of the week, resulting + # in daily backups on a rolling weekly cycle + - hosts: postgresql-servers + roles: + - role: ome.postgresql_backup + postgresql_backup_dir: /nfs/backups + postgresql_backup_filename_format: "{{ ansible_hostname }}-%a.pgdump" + postgresql_backup_minimum_expected_size: 100000 + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.postgresql_backup/defaults/main.yml b/omero/roles/ome.postgresql_backup/defaults/main.yml new file mode 100644 index 00000000..076ef161 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/defaults/main.yml @@ -0,0 +1,11 @@ +--- +# defaults file for postgresql-backup + +# postgresql_backup_dir: +postgresql_backup_filename_format: >- + {{ ansible_hostname }}-%Y%m%d-%H%M%S.pgdump{{ + postgresql_backup_compress | ternary('.gz', '') + }} +postgresql_backup_frequency: daily +postgresql_backup_minimum_expected_size: 1 +postgresql_backup_compress: false diff --git a/omero/roles/ome.postgresql_backup/meta/.galaxy_install_info b/omero/roles/ome.postgresql_backup/meta/.galaxy_install_info new file mode 100644 index 00000000..8b844111 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:34:02 2024 +version: 0.3.0 diff --git a/omero/roles/ome.postgresql_backup/meta/main.yml b/omero/roles/ome.postgresql_backup/meta/main.yml new file mode 100644 index 00000000..14ec9ed2 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/meta/main.yml @@ -0,0 +1,14 @@ +--- +galaxy_info: + role_name: postgresql_backup + author: ome-devel@lists.openmicroscopy.org.uk + description: Setup a cron job for regular full PostgreSQL database dumps + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.3 + platforms: + - name: EL + versions: + - 9 + namespace: ome + galaxy_tags: [] diff --git a/omero/roles/ome.postgresql_backup/molecule/default/molecule.yml b/omero/roles/ome.postgresql_backup/molecule/default/molecule.yml new file mode 100644 index 00000000..bfecaa1c --- /dev/null +++ b/omero/roles/ome.postgresql_backup/molecule/default/molecule.yml @@ -0,0 +1,36 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: postgresql-backup + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + - name: postgresql-backupgz + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup +provisioner: + name: ansible + lint: + name: ansible-lint + inventory: + host_vars: + postgresql-backupgz: + postgresql_backup_compress: true +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.postgresql_backup/molecule/default/playbook.yml b/omero/roles/ome.postgresql_backup/molecule/default/playbook.yml new file mode 100644 index 00000000..85e62086 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/molecule/default/playbook.yml @@ -0,0 +1,24 @@ +--- +- name: Converge + hosts: all + + # If testing in Docker cron won't be installed + pre_tasks: + - name: Install cron + become: true + ansible.builtin.dnf: + update_cache: true + name: cronie + state: present + + roles: + + - role: ome.postgresql + postgresql_version: "13" + + - role: ome.postgresql_backup + postgresql_backup_dir: /backup/postgresql + postgresql_backup_filename_format: >- + {{ ansible_hostname }}-%Y%m%d.pgdump{{ + postgresql_backup_compress | ternary('.gz', '') + }} diff --git a/omero/roles/ome.postgresql_backup/molecule/default/requirements.yml b/omero/roles/ome.postgresql_backup/molecule/default/requirements.yml new file mode 100644 index 00000000..2f29355e --- /dev/null +++ b/omero/roles/ome.postgresql_backup/molecule/default/requirements.yml @@ -0,0 +1,3 @@ +--- + +- src: ome.postgresql diff --git a/omero/roles/ome.postgresql_backup/molecule/default/tests/test_compress.py b/omero/roles/ome.postgresql_backup/molecule/default/tests/test_compress.py new file mode 100644 index 00000000..15f10330 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/molecule/default/tests/test_compress.py @@ -0,0 +1,28 @@ +import os +from datetime import datetime + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('postgresql-backupgz') + + +def test_run_backup_script(host): + # Note there's a small chance this test will incorrectly fail if it's run + # run at midnight + d = datetime.now() + expected = ('/backup/postgresql/postgresql-backupgz-%s.pgdump.gz' % + d.strftime('%Y%m%d')) + + with host.sudo(): + out = host.run('/etc/cron.daily/postgresql-backup') + assert out.rc == 0 + assert out.stdout == '' + + f = host.file(expected) + assert f.is_file + + with host.sudo(): + content = host.check_output('gunzip -c %s', expected) + assert content.startswith( + '--\n-- PostgreSQL database cluster dump\n--\n') diff --git a/omero/roles/ome.postgresql_backup/molecule/default/tests/test_default.py b/omero/roles/ome.postgresql_backup/molecule/default/tests/test_default.py new file mode 100644 index 00000000..daa67418 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/molecule/default/tests/test_default.py @@ -0,0 +1,27 @@ +import os +from datetime import datetime + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts( + 'all,!postgresql-backupgz') + + +def test_run_backup_script(host): + # Note there's a small chance this test will incorrectly fail if it's run + # run at midnight + d = datetime.now() + expected = ('/backup/postgresql/postgresql-backup-%s.pgdump' % + d.strftime('%Y%m%d')) + + with host.sudo(): + out = host.run('/etc/cron.daily/postgresql-backup') + assert out.rc == 0 + assert out.stdout == '' + + f = host.file(expected) + assert f.is_file + assert f.size > 2000 + assert f.content_string.startswith( + '--\n-- PostgreSQL database cluster dump\n--\n') diff --git a/omero/roles/ome.postgresql_backup/tasks/main.yml b/omero/roles/ome.postgresql_backup/tasks/main.yml new file mode 100644 index 00000000..da3e0f76 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/tasks/main.yml @@ -0,0 +1,17 @@ +--- +# tasks file for postgresql-backup + +- name: postgresql backup | create backup directory + become: true + file: + path: "{{ postgresql_backup_dir }}" + state: directory + owner: postgres + mode: 0700 + +- name: postgresql backup | create cron job + become: true + template: + src: etc-crond-postgresql-backup.j2 + dest: /etc/cron.{{ postgresql_backup_frequency }}/postgresql-backup + mode: 0755 diff --git a/omero/roles/ome.postgresql_backup/templates/etc-crond-postgresql-backup.j2 b/omero/roles/ome.postgresql_backup/templates/etc-crond-postgresql-backup.j2 new file mode 100644 index 00000000..00fa5024 --- /dev/null +++ b/omero/roles/ome.postgresql_backup/templates/etc-crond-postgresql-backup.j2 @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Dump all PostgreSQL databases + +OUTPUT="{{ postgresql_backup_dir | quote }}/$(date +{{ postgresql_backup_filename_format | quote }})" +{% if postgresql_backup_compress %} +su postgres -c "/usr/bin/pg_dumpall | gzip -c > \"$OUTPUT.tmp\"" +{% else %} +su postgres -c "/usr/bin/pg_dumpall -f \"$OUTPUT.tmp\"" +{% endif %} + +size=$(stat -c%s "$OUTPUT.tmp") +if [ $size -lt {{ postgresql_backup_minimum_expected_size }} ]; then + echo "ERROR: Database backup '$OUTPUT.tmp' is less than {{ postgresql_backup_minimum_expected_size }} bytes" + exit 2 +fi + +mv "$OUTPUT.tmp" "$OUTPUT" diff --git a/omero/roles/ome.postgresql_client/.github/workflows/molecule.yml b/omero/roles/ome.postgresql_client/.github/workflows/molecule.yml new file mode 100644 index 00000000..34fa2d47 --- /dev/null +++ b/omero/roles/ome.postgresql_client/.github/workflows/molecule.yml @@ -0,0 +1,62 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Read the role name + id: role-name + run: | + name=$(grep 'role_name' meta/main.yml | sed -r 's/^[^:]*:(.*)$/\1/' | tr -d '[:space:]') + echo "rolename=$name" >> "$GITHUB_OUTPUT" + - name: Publish to Galaxy + uses: ome/action-ansible-galaxy-publish@main + with: + galaxy-api-key: ${{ secrets.GALAXY_API_KEY }} + galaxy-version: ${{ github.ref_name }} + role-name: ${{ steps.role-name.outputs.rolename }} diff --git a/omero/roles/ome.postgresql_client/.gitignore b/omero/roles/ome.postgresql_client/.gitignore new file mode 100644 index 00000000..97752ea8 --- /dev/null +++ b/omero/roles/ome.postgresql_client/.gitignore @@ -0,0 +1,4 @@ +.*~ +*.pyc +.molecule +.vagrant diff --git a/omero/roles/ome.postgresql_client/LICENSE.md b/omero/roles/ome.postgresql_client/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.postgresql_client/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.postgresql_client/README.md b/omero/roles/ome.postgresql_client/README.md new file mode 100644 index 00000000..ad579eef --- /dev/null +++ b/omero/roles/ome.postgresql_client/README.md @@ -0,0 +1,37 @@ +Postgresql Client +================= + +[![Actions Status](https://github.com/ome/ansible-role-postgresql-client/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-postgresql-client/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-postgresql_client-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/postgresql_client/) + +Install PostgreSQL clients from the upstream distribution. + +If you wish to use your distributions packages do not use this role. + + +Role Variables +-------------- + +Required: + +- `postgresql_version`: The PostgreSQL major version, e.g. `11`, `12`, `13`, `14`, `15`, `16` + +Optional: +- `postgresql_package_version`: The PostgreSQL full version, ignored on Ubuntu, e.g. `12.11` + + +Example Playbook +---------------- + + # Simple example relying on the default Postgres PUBLIC privileges + # which allow access to all users + - hosts: localhost + roles: + - role: ome.postgresql_client + postgresql_version: "12" + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.postgresql_client/defaults/main.yml b/omero/roles/ome.postgresql_client/defaults/main.yml new file mode 100644 index 00000000..5fc77a02 --- /dev/null +++ b/omero/roles/ome.postgresql_client/defaults/main.yml @@ -0,0 +1,8 @@ +--- +# defaults file for ome.postgresql-client + +# The PostgreSQL major version, required +# postgresql_version + +# Full package version of postgres +postgresql_package_version: "" diff --git a/omero/roles/ome.postgresql_client/meta/.galaxy_install_info b/omero/roles/ome.postgresql_client/meta/.galaxy_install_info new file mode 100644 index 00000000..2cd74862 --- /dev/null +++ b/omero/roles/ome.postgresql_client/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:46 2024 +version: 0.4.3 diff --git a/omero/roles/ome.postgresql_client/meta/main.yml b/omero/roles/ome.postgresql_client/meta/main.yml new file mode 100644 index 00000000..c757aee7 --- /dev/null +++ b/omero/roles/ome.postgresql_client/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Upstream PostgreSQL client + company: Open Microscopy Environment + license: BSD + min_ansible_version: '2.10' + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + role_name: postgresql_client + galaxy_tags: ['postgresql', 'database'] diff --git a/omero/roles/ome.postgresql_client/molecule/resources/playbook.yml b/omero/roles/ome.postgresql_client/molecule/resources/playbook.yml new file mode 100644 index 00000000..d6d47023 --- /dev/null +++ b/omero/roles/ome.postgresql_client/molecule/resources/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.postgresql_client diff --git a/omero/roles/ome.postgresql_client/molecule/resources/tests/test_default.py b/omero/roles/ome.postgresql_client/molecule/resources/tests/test_default.py new file mode 100644 index 00000000..eff7d17e --- /dev/null +++ b/omero/roles/ome.postgresql_client/molecule/resources/tests/test_default.py @@ -0,0 +1,12 @@ +import testinfra.utils.ansible_runner +import os + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_psql_version(host): + variables = host.ansible.get_variables() + version = variables["postgresql_version"] + out = host.check_output('psql --version') + assert out.startswith('psql (PostgreSQL) {}.'.format(version)) diff --git a/omero/roles/ome.postgresql_client/molecule/resources/tests/test_exactversion.py b/omero/roles/ome.postgresql_client/molecule/resources/tests/test_exactversion.py new file mode 100644 index 00000000..b5cad7f1 --- /dev/null +++ b/omero/roles/ome.postgresql_client/molecule/resources/tests/test_exactversion.py @@ -0,0 +1,10 @@ +import testinfra.utils.ansible_runner +import os + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('exactversion') + + +def test_psql_version(host): + out = host.check_output('psql --version') + assert out == 'psql (PostgreSQL) 12.11' diff --git a/omero/roles/ome.postgresql_client/molecule/rockylinux9/molecule.yml b/omero/roles/ome.postgresql_client/molecule/rockylinux9/molecule.yml new file mode 100644 index 00000000..88870a4c --- /dev/null +++ b/omero/roles/ome.postgresql_client/molecule/rockylinux9/molecule.yml @@ -0,0 +1,44 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: postgresql12 + image: rockylinux:9 + - name: postgresql13 + image: rockylinux:9 + - name: postgresql14 + image: rockylinux:9 + - name: postgresql15 + image: rockylinux:9 + - name: postgresql16 + image: rockylinux:9 +provisioner: + name: ansible + lint: + name: ansible-lint + inventory: + host_vars: + postgresql_exact: + postgresql12: + postgresql_version: "12" + postgresql13: + postgresql_version: "13" + postgresql14: + postgresql_version: "14" + postgresql15: + postgresql_version: "15" + postgresql16: + postgresql_version: "16" + playbooks: + converge: ../resources/playbook.yml +scenario: + name: rockylinux9 +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.postgresql_client/molecule/ubuntu2204/molecule.yml b/omero/roles/ome.postgresql_client/molecule/ubuntu2204/molecule.yml new file mode 100644 index 00000000..06e3e6db --- /dev/null +++ b/omero/roles/ome.postgresql_client/molecule/ubuntu2204/molecule.yml @@ -0,0 +1,43 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: postgresql12 + image: ubuntu:22.04 + - name: postgresql13 + image: ubuntu:22.04 + - name: postgresql14 + image: ubuntu:22.04 + - name: postgresql15 + image: ubuntu:22.04 + - name: postgresql16 + image: ubuntu:22.04 +provisioner: + name: ansible + lint: + name: ansible-lint + inventory: + host_vars: + postgresql12: + postgresql_version: "12" + postgresql13: + postgresql_version: "13" + postgresql14: + postgresql_version: "14" + postgresql15: + postgresql_version: "15" + postgresql16: + postgresql_version: "16" + playbooks: + converge: ../resources/playbook.yml +scenario: + name: ubuntu2204 +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.postgresql_client/tasks/debian.yml b/omero/roles/ome.postgresql_client/tasks/debian.yml new file mode 100644 index 00000000..e6a4b847 --- /dev/null +++ b/omero/roles/ome.postgresql_client/tasks/debian.yml @@ -0,0 +1,28 @@ +--- + +- name: Postgres | install gpg for apt repo + become: true + ansible.builtin.apt: + update_cache: true + name: gnupg + state: present + +- name: Postgres | get postgresql apt key + become: true + ansible.builtin.apt_key: + url: https://www.postgresql.org/media/keys/ACCC4CF8.asc + state: present + +- name: Postgres | setup apt repo + become: true + ansible.builtin.apt_repository: + codename: "{{ ansible_distribution_release }}" + repo: deb http://apt.postgresql.org/pub/repos/apt/ + {{ ansible_distribution_release }}-pgdg main + +- name: Postgres | install client packages + become: true + ansible.builtin.apt: + update_cache: true + name: postgresql-client-{{ postgresql_version }} + state: present diff --git a/omero/roles/ome.postgresql_client/tasks/main.yml b/omero/roles/ome.postgresql_client/tasks/main.yml new file mode 100644 index 00000000..9922bbfe --- /dev/null +++ b/omero/roles/ome.postgresql_client/tasks/main.yml @@ -0,0 +1,9 @@ +--- + +- name: Import tasks for redhat + ansible.builtin.import_tasks: redhat.yml + when: ansible_os_family | lower == 'redhat' + +- name: Import tasks for debian + ansible.builtin.import_tasks: debian.yml + when: ansible_os_family | lower == 'debian' diff --git a/omero/roles/ome.postgresql_client/tasks/redhat.yml b/omero/roles/ome.postgresql_client/tasks/redhat.yml new file mode 100644 index 00000000..0365f4e1 --- /dev/null +++ b/omero/roles/ome.postgresql_client/tasks/redhat.yml @@ -0,0 +1,44 @@ +--- + +- name: Import a key for postgres (x86_64) + become: true + ansible.builtin.rpm_key: + state: present + key: https://download.postgresql.org/pub/repos/yum/keys/PGDG-RPM-GPG-KEY-RHEL + when: ansible_facts.get('architecture') is search("x86_64") + +- name: Import a key for postgres (aarch64) + become: true + ansible.builtin.rpm_key: + state: present + key: https://download.postgresql.org/pub/repos/yum/keys/PGDG-RPM-GPG-KEY-AARCH64-RHEL + when: ansible_facts.get('architecture') is search("aarch64") + +- name: Postgres | setup dnf repository for arch64 + become: true + ansible.builtin.dnf: + update_cache: true + name: + https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-aarch64/pgdg-redhat-repo-latest.noarch.rpm + state: present + when: ansible_facts.get('architecture') is search("aarch64") + +- name: Postgres | setup dnf repository for amd64 + become: true + ansible.builtin.dnf: + update_cache: true + name: + https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm + state: present + when: ansible_facts.get('architecture') is search("x86_64") + +- name: Postgres | install client packages + become: true + ansible.builtin.dnf: + update_cache: true + name: >- + postgresql{{ postgresql_version }}{{ + (postgresql_package_version | length > 0) | + ternary('-' + postgresql_package_version, '') + }} + state: present diff --git a/omero/roles/ome.postgresql_client/templates/pg_hba-conf.j2 b/omero/roles/ome.postgresql_client/templates/pg_hba-conf.j2 new file mode 100644 index 00000000..328c05fe --- /dev/null +++ b/omero/roles/ome.postgresql_client/templates/pg_hba-conf.j2 @@ -0,0 +1,11 @@ +# PostgreSQL Client Authentication Configuration File (Ansible) +# TYPE DATABASE USER ADDRESS METHOD +{% if postgresql_server_auth_local %} +local all all peer +host all all 127.0.0.1/32 md5 +host all all ::1/128 md5 +{% endif %} + +{% for item in postgresql_server_auth %} +host {{ item.database }} {{ item.user }} {{ item.address }} {{ item.method | default("md5") }} +{% endfor %} diff --git a/omero/roles/ome.postgresql_client/templates/postgresql-conf-10-ubuntu.j2 b/omero/roles/ome.postgresql_client/templates/postgresql-conf-10-ubuntu.j2 new file mode 100644 index 00000000..c8da6439 --- /dev/null +++ b/omero/roles/ome.postgresql_client/templates/postgresql-conf-10-ubuntu.j2 @@ -0,0 +1,673 @@ +# ----------------------------- +# PostgreSQL configuration file +# ----------------------------- +# +# This file consists of lines of the form: +# +# name = value +# +# (The "=" is optional.) Whitespace may be used. Comments are introduced with +# "#" anywhere on a line. The complete list of parameter names and allowed +# values can be found in the PostgreSQL documentation. +# +# The commented-out settings shown in this file represent the default values. +# Re-commenting a setting is NOT sufficient to revert it to the default value; +# you need to reload the server. +# +# This file is read on server startup and when the server receives a SIGHUP +# signal. If you edit the file on a running system, you have to SIGHUP the +# server for the changes to take effect, run "pg_ctl reload", or execute +# "SELECT pg_reload_conf()". Some parameters, which are marked below, +# require a server shutdown and restart to take effect. +# +# Any parameter can also be given as a command-line option to the server, e.g., +# "postgres -c log_connections=on". Some parameters can be changed at run time +# with the "SET" SQL command. +# +# Memory units: kB = kilobytes Time units: ms = milliseconds +# MB = megabytes s = seconds +# GB = gigabytes min = minutes +# TB = terabytes h = hours +# d = days + + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +# The default values of these variables are driven from the -D command-line +# option or PGDATA environment variable, represented here as ConfigDir. + +data_directory = '/var/lib/postgresql/10/main' # use data in another directory + # (change requires restart) +hba_file = '/etc/postgresql/10/main/pg_hba.conf' # host-based authentication file + # (change requires restart) +ident_file = '/etc/postgresql/10/main/pg_ident.conf' # ident configuration file + # (change requires restart) + +# If external_pid_file is not explicitly set, no extra PID file is written. +external_pid_file = '/var/run/postgresql/10-main.pid' # write an extra PID file + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +#listen_addresses = 'localhost' # what IP address(es) to listen on; + # comma-separated list of addresses; + # defaults to 'localhost'; use '*' for all + # (change requires restart) +port = 5432 # (change requires restart) +max_connections = 100 # (change requires restart) +#superuser_reserved_connections = 3 # (change requires restart) +unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories + # (change requires restart) +#unix_socket_group = '' # (change requires restart) +#unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +#bonjour = off # advertise server via Bonjour + # (change requires restart) +#bonjour_name = '' # defaults to the computer name + # (change requires restart) + +# - Security and Authentication - + +#authentication_timeout = 1min # 1s-600s +ssl = on +#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers +#ssl_prefer_server_ciphers = on +#ssl_ecdh_curve = 'prime256v1' +#ssl_dh_params_file = '' +ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem' +ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key' +#ssl_ca_file = '' +#ssl_crl_file = '' +#password_encryption = md5 # md5 or scram-sha-256 +#db_user_namespace = off +#row_security = on + +# GSSAPI using Kerberos +#krb_server_keyfile = '' +#krb_caseins_users = off + +# - TCP Keepalives - +# see "man 7 tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default + + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +shared_buffers = 128MB # min 128kB + # (change requires restart) +#huge_pages = try # on, off, or try + # (change requires restart) +#temp_buffers = 8MB # min 800kB +#max_prepared_transactions = 0 # zero disables the feature + # (change requires restart) +# Caution: it is not advisable to set max_prepared_transactions nonzero unless +# you actively intend to use prepared transactions. +#work_mem = 4MB # min 64kB +#maintenance_work_mem = 64MB # min 1MB +#replacement_sort_tuples = 150000 # limits use of replacement selection sort +#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem +#max_stack_depth = 2MB # min 100kB +dynamic_shared_memory_type = posix # the default is the first option + # supported by the operating system: + # posix + # sysv + # windows + # mmap + # use none to disable dynamic shared memory + # (change requires restart) + +# - Disk - + +#temp_file_limit = -1 # limits per-process temp file space + # in kB, or -1 for no limit + +# - Kernel Resource Usage - + +#max_files_per_process = 1000 # min 25 + # (change requires restart) +#shared_preload_libraries = '' # (change requires restart) + +# - Cost-Based Vacuum Delay - + +#vacuum_cost_delay = 0 # 0-100 milliseconds +#vacuum_cost_page_hit = 1 # 0-10000 credits +#vacuum_cost_page_miss = 10 # 0-10000 credits +#vacuum_cost_page_dirty = 20 # 0-10000 credits +#vacuum_cost_limit = 200 # 1-10000 credits + +# - Background Writer - + +#bgwriter_delay = 200ms # 10-10000ms between rounds +#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round +#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round +#bgwriter_flush_after = 512kB # measured in pages, 0 disables + +# - Asynchronous Behavior - + +#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching +#max_worker_processes = 8 # (change requires restart) +#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers +#max_parallel_workers = 8 # maximum number of max_worker_processes that + # can be used in parallel queries +#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate + # (change requires restart) +#backend_flush_after = 0 # measured in pages, 0 disables + + +#------------------------------------------------------------------------------ +# WRITE AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +#wal_level = replica # minimal, replica, or logical + # (change requires restart) +#fsync = on # flush data to disk for crash safety + # (turning this off can cause + # unrecoverable data corruption) +#synchronous_commit = on # synchronization level; + # off, local, remote_write, remote_apply, or on +#wal_sync_method = fsync # the default is the first option + # supported by the operating system: + # open_datasync + # fdatasync (default on Linux) + # fsync + # fsync_writethrough + # open_sync +#full_page_writes = on # recover from partial page writes +#wal_compression = off # enable compression of full-page writes +#wal_log_hints = off # also do full page writes of non-critical updates + # (change requires restart) +#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers + # (change requires restart) +#wal_writer_delay = 200ms # 1-10000 milliseconds +#wal_writer_flush_after = 1MB # measured in pages, 0 disables + +#commit_delay = 0 # range 0-100000, in microseconds +#commit_siblings = 5 # range 1-1000 + +# - Checkpoints - + +#checkpoint_timeout = 5min # range 30s-1d +#max_wal_size = 1GB +#min_wal_size = 80MB +#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 +#checkpoint_flush_after = 256kB # measured in pages, 0 disables +#checkpoint_warning = 30s # 0 disables + +# - Archiving - + +#archive_mode = off # enables archiving; off, on, or always + # (change requires restart) +#archive_command = '' # command to use to archive a logfile segment + # placeholders: %p = path of file to archive + # %f = file name only + # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' +#archive_timeout = 0 # force a logfile segment switch after this + # number of seconds; 0 disables + + +#------------------------------------------------------------------------------ +# REPLICATION +#------------------------------------------------------------------------------ + +# - Sending Server(s) - + +# Set these on the master and on any standby that will send replication data. + +#max_wal_senders = 10 # max number of walsender processes + # (change requires restart) +#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables +#wal_sender_timeout = 60s # in milliseconds; 0 disables + +#max_replication_slots = 10 # max number of replication slots + # (change requires restart) +#track_commit_timestamp = off # collect timestamp of transaction commit + # (change requires restart) + +# - Master Server - + +# These settings are ignored on a standby server. + +#synchronous_standby_names = '' # standby servers that provide sync rep + # method to choose sync standbys, number of sync standbys, + # and comma-separated list of application_name + # from standby(s); '*' = all +#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed + +# - Standby Servers - + +# These settings are ignored on a master server. + +#hot_standby = on # "off" disallows queries during recovery + # (change requires restart) +#max_standby_archive_delay = 30s # max delay before canceling queries + # when reading WAL from archive; + # -1 allows indefinite delay +#max_standby_streaming_delay = 30s # max delay before canceling queries + # when reading streaming WAL; + # -1 allows indefinite delay +#wal_receiver_status_interval = 10s # send replies at least this often + # 0 disables +#hot_standby_feedback = off # send info from standby to prevent + # query conflicts +#wal_receiver_timeout = 60s # time that receiver waits for + # communication from master + # in milliseconds; 0 disables +#wal_retrieve_retry_interval = 5s # time to wait before retrying to + # retrieve WAL after a failed attempt + +# - Subscribers - + +# These settings are ignored on a publisher. + +#max_logical_replication_workers = 4 # taken from max_worker_processes + # (change requires restart) +#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers + + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Method Configuration - + +#enable_bitmapscan = on +#enable_hashagg = on +#enable_hashjoin = on +#enable_indexscan = on +#enable_indexonlyscan = on +#enable_material = on +#enable_mergejoin = on +#enable_nestloop = on +#enable_seqscan = on +#enable_sort = on +#enable_tidscan = on + +# - Planner Cost Constants - + +#seq_page_cost = 1.0 # measured on an arbitrary scale +#random_page_cost = 4.0 # same scale as above +#cpu_tuple_cost = 0.01 # same scale as above +#cpu_index_tuple_cost = 0.005 # same scale as above +#cpu_operator_cost = 0.0025 # same scale as above +#parallel_tuple_cost = 0.1 # same scale as above +#parallel_setup_cost = 1000.0 # same scale as above +#min_parallel_table_scan_size = 8MB +#min_parallel_index_scan_size = 512kB +#effective_cache_size = 4GB + +# - Genetic Query Optimizer - + +#geqo = on +#geqo_threshold = 12 +#geqo_effort = 5 # range 1-10 +#geqo_pool_size = 0 # selects default based on effort +#geqo_generations = 0 # selects default based on effort +#geqo_selection_bias = 2.0 # range 1.5-2.0 +#geqo_seed = 0.0 # range 0.0-1.0 + +# - Other Planner Options - + +#default_statistics_target = 100 # range 1-10000 +#constraint_exclusion = partition # on, off, or partition +#cursor_tuple_fraction = 0.1 # range 0.0-1.0 +#from_collapse_limit = 8 +#join_collapse_limit = 8 # 1 disables collapsing of explicit + # JOIN clauses +#force_parallel_mode = off + + +#------------------------------------------------------------------------------ +# ERROR REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - Where to Log - + +log_destination = 'stderr' # Valid values are combinations of + # stderr, csvlog, syslog, and eventlog, + # depending on platform. csvlog + # requires logging_collector to be on. + +# This is used when logging to stderr: +logging_collector = on # Enable capturing of stderr and csvlog + # into log files. Required to be on for + # csvlogs. + # (change requires restart) + +# These are only used if logging_collector is on: +log_directory = 'pg_log' # directory where log files are written, + # can be absolute or relative to PGDATA +log_filename = 'postgresql-%a.log' # log file name pattern, + # can include strftime() escapes +#log_file_mode = 0600 # creation mode for log files, + # begin with 0 to use octal notation +log_truncate_on_rotation = on # If on, an existing log file with the + # same name as the new log file will be + # truncated rather than appended to. + # But such truncation only occurs on + # time-driven rotation, not on restarts + # or size-driven rotation. Default is + # off, meaning append to existing files + # in all cases. +log_rotation_age = 1d # Automatic rotation of logfiles will + # happen after that time. 0 disables. +log_rotation_size = 0 # Automatic rotation of logfiles will + # happen after that much log output. + # 0 disables. + +# These are relevant when logging to syslog: +#syslog_facility = 'LOCAL0' +#syslog_ident = 'postgres' +#syslog_sequence_numbers = on +#syslog_split_messages = on + +# This is only relevant when logging to eventlog (win32): +# (change requires restart) +#event_source = 'PostgreSQL' + +# - When to Log - + +#client_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # log + # notice + # warning + # error + +#log_min_messages = warning # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic + +#log_min_error_statement = error # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic (effectively off) + +#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements + # and their durations, > 0 logs only + # statements running at least this number + # of milliseconds + + +# - What to Log - + +#debug_print_parse = off +#debug_print_rewritten = off +#debug_print_plan = off +#debug_pretty_print = on +#log_checkpoints = off +#log_connections = off +#log_disconnections = off +#log_duration = off +#log_error_verbosity = default # terse, default, or verbose messages +#log_hostname = off +log_line_prefix = '%m [%p] %q%u@%d ' # special values: + # %a = application name + # %u = user name + # %d = database name + # %r = remote host and port + # %h = remote host + # %p = process ID + # %t = timestamp without milliseconds + # %m = timestamp with milliseconds + # %n = timestamp with milliseconds (as a Unix epoch) + # %i = command tag + # %e = SQL state + # %c = session ID + # %l = session line number + # %s = session start timestamp + # %v = virtual transaction ID + # %x = transaction ID (0 if none) + # %q = stop here in non-session + # processes + # %% = '%' + # e.g. '<%u%%%d> ' +#log_lock_waits = off # log lock waits >= deadlock_timeout +#log_statement = 'none' # none, ddl, mod, all +#log_replication_commands = off +#log_temp_files = -1 # log temporary files equal or larger + # than the specified size in kilobytes; + # -1 disables, 0 logs all temp files +log_timezone = 'Etc/UTC' + + +# - Process Title - + +cluster_name = '10/main' # added to process titles if nonempty + # (change requires restart) +#update_process_title = on + + +#------------------------------------------------------------------------------ +# RUNTIME STATISTICS +#------------------------------------------------------------------------------ + +# - Query/Index Statistics Collector - + +#track_activities = on +#track_counts = on +#track_io_timing = off +#track_functions = none # none, pl, all +#track_activity_query_size = 1024 # (change requires restart) +stats_temp_directory = '/var/run/postgresql/10-main.pg_stat_tmp' + + +# - Statistics Monitoring - + +#log_parser_stats = off +#log_planner_stats = off +#log_executor_stats = off +#log_statement_stats = off + + +#------------------------------------------------------------------------------ +# AUTOVACUUM PARAMETERS +#------------------------------------------------------------------------------ + +#autovacuum = on # Enable autovacuum subprocess? 'on' + # requires track_counts to also be on. +#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and + # their durations, > 0 logs only + # actions running at least this number + # of milliseconds. +#autovacuum_max_workers = 3 # max number of autovacuum subprocesses + # (change requires restart) +#autovacuum_naptime = 1min # time between autovacuum runs +#autovacuum_vacuum_threshold = 50 # min number of row updates before + # vacuum +#autovacuum_analyze_threshold = 50 # min number of row updates before + # analyze +#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze +#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum + # (change requires restart) +#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age + # before forced vacuum + # (change requires restart) +#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for + # autovacuum, in milliseconds; + # -1 means use vacuum_cost_delay +#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for + # autovacuum, -1 means use + # vacuum_cost_limit + + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Statement Behavior - + +#search_path = '"$user", public' # schema names +#default_tablespace = '' # a tablespace name, '' uses the default +#temp_tablespaces = '' # a list of tablespace names, '' uses + # only default tablespace +#check_function_bodies = on +#default_transaction_isolation = 'read committed' +#default_transaction_read_only = off +#default_transaction_deferrable = off +#session_replication_role = 'origin' +#statement_timeout = 0 # in milliseconds, 0 is disabled +#lock_timeout = 0 # in milliseconds, 0 is disabled +#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#vacuum_freeze_min_age = 50000000 +#vacuum_freeze_table_age = 150000000 +#vacuum_multixact_freeze_min_age = 5000000 +#vacuum_multixact_freeze_table_age = 150000000 +#bytea_output = 'hex' # hex, escape +#xmlbinary = 'base64' +#xmloption = 'content' +#gin_fuzzy_search_limit = 0 +#gin_pending_list_limit = 4MB + +# - Locale and Formatting - + +datestyle = 'iso, mdy' +#intervalstyle = 'postgres' +timezone = 'Etc/UTC' +#timezone_abbreviations = 'Default' # Select the set of available time zone + # abbreviations. Currently, there are + # Default + # Australia (historical usage) + # India + # You can create your own file in + # share/timezonesets/. +#extra_float_digits = 0 # min -15, max 3 +#client_encoding = sql_ascii # actually, defaults to database + # encoding + +# These settings are initialized by initdb, but they can be changed. +lc_messages = 'C.UTF-8' # locale for system error message + # strings +lc_monetary = 'C.UTF-8' # locale for monetary formatting +lc_numeric = 'C.UTF-8' # locale for number formatting +lc_time = 'C.UTF-8' # locale for time formatting + +# default configuration for text search +default_text_search_config = 'pg_catalog.english' + +# - Other Defaults - + +#dynamic_library_path = '$libdir' +#local_preload_libraries = '' +#session_preload_libraries = '' + + +#------------------------------------------------------------------------------ +# LOCK MANAGEMENT +#------------------------------------------------------------------------------ + +#deadlock_timeout = 1s +#max_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_relation = -2 # negative values mean + # (max_pred_locks_per_transaction + # / -max_pred_locks_per_relation) - 1 +#max_pred_locks_per_page = 2 # min 0 + + +#------------------------------------------------------------------------------ +# VERSION/PLATFORM COMPATIBILITY +#------------------------------------------------------------------------------ + +# - Previous PostgreSQL Versions - + +#array_nulls = on +#backslash_quote = safe_encoding # on, off, or safe_encoding +#default_with_oids = off +#escape_string_warning = on +#lo_compat_privileges = off +#operator_precedence_warning = off +#quote_all_identifiers = off +#standard_conforming_strings = on +#synchronize_seqscans = on + +# - Other Platforms and Clients - + +#transform_null_equals = off + + +#------------------------------------------------------------------------------ +# ERROR HANDLING +#------------------------------------------------------------------------------ + +#exit_on_error = off # terminate session on any error? +#restart_after_crash = on # reinitialize after backend crash? +#data_sync_retry = off # retry or panic on failure to fsync + # data? + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONFIG FILE INCLUDES +#------------------------------------------------------------------------------ + +# These options allow settings to be loaded from files other than the +# default postgresql.conf. Note that these are directives, not variable +# assignments, so they can usefully be given more than once. + +include_dir = 'conf.d' # include files ending in '.conf' from + # a directory, e.g., 'conf.d' +#include_if_exists = '...' # include file only if it exists +#include = '...' # include file + + +#------------------------------------------------------------------------------ +# CUSTOMIZED OPTIONS +#------------------------------------------------------------------------------ + +# Add settings for extensions here + + +#------------------------------------------------------------------------------ +# ANSIBLE OPTIONS +#------------------------------------------------------------------------------ + +listen_addresses = {{ postgresql_server_listen }} + +{% for option in (postgresql_server_conf | sort) %} +{{ option }} = {{ postgresql_server_conf[option] }} +{% endfor %} diff --git a/omero/roles/ome.postgresql_client/templates/postgresql-conf.j2 b/omero/roles/ome.postgresql_client/templates/postgresql-conf.j2 new file mode 100644 index 00000000..0f1193d6 --- /dev/null +++ b/omero/roles/ome.postgresql_client/templates/postgresql-conf.j2 @@ -0,0 +1,654 @@ +# {{ ansible_managed }} + +# ----------------------------- +# PostgreSQL configuration file +# ----------------------------- +# +# This file consists of lines of the form: +# +# name = value +# +# (The "=" is optional.) Whitespace may be used. Comments are introduced with +# "#" anywhere on a line. The complete list of parameter names and allowed +# values can be found in the PostgreSQL documentation. +# +# The commented-out settings shown in this file represent the default values. +# Re-commenting a setting is NOT sufficient to revert it to the default value; +# you need to reload the server. +# +# This file is read on server startup and when the server receives a SIGHUP +# signal. If you edit the file on a running system, you have to SIGHUP the +# server for the changes to take effect, or use "pg_ctl reload". Some +# parameters, which are marked below, require a server shutdown and restart to +# take effect. +# +# Any parameter can also be given as a command-line option to the server, e.g., +# "postgres -c log_connections=on". Some parameters can be changed at run time +# with the "SET" SQL command. +# +# Memory units: kB = kilobytes Time units: ms = milliseconds +# MB = megabytes s = seconds +# GB = gigabytes min = minutes +# TB = terabytes h = hours +# d = days + + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +# The default values of these variables are driven from the -D command-line +# option or PGDATA environment variable, represented here as ConfigDir. + +#data_directory = 'ConfigDir' # use data in another directory + # (change requires restart) +#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file + # (change requires restart) +#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file + # (change requires restart) + +# If external_pid_file is not explicitly set, no extra PID file is written. +#external_pid_file = '' # write an extra PID file + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +#listen_addresses = 'localhost' # what IP address(es) to listen on; + # comma-separated list of addresses; + # defaults to 'localhost'; use '*' for all + # (change requires restart) +#port = 5432 # (change requires restart) +max_connections = 100 # (change requires restart) +#superuser_reserved_connections = 3 # (change requires restart) +#unix_socket_directories = '/var/run/postgresql, /tmp' # comma-separated list of directories + # (change requires restart) +#unix_socket_group = '' # (change requires restart) +#unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +#bonjour = off # advertise server via Bonjour + # (change requires restart) +#bonjour_name = '' # defaults to the computer name + # (change requires restart) + +# - Security and Authentication - + +#authentication_timeout = 1min # 1s-600s +#ssl = off # (change requires restart) +#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers + # (change requires restart) +#ssl_prefer_server_ciphers = on # (change requires restart) +#ssl_ecdh_curve = 'prime256v1' # (change requires restart) +#ssl_cert_file = 'server.crt' # (change requires restart) +#ssl_key_file = 'server.key' # (change requires restart) +#ssl_ca_file = '' # (change requires restart) +#ssl_crl_file = '' # (change requires restart) +#password_encryption = on +#db_user_namespace = off +#row_security = on + +# GSSAPI using Kerberos +#krb_server_keyfile = '' +#krb_caseins_users = off + +# - TCP Keepalives - +# see "man 7 tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default + + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +shared_buffers = 128MB # min 128kB + # (change requires restart) +#huge_pages = try # on, off, or try + # (change requires restart) +#temp_buffers = 8MB # min 800kB +#max_prepared_transactions = 0 # zero disables the feature + # (change requires restart) +# Caution: it is not advisable to set max_prepared_transactions nonzero unless +# you actively intend to use prepared transactions. +#work_mem = 4MB # min 64kB +#maintenance_work_mem = 64MB # min 1MB +#replacement_sort_tuples = 150000 # limits use of replacement selection sort +#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem +#max_stack_depth = 2MB # min 100kB +dynamic_shared_memory_type = posix # the default is the first option + # supported by the operating system: + # posix + # sysv + # windows + # mmap + # use none to disable dynamic shared memory + +# - Disk - + +#temp_file_limit = -1 # limits per-process temp file space + # in kB, or -1 for no limit + +# - Kernel Resource Usage - + +#max_files_per_process = 1000 # min 25 + # (change requires restart) +#shared_preload_libraries = '' # (change requires restart) + +# - Cost-Based Vacuum Delay - + +#vacuum_cost_delay = 0 # 0-100 milliseconds +#vacuum_cost_page_hit = 1 # 0-10000 credits +#vacuum_cost_page_miss = 10 # 0-10000 credits +#vacuum_cost_page_dirty = 20 # 0-10000 credits +#vacuum_cost_limit = 200 # 1-10000 credits + +# - Background Writer - + +#bgwriter_delay = 200ms # 10-10000ms between rounds +#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round +#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round +#bgwriter_flush_after = 512kB # measured in pages, 0 disables + +# - Asynchronous Behavior - + +#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching +#max_worker_processes = 8 # (change requires restart) +#max_parallel_workers_per_gather = 0 # taken from max_worker_processes +#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate + # (change requires restart) +#backend_flush_after = 0 # measured in pages, 0 disables + + +#------------------------------------------------------------------------------ +# WRITE AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +#wal_level = minimal # minimal, replica, or logical + # (change requires restart) +#fsync = on # flush data to disk for crash safety + # (turning this off can cause + # unrecoverable data corruption) +#synchronous_commit = on # synchronization level; + # off, local, remote_write, remote_apply, or on +#wal_sync_method = fsync # the default is the first option + # supported by the operating system: + # open_datasync + # fdatasync (default on Linux) + # fsync + # fsync_writethrough + # open_sync +#full_page_writes = on # recover from partial page writes +#wal_compression = off # enable compression of full-page writes +#wal_log_hints = off # also do full page writes of non-critical updates + # (change requires restart) +#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers + # (change requires restart) +#wal_writer_delay = 200ms # 1-10000 milliseconds +#wal_writer_flush_after = 1MB # measured in pages, 0 disables + +#commit_delay = 0 # range 0-100000, in microseconds +#commit_siblings = 5 # range 1-1000 + +# - Checkpoints - + +#checkpoint_timeout = 5min # range 30s-1d +#max_wal_size = 1GB +#min_wal_size = 80MB +#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 +#checkpoint_flush_after = 256kB # measured in pages, 0 disables +#checkpoint_warning = 30s # 0 disables + +# - Archiving - + +#archive_mode = off # enables archiving; off, on, or always + # (change requires restart) +#archive_command = '' # command to use to archive a logfile segment + # placeholders: %p = path of file to archive + # %f = file name only + # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' +#archive_timeout = 0 # force a logfile segment switch after this + # number of seconds; 0 disables + + +#------------------------------------------------------------------------------ +# REPLICATION +#------------------------------------------------------------------------------ + +# - Sending Server(s) - + +# Set these on the master and on any standby that will send replication data. + +#max_wal_senders = 0 # max number of walsender processes + # (change requires restart) +#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables +#wal_sender_timeout = 60s # in milliseconds; 0 disables + +#max_replication_slots = 0 # max number of replication slots + # (change requires restart) +#track_commit_timestamp = off # collect timestamp of transaction commit + # (change requires restart) + +# - Master Server - + +# These settings are ignored on a standby server. + +#synchronous_standby_names = '' # standby servers that provide sync rep + # number of sync standbys and comma-separated list of application_name + # from standby(s); '*' = all +#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed + +# - Standby Servers - + +# These settings are ignored on a master server. + +#hot_standby = off # "on" allows queries during recovery + # (change requires restart) +#max_standby_archive_delay = 30s # max delay before canceling queries + # when reading WAL from archive; + # -1 allows indefinite delay +#max_standby_streaming_delay = 30s # max delay before canceling queries + # when reading streaming WAL; + # -1 allows indefinite delay +#wal_receiver_status_interval = 10s # send replies at least this often + # 0 disables +#hot_standby_feedback = off # send info from standby to prevent + # query conflicts +#wal_receiver_timeout = 60s # time that receiver waits for + # communication from master + # in milliseconds; 0 disables +#wal_retrieve_retry_interval = 5s # time to wait before retrying to + # retrieve WAL after a failed attempt + + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Method Configuration - + +#enable_bitmapscan = on +#enable_hashagg = on +#enable_hashjoin = on +#enable_indexscan = on +#enable_indexonlyscan = on +#enable_material = on +#enable_mergejoin = on +#enable_nestloop = on +#enable_seqscan = on +#enable_sort = on +#enable_tidscan = on + +# - Planner Cost Constants - + +#seq_page_cost = 1.0 # measured on an arbitrary scale +#random_page_cost = 4.0 # same scale as above +#cpu_tuple_cost = 0.01 # same scale as above +#cpu_index_tuple_cost = 0.005 # same scale as above +#cpu_operator_cost = 0.0025 # same scale as above +#parallel_tuple_cost = 0.1 # same scale as above +#parallel_setup_cost = 1000.0 # same scale as above +#min_parallel_relation_size = 8MB +#effective_cache_size = 4GB + +# - Genetic Query Optimizer - + +#geqo = on +#geqo_threshold = 12 +#geqo_effort = 5 # range 1-10 +#geqo_pool_size = 0 # selects default based on effort +#geqo_generations = 0 # selects default based on effort +#geqo_selection_bias = 2.0 # range 1.5-2.0 +#geqo_seed = 0.0 # range 0.0-1.0 + +# - Other Planner Options - + +#default_statistics_target = 100 # range 1-10000 +#constraint_exclusion = partition # on, off, or partition +#cursor_tuple_fraction = 0.1 # range 0.0-1.0 +#from_collapse_limit = 8 +#join_collapse_limit = 8 # 1 disables collapsing of explicit + # JOIN clauses +#force_parallel_mode = off + + +#------------------------------------------------------------------------------ +# ERROR REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - Where to Log - + +log_destination = 'stderr' # Valid values are combinations of + # stderr, csvlog, syslog, and eventlog, + # depending on platform. csvlog + # requires logging_collector to be on. + +# This is used when logging to stderr: +logging_collector = on # Enable capturing of stderr and csvlog + # into log files. Required to be on for + # csvlogs. + # (change requires restart) + +# These are only used if logging_collector is on: +log_directory = 'pg_log' # directory where log files are written, + # can be absolute or relative to PGDATA +log_filename = 'postgresql-%a.log' # log file name pattern, + # can include strftime() escapes +#log_file_mode = 0600 # creation mode for log files, + # begin with 0 to use octal notation +log_truncate_on_rotation = on # If on, an existing log file with the + # same name as the new log file will be + # truncated rather than appended to. + # But such truncation only occurs on + # time-driven rotation, not on restarts + # or size-driven rotation. Default is + # off, meaning append to existing files + # in all cases. +log_rotation_age = 1d # Automatic rotation of logfiles will + # happen after that time. 0 disables. +log_rotation_size = 0 # Automatic rotation of logfiles will + # happen after that much log output. + # 0 disables. + +# These are relevant when logging to syslog: +#syslog_facility = 'LOCAL0' +#syslog_ident = 'postgres' +#syslog_sequence_numbers = on +#syslog_split_messages = on + +# This is only relevant when logging to eventlog (win32): +#event_source = 'PostgreSQL' + +# - When to Log - + +#client_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # log + # notice + # warning + # error + +#log_min_messages = warning # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic + +#log_min_error_statement = error # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic (effectively off) + +#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements + # and their durations, > 0 logs only + # statements running at least this number + # of milliseconds + + +# - What to Log - + +#debug_print_parse = off +#debug_print_rewritten = off +#debug_print_plan = off +#debug_pretty_print = on +#log_checkpoints = off +#log_connections = off +#log_disconnections = off +#log_duration = off +#log_error_verbosity = default # terse, default, or verbose messages +#log_hostname = off +log_line_prefix = '< %m > ' # special values: + # %a = application name + # %u = user name + # %d = database name + # %r = remote host and port + # %h = remote host + # %p = process ID + # %t = timestamp without milliseconds + # %m = timestamp with milliseconds + # %n = timestamp with milliseconds (as a Unix epoch) + # %i = command tag + # %e = SQL state + # %c = session ID + # %l = session line number + # %s = session start timestamp + # %v = virtual transaction ID + # %x = transaction ID (0 if none) + # %q = stop here in non-session + # processes + # %% = '%' + # e.g. '<%u%%%d> ' +#log_lock_waits = off # log lock waits >= deadlock_timeout +#log_statement = 'none' # none, ddl, mod, all +#log_replication_commands = off +#log_temp_files = -1 # log temporary files equal or larger + # than the specified size in kilobytes; + # -1 disables, 0 logs all temp files +log_timezone = 'UTC' + + +# - Process Title - + +#cluster_name = '' # added to process titles if nonempty + # (change requires restart) +#update_process_title = on + + +#------------------------------------------------------------------------------ +# RUNTIME STATISTICS +#------------------------------------------------------------------------------ + +# - Query/Index Statistics Collector - + +#track_activities = on +#track_counts = on +#track_io_timing = off +#track_functions = none # none, pl, all +#track_activity_query_size = 1024 # (change requires restart) +#stats_temp_directory = 'pg_stat_tmp' + + +# - Statistics Monitoring - + +#log_parser_stats = off +#log_planner_stats = off +#log_executor_stats = off +#log_statement_stats = off + + +#------------------------------------------------------------------------------ +# AUTOVACUUM PARAMETERS +#------------------------------------------------------------------------------ + +#autovacuum = on # Enable autovacuum subprocess? 'on' + # requires track_counts to also be on. +#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and + # their durations, > 0 logs only + # actions running at least this number + # of milliseconds. +#autovacuum_max_workers = 3 # max number of autovacuum subprocesses + # (change requires restart) +#autovacuum_naptime = 1min # time between autovacuum runs +#autovacuum_vacuum_threshold = 50 # min number of row updates before + # vacuum +#autovacuum_analyze_threshold = 50 # min number of row updates before + # analyze +#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze +#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum + # (change requires restart) +#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age + # before forced vacuum + # (change requires restart) +#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for + # autovacuum, in milliseconds; + # -1 means use vacuum_cost_delay +#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for + # autovacuum, -1 means use + # vacuum_cost_limit + + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Statement Behavior - + +#search_path = '"$user", public' # schema names +#default_tablespace = '' # a tablespace name, '' uses the default +#temp_tablespaces = '' # a list of tablespace names, '' uses + # only default tablespace +#check_function_bodies = on +#default_transaction_isolation = 'read committed' +#default_transaction_read_only = off +#default_transaction_deferrable = off +#session_replication_role = 'origin' +#statement_timeout = 0 # in milliseconds, 0 is disabled +#lock_timeout = 0 # in milliseconds, 0 is disabled +#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#vacuum_freeze_min_age = 50000000 +#vacuum_freeze_table_age = 150000000 +#vacuum_multixact_freeze_min_age = 5000000 +#vacuum_multixact_freeze_table_age = 150000000 +#bytea_output = 'hex' # hex, escape +#xmlbinary = 'base64' +#xmloption = 'content' +#gin_fuzzy_search_limit = 0 +#gin_pending_list_limit = 4MB + +# - Locale and Formatting - + +datestyle = 'iso, mdy' +#intervalstyle = 'postgres' +timezone = 'UTC' +#timezone_abbreviations = 'Default' # Select the set of available time zone + # abbreviations. Currently, there are + # Default + # Australia (historical usage) + # India + # You can create your own file in + # share/timezonesets/. +#extra_float_digits = 0 # min -15, max 3 +#client_encoding = sql_ascii # actually, defaults to database + # encoding + +# These settings are initialized by initdb, but they can be changed. +lc_messages = 'en_US.UTF-8' # locale for system error message + # strings +lc_monetary = 'en_US.UTF-8' # locale for monetary formatting +lc_numeric = 'en_US.UTF-8' # locale for number formatting +lc_time = 'en_US.UTF-8' # locale for time formatting + +# default configuration for text search +default_text_search_config = 'pg_catalog.english' + +# - Other Defaults - + +#dynamic_library_path = '$libdir' +#local_preload_libraries = '' +#session_preload_libraries = '' + + +#------------------------------------------------------------------------------ +# LOCK MANAGEMENT +#------------------------------------------------------------------------------ + +#deadlock_timeout = 1s +#max_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_transaction = 64 # min 10 + # (change requires restart) + + +#------------------------------------------------------------------------------ +# VERSION/PLATFORM COMPATIBILITY +#------------------------------------------------------------------------------ + +# - Previous PostgreSQL Versions - + +#array_nulls = on +#backslash_quote = safe_encoding # on, off, or safe_encoding +#default_with_oids = off +#escape_string_warning = on +#lo_compat_privileges = off +#operator_precedence_warning = off +#quote_all_identifiers = off +#sql_inheritance = on +#standard_conforming_strings = on +#synchronize_seqscans = on + +# - Other Platforms and Clients - + +#transform_null_equals = off + + +#------------------------------------------------------------------------------ +# ERROR HANDLING +#------------------------------------------------------------------------------ + +#exit_on_error = off # terminate session on any error? +#restart_after_crash = on # reinitialize after backend crash? + + +#------------------------------------------------------------------------------ +# CONFIG FILE INCLUDES +#------------------------------------------------------------------------------ + +# These options allow settings to be loaded from files other than the +# default postgresql.conf. + +#include_dir = 'conf.d' # include files ending in '.conf' from + # directory 'conf.d' +#include_if_exists = 'exists.conf' # include file only if it exists +#include = 'special.conf' # include file + + +#------------------------------------------------------------------------------ +# CUSTOMIZED OPTIONS +#------------------------------------------------------------------------------ + +# Add settings for extensions here + + +#------------------------------------------------------------------------------ +# ANSIBLE OPTIONS +#------------------------------------------------------------------------------ + +listen_addresses = {{ postgresql_server_listen }} + +{% for option in (postgresql_server_conf | sort) %} +{{ option }} = {{ postgresql_server_conf[option] }} +{% endfor %} diff --git a/omero/roles/ome.postgresql_client/vars/main.yml b/omero/roles/ome.postgresql_client/vars/main.yml new file mode 100644 index 00000000..573edb16 --- /dev/null +++ b/omero/roles/ome.postgresql_client/vars/main.yml @@ -0,0 +1,26 @@ +--- +# vars file for ome.postgresql_client + +# DEPRECATED +# This variable includes information used by the postgresql (server) role +postgresql_distribution_redhat: + "12": + repo: pgdg12 + basename: postgresql12 + setup: postgresql-12-setup + "13": + repo: pgdg13 + basename: postgresql13 + setup: postgresql-13-setup + "14": + repo: pgdg14 + basename: postgresql14 + setup: postgresql-14-setup + "15": + repo: pgdg15 + basename: postgresql15 + setup: postgresql-15-setup + "16": + repo: pgdg16 + basename: postgresql16 + setup: postgresql-16-setup diff --git a/omero/roles/ome.python3_virtualenv/.github/workflows/molecule.yml b/omero/roles/ome.python3_virtualenv/.github/workflows/molecule.yml new file mode 100644 index 00000000..89f3b866 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} diff --git a/omero/roles/ome.python3_virtualenv/.gitignore b/omero/roles/ome.python3_virtualenv/.gitignore new file mode 100644 index 00000000..0bf56261 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/.gitignore @@ -0,0 +1,2 @@ +.*~ +__pycache__ diff --git a/omero/roles/ome.python3_virtualenv/LICENSE.md b/omero/roles/ome.python3_virtualenv/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.python3_virtualenv/README.md b/omero/roles/ome.python3_virtualenv/README.md new file mode 100644 index 00000000..6ce05dfc --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/README.md @@ -0,0 +1,24 @@ +Python3 Virtualenv +================== + +[![Actions Status](https://github.com/ome/ansible-role-python3-virtualenv/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-python3-virtualenv/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-python3_virtualenv-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/python3_virtualenv/) + +Install Python3 virtualenv dependencies and a wrapper script for the Ansible `pip` module. + +There are multiple ways of creating Python virtualenvs including `virtualenv`, `python3 -mvenv`, but these may take different parameters. +In some situations, particularly if `ansible_python_interpreter` is set, the Ansible `pip` modules pass unrecognised parameters. +This role installs a wrapper script `/usr/local/bin/ome-python3-virtualenv` should work in all cases. + + +The compatibility with Python 2 has been removed in version 0.2.0. + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk + +License +------- + +BSD diff --git a/omero/roles/ome.python3_virtualenv/files/ome-python3-virtualenv.sh b/omero/roles/ome.python3_virtualenv/files/ome-python3-virtualenv.sh new file mode 100644 index 00000000..3170f7d2 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/files/ome-python3-virtualenv.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# There are multiple ways of creating Python virtualenvs including +# virtualenv, python3 -mvenv, but these may take different parameters. +# In some situations, particularly if ansible_python_interpreter is set, +# the Ansible pip modules passes unrecognised parameters. +# This wrapper script should work in all cases. + +set -eu + +for arg in "$@"; do + # Ignore -p argument + if [[ $arg = -p ]]; then + shift + shift + elif [[ "$arg" = -p* ]]; then + shift + fi +done +python3 -mvenv "$@" diff --git a/omero/roles/ome.python3_virtualenv/meta/.galaxy_install_info b/omero/roles/ome.python3_virtualenv/meta/.galaxy_install_info new file mode 100644 index 00000000..603cf8ec --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:43 2024 +version: 0.2.0 diff --git a/omero/roles/ome.python3_virtualenv/meta/main.yml b/omero/roles/ome.python3_virtualenv/meta/main.yml new file mode 100644 index 00000000..4c979ff2 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/meta/main.yml @@ -0,0 +1,19 @@ +--- +galaxy_info: + role_name: python3_virtualenv + author: ome-devel@lists.openmicroscopy.org.uk + description: Install Python3 virtualenv dependencies + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.6 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + galaxy_tags: + - system + - python diff --git a/omero/roles/ome.python3_virtualenv/molecule/default/Dockerfile.j2 b/omero/roles/ome.python3_virtualenv/molecule/default/Dockerfile.j2 new file mode 100644 index 00000000..53cd6824 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/molecule/default/Dockerfile.j2 @@ -0,0 +1,12 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python3 sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python3 sudo bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python3 sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + fi diff --git a/omero/roles/ome.python3_virtualenv/molecule/default/molecule.yml b/omero/roles/ome.python3_virtualenv/molecule/default/molecule.yml new file mode 100644 index 00000000..b2dfeb09 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/molecule/default/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: rockylinux-9 + image: rockylinux:9 + groups: + - py3 + - name: ubuntu-2204 + image: ubuntu:22.04 + groups: + - py3 + +provisioner: + name: ansible + playbooks: + converge: ../resources/playbook.yml + lint: + name: ansible-lint + inventory: + group_vars: + py3: + ansible_python_interpreter: python3 + +scenario: + name: default +verifier: + name: testinfra + directory: ../resources/tests/ diff --git a/omero/roles/ome.python3_virtualenv/molecule/resources/playbook.yml b/omero/roles/ome.python3_virtualenv/molecule/resources/playbook.yml new file mode 100644 index 00000000..89468203 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/molecule/resources/playbook.yml @@ -0,0 +1,24 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.python3_virtualenv + + tasks: + - name: test | upgrade pip + become: true + pip: + name: "pip>=21" + state: present + virtualenv: /opt/test/python3-virtualenv + virtualenv_command: /usr/local/bin/ome-python3-virtualenv + + - name: test | install packages + become: true + pip: + name: + - omego + - scc + state: present + virtualenv: /opt/test/python3-virtualenv + virtualenv_command: /usr/local/bin/ome-python3-virtualenv diff --git a/omero/roles/ome.python3_virtualenv/molecule/resources/tests/test_default.py b/omero/roles/ome.python3_virtualenv/molecule/resources/tests/test_default.py new file mode 100644 index 00000000..6f4d7be7 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/molecule/resources/tests/test_default.py @@ -0,0 +1,18 @@ +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_virtualenv(host): + venv = '/opt/test/python3-virtualenv' + host.check_output(venv + '/bin/python --version').startswith('Python 3.') + host.check_output(venv + '/bin/pip --version').startswith('Python 3.') + assert host.file(venv + '/bin/python').is_file + assert host.file(venv + '/bin/python3').is_file + assert host.file(venv + '/bin/pip').is_file + assert host.file(venv + '/bin/pip3').is_file + packages = host.check_output(venv + '/bin/pip freeze') + assert 'omego==' in packages + assert 'scc==' in packages diff --git a/omero/roles/ome.python3_virtualenv/tasks/debian.yml b/omero/roles/ome.python3_virtualenv/tasks/debian.yml new file mode 100644 index 00000000..10419dc0 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/tasks/debian.yml @@ -0,0 +1,13 @@ +--- + +- name: python3 venv | install python3 + become: true + apt: + update_cache: true + name: + - python3 + - python3-distutils + - python3-venv + - python3-pip + - python3-setuptools + state: present diff --git a/omero/roles/ome.python3_virtualenv/tasks/main.yml b/omero/roles/ome.python3_virtualenv/tasks/main.yml new file mode 100644 index 00000000..20bb7b2f --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/tasks/main.yml @@ -0,0 +1,14 @@ +--- + +- import_tasks: redhat.yml + when: ansible_os_family | lower == 'redhat' + +- import_tasks: debian.yml + when: ansible_os_family | lower == 'debian' + +- name: python3 venv | create python virtualenv wrapper + become: true + copy: + dest: /usr/local/bin/ome-python3-virtualenv + src: ome-python3-virtualenv.sh + mode: 'u=rwx,g=rx,o=rx' diff --git a/omero/roles/ome.python3_virtualenv/tasks/redhat.yml b/omero/roles/ome.python3_virtualenv/tasks/redhat.yml new file mode 100644 index 00000000..bd5760c0 --- /dev/null +++ b/omero/roles/ome.python3_virtualenv/tasks/redhat.yml @@ -0,0 +1,11 @@ +--- + +- name: python3 venv | install packages + become: true + ansible.builtin.dnf: + update_cache: true + name: + - python3 + - python3-pip + - python3-setuptools + state: present diff --git a/omero/roles/ome.redis/.github/workflows/molecule.yml b/omero/roles/ome.redis/.github/workflows/molecule.yml new file mode 100644 index 00000000..af6569b9 --- /dev/null +++ b/omero/roles/ome.redis/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - name: galaxy + uses: ansible-actions/ansible-galaxy-action@v1.2.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + galaxy_version: ${{ github.ref_name }} diff --git a/omero/roles/ome.redis/.gitignore b/omero/roles/ome.redis/.gitignore new file mode 100644 index 00000000..b6261c93 --- /dev/null +++ b/omero/roles/ome.redis/.gitignore @@ -0,0 +1 @@ +.*~ diff --git a/omero/roles/ome.redis/LICENSE.md b/omero/roles/ome.redis/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.redis/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.redis/README.md b/omero/roles/ome.redis/README.md new file mode 100644 index 00000000..80f3d0b3 --- /dev/null +++ b/omero/roles/ome.redis/README.md @@ -0,0 +1,20 @@ +Redis +===== + +[![Actions Status](https://github.com/ome/ansible-role-redis/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-redis/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-redis-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/redis/) + +Install Redis. + + +Role Variables +-------------- + +All variables are optional. +- `redis_listen`: String containing interfaces to bind to, default `127.0.0.1` + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.redis/handlers/main.yml b/omero/roles/ome.redis/handlers/main.yml new file mode 100644 index 00000000..a6389d66 --- /dev/null +++ b/omero/roles/ome.redis/handlers/main.yml @@ -0,0 +1,8 @@ +--- +# Handlers for redis + +- name: restart redis + become: true + service: + name: redis + state: restarted diff --git a/omero/roles/ome.redis/meta/.galaxy_install_info b/omero/roles/ome.redis/meta/.galaxy_install_info new file mode 100644 index 00000000..11d88fb9 --- /dev/null +++ b/omero/roles/ome.redis/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:52 2024 +version: 1.3.0 diff --git a/omero/roles/ome.redis/meta/main.yml b/omero/roles/ome.redis/meta/main.yml new file mode 100644 index 00000000..7e9fa42a --- /dev/null +++ b/omero/roles/ome.redis/meta/main.yml @@ -0,0 +1,19 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Install Redis + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + namespace: ome + role_name: redis + galaxy_tags: [] + +dependencies: [] diff --git a/omero/roles/ome.redis/molecule/default/molecule.yml b/omero/roles/ome.redis/molecule/default/molecule.yml new file mode 100644 index 00000000..59be675b --- /dev/null +++ b/omero/roles/ome.redis/molecule/default/molecule.yml @@ -0,0 +1,36 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: rockylinux-9 + image: eniocarboni/docker-rockylinux-systemd:9 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options + - name: ubuntu-2204 + image: eniocarboni/docker-ubuntu-systemd:22.04 + command: /sbin/init + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.redis/molecule/default/playbook.yml b/omero/roles/ome.redis/molecule/default/playbook.yml new file mode 100644 index 00000000..2f3b85b1 --- /dev/null +++ b/omero/roles/ome.redis/molecule/default/playbook.yml @@ -0,0 +1,6 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.redis + redis_listen: 0.0.0.0 diff --git a/omero/roles/ome.redis/molecule/default/tests/test_default.py b/omero/roles/ome.redis/molecule/default/tests/test_default.py new file mode 100644 index 00000000..b7aa5149 --- /dev/null +++ b/omero/roles/ome.redis/molecule/default/tests/test_default.py @@ -0,0 +1,15 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_service_running_and_enabled(host): + assert host.service('redis').is_running + assert host.service('redis').is_enabled + + +def test_redis_config(host): + assert host.file('/etc/redis/redis.conf').contains('bind 0.0.0.0') diff --git a/omero/roles/ome.redis/tasks/main.yml b/omero/roles/ome.redis/tasks/main.yml new file mode 100644 index 00000000..b8725b7e --- /dev/null +++ b/omero/roles/ome.redis/tasks/main.yml @@ -0,0 +1,51 @@ +--- +# tasks file for roles/redis + +- name: Import a key for epel + ansible.builtin.rpm_key: + state: present + key: https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-9 + when: ansible_os_family == 'RedHat' + +- name: Setup dnf repository, epel + become: true + ansible.builtin.dnf: + update_cache: true + name: + https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm + state: present + when: ansible_os_family == 'RedHat' + +- name: install redis + become: true + ansible.builtin.dnf: + name: redis + state: present + when: ansible_os_family == 'RedHat' + +- name: Install redis + become: true + ansible.builtin.apt: + update_cache: true + name: redis + state: present + when: ansible_os_family == 'Debian' + +# Note: Fails in --check mode with /etc/redis/redis.conf +# does not exist +- name: configure redis for RHEL + become: true + lineinfile: + dest: /etc/redis/redis.conf + line: "bind {{ redis_listen | default('127.0.0.1') }}" + regexp: "^bind\\s.*" + state: present + notify: + - restart redis + +- name: set redis to start on startup + become: true + service: + name: redis + state: started + enabled: true diff --git a/omero/roles/ome.selinux_utils/.github/workflows/molecule.yml b/omero/roles/ome.selinux_utils/.github/workflows/molecule.yml new file mode 100644 index 00000000..543b1e7f --- /dev/null +++ b/omero/roles/ome.selinux_utils/.github/workflows/molecule.yml @@ -0,0 +1,62 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Read the role name + id: role-name + run: | + name=$(grep 'role_name' meta/main.yml | sed -r 's/^[^:]*:(.*)$/\1/' | tr -d '[:space:]') # noqa + echo "rolename=$name" >> "$GITHUB_OUTPUT" + - name: Publish to Galaxy + uses: ome/action-ansible-galaxy-publish@main + with: + galaxy-api-key: ${{ secrets.GALAXY_API_KEY }} + galaxy-version: ${{ github.ref_name }} + role-name: ${{ steps.role-name.outputs.rolename }} diff --git a/omero/roles/ome.selinux_utils/.gitignore b/omero/roles/ome.selinux_utils/.gitignore new file mode 100644 index 00000000..b6261c93 --- /dev/null +++ b/omero/roles/ome.selinux_utils/.gitignore @@ -0,0 +1 @@ +.*~ diff --git a/omero/roles/ome.selinux_utils/LICENSE.md b/omero/roles/ome.selinux_utils/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.selinux_utils/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.selinux_utils/README.md b/omero/roles/ome.selinux_utils/README.md new file mode 100644 index 00000000..430df72c --- /dev/null +++ b/omero/roles/ome.selinux_utils/README.md @@ -0,0 +1,32 @@ +SELinux Utils +============= + +[![Actions Status](https://github.com/ome/ansible-role-selinux-utils/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-selinux-utils/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-selinux_utils-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/selinux_utils/) + +Sets a host variable indicating whether SELinux is enabled or not. +Installs utilities for interacting with SELinux if it is. + +These utilities may be required by some Ansible modules when SELinux is enabled, and are not always present in CentOS 7 base images. + +This role will set the host variable `selinux_enabled: {True,False}` which can be used in later roles. + +Ideally this role should be included as a dependency in `meta/main.yml` of any roles that need to know whether SELinux is enabled. + + +Example Playbook +---------------- + + - hosts: localhost + roles: + - ome.selinux_utils + tasks: + debug: + msg: "SELinux is enabled or permissive" + when: selinux_enabled + + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.selinux_utils/meta/.galaxy_install_info b/omero/roles/ome.selinux_utils/meta/.galaxy_install_info new file mode 100644 index 00000000..6e9df54f --- /dev/null +++ b/omero/roles/ome.selinux_utils/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:53 2024 +version: 2.1.1 diff --git a/omero/roles/ome.selinux_utils/meta/main.yml b/omero/roles/ome.selinux_utils/meta/main.yml new file mode 100644 index 00000000..9a124c15 --- /dev/null +++ b/omero/roles/ome.selinux_utils/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Installs utilities and sets variable for interacting with SELinux + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + namespace: ome + role_name: selinux_utils + galaxy_tags: ['selinux'] + +dependencies: [] diff --git a/omero/roles/ome.selinux_utils/molecule/default/molecule.yml b/omero/roles/ome.selinux_utils/molecule/default/molecule.yml new file mode 100644 index 00000000..2ed6d5d9 --- /dev/null +++ b/omero/roles/ome.selinux_utils/molecule/default/molecule.yml @@ -0,0 +1,25 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: selinux-utils-docker + image: eniocarboni/docker-rockylinux-systemd:9 + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint +verifier: + name: testinfra + +# TODO: Add a vagrant test scenario diff --git a/omero/roles/ome.selinux_utils/molecule/default/playbook.yml b/omero/roles/ome.selinux_utils/molecule/default/playbook.yml new file mode 100644 index 00000000..6fd9b4ca --- /dev/null +++ b/omero/roles/ome.selinux_utils/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.selinux_utils diff --git a/omero/roles/ome.selinux_utils/molecule/default/tests/test_default.py b/omero/roles/ome.selinux_utils/molecule/default/tests/test_default.py new file mode 100644 index 00000000..96c8b36b --- /dev/null +++ b/omero/roles/ome.selinux_utils/molecule/default/tests/test_default.py @@ -0,0 +1,22 @@ +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE'] +).get_hosts('all') + + +# The behaviour of this test depends on whether it's running with a docker +# container or full VM +def test_selinux_utils(host): + # We could do this by having separate test_files, but by keeping it + # in one we can guarantee we always match one of the test conditions + hostname = host.backend.get_hostname() + + if hostname == 'selinux-utils-docker': + assert not host.exists('/usr/sbin/getenforce') + assert not host.package('policycoreutils-python').is_installed + else: + getenforce = host.check_output('/usr/sbin/getenforce') + assert getenforce == 'Enforcing' + assert host.package('policycoreutils-python').is_installed diff --git a/omero/roles/ome.selinux_utils/tasks/main.yml b/omero/roles/ome.selinux_utils/tasks/main.yml new file mode 100644 index 00000000..e69d682f --- /dev/null +++ b/omero/roles/ome.selinux_utils/tasks/main.yml @@ -0,0 +1,27 @@ +--- +# tasks file for roles/selinux-utils + +- name: system packages | set selinux variable + set_fact: + selinux_enabled: "{{ ansible_facts.selinux.status == 'enabled' }}" + +- name : check rocky.repo file + stat: + path: /etc/yum.repos.d/rocky.repo + register: rockyrepo_name + +- name: system packages | Add CRB repository for RHEL + become: true + ansible.builtin.command: + subscription-manager repos --enable codeready-builder-for-rhel-9-x86_64-rpms + when: ansible_os_family == 'RedHat' and not rockyrepo_name.stat.exists + +- name: system packages | install selinux utilities + become: true + package: + name: + - libselinux-python3 + - libsemanage-python3 + - policycoreutils-python3 + state: present + when: selinux_enabled diff --git a/omero/roles/ome.ssl_certificate/.github/workflows/molecule.yml b/omero/roles/ome.ssl_certificate/.github/workflows/molecule.yml new file mode 100644 index 00000000..79a2b20d --- /dev/null +++ b/omero/roles/ome.ssl_certificate/.github/workflows/molecule.yml @@ -0,0 +1,63 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Read the role name + id: role-name + run: | + name=$(grep 'role_name' meta/main.yml) + name=$(echo $name | sed -r 's/^[^:]*:(.*)$/\1/' | tr -d '[:space:]') + echo "rolename=$name" >> "$GITHUB_OUTPUT" + - name: Publish to Galaxy + uses: ome/action-ansible-galaxy-publish@main + with: + galaxy-api-key: ${{ secrets.GALAXY_API_KEY }} + galaxy-version: ${{ github.ref_name }} + role-name: ${{ steps.role-name.outputs.rolename }} diff --git a/omero/roles/ome.ssl_certificate/.gitignore b/omero/roles/ome.ssl_certificate/.gitignore new file mode 100644 index 00000000..0d20b648 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/omero/roles/ome.ssl_certificate/LICENSE.md b/omero/roles/ome.ssl_certificate/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.ssl_certificate/README.md b/omero/roles/ome.ssl_certificate/README.md new file mode 100644 index 00000000..8e9b8076 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/README.md @@ -0,0 +1,69 @@ +SSL Certificates +================ + +[![Actions Status](https://github.com/ome/ansible-role-ssl-certificate/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-ssl-certificate/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-ssl_certificate-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/ssl_certificate/) + +Manage SSL certificates for web-servers. + +Optionally generate self-signed SSL certificates for internal testing. + + +Role Variables +-------------- + +Defaults: `defaults/main.yml` + +Optional variables: + +- `ssl_certificate_public_path`: Server path to SSL public certificate +- `ssl_certificate_intermediate_path`: Server path to SSL intermediate certificate(s) +- `ssl_certificate_bundled_path`: Server path to SSL bundled public and intermediate certificates (e.g. for Nginx) +- `ssl_certificate_key_path`: Server path to SSL certificate key +- `ssl_certificate_combined_path`: Server path to SSL combined certificate and key (e.g. for Haproxy), set to empty to disable +- `ssl_certificate_public_content`: Text content of the certificate, for instance from vault +- `ssl_certificate_intermediate_content`: Text content of the intermediate certificate(s) +- `ssl_certificate_key_content`: Text content of the certificate key +- `ssl_certificate_selfsigned_create`: Create a self-signed certificate if necessary, default `True` +- `ssl_certificate_selfsigned_subject`: Self-signed certificate subject +- `ssl_certificate_selfsigned_days`: Self-signed certificate validity (days) +- `ssl_certificate_install_openssl`: Install OpenSSL, default `True` + +Listeners/Handlers +------------------ + +This role notifies a listener `ssl certificate changed` when any changes are made. +This should be used to trigger a restart of any services dependent on the certificates. + + +Example Playbooks +----------------- + +Create a self-signed certificate with defaults and restart Nginx (assumed to be already installed and configured): + + - hosts: all + roles: + - role: ome.ssl_certificate + handlers: + - name: restart nginx + listen: ssl certificate changed + service: + name: nginx + state: restarted + +Install certificates stored locally on machine running Ansible: + + - hosts: all + roles: + - role: ssl-certificate + ssl_certificate_public_content: "{{ lookup('file', '/path/to/server.crt') + '\n' }}" + ssl_certificate_key_content: "{{ lookup('file', '/path/to/server.key') + '\n' }}" + ssl_certificate_selfsigned_create: False + + +Note: the additional newline being added after the lookup content is to correct Ansible bug https://github.com/ansible/ansible/issues/30829. + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.ssl_certificate/defaults/main.yml b/omero/roles/ome.ssl_certificate/defaults/main.yml new file mode 100644 index 00000000..774c14fa --- /dev/null +++ b/omero/roles/ome.ssl_certificate/defaults/main.yml @@ -0,0 +1,39 @@ +--- +# defaults file for roles/ssl-certificates + +# Server path to SSL public certificate +ssl_certificate_public_path: /etc/ssl/localcerts/server.crt + +# Server path to SSL intermediate certificate(s) +ssl_certificate_intermediate_path: /etc/ssl/localcerts/intermediate.crt + +# Server path to SSL bundled public and intermediate certificates +ssl_certificate_bundled_path: /etc/ssl/localcerts/bundled.crt + +# Server path to SSL certificate key +ssl_certificate_key_path: /etc/ssl/localcerts/server.key + +# Server path to SSL combined certificate and key, set to empty to disable +ssl_certificate_combined_path: /etc/ssl/localcerts/combined.pem + +# Text content of the public certificate +ssl_certificate_public_content: '' + +# Text content of the intermediate certificate(s) +ssl_certificate_intermediate_content: '' + +# Text content of the certificate key +ssl_certificate_key_content: '' + +# Create a self-signed certificate if necessary +ssl_certificate_selfsigned_create: true + +# Certificate subject +ssl_certificate_selfsigned_subject: |- + /C=UK/ST=Scotland/L=Dundee/O=OME/CN={{ ansible_fqdn }} + +# Certificate validity (days) +ssl_certificate_selfsigned_days: 365 + +# Whether or not to install OpenSSL +ssl_certificate_install_openssl: true diff --git a/omero/roles/ome.ssl_certificate/handlers/main.yml b/omero/roles/ome.ssl_certificate/handlers/main.yml new file mode 100644 index 00000000..137b3e14 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/handlers/main.yml @@ -0,0 +1,7 @@ +--- +# Handlers for ssl-certificate + +# Ensures there is always at least one listener to prevent Ansible errors +- name: ssl certificate changed + debug: + msg: ssl certificate changed diff --git a/omero/roles/ome.ssl_certificate/meta/.galaxy_install_info b/omero/roles/ome.ssl_certificate/meta/.galaxy_install_info new file mode 100644 index 00000000..1a3050a2 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:56 2024 +version: 0.5.0 diff --git a/omero/roles/ome.ssl_certificate/meta/main.yml b/omero/roles/ome.ssl_certificate/meta/main.yml new file mode 100644 index 00000000..c412a9b2 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/meta/main.yml @@ -0,0 +1,19 @@ +--- +galaxy_info: + author: ome-devel@lists.openmicroscopy.org.uk + description: Manage SSL certificates for web-servers + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.10 + platforms: + - name: EL + versions: + - 9 + - name: Ubuntu + versions: + - jammy + role_name: ssl_certificate + namespace: ome + galaxy_tags: [] + +dependencies: [] diff --git a/omero/roles/ome.ssl_certificate/molecule/default/converge.yml b/omero/roles/ome.ssl_certificate/molecule/default/converge.yml new file mode 100644 index 00000000..8a2f9ba2 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/molecule/default/converge.yml @@ -0,0 +1,15 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.ssl_certificate + + handlers: + - name: Create file when ssl certificate changed + listen: ssl certificate changed + # Use file so that we get an error if the handler is triggered during + # the idempotence check + file: + path: /tmp/ssl-certificate-changed + state: touch + mode: 0644 diff --git a/omero/roles/ome.ssl_certificate/molecule/default/intermediate.pem b/omero/roles/ome.ssl_certificate/molecule/default/intermediate.pem new file mode 100644 index 00000000..a4995835 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/molecule/default/intermediate.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBhjCCATACCQDxto+F3JFJoTANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJV +SzEOMAwGA1UECAwFRHVtbXkxFTATBgNVBAcMDEludGVybWVkaWF0ZTEUMBIGA1UE +CgwLQ2VydGlmaWNhdGUwHhcNMTgwMzIyMTgyNzQ1WhcNMTkwMzIyMTgyNzQ1WjBK +MQswCQYDVQQGEwJVSzEOMAwGA1UECAwFRHVtbXkxFTATBgNVBAcMDEludGVybWVk +aWF0ZTEUMBIGA1UECgwLQ2VydGlmaWNhdGUwXDANBgkqhkiG9w0BAQEFAANLADBI +AkEA3wcqKdD2kuKfQfy1Sy5gZvWE1onOPLGVlK8TXDrdTZOYHVSQrkZqEJaDFwQ4 +hAb8DS5dQCi5Tz62y1Q2k446bQIDAQABMA0GCSqGSIb3DQEBCwUAA0EAbY5+BsTY +s0ZRsu44+j8atIlj4XkfgrP7OZQ+SYZUclVEZIZEz3W5fyJ2UuzLBqkwe9flbZUb +9tEh5pv9vAsgaw== +-----END CERTIFICATE----- diff --git a/omero/roles/ome.ssl_certificate/molecule/default/molecule.yml b/omero/roles/ome.ssl_certificate/molecule/default/molecule.yml new file mode 100644 index 00000000..04203ee6 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/molecule/default/molecule.yml @@ -0,0 +1,25 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: rockylinux-9 + image: rockylinux:9 + - name: ubuntu-2204 + image: ubuntu:22.04 +provisioner: + name: ansible + lint: + name: ansible-lint + inventory: + host_vars: + ssl-certificate-u1604: + ssl_certificate_intermediate_content: | + {{ lookup('file', 'intermediate.pem') }} +verifier: + name: testinfra diff --git a/omero/roles/ome.ssl_certificate/molecule/default/tests/test_default.py b/omero/roles/ome.ssl_certificate/molecule/default/tests/test_default.py new file mode 100644 index 00000000..244836a5 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/molecule/default/tests/test_default.py @@ -0,0 +1,18 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_certificate(host): + with host.sudo(): + out = host.check_output( + 'openssl x509 -in /etc/ssl/localcerts/server.crt -noout -subject') + assert out.startswith( + 'subject=C = UK, ST = Scotland, L = Dundee, O = OME, CN =') + + +def test_listener_trigger(host): + assert host.file('/tmp/ssl-certificate-changed').exists diff --git a/omero/roles/ome.ssl_certificate/molecule/default/tests/test_intermediate.py b/omero/roles/ome.ssl_certificate/molecule/default/tests/test_intermediate.py new file mode 100644 index 00000000..79c343cc --- /dev/null +++ b/omero/roles/ome.ssl_certificate/molecule/default/tests/test_intermediate.py @@ -0,0 +1,41 @@ +import os + +import testinfra.utils.ansible_runner +import pytest + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('ssl-certificate-u1604') + + +@pytest.mark.parametrize("cert", [ + 'bundled.crt', + 'combined.pem', +]) +def test_intermediate(host, cert): + with host.sudo(): + out = host.check_output( + 'openssl crl2pkcs7 -nocrl -certfile /etc/ssl/localcerts/%s | ' + 'openssl pkcs7 -print_certs -text -noout |grep Subject:' + % cert) + lines = out.splitlines() + assert lines[0].strip().startswith( + 'Subject: C=UK, ST=Scotland, L=Dundee, O=OME, CN=') + assert lines[1].strip().startswith( + 'Subject: C=UK, ST=Dummy, L=Intermediate, O=Certificate') + + +@pytest.mark.parametrize("cert", [ + 'bundled.crt', + 'combined.pem', +]) +def test_combined(host, cert): + with host.sudo(): + out = host.check_output('grep BEGIN /etc/ssl/localcerts/%s' % cert) + lines = out.splitlines() + assert lines[0] == '-----BEGIN CERTIFICATE-----' + assert lines[1] == '-----BEGIN CERTIFICATE-----' + if cert == 'bundled.crt': + assert len(lines) == 2 + else: + assert len(lines) == 3 + assert lines[2] == '-----BEGIN PRIVATE KEY-----' diff --git a/omero/roles/ome.ssl_certificate/tasks/main.yml b/omero/roles/ome.ssl_certificate/tasks/main.yml new file mode 100644 index 00000000..6e388df3 --- /dev/null +++ b/omero/roles/ome.ssl_certificate/tasks/main.yml @@ -0,0 +1,116 @@ +--- +# tasks file for roles/ssl-certificate + +- name: check parameters + fail: + msg: ssl_certificate_public_content or ssl_certificate_key_content is empty + when: >- + (not ssl_certificate_selfsigned_create) and + (not ssl_certificate_public_content or not ssl_certificate_key_content) + +- name: install openssl + become: true + package: + name: openssl + state: present + when: ssl_certificate_install_openssl + +- name: create certificates directory + become: true + file: + path: "{{ item | dirname }}" + state: directory + mode: 0755 + with_items: + - "{{ ssl_certificate_public_path }}" + - "{{ ssl_certificate_intermediate_path }}" + - "{{ ssl_certificate_bundled_path }}" + - "{{ ssl_certificate_key_path }}" + +# Create from content of variable e.g. from vault +# Only the key needs to be kept private + +- name: write SSL public certificate + become: true + copy: + content: "{{ ssl_certificate_public_content }}" + dest: "{{ ssl_certificate_public_path }}" + mode: 0444 + when: 'ssl_certificate_public_content | length > 0' + notify: ssl certificate changed + +- name: write SSL intermediate certificate + become: true + copy: + content: "{{ ssl_certificate_intermediate_content }}" + dest: "{{ ssl_certificate_intermediate_path }}" + mode: 0444 + when: 'ssl_certificate_intermediate_content | length > 0' + notify: ssl certificate changed + +- name: write SSL certificate key + become: true + copy: + content: "{{ ssl_certificate_key_content }}" + dest: "{{ ssl_certificate_key_path }}" + mode: 0400 + no_log: true + when: 'ssl_certificate_key_content | length > 0' + notify: ssl certificate changed + +# Self-signed +# http://serialized.net/2013/04/simply-generating-self-signed-ssl-certs-with-ansible/ + +- name: generate self-signed SSL certificate + become: true + command: > + openssl req -new -nodes -x509 -subj + {{ ssl_certificate_selfsigned_subject }} + -days {{ ssl_certificate_selfsigned_days }} + -keyout {{ ssl_certificate_key_path }} + -out {{ ssl_certificate_public_path }} + -extensions v3_ca + args: + # Don't overwrite existing certificate + creates: "{{ ssl_certificate_key_path }}" + when: ssl_certificate_selfsigned_create + notify: ssl certificate changed + +# Create combined certificate and key + +- name: read public certificate + become: true + slurp: + src: "{{ ssl_certificate_public_path }}" + register: _ssl_certificate_public_content + +- name: read certificate key + become: true + slurp: + src: "{{ ssl_certificate_key_path }}" + register: _ssl_certificate_key_content + no_log: true + +- name: write bundled certificate + become: true + copy: + content: |- + {{ _ssl_certificate_public_content.content | b64decode | trim }} + {{ ssl_certificate_intermediate_content }} + dest: "{{ ssl_certificate_bundled_path }}" + mode: 0444 + when: "ssl_certificate_bundled_path | length > 0" + notify: ssl certificate changed + +- name: write SSL combined certificate key + become: true + copy: + content: |- + {{ _ssl_certificate_public_content.content | b64decode | trim }} + {{ ssl_certificate_intermediate_content | trim }} + {{ _ssl_certificate_key_content.content | b64decode }} + dest: "{{ ssl_certificate_combined_path }}" + mode: 0400 + no_log: true + when: "ssl_certificate_combined_path | length > 0" + notify: ssl certificate changed diff --git a/omero/roles/ome.versioncontrol_utils/.github/workflows/molecule.yml b/omero/roles/ome.versioncontrol_utils/.github/workflows/molecule.yml new file mode 100644 index 00000000..3fa7ef7c --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/.github/workflows/molecule.yml @@ -0,0 +1,55 @@ +--- +name: Molecule +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: '29 21 * * 0' + +jobs: + + list-scenarios: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.listscenarios.outputs.scenarios }} + steps: + - uses: actions/checkout@v4 + - id: listscenarios + uses: ome/action-ansible-molecule-list-scenarios@main + + test: + name: Test + needs: + - list-scenarios + runs-on: ubuntu-22.04 + strategy: + # Keep running so we can see if other tests pass + fail-fast: false + matrix: + scenario: ${{fromJson(needs.list-scenarios.outputs.matrix)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Install Ansible & Molecule + run: | + pip install "ansible<8" "ansible-lint<6.13" flake8 + pip install "molecule<5" "ansible-compat<4" + pip install molecule-plugins[docker] pytest-testinfra + - name: Run molecule + run: molecule test -s "${{ matrix.scenario }}" + + publish: + name: Galaxy + if: startsWith(github.ref, 'refs/tags') + needs: + - test + runs-on: ubuntu-20.04 + steps: + - name: galaxy + uses: robertdebock/galaxy-action@1.2.1 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + git_branch: ${{ github.ref_name }} diff --git a/omero/roles/ome.versioncontrol_utils/.gitignore b/omero/roles/ome.versioncontrol_utils/.gitignore new file mode 100644 index 00000000..d35ab669 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/.gitignore @@ -0,0 +1,2 @@ +.*~ +*.pyc diff --git a/omero/roles/ome.versioncontrol_utils/LICENSE.md b/omero/roles/ome.versioncontrol_utils/LICENSE.md new file mode 100644 index 00000000..a3181283 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2019, University of Dundee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/omero/roles/ome.versioncontrol_utils/README.md b/omero/roles/ome.versioncontrol_utils/README.md new file mode 100644 index 00000000..2e7bb874 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/README.md @@ -0,0 +1,12 @@ +Version control utilities +========================= + +[![Actions Status](https://github.com/ome/ansible-role-versioncontrol-utils/workflows/Molecule/badge.svg)](https://github.com/ome/ansible-role-versioncontrol-utils/actions) +[![Ansible Role](https://img.shields.io/badge/ansible--galaxy-versioncontrol_utils-blue.svg)](https://galaxy.ansible.com/ui/standalone/roles/ome/versioncontrol_utils/) + +Utilities for managing source code. + +Author Information +------------------ + +ome-devel@lists.openmicroscopy.org.uk diff --git a/omero/roles/ome.versioncontrol_utils/meta/.galaxy_install_info b/omero/roles/ome.versioncontrol_utils/meta/.galaxy_install_info new file mode 100644 index 00000000..b7f1fcb9 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Wed 13 Nov 17:33:54 2024 +version: 1.1.0 diff --git a/omero/roles/ome.versioncontrol_utils/meta/main.yml b/omero/roles/ome.versioncontrol_utils/meta/main.yml new file mode 100644 index 00000000..e76bc9f5 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + role_name: versioncontrol_utils + author: ome-devel@lists.openmicroscopy.org.uk + description: Utilities for managing source code + company: Open Microscopy Environment + license: BSD + min_ansible_version: 2.1 + platforms: + - name: EL + versions: + - 9 + namespace: ome + galaxy_tags: [] + +dependencies: [] diff --git a/omero/roles/ome.versioncontrol_utils/molecule/default/molecule.yml b/omero/roles/ome.versioncontrol_utils/molecule/default/molecule.yml new file mode 100644 index 00000000..73026c50 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint + flake8 +platforms: + - name: instance + image: rockylinux:9 + image_version: latest + privileged: true + cgroupns_mode: host + tmpfs: + - /sys/fs/cgroup + groups: + - extra_options +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra diff --git a/omero/roles/ome.versioncontrol_utils/molecule/default/playbook.yml b/omero/roles/ome.versioncontrol_utils/molecule/default/playbook.yml new file mode 100644 index 00000000..86756ec2 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: ome.versioncontrol_utils diff --git a/omero/roles/ome.versioncontrol_utils/molecule/default/tests/test_default.py b/omero/roles/ome.versioncontrol_utils/molecule/default/tests/test_default.py new file mode 100644 index 00000000..73bed884 --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/molecule/default/tests/test_default.py @@ -0,0 +1,10 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_hosts_file(host): + assert host.package('git').is_installed diff --git a/omero/roles/ome.versioncontrol_utils/tasks/main.yml b/omero/roles/ome.versioncontrol_utils/tasks/main.yml new file mode 100644 index 00000000..cf32af0c --- /dev/null +++ b/omero/roles/ome.versioncontrol_utils/tasks/main.yml @@ -0,0 +1,18 @@ +--- +# tasks file for roles/versioncontrol-utils + +- name: system packages | install epel repo + become: true + ansible.builtin.dnf: + update_cache: true + name: epel-release + state: present + +- name: system packages | basic system utils + become: true + ansible.builtin.dnf: + update_cache: true + name: "{{ item }}" + state: present + with_items: + - git