From a162879d2073cb7995bcc3d22d41f34f2137a303 Mon Sep 17 00:00:00 2001 From: Bertrand Lanson Date: Fri, 15 Dec 2023 18:45:58 +0100 Subject: [PATCH] feat(tests): test playbboks are played correctly on molecule scenarios --- .../molecule/no_tls_single_node/converge.yml | 8 - molecule/no_tls_multi_node/converge.yml | 3 + molecule/no_tls_multi_node/molecule.yml | 42 +++++ molecule/no_tls_multi_node/prepare.yml | 5 + .../no_tls_multi_node}/requirements.yml | 3 + .../no_tls_multi_node}/verify.yml | 0 playbooks/deploy.yml | 9 + playbooks/inventory/multinode.ini | 22 +++ playbooks/prepare.yml | 6 + playbooks/vars/global.yml | 45 ++++- .../.ansible-lint | 8 + .../.gitea/workflows/test.yml | 52 ++++++ .../.github/workflows/publish.yml | 18 ++ .../ednxzu.docker_systemd_service/.gitignore | 3 + roles/ednxzu.docker_systemd_service/.yamllint | 40 +++++ roles/ednxzu.docker_systemd_service/LICENSE | 20 +++ roles/ednxzu.docker_systemd_service/README.md | 118 ++++++++++++ .../docker_systemd_service.yml.sample | 14 ++ .../defaults/main.yml | 15 ++ .../files/.gitkeep | 0 .../filter_plugins/docker_filters.py | 32 ++++ .../handlers/main.yml | 10 ++ .../meta/.galaxy_install_info | 2 + .../meta/main.yml | 25 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/group_vars/all.yml | 14 ++ .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 5 + .../molecule/default/verify.yml | 78 ++++++++ .../molecule/default_vagrant/converge.yml | 8 + .../default_vagrant/group_vars/all.yml | 14 ++ .../molecule/default_vagrant}/molecule.yml | 3 +- .../molecule/default_vagrant}/prepare.yml | 2 +- .../molecule/default_vagrant/requirements.yml | 6 + .../molecule/default_vagrant/verify.yml | 78 ++++++++ .../molecule/with_custom_flags/converge.yml | 8 + .../with_custom_flags/group_vars/all.yml | 19 ++ .../molecule/with_custom_flags/molecule.yml | 37 ++++ .../with_custom_flags/requirements.yml | 5 + .../molecule/with_custom_flags/verify.yml | 84 +++++++++ .../with_custom_flags_vagrant/converge.yml | 8 + .../group_vars/all.yml | 19 ++ .../with_custom_flags_vagrant/molecule.yml | 35 ++++ .../with_custom_flags_vagrant/prepare.yml | 10 ++ .../requirements.yml | 6 + .../with_custom_flags_vagrant/verify.yml | 84 +++++++++ .../tasks/install.yml | 36 ++++ .../tasks/main.yml | 9 + .../tasks/uninstall.yml | 22 +++ .../templates/env.j2 | 3 + .../templates/unit.j2 | 43 +++++ .../vars/main.yml | 8 + roles/ednxzu.install_docker/.ansible-lint | 8 + .../.gitea/workflows/test.yml | 52 ++++++ .../.github/workflows/publish.yml | 18 ++ roles/ednxzu.install_docker/.gitignore | 3 + roles/ednxzu.install_docker/.yamllint | 40 +++++ roles/ednxzu.install_docker/LICENSE | 19 ++ roles/ednxzu.install_docker/README.md | 87 +++++++++ .../defaults/install_docker.yml.sample | 10 ++ roles/ednxzu.install_docker/defaults/main.yml | 11 ++ roles/ednxzu.install_docker/handlers/main.yml | 14 ++ .../meta/.galaxy_install_info | 2 + roles/ednxzu.install_docker/meta/main.yml | 27 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 5 + .../molecule/default/verify.yml | 96 ++++++++++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/prepare.yml | 12 ++ .../molecule/default_vagrant/requirements.yml | 5 + .../molecule/default_vagrant/verify.yml | 96 ++++++++++ .../molecule/with_custom_config/converge.yml | 8 + .../with_custom_config/group_vars/all.yml | 11 ++ .../molecule/with_custom_config/molecule.yml | 37 ++++ .../with_custom_config/requirements.yml | 5 + .../molecule/with_custom_config/verify.yml | 106 +++++++++++ .../with_custom_config_vagrant/converge.yml | 8 + .../group_vars/all.yml | 11 ++ .../with_custom_config_vagrant/molecule.yml | 35 ++++ .../with_custom_config_vagrant/prepare.yml | 12 ++ .../requirements.yml | 5 + .../with_custom_config_vagrant/verify.yml | 106 +++++++++++ .../ednxzu.install_docker/tasks/configure.yml | 19 ++ roles/ednxzu.install_docker/tasks/install.yml | 15 ++ .../tasks/install_compose.yml | 46 +++++ .../tasks/install_python_docker.yml | 7 + roles/ednxzu.install_docker/tasks/main.yml | 24 +++ .../tasks/prerequisites.yml | 14 ++ .../templates/daemon.json.j2 | 1 + roles/ednxzu.install_docker/vars/main.yml | 36 ++++ .../ednxzu.manage_apt_packages/.ansible-lint | 8 + .../.gitea/workflows/test.yml | 52 ++++++ .../.github/workflows/publish.yml | 18 ++ roles/ednxzu.manage_apt_packages/.gitignore | 3 + roles/ednxzu.manage_apt_packages/.yamllint | 40 +++++ roles/ednxzu.manage_apt_packages/LICENSE | 20 +++ roles/ednxzu.manage_apt_packages/README.md | 62 +++++++ .../defaults/main.yml | 6 + .../defaults/manage_apt_packages.yml.sample | 11 ++ .../handlers/main.yml | 6 + .../meta/.galaxy_install_info | 2 + .../ednxzu.manage_apt_packages/meta/main.yml | 24 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 3 + .../molecule/default/verify.yml | 16 ++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/requirements.yml | 3 + .../molecule/default_vagrant/verify.yml | 16 ++ .../with_custom_packages/converge.yml | 8 + .../with_custom_packages/group_vars/all.yml | 11 ++ .../with_custom_packages/molecule.yml | 37 ++++ .../molecule/with_custom_packages/prepare.yml | 22 +++ .../with_custom_packages/requirements.yml | 4 + .../molecule/with_custom_packages/verify.yml | 19 ++ .../with_custom_packages_vagrant/converge.yml | 8 + .../group_vars/all.yml | 11 ++ .../with_custom_packages_vagrant/molecule.yml | 36 ++++ .../with_custom_packages_vagrant/prepare.yml | 22 +++ .../requirements.yml | 4 + .../with_custom_packages_vagrant/verify.yml | 19 ++ .../ednxzu.manage_apt_packages/tasks/main.yml | 16 ++ .../ednxzu.manage_apt_packages/vars/main.yml | 3 + .../ednxzu.manage_repositories/.ansible-lint | 8 + .../.gitea/workflows/test.yml | 52 ++++++ .../.github/workflows/publish.yml | 18 ++ roles/ednxzu.manage_repositories/.gitignore | 3 + roles/ednxzu.manage_repositories/.yamllint | 40 +++++ roles/ednxzu.manage_repositories/LICENSE | 20 +++ roles/ednxzu.manage_repositories/README.md | 97 ++++++++++ .../defaults/main.yml | 7 + .../defaults/manage_repositories.yml.sample | 29 +++ .../handlers/main.yml | 6 + .../meta/.galaxy_install_info | 2 + .../ednxzu.manage_repositories/meta/main.yml | 25 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 4 + .../molecule/default/verify.yml | 74 ++++++++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/requirements.yml | 4 + .../molecule/default_vagrant/verify.yml | 74 ++++++++ .../molecule/with_custom_repo/converge.yml | 8 + .../with_custom_repo/group_vars/all.yml | 26 +++ .../molecule/with_custom_repo/molecule.yml | 37 ++++ .../with_custom_repo/requirements.yml | 4 + .../molecule/with_custom_repo/verify.yml | 138 ++++++++++++++ .../with_custom_repo_vagrant/converge.yml | 7 + .../group_vars/all.yml | 26 +++ .../with_custom_repo_vagrant/molecule.yml | 35 ++++ .../with_custom_repo_vagrant/requirements.yml | 4 + .../with_custom_repo_vagrant/verify.yml | 138 ++++++++++++++ .../tasks/custom_repositories.yml | 24 +++ .../ednxzu.manage_repositories/tasks/main.yml | 19 ++ .../tasks/main_repositories.yml | 44 +++++ .../tasks/prerequisites.yml | 7 + .../templates/repo.sources.j2 | 17 ++ .../vars/debian.yml | 23 +++ .../ednxzu.manage_repositories/vars/main.yml | 10 ++ .../vars/ubuntu.yml | 18 ++ roles/hashicorp_consul/LICENSE | 20 +++ roles/hashicorp_consul/README.md | 106 +++++++++++ .../defaults/hashicorp_consul.yml.sample | 69 +++++++ roles/hashicorp_consul/defaults/main.yml | 70 ++++++++ roles/hashicorp_consul/files/.gitkeep | 0 roles/hashicorp_consul/handlers/main.yml | 20 +++ roles/hashicorp_consul/meta/main.yml | 25 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 5 + .../molecule/default/verify.yml | 146 +++++++++++++++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/requirements.yml | 5 + .../molecule/default_vagrant/verify.yml | 146 +++++++++++++++ .../molecule/with_acl_enabled/converge.yml | 8 + .../with_acl_enabled/group_vars/all.yml | 69 +++++++ .../molecule/with_acl_enabled/molecule.yml | 37 ++++ .../with_acl_enabled/requirements.yml | 5 + .../molecule/with_acl_enabled/verify.yml | 156 ++++++++++++++++ .../with_acl_enabled_vagrant/converge.yml | 8 + .../group_vars/all.yml | 69 +++++++ .../with_acl_enabled_vagrant/molecule.yml | 35 ++++ .../with_acl_enabled_vagrant/requirements.yml | 5 + .../with_acl_enabled_vagrant/verify.yml | 156 ++++++++++++++++ roles/hashicorp_consul/tasks/configure.yml | 46 +++++ roles/hashicorp_consul/tasks/install.yml | 25 +++ .../hashicorp_consul/tasks/install_envoy.yml | 66 +++++++ roles/hashicorp_consul/tasks/main.yml | 14 ++ .../hashicorp_consul/tasks/prerequisites.yml | 29 +++ .../hashicorp_consul/templates/consul.env.j2 | 4 + .../hashicorp_consul/templates/consul.json.j2 | 1 + .../templates/consul.service.j2 | 20 +++ roles/hashicorp_consul/vars/main.yml | 28 +++ roles/hashicorp_nomad/LICENSE | 20 +++ roles/hashicorp_nomad/README.md | 107 +++++++++++ .../defaults/hashicorp_nomad.yml.sample | 86 +++++++++ roles/hashicorp_nomad/defaults/main.yml | 87 +++++++++ roles/hashicorp_nomad/handlers/main.yml | 20 +++ roles/hashicorp_nomad/meta/main.yml | 25 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 5 + .../molecule/default/verify.yml | 146 +++++++++++++++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/requirements.yml | 5 + .../molecule/default_vagrant/verify.yml | 146 +++++++++++++++ .../molecule/with_acl_enabled/converge.yml | 8 + .../with_acl_enabled/group_vars/all.yml | 86 +++++++++ .../molecule/with_acl_enabled/molecule.yml | 37 ++++ .../with_acl_enabled/requirements.yml | 5 + .../molecule/with_acl_enabled/verify.yml | 163 +++++++++++++++++ .../with_acl_enabled_vagrant/converge.yml | 8 + .../group_vars/all.yml | 86 +++++++++ .../with_acl_enabled_vagrant/molecule.yml | 35 ++++ .../with_acl_enabled_vagrant/requirements.yml | 5 + .../with_acl_enabled_vagrant/verify.yml | 163 +++++++++++++++++ roles/hashicorp_nomad/tasks/cni_install.yml | 73 ++++++++ roles/hashicorp_nomad/tasks/configure.yml | 46 +++++ roles/hashicorp_nomad/tasks/install.yml | 25 +++ roles/hashicorp_nomad/tasks/main.yml | 15 ++ roles/hashicorp_nomad/tasks/prerequisites.yml | 29 +++ roles/hashicorp_nomad/templates/nomad.env.j2 | 4 + roles/hashicorp_nomad/templates/nomad.json.j2 | 1 + .../templates/nomad.service.j2 | 33 ++++ roles/hashicorp_nomad/vars/main.yml | 30 ++++ roles/hashicorp_vault/LICENSE | 20 +++ roles/hashicorp_vault/README.md | 98 ++++++++++ .../defaults/hashicorp_vault.yml.sample | 46 +++++ roles/hashicorp_vault/defaults/main.yml | 47 +++++ roles/hashicorp_vault/handlers/main.yml | 20 +++ roles/hashicorp_vault/meta/main.yml | 25 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 5 + .../molecule/default/verify.yml | 162 +++++++++++++++++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/requirements.yml | 5 + .../molecule/default_vagrant/verify.yml | 162 +++++++++++++++++ .../molecule/with_raft_enabled/converge.yml | 8 + .../with_raft_enabled/group_vars/all.yml | 52 ++++++ .../molecule/with_raft_enabled/molecule.yml | 37 ++++ .../with_raft_enabled/requirements.yml | 5 + .../molecule/with_raft_enabled/verify.yml | 169 ++++++++++++++++++ .../with_raft_enabled_vagrant/converge.yml | 8 + .../group_vars/all.yml | 52 ++++++ .../with_raft_enabled_vagrant/molecule.yml | 35 ++++ .../requirements.yml | 5 + .../with_raft_enabled_vagrant/verify.yml | 169 ++++++++++++++++++ roles/hashicorp_vault/tasks/configure.yml | 46 +++++ roles/hashicorp_vault/tasks/install.yml | 25 +++ roles/hashicorp_vault/tasks/main.yml | 11 ++ roles/hashicorp_vault/tasks/prerequisites.yml | 29 +++ roles/hashicorp_vault/templates/vault.env.j2 | 4 + roles/hashicorp_vault/templates/vault.json.j2 | 1 + .../templates/vault.service.j2 | 38 ++++ roles/hashicorp_vault/vars/main.yml | 21 +++ roles/import_vault_root_ca/LICENSE | 20 +++ roles/import_vault_root_ca/README.md | 51 ++++++ roles/import_vault_root_ca/defaults/main.yml | 4 + roles/import_vault_root_ca/handlers/main.yml | 6 + roles/import_vault_root_ca/meta/main.yml | 27 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/requirements.yml | 4 + .../molecule/default/verify.yml | 28 +++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/requirements.yml | 4 + .../molecule/default_vagrant/verify.yml | 28 +++ .../molecule/with_custom_ca/converge.yml | 8 + .../with_custom_ca/group_vars/all.yml | 5 + .../molecule/with_custom_ca/molecule.yml | 37 ++++ .../molecule/with_custom_ca/requirements.yml | 4 + .../molecule/with_custom_ca/verify.yml | 53 ++++++ .../with_custom_ca_vagrant/converge.yml | 8 + .../with_custom_ca_vagrant/group_vars/all.yml | 5 + .../with_custom_ca_vagrant/molecule.yml | 35 ++++ .../with_custom_ca_vagrant/requirements.yml | 4 + .../with_custom_ca_vagrant/verify.yml | 53 ++++++ roles/import_vault_root_ca/tasks/import.yml | 27 +++ roles/import_vault_root_ca/tasks/main.yml | 7 + .../tasks/prerequisites.yml | 15 ++ roles/import_vault_root_ca/vars/main.yml | 10 ++ roles/renew_consul_certificates/LICENSE | 20 +++ roles/renew_consul_certificates/README.md | 123 +++++++++++++ .../defaults/main.yml | 24 +++ .../renew_consul_certificates.yml.sample | 23 +++ .../handlers/main.yml | 19 ++ roles/renew_consul_certificates/meta/main.yml | 25 +++ .../molecule/default/converge.yml | 8 + .../molecule/default/molecule.yml | 37 ++++ .../molecule/default/prepare.yml | 16 ++ .../molecule/default/requirements.yml | 5 + .../molecule/default/verify.yml | 140 +++++++++++++++ .../molecule/default_vagrant/converge.yml | 8 + .../molecule/default_vagrant/molecule.yml | 35 ++++ .../molecule/default_vagrant/prepare.yml | 16 ++ .../molecule/default_vagrant/requirements.yml | 5 + .../molecule/default_vagrant/verify.yml | 140 +++++++++++++++ .../molecule/with_custom_config/converge.yml | 8 + .../with_custom_config/group_vars/all.yml | 23 +++ .../molecule/with_custom_config/molecule.yml | 37 ++++ .../molecule/with_custom_config/prepare.yml | 16 ++ .../with_custom_config/requirements.yml | 5 + .../molecule/with_custom_config/verify.yml | 140 +++++++++++++++ .../with_custom_config_vagrant/converge.yml | 8 + .../group_vars/all.yml | 23 +++ .../with_custom_config_vagrant/molecule.yml | 35 ++++ .../with_custom_config_vagrant/prepare.yml | 16 ++ .../requirements.yml | 5 + .../with_custom_config_vagrant/verify.yml | 140 +++++++++++++++ .../tasks/configure.yml | 58 ++++++ .../tasks/install.yml | 15 ++ .../renew_consul_certificates/tasks/main.yml | 10 ++ .../tasks/prerequisites.yml | 29 +++ .../templates/consul-certs.env.j2 | 4 + .../templates/consul-certs.service.j2 | 17 ++ .../templates/consul_ca.pem.tpl.j2 | 5 + .../templates/consul_cert.pem.tpl.j2 | 7 + .../templates/consul_config.hcl.j2 | 33 ++++ .../templates/consul_key.pem.tpl.j2 | 5 + roles/renew_consul_certificates/vars/main.yml | 18 ++ 329 files changed, 10304 insertions(+), 11 deletions(-) delete mode 100644 extensions/molecule/no_tls_single_node/converge.yml create mode 100644 molecule/no_tls_multi_node/converge.yml create mode 100644 molecule/no_tls_multi_node/molecule.yml create mode 100644 molecule/no_tls_multi_node/prepare.yml rename {extensions/molecule/no_tls_single_node => molecule/no_tls_multi_node}/requirements.yml (81%) rename {extensions/molecule/no_tls_single_node => molecule/no_tls_multi_node}/verify.yml (100%) create mode 100644 playbooks/deploy.yml create mode 100644 playbooks/prepare.yml create mode 100644 roles/ednxzu.docker_systemd_service/.ansible-lint create mode 100644 roles/ednxzu.docker_systemd_service/.gitea/workflows/test.yml create mode 100644 roles/ednxzu.docker_systemd_service/.github/workflows/publish.yml create mode 100644 roles/ednxzu.docker_systemd_service/.gitignore create mode 100644 roles/ednxzu.docker_systemd_service/.yamllint create mode 100644 roles/ednxzu.docker_systemd_service/LICENSE create mode 100644 roles/ednxzu.docker_systemd_service/README.md create mode 100644 roles/ednxzu.docker_systemd_service/defaults/docker_systemd_service.yml.sample create mode 100644 roles/ednxzu.docker_systemd_service/defaults/main.yml create mode 100644 roles/ednxzu.docker_systemd_service/files/.gitkeep create mode 100644 roles/ednxzu.docker_systemd_service/filter_plugins/docker_filters.py create mode 100644 roles/ednxzu.docker_systemd_service/handlers/main.yml create mode 100644 roles/ednxzu.docker_systemd_service/meta/.galaxy_install_info create mode 100644 roles/ednxzu.docker_systemd_service/meta/main.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default/converge.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default/group_vars/all.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default/molecule.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default/requirements.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default/verify.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default_vagrant/converge.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default_vagrant/group_vars/all.yml rename {extensions/molecule/no_tls_single_node => roles/ednxzu.docker_systemd_service/molecule/default_vagrant}/molecule.yml (95%) rename {extensions/molecule/no_tls_single_node => roles/ednxzu.docker_systemd_service/molecule/default_vagrant}/prepare.yml (80%) create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default_vagrant/requirements.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/default_vagrant/verify.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/converge.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/group_vars/all.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/molecule.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/requirements.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/verify.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/converge.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/group_vars/all.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/molecule.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/prepare.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/requirements.yml create mode 100644 roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/verify.yml create mode 100644 roles/ednxzu.docker_systemd_service/tasks/install.yml create mode 100644 roles/ednxzu.docker_systemd_service/tasks/main.yml create mode 100644 roles/ednxzu.docker_systemd_service/tasks/uninstall.yml create mode 100644 roles/ednxzu.docker_systemd_service/templates/env.j2 create mode 100644 roles/ednxzu.docker_systemd_service/templates/unit.j2 create mode 100644 roles/ednxzu.docker_systemd_service/vars/main.yml create mode 100644 roles/ednxzu.install_docker/.ansible-lint create mode 100644 roles/ednxzu.install_docker/.gitea/workflows/test.yml create mode 100644 roles/ednxzu.install_docker/.github/workflows/publish.yml create mode 100644 roles/ednxzu.install_docker/.gitignore create mode 100644 roles/ednxzu.install_docker/.yamllint create mode 100644 roles/ednxzu.install_docker/LICENSE create mode 100644 roles/ednxzu.install_docker/README.md create mode 100644 roles/ednxzu.install_docker/defaults/install_docker.yml.sample create mode 100644 roles/ednxzu.install_docker/defaults/main.yml create mode 100644 roles/ednxzu.install_docker/handlers/main.yml create mode 100644 roles/ednxzu.install_docker/meta/.galaxy_install_info create mode 100644 roles/ednxzu.install_docker/meta/main.yml create mode 100644 roles/ednxzu.install_docker/molecule/default/converge.yml create mode 100644 roles/ednxzu.install_docker/molecule/default/molecule.yml create mode 100644 roles/ednxzu.install_docker/molecule/default/requirements.yml create mode 100644 roles/ednxzu.install_docker/molecule/default/verify.yml create mode 100644 roles/ednxzu.install_docker/molecule/default_vagrant/converge.yml create mode 100644 roles/ednxzu.install_docker/molecule/default_vagrant/molecule.yml create mode 100644 roles/ednxzu.install_docker/molecule/default_vagrant/prepare.yml create mode 100644 roles/ednxzu.install_docker/molecule/default_vagrant/requirements.yml create mode 100644 roles/ednxzu.install_docker/molecule/default_vagrant/verify.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config/converge.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config/group_vars/all.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config/molecule.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config/requirements.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config/verify.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/converge.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/group_vars/all.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/molecule.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/prepare.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/requirements.yml create mode 100644 roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/verify.yml create mode 100644 roles/ednxzu.install_docker/tasks/configure.yml create mode 100644 roles/ednxzu.install_docker/tasks/install.yml create mode 100644 roles/ednxzu.install_docker/tasks/install_compose.yml create mode 100644 roles/ednxzu.install_docker/tasks/install_python_docker.yml create mode 100644 roles/ednxzu.install_docker/tasks/main.yml create mode 100644 roles/ednxzu.install_docker/tasks/prerequisites.yml create mode 100644 roles/ednxzu.install_docker/templates/daemon.json.j2 create mode 100644 roles/ednxzu.install_docker/vars/main.yml create mode 100644 roles/ednxzu.manage_apt_packages/.ansible-lint create mode 100644 roles/ednxzu.manage_apt_packages/.gitea/workflows/test.yml create mode 100644 roles/ednxzu.manage_apt_packages/.github/workflows/publish.yml create mode 100644 roles/ednxzu.manage_apt_packages/.gitignore create mode 100644 roles/ednxzu.manage_apt_packages/.yamllint create mode 100644 roles/ednxzu.manage_apt_packages/LICENSE create mode 100644 roles/ednxzu.manage_apt_packages/README.md create mode 100644 roles/ednxzu.manage_apt_packages/defaults/main.yml create mode 100644 roles/ednxzu.manage_apt_packages/defaults/manage_apt_packages.yml.sample create mode 100644 roles/ednxzu.manage_apt_packages/handlers/main.yml create mode 100644 roles/ednxzu.manage_apt_packages/meta/.galaxy_install_info create mode 100644 roles/ednxzu.manage_apt_packages/meta/main.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default/converge.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default/molecule.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default/requirements.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default/verify.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default_vagrant/converge.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default_vagrant/molecule.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default_vagrant/requirements.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/default_vagrant/verify.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/converge.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/group_vars/all.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/molecule.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/prepare.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/requirements.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/verify.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/converge.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/group_vars/all.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/molecule.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/prepare.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/requirements.yml create mode 100644 roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/verify.yml create mode 100644 roles/ednxzu.manage_apt_packages/tasks/main.yml create mode 100644 roles/ednxzu.manage_apt_packages/vars/main.yml create mode 100644 roles/ednxzu.manage_repositories/.ansible-lint create mode 100644 roles/ednxzu.manage_repositories/.gitea/workflows/test.yml create mode 100644 roles/ednxzu.manage_repositories/.github/workflows/publish.yml create mode 100644 roles/ednxzu.manage_repositories/.gitignore create mode 100644 roles/ednxzu.manage_repositories/.yamllint create mode 100644 roles/ednxzu.manage_repositories/LICENSE create mode 100644 roles/ednxzu.manage_repositories/README.md create mode 100644 roles/ednxzu.manage_repositories/defaults/main.yml create mode 100644 roles/ednxzu.manage_repositories/defaults/manage_repositories.yml.sample create mode 100644 roles/ednxzu.manage_repositories/handlers/main.yml create mode 100644 roles/ednxzu.manage_repositories/meta/.galaxy_install_info create mode 100644 roles/ednxzu.manage_repositories/meta/main.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default/converge.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default/molecule.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default/requirements.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default/verify.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default_vagrant/converge.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default_vagrant/molecule.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default_vagrant/requirements.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/default_vagrant/verify.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo/converge.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo/group_vars/all.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo/molecule.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo/requirements.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo/verify.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/converge.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/group_vars/all.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/molecule.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/requirements.yml create mode 100644 roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/verify.yml create mode 100644 roles/ednxzu.manage_repositories/tasks/custom_repositories.yml create mode 100644 roles/ednxzu.manage_repositories/tasks/main.yml create mode 100644 roles/ednxzu.manage_repositories/tasks/main_repositories.yml create mode 100644 roles/ednxzu.manage_repositories/tasks/prerequisites.yml create mode 100644 roles/ednxzu.manage_repositories/templates/repo.sources.j2 create mode 100644 roles/ednxzu.manage_repositories/vars/debian.yml create mode 100644 roles/ednxzu.manage_repositories/vars/main.yml create mode 100644 roles/ednxzu.manage_repositories/vars/ubuntu.yml create mode 100644 roles/hashicorp_consul/LICENSE create mode 100644 roles/hashicorp_consul/README.md create mode 100644 roles/hashicorp_consul/defaults/hashicorp_consul.yml.sample create mode 100644 roles/hashicorp_consul/defaults/main.yml create mode 100644 roles/hashicorp_consul/files/.gitkeep create mode 100644 roles/hashicorp_consul/handlers/main.yml create mode 100644 roles/hashicorp_consul/meta/main.yml create mode 100644 roles/hashicorp_consul/molecule/default/converge.yml create mode 100644 roles/hashicorp_consul/molecule/default/molecule.yml create mode 100644 roles/hashicorp_consul/molecule/default/requirements.yml create mode 100644 roles/hashicorp_consul/molecule/default/verify.yml create mode 100644 roles/hashicorp_consul/molecule/default_vagrant/converge.yml create mode 100644 roles/hashicorp_consul/molecule/default_vagrant/molecule.yml create mode 100644 roles/hashicorp_consul/molecule/default_vagrant/requirements.yml create mode 100644 roles/hashicorp_consul/molecule/default_vagrant/verify.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled/converge.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled/group_vars/all.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled/molecule.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled/requirements.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled/verify.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/converge.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/group_vars/all.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/molecule.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/requirements.yml create mode 100644 roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/verify.yml create mode 100644 roles/hashicorp_consul/tasks/configure.yml create mode 100644 roles/hashicorp_consul/tasks/install.yml create mode 100644 roles/hashicorp_consul/tasks/install_envoy.yml create mode 100644 roles/hashicorp_consul/tasks/main.yml create mode 100644 roles/hashicorp_consul/tasks/prerequisites.yml create mode 100644 roles/hashicorp_consul/templates/consul.env.j2 create mode 100644 roles/hashicorp_consul/templates/consul.json.j2 create mode 100644 roles/hashicorp_consul/templates/consul.service.j2 create mode 100644 roles/hashicorp_consul/vars/main.yml create mode 100644 roles/hashicorp_nomad/LICENSE create mode 100644 roles/hashicorp_nomad/README.md create mode 100644 roles/hashicorp_nomad/defaults/hashicorp_nomad.yml.sample create mode 100644 roles/hashicorp_nomad/defaults/main.yml create mode 100644 roles/hashicorp_nomad/handlers/main.yml create mode 100644 roles/hashicorp_nomad/meta/main.yml create mode 100644 roles/hashicorp_nomad/molecule/default/converge.yml create mode 100644 roles/hashicorp_nomad/molecule/default/molecule.yml create mode 100644 roles/hashicorp_nomad/molecule/default/requirements.yml create mode 100644 roles/hashicorp_nomad/molecule/default/verify.yml create mode 100644 roles/hashicorp_nomad/molecule/default_vagrant/converge.yml create mode 100644 roles/hashicorp_nomad/molecule/default_vagrant/molecule.yml create mode 100644 roles/hashicorp_nomad/molecule/default_vagrant/requirements.yml create mode 100644 roles/hashicorp_nomad/molecule/default_vagrant/verify.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled/converge.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled/group_vars/all.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled/molecule.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled/requirements.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled/verify.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/converge.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/group_vars/all.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/molecule.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/requirements.yml create mode 100644 roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/verify.yml create mode 100644 roles/hashicorp_nomad/tasks/cni_install.yml create mode 100644 roles/hashicorp_nomad/tasks/configure.yml create mode 100644 roles/hashicorp_nomad/tasks/install.yml create mode 100644 roles/hashicorp_nomad/tasks/main.yml create mode 100644 roles/hashicorp_nomad/tasks/prerequisites.yml create mode 100644 roles/hashicorp_nomad/templates/nomad.env.j2 create mode 100644 roles/hashicorp_nomad/templates/nomad.json.j2 create mode 100644 roles/hashicorp_nomad/templates/nomad.service.j2 create mode 100644 roles/hashicorp_nomad/vars/main.yml create mode 100644 roles/hashicorp_vault/LICENSE create mode 100644 roles/hashicorp_vault/README.md create mode 100644 roles/hashicorp_vault/defaults/hashicorp_vault.yml.sample create mode 100644 roles/hashicorp_vault/defaults/main.yml create mode 100644 roles/hashicorp_vault/handlers/main.yml create mode 100644 roles/hashicorp_vault/meta/main.yml create mode 100644 roles/hashicorp_vault/molecule/default/converge.yml create mode 100644 roles/hashicorp_vault/molecule/default/molecule.yml create mode 100644 roles/hashicorp_vault/molecule/default/requirements.yml create mode 100644 roles/hashicorp_vault/molecule/default/verify.yml create mode 100644 roles/hashicorp_vault/molecule/default_vagrant/converge.yml create mode 100644 roles/hashicorp_vault/molecule/default_vagrant/molecule.yml create mode 100644 roles/hashicorp_vault/molecule/default_vagrant/requirements.yml create mode 100644 roles/hashicorp_vault/molecule/default_vagrant/verify.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled/converge.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled/group_vars/all.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled/molecule.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled/requirements.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled/verify.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/converge.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/group_vars/all.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/molecule.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/requirements.yml create mode 100644 roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/verify.yml create mode 100644 roles/hashicorp_vault/tasks/configure.yml create mode 100644 roles/hashicorp_vault/tasks/install.yml create mode 100644 roles/hashicorp_vault/tasks/main.yml create mode 100644 roles/hashicorp_vault/tasks/prerequisites.yml create mode 100644 roles/hashicorp_vault/templates/vault.env.j2 create mode 100644 roles/hashicorp_vault/templates/vault.json.j2 create mode 100644 roles/hashicorp_vault/templates/vault.service.j2 create mode 100644 roles/hashicorp_vault/vars/main.yml create mode 100644 roles/import_vault_root_ca/LICENSE create mode 100644 roles/import_vault_root_ca/README.md create mode 100644 roles/import_vault_root_ca/defaults/main.yml create mode 100644 roles/import_vault_root_ca/handlers/main.yml create mode 100644 roles/import_vault_root_ca/meta/main.yml create mode 100644 roles/import_vault_root_ca/molecule/default/converge.yml create mode 100644 roles/import_vault_root_ca/molecule/default/molecule.yml create mode 100644 roles/import_vault_root_ca/molecule/default/requirements.yml create mode 100644 roles/import_vault_root_ca/molecule/default/verify.yml create mode 100644 roles/import_vault_root_ca/molecule/default_vagrant/converge.yml create mode 100644 roles/import_vault_root_ca/molecule/default_vagrant/molecule.yml create mode 100644 roles/import_vault_root_ca/molecule/default_vagrant/requirements.yml create mode 100644 roles/import_vault_root_ca/molecule/default_vagrant/verify.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca/converge.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca/group_vars/all.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca/molecule.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca/requirements.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca/verify.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/converge.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/group_vars/all.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/molecule.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/requirements.yml create mode 100644 roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/verify.yml create mode 100644 roles/import_vault_root_ca/tasks/import.yml create mode 100644 roles/import_vault_root_ca/tasks/main.yml create mode 100644 roles/import_vault_root_ca/tasks/prerequisites.yml create mode 100644 roles/import_vault_root_ca/vars/main.yml create mode 100644 roles/renew_consul_certificates/LICENSE create mode 100644 roles/renew_consul_certificates/README.md create mode 100644 roles/renew_consul_certificates/defaults/main.yml create mode 100644 roles/renew_consul_certificates/defaults/renew_consul_certificates.yml.sample create mode 100644 roles/renew_consul_certificates/handlers/main.yml create mode 100644 roles/renew_consul_certificates/meta/main.yml create mode 100644 roles/renew_consul_certificates/molecule/default/converge.yml create mode 100644 roles/renew_consul_certificates/molecule/default/molecule.yml create mode 100644 roles/renew_consul_certificates/molecule/default/prepare.yml create mode 100644 roles/renew_consul_certificates/molecule/default/requirements.yml create mode 100644 roles/renew_consul_certificates/molecule/default/verify.yml create mode 100644 roles/renew_consul_certificates/molecule/default_vagrant/converge.yml create mode 100644 roles/renew_consul_certificates/molecule/default_vagrant/molecule.yml create mode 100644 roles/renew_consul_certificates/molecule/default_vagrant/prepare.yml create mode 100644 roles/renew_consul_certificates/molecule/default_vagrant/requirements.yml create mode 100644 roles/renew_consul_certificates/molecule/default_vagrant/verify.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config/converge.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config/group_vars/all.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config/molecule.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config/prepare.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config/requirements.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config/verify.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config_vagrant/converge.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config_vagrant/group_vars/all.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config_vagrant/molecule.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config_vagrant/prepare.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config_vagrant/requirements.yml create mode 100644 roles/renew_consul_certificates/molecule/with_custom_config_vagrant/verify.yml create mode 100644 roles/renew_consul_certificates/tasks/configure.yml create mode 100644 roles/renew_consul_certificates/tasks/install.yml create mode 100644 roles/renew_consul_certificates/tasks/main.yml create mode 100644 roles/renew_consul_certificates/tasks/prerequisites.yml create mode 100644 roles/renew_consul_certificates/templates/consul-certs.env.j2 create mode 100644 roles/renew_consul_certificates/templates/consul-certs.service.j2 create mode 100644 roles/renew_consul_certificates/templates/consul_ca.pem.tpl.j2 create mode 100644 roles/renew_consul_certificates/templates/consul_cert.pem.tpl.j2 create mode 100644 roles/renew_consul_certificates/templates/consul_config.hcl.j2 create mode 100644 roles/renew_consul_certificates/templates/consul_key.pem.tpl.j2 create mode 100644 roles/renew_consul_certificates/vars/main.yml diff --git a/extensions/molecule/no_tls_single_node/converge.yml b/extensions/molecule/no_tls_single_node/converge.yml deleted file mode 100644 index e600756..0000000 --- a/extensions/molecule/no_tls_single_node/converge.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -- name: Converge - hosts: all - gather_facts: false - tasks: - - name: Replace this task with one that validates your content - ansible.builtin.debug: - msg: "This is the effective test" diff --git a/molecule/no_tls_multi_node/converge.yml b/molecule/no_tls_multi_node/converge.yml new file mode 100644 index 0000000..cbc0a88 --- /dev/null +++ b/molecule/no_tls_multi_node/converge.yml @@ -0,0 +1,3 @@ +--- +- name: Include a playbook from a collection + ansible.builtin.import_playbook: ednxzu.hashistack.deploy.yml diff --git a/molecule/no_tls_multi_node/molecule.yml b/molecule/no_tls_multi_node/molecule.yml new file mode 100644 index 0000000..4e1da3c --- /dev/null +++ b/molecule/no_tls_multi_node/molecule.yml @@ -0,0 +1,42 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: hashistack01 + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 + - name: hashistack02 + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 + - name: hashistack03 + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: no_tls_multi_node + test_sequence: + - dependency + - cleanup + - destroy + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy \ No newline at end of file diff --git a/molecule/no_tls_multi_node/prepare.yml b/molecule/no_tls_multi_node/prepare.yml new file mode 100644 index 0000000..9a6673d --- /dev/null +++ b/molecule/no_tls_multi_node/prepare.yml @@ -0,0 +1,5 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: [] diff --git a/extensions/molecule/no_tls_single_node/requirements.yml b/molecule/no_tls_multi_node/requirements.yml similarity index 81% rename from extensions/molecule/no_tls_single_node/requirements.yml rename to molecule/no_tls_multi_node/requirements.yml index 94c5a52..ed11fdb 100644 --- a/extensions/molecule/no_tls_single_node/requirements.yml +++ b/molecule/no_tls_multi_node/requirements.yml @@ -5,3 +5,6 @@ roles: - name: ednxzu.manage_apt_packages - name: ednxzu.install_docker - name: ednxzu.docker_systemd_service + +collections: + - name: ednxzu.hashistack diff --git a/extensions/molecule/no_tls_single_node/verify.yml b/molecule/no_tls_multi_node/verify.yml similarity index 100% rename from extensions/molecule/no_tls_single_node/verify.yml rename to molecule/no_tls_multi_node/verify.yml diff --git a/playbooks/deploy.yml b/playbooks/deploy.yml new file mode 100644 index 0000000..3df68f6 --- /dev/null +++ b/playbooks/deploy.yml @@ -0,0 +1,9 @@ +--- +# hashistack deployment playbook +- name: "Deploy" + hosts: all + gather_facts: true + tasks: + - name: "Debug" + ansible.builtin.debug: + msg: "{{ ansible_hostname }}" diff --git a/playbooks/inventory/multinode.ini b/playbooks/inventory/multinode.ini index e69de29..ac433c1 100644 --- a/playbooks/inventory/multinode.ini +++ b/playbooks/inventory/multinode.ini @@ -0,0 +1,22 @@ +[vault_servers] +vault01 +vault02 +vault03 + +[consul_servers] +consul01 +consul02 +consul03 + +[nomad_servers] +nomad01 +nomad02 +nomad03 + +[deployment] +localhost ansible_connection=local + +[common:children] +vault_servers +consul_servers +nomad_servers diff --git a/playbooks/prepare.yml b/playbooks/prepare.yml new file mode 100644 index 0000000..330a765 --- /dev/null +++ b/playbooks/prepare.yml @@ -0,0 +1,6 @@ +--- +# hashistack prepare playbook +- name: "Deploy" + hosts: all + gather_facts: true + tasks: [] diff --git a/playbooks/vars/global.yml b/playbooks/vars/global.yml index 73b314f..2dbe452 100644 --- a/playbooks/vars/global.yml +++ b/playbooks/vars/global.yml @@ -1 +1,44 @@ ---- \ No newline at end of file +--- +hashi_nomad_install: true +hashi_nomad_auto_update: false +hashi_nomad_cni_plugins_install: true +hashi_nomad_start_service: true +hashi_nomad_cni_plugins_version: latest +hashi_nomad_cni_plugins_install_path: /opt/cni/bin +hashi_nomad_version: latest +hashi_nomad_deploy_method: host # deployment method, either host or docker +hashi_nomad_env_variables: {} +hashi_nomad_data_dir: /opt/nomad +hashi_nomad_extra_files: false +hashi_nomad_extra_files_src: /tmp/extra_files +hashi_nomad_extra_files_dst: /etc/nomad.d/extra_files +#! nomad configuration +hashi_nomad_configuration: {} + +hashi_vault_install: true +hashi_vault_auto_update: false +hashi_vault_start_service: true +hashi_vault_version: latest +hashi_vault_deploy_method: host # deployment method, either host or docker +hashi_vault_env_variables: {} +hashi_vault_data_dir: "/opt/vault" +hashi_vault_extra_files: false +hashi_vault_extra_files_src: /tmp/extra_files +hashi_vault_extra_files_dst: /etc/vault.d/extra_files +#! vault configuration +hashi_vault_configuration: {} + +hashi_consul_install: true +hashi_consul_auto_update: false +hashi_consul_start_service: true +hashi_consul_version: latest +hashi_consul_deploy_method: host # deployment method, either host or docker. +hashi_consul_env_variables: {} +hashi_consul_data_dir: "/opt/consul" +hashi_consul_extra_files: false +hashi_consul_extra_files_src: /tmp/extra_files +hashi_consul_extra_files_dst: /etc/consul.d/extra_files +hashi_consul_envoy_install: false +hashi_consul_envoy_version: latest +#! consul configuration +hashi_consul_configuration: {} diff --git a/roles/ednxzu.docker_systemd_service/.ansible-lint b/roles/ednxzu.docker_systemd_service/.ansible-lint new file mode 100644 index 0000000..0d93798 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/.ansible-lint @@ -0,0 +1,8 @@ +--- +warn_list: + - experimental # all rules tagged as experimental + - yaml # violations reported by yamllint + - meta-no-info + +skip_list: + - jinja[spacing] # Rule that looks inside jinja2 templates. diff --git a/roles/ednxzu.docker_systemd_service/.gitea/workflows/test.yml b/roles/ednxzu.docker_systemd_service/.gitea/workflows/test.yml new file mode 100644 index 0000000..3a74d0a --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/.gitea/workflows/test.yml @@ -0,0 +1,52 @@ +--- +name: test +on: [push] + +jobs: + lint: + name: Linting + runs-on: ubuntu-latest + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Ansible lint" + run: ansible-lint --force-color + working-directory: ${{ gitea.workspace }} + + - name: "YAML lint" + run: yamllint . -f colored -c .yamllint + working-directory: ${{ gitea.workspace }} + + molecule-test: + name: Molecule tests + runs-on: ubuntu-latest + needs: lint + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + strategy: + matrix: + test_os: [debian11, debian12, ubuntu2004, ubuntu2204] + scenario: [default, with_custom_flags] + env: + ANSIBLE_HOST_KEY_CHECKING: 'false' + ANSIBLE_FORCE_COLOR: 'true' + ANSIBLE_PYTHON_INTERPRETER: /usr/bin/python3 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Molecule test" + run: molecule test -s ${{ matrix.scenario }} + shell: bash + working-directory: ${{ gitea.workspace }} + env: + MOLECULE_TEST_OS: ${{ matrix.test_os }} diff --git a/roles/ednxzu.docker_systemd_service/.github/workflows/publish.yml b/roles/ednxzu.docker_systemd_service/.github/workflows/publish.yml new file mode 100644 index 0000000..784f2c9 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/.github/workflows/publish.yml @@ -0,0 +1,18 @@ +--- +name: publish +on: + push: + branches: + - main + +jobs: + publish: + name: Publish to galaxy + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Publish + uses: ednxzu/galaxy-import-role@v1 + with: + galaxy-api-key: ${{ secrets.GALAXY_API_TOKEN }} diff --git a/roles/ednxzu.docker_systemd_service/.gitignore b/roles/ednxzu.docker_systemd_service/.gitignore new file mode 100644 index 0000000..bccf235 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/.gitignore @@ -0,0 +1,3 @@ +# ignore molecule/testinfra pycache +**/__pycache__ +.vscode \ No newline at end of file diff --git a/roles/ednxzu.docker_systemd_service/.yamllint b/roles/ednxzu.docker_systemd_service/.yamllint new file mode 100644 index 0000000..24fdec5 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/.yamllint @@ -0,0 +1,40 @@ +--- +# Based on ansible-lint config +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + comments: enable + comments-indentation: disable + document-start: enable + empty-lines: + max: 3 + level: error + hyphens: + level: error + indentation: enable + key-duplicates: enable + line-length: + max: 80 + level: warning + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + allowed-values: + - 'true' + - 'false' + - 'yes' + - 'no' diff --git a/roles/ednxzu.docker_systemd_service/LICENSE b/roles/ednxzu.docker_systemd_service/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/ednxzu.docker_systemd_service/README.md b/roles/ednxzu.docker_systemd_service/README.md new file mode 100644 index 0000000..f08d6a6 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/README.md @@ -0,0 +1,118 @@ +docker_systemd_service +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role lets you configure a docker container and run it as a systemd service on **debian-based** distributions. This role is heavily sourced from [mhutter.docker-systemd-service](https://github.com/mhutter/ansible-docker-systemd-service), but aims at providing some of the missing features of said role. + +Requirements +------------ + +This roles assumes you have docker installed on the target host. You can use [ednxzu.install_docker](https://github.com/ednxzu/install_docker) to do so. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/docker_systemd_service.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +docker_systemd_service_container_name: "My-Service" # by default, set to "My-Service" +``` +The name that will be assigned to the container. + +```yaml +docker_systemd_service_image: # by default, not defined +``` +The image (and optionally tag) to use for the service. + +```yaml +docker_systemd_service_container_env: {} # by default, set to {} +``` +A list of key/value pairs, that will be written to the environment file for the container. the key NEEDS TO BE CAPTIALIZED, it will not be done automatically. Example: `MY_ENV_VAR: foobar`. + +```yaml +docker_systemd_service_container_pull_image: true # by default, set to true +``` +Whether or not the role should pull the image during its run. + +```yaml +docker_systemd_service_container_pull_force_source: true # by default, set to true +``` +If `docker_systemd_service_container_pull_image: true`, whether the pull you be executed at every run. See [`docker_image.force_source`](https://docs.ansible.com/ansible/latest/collections/community/docker/docker_image_module.html#parameter-force_source) + +```yaml +docker_systemd_service_flags: [] # by default, set to [] +``` +This variable lets you pass whatever flags you need to the docker run command. It is a list, to which you can add multiple types of flags: + - ```yaml + - key: value + # will pass the flag --key "value" to the container. + Example: + - network: host + - ```yaml + - simple_key + # will pass the flag --simple_key to the container. + Example: + - privileged + - ```yaml + - key: + - value1 + - value2 + # will pass the flags --key "value1" --key "value2" to the container. + Example: + - volume: + - /path/on/host:/path/on/container + - /var/run/docker.sock:/var/run/docker.sock:ro + +```yaml +docker_systemd_service_name: "{{ docker_systemd_service_container_name }}_container" # by default, set to "{{ docker_systemd_service_container_name }}_container" +``` +The name of the systemd service to register. + +```yaml +docker_systemd_service_systemd_options: [] # by default, set to [] +``` +Extra options to include in systemd service file. + +```yaml +docker_systemd_service_enabled: true # by default, set to true +``` +Whether the service should be enabled during the role's run. + +```yaml +docker_systemd_service_masked: false # by default, set to false +``` +Whether the service should be marked as masked. + +```yaml +docker_systemd_service_state: started # by default, set to started +``` +The state the service should be put in. Valid options are: `reloaded`, `restarted`, `started`, `stopped`, and `absent`. Realistically, you probably want to use `started` or `stopped`. `absent` can be used to remove the service and all associated files from the host. + +```yaml +docker_systemd_service_restart: true # by default, set to true +``` +Whether the role should restart the service if changes are made to any of the files (when service is already runing). + +Dependencies +------------ + +None. + +Example Playbook +---------------- + +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.docker_systemd_service +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/ednxzu.docker_systemd_service/defaults/docker_systemd_service.yml.sample b/roles/ednxzu.docker_systemd_service/defaults/docker_systemd_service.yml.sample new file mode 100644 index 0000000..d00d9ac --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/defaults/docker_systemd_service.yml.sample @@ -0,0 +1,14 @@ +--- +# docker_systemd_service_container_name: "My-Service" +# docker_systemd_service_image: +# docker_systemd_service_container_env: {} +# docker_systemd_service_container_pull_image: true +# docker_systemd_service_container_pull_force_source: true +# docker_systemd_service_flags: [] +# docker_systemd_service_container_cmd: [] +# docker_systemd_service_name: "{{ docker_systemd_service_container_name }}_container" +# docker_systemd_service_systemd_options: [] +# docker_systemd_service_enabled: true +# docker_systemd_service_masked: false +# docker_systemd_service_state: started +# docker_systemd_service_restart: true diff --git a/roles/ednxzu.docker_systemd_service/defaults/main.yml b/roles/ednxzu.docker_systemd_service/defaults/main.yml new file mode 100644 index 0000000..f70688b --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/defaults/main.yml @@ -0,0 +1,15 @@ +--- +# defaults file for docker_systemd_service +docker_systemd_service_container_name: "My-Service" +docker_systemd_service_image: +docker_systemd_service_container_env: {} +docker_systemd_service_container_pull_image: true +docker_systemd_service_container_pull_force_source: true +docker_systemd_service_flags: [] +docker_systemd_service_container_cmd: [] +docker_systemd_service_name: "{{ docker_systemd_service_container_name }}_container" +docker_systemd_service_systemd_options: [] +docker_systemd_service_enabled: true +docker_systemd_service_masked: false +docker_systemd_service_state: started +docker_systemd_service_restart: true diff --git a/roles/ednxzu.docker_systemd_service/files/.gitkeep b/roles/ednxzu.docker_systemd_service/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/roles/ednxzu.docker_systemd_service/filter_plugins/docker_filters.py b/roles/ednxzu.docker_systemd_service/filter_plugins/docker_filters.py new file mode 100644 index 0000000..25c89b6 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/filter_plugins/docker_filters.py @@ -0,0 +1,32 @@ +# filter_plugins/docker_filters.py + +def create_docker_flags(flags): + if flags: + filtered_flags = [ + create_docker_flag(item) for item in flags if create_docker_flag(item) + ] + return "\n".join(filtered_flags) + return None + + +def create_docker_flag(item): + if isinstance(item, dict): + key = list(item.keys())[0] + value = item[key] + if value is not None: + if isinstance(value, list): + flag_values = ['--{} "{}"'.format(key, val) for val in value] + joined_values = " \\\n".join(flag_values) + return f"{joined_values} \\" if joined_values else None + else: + return '--{} "{}" \\'.format(key, value) + elif isinstance(item, str): + return "--{} \\".format(item) + return None + + +class FilterModule(object): + def filters(self): + return { + "create_docker_flags": create_docker_flags, + } diff --git a/roles/ednxzu.docker_systemd_service/handlers/main.yml b/roles/ednxzu.docker_systemd_service/handlers/main.yml new file mode 100644 index 0000000..ef576c2 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/handlers/main.yml @@ -0,0 +1,10 @@ +--- +# handlers file for docker_systemd_service +- name: "Restart service(s)" + ansible.builtin.service: + name: "{{ docker_systemd_service_name }}.service" + state: restarted + listen: "systemctl-restart-service" + when: docker_systemd_service_restart + and docker_systemd_service_state != "stopped" + and not _enable_and_start.changed diff --git a/roles/ednxzu.docker_systemd_service/meta/.galaxy_install_info b/roles/ednxzu.docker_systemd_service/meta/.galaxy_install_info new file mode 100644 index 0000000..4fa61bf --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: 'Fri 15 Dec 2023 05:25:28 PM ' +version: main diff --git a/roles/ednxzu.docker_systemd_service/meta/main.yml b/roles/ednxzu.docker_systemd_service/meta/main.yml new file mode 100644 index 0000000..73f4395 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/meta/main.yml @@ -0,0 +1,25 @@ +--- +# meta file for docker_systemd_service +galaxy_info: + namespace: 'ednxzu' + role_name: 'docker_systemd_service' + author: 'Bertrand Lanson' + description: 'Create Systemd services for docker containers.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'docker' + - 'systemd' + +dependencies: [] diff --git a/roles/ednxzu.docker_systemd_service/molecule/default/converge.yml b/roles/ednxzu.docker_systemd_service/molecule/default/converge.yml new file mode 100644 index 0000000..1271eed --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.docker_systemd_service" + ansible.builtin.include_role: + name: "ednxzu.docker_systemd_service" diff --git a/roles/ednxzu.docker_systemd_service/molecule/default/group_vars/all.yml b/roles/ednxzu.docker_systemd_service/molecule/default/group_vars/all.yml new file mode 100644 index 0000000..1546e18 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default/group_vars/all.yml @@ -0,0 +1,14 @@ +--- +docker_systemd_service_container_name: "nginx" +docker_systemd_service_image: nginx +docker_systemd_service_container_env: {} +docker_systemd_service_container_pull_image: false +docker_systemd_service_container_pull_force_source: false +docker_systemd_service_flags: [] +docker_systemd_service_container_cmd: [] +docker_systemd_service_name: "{{ docker_systemd_service_container_name }}_container" +docker_systemd_service_systemd_options: [] +docker_systemd_service_enabled: true +docker_systemd_service_masked: false +docker_systemd_service_state: stopped +docker_systemd_service_restart: false diff --git a/roles/ednxzu.docker_systemd_service/molecule/default/molecule.yml b/roles/ednxzu.docker_systemd_service/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.docker_systemd_service/molecule/default/requirements.yml b/roles/ednxzu.docker_systemd_service/molecule/default/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.docker_systemd_service/molecule/default/verify.yml b/roles/ednxzu.docker_systemd_service/molecule/default/verify.yml new file mode 100644 index 0000000..433b360 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default/verify.yml @@ -0,0 +1,78 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/default/nginx" + block: + - name: "Stat file /etc/default/nginx" + ansible.builtin.stat: + path: "/etc/default/nginx" + register: stat_etc_default_nginx + + - name: "Slurp file /etc/default/nginx" + ansible.builtin.slurp: + src: "/etc/default/nginx" + register: slurp_etc_default_nginx + + - name: "Verify file /etc/systemd/system/nginx_container.service" + ansible.builtin.assert: + that: + - stat_etc_default_nginx.stat.exists + - stat_etc_default_nginx.stat.isreg + - stat_etc_default_nginx.stat.pw_name == 'root' + - stat_etc_default_nginx.stat.gr_name == 'root' + - stat_etc_default_nginx.stat.mode == '0600' + - (slurp_etc_default_nginx.content|b64decode) == '' + + - name: "Test: service nginx_container" + block: + - name: "Get service nginx_container" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nginx_container.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nginx_container.service" + register: stat_etc_systemd_system_nginx_container_service + + - name: "Slurp file /etc/systemd/system/nginx_container.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nginx_container.service" + register: slurp_etc_systemd_system_nginx_container_service + + - name: "Verify service nginx_container" + vars: + nginx_expected_service_file: | + # Ansible managed: Do NOT edit this file manually! + [Unit] + After=docker.service + PartOf=docker.service + Requires=docker.service + + [Service] + EnvironmentFile=/etc/default/nginx + ExecStartPre=-/usr/bin/docker rm -f nginx + ExecStart=/usr/bin/docker run --name nginx \ + --rm \ + --env-file /etc/default/nginx \ + nginx + ExecStop=/usr/bin/docker stop nginx + SyslogIdentifier=nginx + Restart=always + RestartSec=10s + + [Install] + WantedBy=docker.service + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nginx_container_service.stat.exists + - stat_etc_systemd_system_nginx_container_service.stat.isreg + - stat_etc_systemd_system_nginx_container_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.mode == '0644' + - (slurp_etc_systemd_system_nginx_container_service.content|b64decode) == nginx_expected_service_file + - ansible_facts.services['nginx_container.service'] is defined + - ansible_facts.services['nginx_container.service']['source'] == 'systemd' + - ansible_facts.services['nginx_container.service']['state'] == 'inactive' + - ansible_facts.services['nginx_container.service']['status'] == 'enabled' diff --git a/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/converge.yml b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..1271eed --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.docker_systemd_service" + ansible.builtin.include_role: + name: "ednxzu.docker_systemd_service" diff --git a/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/group_vars/all.yml b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/group_vars/all.yml new file mode 100644 index 0000000..359ff70 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/group_vars/all.yml @@ -0,0 +1,14 @@ +--- +docker_systemd_service_container_name: "nginx" +docker_systemd_service_image: nginx +docker_systemd_service_container_env: {} +docker_systemd_service_container_pull_image: true +docker_systemd_service_container_pull_force_source: true +docker_systemd_service_flags: [] +docker_systemd_service_container_cmd: [] +docker_systemd_service_name: "{{ docker_systemd_service_container_name }}_container" +docker_systemd_service_systemd_options: [] +docker_systemd_service_enabled: true +docker_systemd_service_masked: false +docker_systemd_service_state: started +docker_systemd_service_restart: true diff --git a/extensions/molecule/no_tls_single_node/molecule.yml b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/molecule.yml similarity index 95% rename from extensions/molecule/no_tls_single_node/molecule.yml rename to roles/ednxzu.docker_systemd_service/molecule/default_vagrant/molecule.yml index 1b53c4b..2b02360 100644 --- a/extensions/molecule/no_tls_single_node/molecule.yml +++ b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/molecule.yml @@ -25,10 +25,11 @@ scenario: - dependency - cleanup - destroy + - syntax - create - prepare - converge - idempotence - verify - cleanup - - destroy \ No newline at end of file + - destroy diff --git a/extensions/molecule/no_tls_single_node/prepare.yml b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/prepare.yml similarity index 80% rename from extensions/molecule/no_tls_single_node/prepare.yml rename to roles/ednxzu.docker_systemd_service/molecule/default_vagrant/prepare.yml index 7f58328..06b4860 100644 --- a/extensions/molecule/no_tls_single_node/prepare.yml +++ b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/prepare.yml @@ -3,7 +3,7 @@ hosts: all become: true tasks: - - name: "Include ednxzu.install_docker" + - name: "Install docker" ansible.builtin.include_role: name: ednxzu.install_docker vars: diff --git a/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/requirements.yml b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..1316891 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/requirements.yml @@ -0,0 +1,6 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages + - name: ednxzu.install_docker diff --git a/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/verify.yml b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..5e1cbce --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/default_vagrant/verify.yml @@ -0,0 +1,78 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/default/nginx" + block: + - name: "Stat file /etc/default/nginx" + ansible.builtin.stat: + path: "/etc/default/nginx" + register: stat_etc_default_nginx + + - name: "Slurp file /etc/default/nginx" + ansible.builtin.slurp: + src: "/etc/default/nginx" + register: slurp_etc_default_nginx + + - name: "Verify file /etc/systemd/system/nginx_container.service" + ansible.builtin.assert: + that: + - stat_etc_default_nginx.stat.exists + - stat_etc_default_nginx.stat.isreg + - stat_etc_default_nginx.stat.pw_name == 'root' + - stat_etc_default_nginx.stat.gr_name == 'root' + - stat_etc_default_nginx.stat.mode == '0600' + - (slurp_etc_default_nginx.content|b64decode) == '' + + - name: "Test: service nginx_container" + block: + - name: "Get service nginx_container" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nginx_container.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nginx_container.service" + register: stat_etc_systemd_system_nginx_container_service + + - name: "Slurp file /etc/systemd/system/nginx_container.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nginx_container.service" + register: slurp_etc_systemd_system_nginx_container_service + + - name: "Verify service nginx_container" + vars: + nginx_expected_service_file: | + # Ansible managed: Do NOT edit this file manually! + [Unit] + After=docker.service + PartOf=docker.service + Requires=docker.service + + [Service] + EnvironmentFile=/etc/default/nginx + ExecStartPre=-/usr/bin/docker rm -f nginx + ExecStart=/usr/bin/docker run --name nginx \ + --rm \ + --env-file /etc/default/nginx \ + nginx + ExecStop=/usr/bin/docker stop nginx + SyslogIdentifier=nginx + Restart=always + RestartSec=10s + + [Install] + WantedBy=docker.service + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nginx_container_service.stat.exists + - stat_etc_systemd_system_nginx_container_service.stat.isreg + - stat_etc_systemd_system_nginx_container_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.mode == '0644' + - (slurp_etc_systemd_system_nginx_container_service.content|b64decode) == nginx_expected_service_file + - ansible_facts.services['nginx_container.service'] is defined + - ansible_facts.services['nginx_container.service']['source'] == 'systemd' + - ansible_facts.services['nginx_container.service']['state'] == 'running' + - ansible_facts.services['nginx_container.service']['status'] == 'enabled' diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/converge.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/converge.yml new file mode 100644 index 0000000..1271eed --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.docker_systemd_service" + ansible.builtin.include_role: + name: "ednxzu.docker_systemd_service" diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/group_vars/all.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/group_vars/all.yml new file mode 100644 index 0000000..11733c3 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/group_vars/all.yml @@ -0,0 +1,19 @@ +--- +docker_systemd_service_container_name: "nginx" +docker_systemd_service_image: nginx +docker_systemd_service_container_env: + TEST_ENV: test +docker_systemd_service_container_pull_image: false +docker_systemd_service_container_pull_force_source: false +docker_systemd_service_flags: + - privileged + - network: host + - cap-add: + - NET_ADMIN +docker_systemd_service_container_cmd: [] +docker_systemd_service_name: "{{ docker_systemd_service_container_name }}_container" +docker_systemd_service_systemd_options: [] +docker_systemd_service_enabled: true +docker_systemd_service_masked: false +docker_systemd_service_state: stopped +docker_systemd_service_restart: false diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/molecule.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/molecule.yml new file mode 100644 index 0000000..ce39f56 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_flags + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/requirements.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/verify.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/verify.yml new file mode 100644 index 0000000..6e80eef --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags/verify.yml @@ -0,0 +1,84 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/default/nginx" + block: + - name: "Stat file /etc/default/nginx" + ansible.builtin.stat: + path: "/etc/default/nginx" + register: stat_etc_default_nginx + + - name: "Slurp file /etc/default/nginx" + ansible.builtin.slurp: + src: "/etc/default/nginx" + register: slurp_etc_default_nginx + + - name: "Verify file /etc/default/nginx" + vars: + nginx_expected_env_file: | + TEST_ENV=test + ansible.builtin.assert: + that: + - stat_etc_default_nginx.stat.exists + - stat_etc_default_nginx.stat.isreg + - stat_etc_default_nginx.stat.pw_name == 'root' + - stat_etc_default_nginx.stat.gr_name == 'root' + - stat_etc_default_nginx.stat.mode == '0600' + - (slurp_etc_default_nginx.content|b64decode) == nginx_expected_env_file + + - name: "Test: service nginx_container" + block: + - name: "Get service nginx_container" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nginx_container.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nginx_container.service" + register: stat_etc_systemd_system_nginx_container_service + + - name: "Slurp file /etc/systemd/system/nginx_container.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nginx_container.service" + register: slurp_etc_systemd_system_nginx_container_service + + - name: "Verify service nginx_container" + vars: + nginx_expected_service_file: | + # Ansible managed: Do NOT edit this file manually! + [Unit] + After=docker.service + PartOf=docker.service + Requires=docker.service + + [Service] + EnvironmentFile=/etc/default/nginx + ExecStartPre=-/usr/bin/docker rm -f nginx + ExecStart=/usr/bin/docker run --name nginx \ + --rm \ + --env-file /etc/default/nginx \ + --privileged \ + --network "host" \ + --cap-add "NET_ADMIN" \ + nginx + ExecStop=/usr/bin/docker stop nginx + SyslogIdentifier=nginx + Restart=always + RestartSec=10s + + [Install] + WantedBy=docker.service + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nginx_container_service.stat.exists + - stat_etc_systemd_system_nginx_container_service.stat.isreg + - stat_etc_systemd_system_nginx_container_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.mode == '0644' + - (slurp_etc_systemd_system_nginx_container_service.content|b64decode) == nginx_expected_service_file + - ansible_facts.services['nginx_container.service'] is defined + - ansible_facts.services['nginx_container.service']['source'] == 'systemd' + - ansible_facts.services['nginx_container.service']['state'] == 'inactive' + - ansible_facts.services['nginx_container.service']['status'] == 'enabled' diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/converge.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/converge.yml new file mode 100644 index 0000000..1271eed --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.docker_systemd_service" + ansible.builtin.include_role: + name: "ednxzu.docker_systemd_service" diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/group_vars/all.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/group_vars/all.yml new file mode 100644 index 0000000..0c8909c --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/group_vars/all.yml @@ -0,0 +1,19 @@ +--- +docker_systemd_service_container_name: "nginx" +docker_systemd_service_image: nginx +docker_systemd_service_container_env: + TEST_ENV: test +docker_systemd_service_container_pull_image: true +docker_systemd_service_container_pull_force_source: true +docker_systemd_service_flags: + - privileged + - network: host + - cap-add: + - NET_ADMIN +docker_systemd_service_container_cmd: [] +docker_systemd_service_name: "{{ docker_systemd_service_container_name }}_container" +docker_systemd_service_systemd_options: [] +docker_systemd_service_enabled: true +docker_systemd_service_masked: false +docker_systemd_service_state: started +docker_systemd_service_restart: true diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/molecule.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/molecule.yml new file mode 100644 index 0000000..fe55051 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_flags_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/prepare.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/prepare.yml new file mode 100644 index 0000000..06b4860 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/prepare.yml @@ -0,0 +1,10 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: + - name: "Install docker" + ansible.builtin.include_role: + name: ednxzu.install_docker + vars: + install_docker_python_packages: true diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/requirements.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/requirements.yml new file mode 100644 index 0000000..1316891 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/requirements.yml @@ -0,0 +1,6 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages + - name: ednxzu.install_docker diff --git a/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/verify.yml b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/verify.yml new file mode 100644 index 0000000..d043f00 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/molecule/with_custom_flags_vagrant/verify.yml @@ -0,0 +1,84 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/default/nginx" + block: + - name: "Stat file /etc/default/nginx" + ansible.builtin.stat: + path: "/etc/default/nginx" + register: stat_etc_default_nginx + + - name: "Slurp file /etc/default/nginx" + ansible.builtin.slurp: + src: "/etc/default/nginx" + register: slurp_etc_default_nginx + + - name: "Verify file /etc/default/nginx" + vars: + nginx_expected_env_file: | + TEST_ENV=test + ansible.builtin.assert: + that: + - stat_etc_default_nginx.stat.exists + - stat_etc_default_nginx.stat.isreg + - stat_etc_default_nginx.stat.pw_name == 'root' + - stat_etc_default_nginx.stat.gr_name == 'root' + - stat_etc_default_nginx.stat.mode == '0600' + - (slurp_etc_default_nginx.content|b64decode) == nginx_expected_env_file + + - name: "Test: service nginx_container" + block: + - name: "Get service nginx_container" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nginx_container.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nginx_container.service" + register: stat_etc_systemd_system_nginx_container_service + + - name: "Slurp file /etc/systemd/system/nginx_container.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nginx_container.service" + register: slurp_etc_systemd_system_nginx_container_service + + - name: "Verify service nginx_container" + vars: + nginx_expected_service_file: | + # Ansible managed: Do NOT edit this file manually! + [Unit] + After=docker.service + PartOf=docker.service + Requires=docker.service + + [Service] + EnvironmentFile=/etc/default/nginx + ExecStartPre=-/usr/bin/docker rm -f nginx + ExecStart=/usr/bin/docker run --name nginx \ + --rm \ + --env-file /etc/default/nginx \ + --privileged \ + --network "host" \ + --cap-add "NET_ADMIN" \ + nginx + ExecStop=/usr/bin/docker stop nginx + SyslogIdentifier=nginx + Restart=always + RestartSec=10s + + [Install] + WantedBy=docker.service + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nginx_container_service.stat.exists + - stat_etc_systemd_system_nginx_container_service.stat.isreg + - stat_etc_systemd_system_nginx_container_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nginx_container_service.stat.mode == '0644' + - (slurp_etc_systemd_system_nginx_container_service.content|b64decode) == nginx_expected_service_file + - ansible_facts.services['nginx_container.service'] is defined + - ansible_facts.services['nginx_container.service']['source'] == 'systemd' + - ansible_facts.services['nginx_container.service']['state'] == 'running' + - ansible_facts.services['nginx_container.service']['status'] == 'enabled' diff --git a/roles/ednxzu.docker_systemd_service/tasks/install.yml b/roles/ednxzu.docker_systemd_service/tasks/install.yml new file mode 100644 index 0000000..c62cc6f --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/tasks/install.yml @@ -0,0 +1,36 @@ +--- +# task/install file for docker_systemd_service +- name: "Create ENV file(s) for docker service(s)" + ansible.builtin.template: + src: env.j2 + dest: "{{ docker_systemd_service_sysconf_dir }}/{{ docker_systemd_service_container_name }}" + owner: root + group: root + mode: '0600' + notify: systemctl-restart-service + +- name: "Pull docker image(s)" + community.docker.docker_image: + name: "{{ docker_systemd_service_image }}" + force_source: "{{ docker_systemd_service_container_pull_force_source | bool }}" + source: pull + when: docker_systemd_service_container_pull_image + notify: systemctl-restart-service + +- name: "Create unit file(s) for service(s)" + ansible.builtin.template: + src: unit.j2 + dest: "/etc/systemd/system/{{ docker_systemd_service_name }}.service" + owner: root + group: root + mode: '0644' + notify: systemctl-restart-service + +- name: "Enable and start service(s)" + ansible.builtin.systemd: + name: '{{ docker_systemd_service_name }}.service' + daemon_reload: true + enabled: "{{ docker_systemd_service_enabled }}" + masked: "{{ docker_systemd_service_masked }}" + state: "{{ docker_systemd_service_state }}" + register: _enable_and_start diff --git a/roles/ednxzu.docker_systemd_service/tasks/main.yml b/roles/ednxzu.docker_systemd_service/tasks/main.yml new file mode 100644 index 0000000..77d46d7 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/tasks/main.yml @@ -0,0 +1,9 @@ +--- +# task/main file for docker_systemd_service +- name: "Import install.yml" + ansible.builtin.include_tasks: install.yml + when: docker_systemd_service_state != "absent" + +- name: "Import uninstall.yml" + ansible.builtin.include_tasks: uninstall.yml + when: docker_systemd_service_state == "absent" diff --git a/roles/ednxzu.docker_systemd_service/tasks/uninstall.yml b/roles/ednxzu.docker_systemd_service/tasks/uninstall.yml new file mode 100644 index 0000000..9faf8d3 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/tasks/uninstall.yml @@ -0,0 +1,22 @@ +--- +# task/uninstall file for docker_systemd_service +- name: "Remove ENV file(s) for service(s)" + ansible.builtin.file: + path: "{{ docker_systemd_service_sysconf_dir }}/{{ docker_systemd_service_container_name }}" + state: absent + +- name: "Disable and stop service(s)" + ansible.builtin.systemd: + name: '{{ docker_systemd_service_name }}.service' + enabled: false + state: stopped + +- name: "Remove unit file(s) for service(s)" + ansible.builtin.file: + path: /etc/systemd/system/{{ docker_systemd_service_name }}.service + state: absent + +- name: "Reload systemd units" + ansible.builtin.systemd: + daemon_reload: true + changed_when: false diff --git a/roles/ednxzu.docker_systemd_service/templates/env.j2 b/roles/ednxzu.docker_systemd_service/templates/env.j2 new file mode 100644 index 0000000..f5e5931 --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/templates/env.j2 @@ -0,0 +1,3 @@ +{% for k,v in docker_systemd_service_container_env|dictsort %} +{{ k }}={{ v }} +{% endfor %} \ No newline at end of file diff --git a/roles/ednxzu.docker_systemd_service/templates/unit.j2 b/roles/ednxzu.docker_systemd_service/templates/unit.j2 new file mode 100644 index 0000000..3a0700c --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/templates/unit.j2 @@ -0,0 +1,43 @@ +# {{ ansible_managed }} +{% set service_systemd_options_keys = docker_systemd_service_systemd_options | selectattr("key") | map(attribute="key") | list %} +[Unit] +{% for key, value in docker_systemd_service_systemd_unit_options | dictsort %} +{{ key }}={{ value }} +{% endfor %} + +[Service] +{% for item in docker_systemd_service_systemd_options %} +{{ item['key'] }}={{ item['value'] }} +{% endfor %} +{% if not 'EnvironmentFile' in service_systemd_options_keys %} +EnvironmentFile={{ docker_systemd_service_sysconf_dir }}/{{ docker_systemd_service_container_name }} +{% endif %} +{% if not 'ExecStartPre' in service_systemd_options_keys %} +ExecStartPre=-{{ docker_systemd_service_docker_path }} rm -f {{ docker_systemd_service_container_name }} +{% endif %} +{% if not 'ExecStart' in service_systemd_options_keys %} +{% set docker_flags = docker_systemd_service_flags | create_docker_flags %} +ExecStart={{ docker_systemd_service_docker_path }} run --name {{ docker_systemd_service_container_name }} \ +--rm \ +--env-file {{ docker_systemd_service_sysconf_dir }}/{{ docker_systemd_service_container_name }} \ +{{ docker_flags -}}{% if docker_flags +%} +{% endif %}{{ docker_systemd_service_image -}}{{ ' ' if docker_systemd_service_container_cmd else '' }}{% if docker_systemd_service_container_cmd is string %}{{ docker_systemd_service_container_cmd | trim }}{% else %}{{ docker_systemd_service_container_cmd | join(' ') | trim }}{% endif %} +{% endif +%} +{% if not 'ExecStop' in service_systemd_options_keys %} +ExecStop={{ docker_systemd_service_docker_path }} stop {{ docker_systemd_service_container_name }} +{% endif %} +{% if container_start_post is defined %} +ExecStartPost=-{{ container_start_post }} +{% endif %} +{% if not 'SyslogIdentifier' in service_systemd_options_keys %} +SyslogIdentifier={{ docker_systemd_service_container_name }} +{% endif %} +{% if not 'Restart' in service_systemd_options_keys %} +Restart=always +{% endif %} +{% if not 'RestartSec' in service_systemd_options_keys %} +RestartSec=10s +{% endif %} + +[Install] +WantedBy=docker.service diff --git a/roles/ednxzu.docker_systemd_service/vars/main.yml b/roles/ednxzu.docker_systemd_service/vars/main.yml new file mode 100644 index 0000000..e2ab7eb --- /dev/null +++ b/roles/ednxzu.docker_systemd_service/vars/main.yml @@ -0,0 +1,8 @@ +--- +# vars file for docker_systemd_service +docker_systemd_service_sysconf_dir: /etc/default +docker_systemd_service_docker_path: "/usr/bin/docker" +docker_systemd_service_systemd_unit_options: + After: docker.service + PartOf: docker.service + Requires: docker.service diff --git a/roles/ednxzu.install_docker/.ansible-lint b/roles/ednxzu.install_docker/.ansible-lint new file mode 100644 index 0000000..0d93798 --- /dev/null +++ b/roles/ednxzu.install_docker/.ansible-lint @@ -0,0 +1,8 @@ +--- +warn_list: + - experimental # all rules tagged as experimental + - yaml # violations reported by yamllint + - meta-no-info + +skip_list: + - jinja[spacing] # Rule that looks inside jinja2 templates. diff --git a/roles/ednxzu.install_docker/.gitea/workflows/test.yml b/roles/ednxzu.install_docker/.gitea/workflows/test.yml new file mode 100644 index 0000000..77b20fa --- /dev/null +++ b/roles/ednxzu.install_docker/.gitea/workflows/test.yml @@ -0,0 +1,52 @@ +--- +name: test +on: [push] + +jobs: + lint: + name: Linting + runs-on: ubuntu-latest + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Ansible lint" + run: ansible-lint --force-color + working-directory: ${{ gitea.workspace }} + + - name: "YAML lint" + run: yamllint . -f colored -c .yamllint + working-directory: ${{ gitea.workspace }} + + molecule-test: + name: Molecule tests + runs-on: ubuntu-latest + needs: lint + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + strategy: + matrix: + test_os: [debian11, debian12, ubuntu2004, ubuntu2204] + scenario: [default, with_custom_config] + env: + ANSIBLE_HOST_KEY_CHECKING: 'false' + ANSIBLE_FORCE_COLOR: 'true' + ANSIBLE_PYTHON_INTERPRETER: /usr/bin/python3 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Molecule test" + run: molecule test -s ${{ matrix.scenario }} + shell: bash + working-directory: ${{ gitea.workspace }} + env: + MOLECULE_TEST_OS: ${{ matrix.test_os }} diff --git a/roles/ednxzu.install_docker/.github/workflows/publish.yml b/roles/ednxzu.install_docker/.github/workflows/publish.yml new file mode 100644 index 0000000..784f2c9 --- /dev/null +++ b/roles/ednxzu.install_docker/.github/workflows/publish.yml @@ -0,0 +1,18 @@ +--- +name: publish +on: + push: + branches: + - main + +jobs: + publish: + name: Publish to galaxy + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Publish + uses: ednxzu/galaxy-import-role@v1 + with: + galaxy-api-key: ${{ secrets.GALAXY_API_TOKEN }} diff --git a/roles/ednxzu.install_docker/.gitignore b/roles/ednxzu.install_docker/.gitignore new file mode 100644 index 0000000..bccf235 --- /dev/null +++ b/roles/ednxzu.install_docker/.gitignore @@ -0,0 +1,3 @@ +# ignore molecule/testinfra pycache +**/__pycache__ +.vscode \ No newline at end of file diff --git a/roles/ednxzu.install_docker/.yamllint b/roles/ednxzu.install_docker/.yamllint new file mode 100644 index 0000000..24fdec5 --- /dev/null +++ b/roles/ednxzu.install_docker/.yamllint @@ -0,0 +1,40 @@ +--- +# Based on ansible-lint config +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + comments: enable + comments-indentation: disable + document-start: enable + empty-lines: + max: 3 + level: error + hyphens: + level: error + indentation: enable + key-duplicates: enable + line-length: + max: 80 + level: warning + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + allowed-values: + - 'true' + - 'false' + - 'yes' + - 'no' diff --git a/roles/ednxzu.install_docker/LICENSE b/roles/ednxzu.install_docker/LICENSE new file mode 100644 index 0000000..1d06074 --- /dev/null +++ b/roles/ednxzu.install_docker/LICENSE @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/ednxzu.install_docker/README.md b/roles/ednxzu.install_docker/README.md new file mode 100644 index 0000000..0941174 --- /dev/null +++ b/roles/ednxzu.install_docker/README.md @@ -0,0 +1,87 @@ +install_docker +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role install and configure docker on **debian-based** distributions. + +Requirements +------------ + +None. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/install_docker.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +install_docker_edition: ce # by default, set to ce +``` +This variable sets the edition of docker to install. It can be either `ce` (community edition) or `ee` (enterprise edition). + +```yaml +install_docker_auto_update: false # by default, set to false +``` +This variable allows you to choose to automatically update docker if a newer version is available whenever the role is replayed. Updating docker is usually pretty safe if done on a regular basis. + +```yaml +install_docker_start_service: true +``` +This variable defines whether or not to start the docker service after installing it. This can be turned off in case you're building golden images, so that your golden image does not start the docker service during it's build process. + +```yaml +install_docker_compose: false # by default, set to false +``` +This variables defines whether or not to install docker-compose on the host. + +```yaml +install_docker_compose_version: latest # by default, set to latest +``` +This variable defines the version of docker-compose to install. It support either `latest`, or the version number (`vX.Y.Z`). Officially, only versions `>=v2.0.1` are supported, as the naming for most packages changed at this release. + +```yaml +install_docker_python_packages: false # by default, set to false +``` +This variable defines whether or not to install the python packages for managing docker with ansible. This package is required if you plan to perform docker operations with ansible, and should be installed if that is your goal. + +```yaml +install_docker_python_packages_version: latest # by default, set to latest +``` +This variable defines the version of the python docker package that should be installed. Refer to [ednxzu/manage_pip_packages](https://github.com/ednxzu/manage_pip_packages) for documentation. + +```yaml +install_docker_users: [] #by default, set to [] +``` +This variable is a list of users to add to the docker group, so that they can perform docker related tasks, without requiring privilege escalation. + +```yaml +install_docker_daemon_options: {} # by default, set to {} +``` +This variable defines the parameters to append to the daemon.json file (in `/etc/docker/daemon.json`). For more details, check out the [documentation](https://docs.docker.com/config/daemon/). + +Dependencies +------------ + +`ednxzu.manage_pip_packages` to install docker python packages for using the `community.docker` modules. +`ednxzu.manage_repositories` to configure the docker apt repository. +`ednxzu.manage_apt_packages` to install docker. + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.install_docker +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/ednxzu.install_docker/defaults/install_docker.yml.sample b/roles/ednxzu.install_docker/defaults/install_docker.yml.sample new file mode 100644 index 0000000..4fe7522 --- /dev/null +++ b/roles/ednxzu.install_docker/defaults/install_docker.yml.sample @@ -0,0 +1,10 @@ +--- +# install_docker_edition: ce # can be ce or ee (community or enterprise) +# install_docker_auto_update: false +# install_docker_start_service: true +# install_docker_compose: false +# install_docker_compose_version: latest +# install_docker_python_packages: false +# install_docker_python_packages_version: latest +# install_docker_users: [] +# install_docker_daemon_options: {} diff --git a/roles/ednxzu.install_docker/defaults/main.yml b/roles/ednxzu.install_docker/defaults/main.yml new file mode 100644 index 0000000..8112f0d --- /dev/null +++ b/roles/ednxzu.install_docker/defaults/main.yml @@ -0,0 +1,11 @@ +--- +# defaults file for install_docker +install_docker_edition: ce # can be ce or ee (community or enterprise) +install_docker_auto_update: false +install_docker_start_service: true +install_docker_compose: false +install_docker_compose_version: latest +install_docker_python_packages: false +install_docker_python_packages_version: latest +install_docker_users: [] +install_docker_daemon_options: {} diff --git a/roles/ednxzu.install_docker/handlers/main.yml b/roles/ednxzu.install_docker/handlers/main.yml new file mode 100644 index 0000000..2b1b5c5 --- /dev/null +++ b/roles/ednxzu.install_docker/handlers/main.yml @@ -0,0 +1,14 @@ +--- +# handlers file for install_docker +- name: "Enable docker service" + ansible.builtin.service: + name: docker + enabled: true + listen: "systemctl-enable-docker" + +- name: "Reload docker service" + ansible.builtin.service: + name: docker + state: reloaded + listen: "systemctl-reload-docker" + when: install_docker_start_service diff --git a/roles/ednxzu.install_docker/meta/.galaxy_install_info b/roles/ednxzu.install_docker/meta/.galaxy_install_info new file mode 100644 index 0000000..cb7ac18 --- /dev/null +++ b/roles/ednxzu.install_docker/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: 'Fri 15 Dec 2023 05:25:27 PM ' +version: main diff --git a/roles/ednxzu.install_docker/meta/main.yml b/roles/ednxzu.install_docker/meta/main.yml new file mode 100644 index 0000000..9dc252e --- /dev/null +++ b/roles/ednxzu.install_docker/meta/main.yml @@ -0,0 +1,27 @@ +--- +# meta file for install_docker +galaxy_info: + namespace: 'ednxzu' + role_name: 'install_docker' + author: 'Bertrand Lanson' + description: 'Install and configure docker for debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'docker' + - 'container' + - 'compose' + - 'containerd' + +dependencies: [] diff --git a/roles/ednxzu.install_docker/molecule/default/converge.yml b/roles/ednxzu.install_docker/molecule/default/converge.yml new file mode 100644 index 0000000..39617ab --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.install_docker" + ansible.builtin.include_role: + name: "ednxzu.install_docker" diff --git a/roles/ednxzu.install_docker/molecule/default/molecule.yml b/roles/ednxzu.install_docker/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.install_docker/molecule/default/requirements.yml b/roles/ednxzu.install_docker/molecule/default/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.install_docker/molecule/default/verify.yml b/roles/ednxzu.install_docker/molecule/default/verify.yml new file mode 100644 index 0000000..ebd1c55 --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default/verify.yml @@ -0,0 +1,96 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: service docker" + block: + - name: "Get service docker" + ansible.builtin.service_facts: + + - name: "Stat file /lib/systemd/system/docker.service" + ansible.builtin.stat: + path: "/lib/systemd/system/docker.service" + register: stat_lib_systemd_system_docker_service + + - name: "Verify service docker" + ansible.builtin.assert: + that: + - stat_lib_systemd_system_docker_service.stat.exists + - stat_lib_systemd_system_docker_service.stat.isreg + - stat_lib_systemd_system_docker_service.stat.pw_name == 'root' + - stat_lib_systemd_system_docker_service.stat.gr_name == 'root' + - stat_lib_systemd_system_docker_service.stat.mode == '0644' + - ansible_facts.services['docker.service'] is defined + - ansible_facts.services['docker.service']['source'] == 'systemd' + - ansible_facts.services['docker.service']['state'] == 'running' + - ansible_facts.services['docker.service']['status'] == 'enabled' + + - name: "Test: file /etc/docker/daemon.json" + block: + - name: "Stat directory /etc/docker" + ansible.builtin.stat: + path: "/etc/docker" + register: stat_etc_docker + + - name: "Stat file /etc/docker/daemon.json" + ansible.builtin.stat: + path: "/etc/docker/daemon.json" + register: stat_etc_docker_docker_json + + - name: "Slurp file /etc/docker/daemon.json" + ansible.builtin.slurp: + src: "/etc/docker/daemon.json" + register: slurp_etc_docker_docker_json + + - name: "Verify directory /etc/docker" + ansible.builtin.assert: + that: + - stat_etc_docker.stat.exists + - stat_etc_docker.stat.isdir + - stat_etc_docker.stat.pw_name == 'root' + - stat_etc_docker.stat.gr_name == 'root' + - stat_etc_docker.stat.mode == '0755' + - stat_etc_docker_docker_json.stat.exists + - stat_etc_docker_docker_json.stat.isreg + - stat_etc_docker_docker_json.stat.pw_name == 'root' + - stat_etc_docker_docker_json.stat.gr_name == 'root' + - stat_etc_docker_docker_json.stat.mode == '0644' + - (slurp_etc_docker_docker_json.content|b64decode) == '{}' + + - name: "Test: interaction docker" + block: + - name: "Command docker ps" + ansible.builtin.command: "docker ps" + changed_when: false + register: docker_ps + + - name: "Verify docker interaction" + ansible.builtin.assert: + that: + - docker_ps.stdout == 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES' + + - name: "Test: file /usr/local/bin/docker-compose" + block: + - name: "Stat file /usr/local/bin/docker-compose" + ansible.builtin.stat: + path: "/usr/local/bin/docker-compose" + register: stat_url_local_bin_docker_compose + + - name: "Verify file /usr/local/bin/docker-compose" + ansible.builtin.assert: + that: + - not stat_url_local_bin_docker_compose.stat.exists + + - name: "Test: python package docker" + block: + - name: "Command pip3 list" + ansible.builtin.command: "pip3 list -o" + changed_when: false + register: pip3_list + + - name: "Verify python package docker" + ansible.builtin.assert: + that: + - "'docker' not in pip3_list" diff --git a/roles/ednxzu.install_docker/molecule/default_vagrant/converge.yml b/roles/ednxzu.install_docker/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..39617ab --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.install_docker" + ansible.builtin.include_role: + name: "ednxzu.install_docker" diff --git a/roles/ednxzu.install_docker/molecule/default_vagrant/molecule.yml b/roles/ednxzu.install_docker/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.install_docker/molecule/default_vagrant/prepare.yml b/roles/ednxzu.install_docker/molecule/default_vagrant/prepare.yml new file mode 100644 index 0000000..65cb4bd --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default_vagrant/prepare.yml @@ -0,0 +1,12 @@ +--- +- name: Prepare + hosts: all + tasks: + - name: "Install pip3 packages" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: + - name: python3-pip + version: latest + state: present diff --git a/roles/ednxzu.install_docker/molecule/default_vagrant/requirements.yml b/roles/ednxzu.install_docker/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.install_docker/molecule/default_vagrant/verify.yml b/roles/ednxzu.install_docker/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..ebd1c55 --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/default_vagrant/verify.yml @@ -0,0 +1,96 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: service docker" + block: + - name: "Get service docker" + ansible.builtin.service_facts: + + - name: "Stat file /lib/systemd/system/docker.service" + ansible.builtin.stat: + path: "/lib/systemd/system/docker.service" + register: stat_lib_systemd_system_docker_service + + - name: "Verify service docker" + ansible.builtin.assert: + that: + - stat_lib_systemd_system_docker_service.stat.exists + - stat_lib_systemd_system_docker_service.stat.isreg + - stat_lib_systemd_system_docker_service.stat.pw_name == 'root' + - stat_lib_systemd_system_docker_service.stat.gr_name == 'root' + - stat_lib_systemd_system_docker_service.stat.mode == '0644' + - ansible_facts.services['docker.service'] is defined + - ansible_facts.services['docker.service']['source'] == 'systemd' + - ansible_facts.services['docker.service']['state'] == 'running' + - ansible_facts.services['docker.service']['status'] == 'enabled' + + - name: "Test: file /etc/docker/daemon.json" + block: + - name: "Stat directory /etc/docker" + ansible.builtin.stat: + path: "/etc/docker" + register: stat_etc_docker + + - name: "Stat file /etc/docker/daemon.json" + ansible.builtin.stat: + path: "/etc/docker/daemon.json" + register: stat_etc_docker_docker_json + + - name: "Slurp file /etc/docker/daemon.json" + ansible.builtin.slurp: + src: "/etc/docker/daemon.json" + register: slurp_etc_docker_docker_json + + - name: "Verify directory /etc/docker" + ansible.builtin.assert: + that: + - stat_etc_docker.stat.exists + - stat_etc_docker.stat.isdir + - stat_etc_docker.stat.pw_name == 'root' + - stat_etc_docker.stat.gr_name == 'root' + - stat_etc_docker.stat.mode == '0755' + - stat_etc_docker_docker_json.stat.exists + - stat_etc_docker_docker_json.stat.isreg + - stat_etc_docker_docker_json.stat.pw_name == 'root' + - stat_etc_docker_docker_json.stat.gr_name == 'root' + - stat_etc_docker_docker_json.stat.mode == '0644' + - (slurp_etc_docker_docker_json.content|b64decode) == '{}' + + - name: "Test: interaction docker" + block: + - name: "Command docker ps" + ansible.builtin.command: "docker ps" + changed_when: false + register: docker_ps + + - name: "Verify docker interaction" + ansible.builtin.assert: + that: + - docker_ps.stdout == 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES' + + - name: "Test: file /usr/local/bin/docker-compose" + block: + - name: "Stat file /usr/local/bin/docker-compose" + ansible.builtin.stat: + path: "/usr/local/bin/docker-compose" + register: stat_url_local_bin_docker_compose + + - name: "Verify file /usr/local/bin/docker-compose" + ansible.builtin.assert: + that: + - not stat_url_local_bin_docker_compose.stat.exists + + - name: "Test: python package docker" + block: + - name: "Command pip3 list" + ansible.builtin.command: "pip3 list -o" + changed_when: false + register: pip3_list + + - name: "Verify python package docker" + ansible.builtin.assert: + that: + - "'docker' not in pip3_list" diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config/converge.yml b/roles/ednxzu.install_docker/molecule/with_custom_config/converge.yml new file mode 100644 index 0000000..39617ab --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.install_docker" + ansible.builtin.include_role: + name: "ednxzu.install_docker" diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config/group_vars/all.yml b/roles/ednxzu.install_docker/molecule/with_custom_config/group_vars/all.yml new file mode 100644 index 0000000..9996b9c --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config/group_vars/all.yml @@ -0,0 +1,11 @@ +--- +install_docker_edition: ce # can be ce or ee (community or enterprise) +install_docker_auto_update: true +install_docker_start_service: true +install_docker_compose: true +install_docker_compose_version: latest +install_docker_python_packages: true +install_docker_python_packages_version: latest +install_docker_users: [] +install_docker_daemon_options: + data-root: "/opt/docker" diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config/molecule.yml b/roles/ednxzu.install_docker/molecule/with_custom_config/molecule.yml new file mode 100644 index 0000000..4df62e9 --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_config + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config/requirements.yml b/roles/ednxzu.install_docker/molecule/with_custom_config/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config/verify.yml b/roles/ednxzu.install_docker/molecule/with_custom_config/verify.yml new file mode 100644 index 0000000..5983536 --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config/verify.yml @@ -0,0 +1,106 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: service docker" + block: + - name: "Get service docker" + ansible.builtin.service_facts: + + - name: "Stat file /lib/systemd/system/docker.service" + ansible.builtin.stat: + path: "/lib/systemd/system/docker.service" + register: stat_lib_systemd_system_docker_service + + - name: "Verify service docker" + ansible.builtin.assert: + that: + - stat_lib_systemd_system_docker_service.stat.exists + - stat_lib_systemd_system_docker_service.stat.isreg + - stat_lib_systemd_system_docker_service.stat.pw_name == 'root' + - stat_lib_systemd_system_docker_service.stat.gr_name == 'root' + - stat_lib_systemd_system_docker_service.stat.mode == '0644' + - ansible_facts.services['docker.service'] is defined + - ansible_facts.services['docker.service']['source'] == 'systemd' + - ansible_facts.services['docker.service']['state'] == 'running' + - ansible_facts.services['docker.service']['status'] == 'enabled' + + - name: "Test: file /etc/docker/daemon.json" + block: + - name: "Stat directory /etc/docker" + ansible.builtin.stat: + path: "/etc/docker" + register: stat_etc_docker + + - name: "Stat file /etc/docker/daemon.json" + ansible.builtin.stat: + path: "/etc/docker/daemon.json" + register: stat_etc_docker_docker_json + + - name: "Slurp file /etc/docker/daemon.json" + ansible.builtin.slurp: + src: "/etc/docker/daemon.json" + register: slurp_etc_docker_docker_json + + - name: "Verify directory /etc/docker" + ansible.builtin.assert: + that: + - stat_etc_docker.stat.exists + - stat_etc_docker.stat.isdir + - stat_etc_docker.stat.pw_name == 'root' + - stat_etc_docker.stat.gr_name == 'root' + - stat_etc_docker.stat.mode == '0755' + - stat_etc_docker_docker_json.stat.exists + - stat_etc_docker_docker_json.stat.isreg + - stat_etc_docker_docker_json.stat.pw_name == 'root' + - stat_etc_docker_docker_json.stat.gr_name == 'root' + - stat_etc_docker_docker_json.stat.mode == '0644' + - "'\"data-root\": \"/opt/docker\"' in (slurp_etc_docker_docker_json.content|b64decode)" + + - name: "Test: interaction docker" + block: + - name: "Command docker ps" + ansible.builtin.command: "docker ps" + changed_when: false + register: docker_ps + + - name: "Verify docker interaction" + ansible.builtin.assert: + that: + - docker_ps.stdout == 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES' + + - name: "Test: file /usr/local/bin/docker-compose" + block: + - name: "Stat file /usr/local/bin/docker-compose" + ansible.builtin.stat: + path: "/usr/local/bin/docker-compose" + register: stat_url_local_bin_docker_compose + + - name: "Command docker-compose --version" + ansible.builtin.command: "docker-compose --version" + changed_when: false + register: docker_compose_version + + - name: "Verify file /usr/local/bin/docker-compose" + ansible.builtin.assert: + that: + - docker_compose_version.stdout | regex_search('^Docker Compose version v\\d+\\.\\d+\\.\\d+$') + - stat_url_local_bin_docker_compose.stat.exists + - stat_url_local_bin_docker_compose.stat.isreg + - stat_url_local_bin_docker_compose.stat.pw_name == 'root' + - stat_url_local_bin_docker_compose.stat.gr_name == 'root' + - stat_url_local_bin_docker_compose.stat.mode == '0755' + + - name: "Test: python package docker" + block: + - name: "Command pip3 list" + ansible.builtin.command: "pip3 list" + changed_when: false + register: pip3_list + + - name: "Verify python package docker" + ansible.builtin.assert: + that: + - "'docker' in pip3_list.stdout" diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/converge.yml b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/converge.yml new file mode 100644 index 0000000..39617ab --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.install_docker" + ansible.builtin.include_role: + name: "ednxzu.install_docker" diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/group_vars/all.yml b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/group_vars/all.yml new file mode 100644 index 0000000..9996b9c --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/group_vars/all.yml @@ -0,0 +1,11 @@ +--- +install_docker_edition: ce # can be ce or ee (community or enterprise) +install_docker_auto_update: true +install_docker_start_service: true +install_docker_compose: true +install_docker_compose_version: latest +install_docker_python_packages: true +install_docker_python_packages_version: latest +install_docker_users: [] +install_docker_daemon_options: + data-root: "/opt/docker" diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/molecule.yml b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/molecule.yml new file mode 100644 index 0000000..890cdd0 --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_config_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/prepare.yml b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/prepare.yml new file mode 100644 index 0000000..65cb4bd --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/prepare.yml @@ -0,0 +1,12 @@ +--- +- name: Prepare + hosts: all + tasks: + - name: "Install pip3 packages" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: + - name: python3-pip + version: latest + state: present diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/requirements.yml b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/verify.yml b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/verify.yml new file mode 100644 index 0000000..5983536 --- /dev/null +++ b/roles/ednxzu.install_docker/molecule/with_custom_config_vagrant/verify.yml @@ -0,0 +1,106 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: service docker" + block: + - name: "Get service docker" + ansible.builtin.service_facts: + + - name: "Stat file /lib/systemd/system/docker.service" + ansible.builtin.stat: + path: "/lib/systemd/system/docker.service" + register: stat_lib_systemd_system_docker_service + + - name: "Verify service docker" + ansible.builtin.assert: + that: + - stat_lib_systemd_system_docker_service.stat.exists + - stat_lib_systemd_system_docker_service.stat.isreg + - stat_lib_systemd_system_docker_service.stat.pw_name == 'root' + - stat_lib_systemd_system_docker_service.stat.gr_name == 'root' + - stat_lib_systemd_system_docker_service.stat.mode == '0644' + - ansible_facts.services['docker.service'] is defined + - ansible_facts.services['docker.service']['source'] == 'systemd' + - ansible_facts.services['docker.service']['state'] == 'running' + - ansible_facts.services['docker.service']['status'] == 'enabled' + + - name: "Test: file /etc/docker/daemon.json" + block: + - name: "Stat directory /etc/docker" + ansible.builtin.stat: + path: "/etc/docker" + register: stat_etc_docker + + - name: "Stat file /etc/docker/daemon.json" + ansible.builtin.stat: + path: "/etc/docker/daemon.json" + register: stat_etc_docker_docker_json + + - name: "Slurp file /etc/docker/daemon.json" + ansible.builtin.slurp: + src: "/etc/docker/daemon.json" + register: slurp_etc_docker_docker_json + + - name: "Verify directory /etc/docker" + ansible.builtin.assert: + that: + - stat_etc_docker.stat.exists + - stat_etc_docker.stat.isdir + - stat_etc_docker.stat.pw_name == 'root' + - stat_etc_docker.stat.gr_name == 'root' + - stat_etc_docker.stat.mode == '0755' + - stat_etc_docker_docker_json.stat.exists + - stat_etc_docker_docker_json.stat.isreg + - stat_etc_docker_docker_json.stat.pw_name == 'root' + - stat_etc_docker_docker_json.stat.gr_name == 'root' + - stat_etc_docker_docker_json.stat.mode == '0644' + - "'\"data-root\": \"/opt/docker\"' in (slurp_etc_docker_docker_json.content|b64decode)" + + - name: "Test: interaction docker" + block: + - name: "Command docker ps" + ansible.builtin.command: "docker ps" + changed_when: false + register: docker_ps + + - name: "Verify docker interaction" + ansible.builtin.assert: + that: + - docker_ps.stdout == 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES' + + - name: "Test: file /usr/local/bin/docker-compose" + block: + - name: "Stat file /usr/local/bin/docker-compose" + ansible.builtin.stat: + path: "/usr/local/bin/docker-compose" + register: stat_url_local_bin_docker_compose + + - name: "Command docker-compose --version" + ansible.builtin.command: "docker-compose --version" + changed_when: false + register: docker_compose_version + + - name: "Verify file /usr/local/bin/docker-compose" + ansible.builtin.assert: + that: + - docker_compose_version.stdout | regex_search('^Docker Compose version v\\d+\\.\\d+\\.\\d+$') + - stat_url_local_bin_docker_compose.stat.exists + - stat_url_local_bin_docker_compose.stat.isreg + - stat_url_local_bin_docker_compose.stat.pw_name == 'root' + - stat_url_local_bin_docker_compose.stat.gr_name == 'root' + - stat_url_local_bin_docker_compose.stat.mode == '0755' + + - name: "Test: python package docker" + block: + - name: "Command pip3 list" + ansible.builtin.command: "pip3 list" + changed_when: false + register: pip3_list + + - name: "Verify python package docker" + ansible.builtin.assert: + that: + - "'docker' in pip3_list.stdout" diff --git a/roles/ednxzu.install_docker/tasks/configure.yml b/roles/ednxzu.install_docker/tasks/configure.yml new file mode 100644 index 0000000..8405372 --- /dev/null +++ b/roles/ednxzu.install_docker/tasks/configure.yml @@ -0,0 +1,19 @@ +--- +# task/configure file for install_docker +- name: "Add specified users to group {{ install_docker_group }}" + ansible.builtin.user: + name: "{{ item }}" + groups: "{{ install_docker_group }}" + append: true + loop: "{{ install_docker_users }}" + +- name: "Copy daemon.json template" + ansible.builtin.template: + src: daemon.json.j2 + dest: "{{ install_docker_daemon_dir }}/daemon.json" + owner: root + group: root + mode: '0644' + notify: + - "systemctl-enable-docker" + - "systemctl-reload-docker" diff --git a/roles/ednxzu.install_docker/tasks/install.yml b/roles/ednxzu.install_docker/tasks/install.yml new file mode 100644 index 0000000..60ee53c --- /dev/null +++ b/roles/ednxzu.install_docker/tasks/install.yml @@ -0,0 +1,15 @@ +--- +# task/install file for install_docker +- name: "Configure docker repository" + ansible.builtin.include_role: + name: ednxzu.manage_repositories + vars: + manage_repositories_enable_default_repo: false + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: "{{ install_docker_repository }}" + +- name: "Install docker packages" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ install_docker_packages }}" diff --git a/roles/ednxzu.install_docker/tasks/install_compose.yml b/roles/ednxzu.install_docker/tasks/install_compose.yml new file mode 100644 index 0000000..c630394 --- /dev/null +++ b/roles/ednxzu.install_docker/tasks/install_compose.yml @@ -0,0 +1,46 @@ +--- +# task/install_compose file for install_docker +- name: "Get release for compose:{{ install_docker_compose_version }}" + vars: + _docker_compose_url_ext: "{% if install_docker_compose_version == 'latest'%}releases{% else %}releases/tags{% endif %}" + ansible.builtin.uri: + url: "{{ install_docker_compose_github_api }}/{{ _docker_compose_url_ext }}/{{ install_docker_compose_version }}" + return_content: true + register: _docker_compose_new_release + +- name: "Check current compose version" + ansible.builtin.command: "{{ install_docker_compose_path }} --version --short" + register: _docker_compose_old_release + check_mode: false + changed_when: false + failed_when: false + +- name: "Set facts for wanted compose release" + ansible.builtin.set_fact: + install_docker_compose_wanted_version: "{{ _docker_compose_new_release.json['tag_name']|regex_replace('v', '') }}" + when: _docker_compose_new_release.json is defined + and (_docker_compose_new_release.json | length > 0) + +- name: "Set facts for current compose release" + ansible.builtin.set_fact: + install_docker_compose_current_version: "{{ _docker_compose_old_release.stdout | regex_replace('v', '') }}" + when: _docker_compose_old_release.stdout is defined + and (_docker_compose_old_release.stdout | length > 0) + +- name: "Remove old compose binary if different" + ansible.builtin.file: + path: "{{ install_docker_compose_path }}" + state: absent + register: _docker_compose_binary_removed + when: install_docker_compose_current_version is defined + and install_docker_compose_wanted_version not in install_docker_compose_current_version + +- name: "Download and install compose:{{ install_docker_compose_version }}" + ansible.builtin.get_url: + url: "{{ install_docker_compose_github_url }}/releases/download/v{{ install_docker_compose_wanted_version }}/docker-compose-linux-{{ ansible_architecture }}" + dest: "{{ install_docker_compose_path }}" + owner: root + group: root + mode: '0755' + when: (install_docker_compose_current_version is not defined) + or (_docker_compose_binary_removed.changed) diff --git a/roles/ednxzu.install_docker/tasks/install_python_docker.yml b/roles/ednxzu.install_docker/tasks/install_python_docker.yml new file mode 100644 index 0000000..35c69fa --- /dev/null +++ b/roles/ednxzu.install_docker/tasks/install_python_docker.yml @@ -0,0 +1,7 @@ +--- +# task/install_docker_pip file for install_docker +- name: "Install docker packages" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ install_docker_python_packages_list }}" diff --git a/roles/ednxzu.install_docker/tasks/main.yml b/roles/ednxzu.install_docker/tasks/main.yml new file mode 100644 index 0000000..037ff5c --- /dev/null +++ b/roles/ednxzu.install_docker/tasks/main.yml @@ -0,0 +1,24 @@ +--- +# task/main file for install_docker +- name: "Import prerequisites.yml" + ansible.builtin.include_tasks: prerequisites.yml + +- name: "Import install.yml" + ansible.builtin.include_tasks: install.yml + +- name: "Import install_compose.yml" + ansible.builtin.include_tasks: install_compose.yml + when: install_docker_compose + +- name: "Import install_python_docker.yml" + ansible.builtin.include_tasks: install_python_docker.yml + when: install_docker_python_packages + +- name: "Import configure.yml" + ansible.builtin.include_tasks: configure.yml + +- name: "Start docker service" + ansible.builtin.service: + name: docker + state: started + when: install_docker_start_service diff --git a/roles/ednxzu.install_docker/tasks/prerequisites.yml b/roles/ednxzu.install_docker/tasks/prerequisites.yml new file mode 100644 index 0000000..7136fb4 --- /dev/null +++ b/roles/ednxzu.install_docker/tasks/prerequisites.yml @@ -0,0 +1,14 @@ +--- +# task/prerequisites file for install_docker +- name: "Create group {{ install_docker_group }}" + ansible.builtin.group: + name: "{{ install_docker_group }}" + state: present + +- name: "Create directory {{ install_docker_daemon_dir }}" + ansible.builtin.file: + path: "{{ install_docker_daemon_dir }}" + state: directory + owner: root + group: root + mode: '0755' diff --git a/roles/ednxzu.install_docker/templates/daemon.json.j2 b/roles/ednxzu.install_docker/templates/daemon.json.j2 new file mode 100644 index 0000000..10bdfe0 --- /dev/null +++ b/roles/ednxzu.install_docker/templates/daemon.json.j2 @@ -0,0 +1 @@ +{{ install_docker_daemon_options | to_nice_json }} \ No newline at end of file diff --git a/roles/ednxzu.install_docker/vars/main.yml b/roles/ednxzu.install_docker/vars/main.yml new file mode 100644 index 0000000..58f6f4c --- /dev/null +++ b/roles/ednxzu.install_docker/vars/main.yml @@ -0,0 +1,36 @@ +--- +# vars file for install_docker +install_docker_compose_path: "/usr/local/bin/docker-compose" +install_docker_compose_github_api: https://api.github.com/repos/docker/compose +install_docker_compose_github_url: https://github.com/docker/compose +install_docker_group: docker +install_docker_daemon_dir: /etc/docker +install_docker_packages: + - name: "docker-{{ install_docker_edition }}" + version: latest + state: "{% if install_docker_auto_update %}latest{% else %}present{% endif %}" + - name: "docker-{{ install_docker_edition }}-cli" + version: latest + state: "{% if install_docker_auto_update %}latest{% else %}present{% endif %}" + - name: "docker-{{ install_docker_edition }}-rootless-extras" + version: latest + state: "{% if install_docker_auto_update %}latest{% else %}present{% endif %}" + - name: "containerd.io" + version: latest + state: "{% if install_docker_auto_update %}latest{% else %}present{% endif %}" +install_docker_python_packages_list: + - name: python3-docker + version: latest + state: "{% if install_docker_auto_update %}latest{% else %}present{% endif %}" +install_docker_repository: + - name: docker + uri: "https://download.docker.com/linux/{{ ansible_distribution|lower }}" + comments: "{{ ansible_distribution|lower }} docker repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - stable + options: + Signed-By: "https://download.docker.com/linux/{{ ansible_distribution|lower }}/gpg" diff --git a/roles/ednxzu.manage_apt_packages/.ansible-lint b/roles/ednxzu.manage_apt_packages/.ansible-lint new file mode 100644 index 0000000..0d93798 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/.ansible-lint @@ -0,0 +1,8 @@ +--- +warn_list: + - experimental # all rules tagged as experimental + - yaml # violations reported by yamllint + - meta-no-info + +skip_list: + - jinja[spacing] # Rule that looks inside jinja2 templates. diff --git a/roles/ednxzu.manage_apt_packages/.gitea/workflows/test.yml b/roles/ednxzu.manage_apt_packages/.gitea/workflows/test.yml new file mode 100644 index 0000000..fd684f6 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/.gitea/workflows/test.yml @@ -0,0 +1,52 @@ +--- +name: test +on: [push] + +jobs: + lint: + name: Linting + runs-on: ubuntu-latest + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Ansible lint" + run: ansible-lint --force-color + working-directory: ${{ gitea.workspace }} + + - name: "YAML lint" + run: yamllint . -f colored -c .yamllint + working-directory: ${{ gitea.workspace }} + + molecule-test: + name: Molecule tests + runs-on: ubuntu-latest + needs: lint + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + strategy: + matrix: + test_os: [debian11, debian12, ubuntu2004, ubuntu2204] + scenario: [default, with_custom_packages] + env: + ANSIBLE_HOST_KEY_CHECKING: 'false' + ANSIBLE_FORCE_COLOR: 'true' + ANSIBLE_PYTHON_INTERPRETER: /usr/bin/python3 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Molecule test" + run: molecule test -s ${{ matrix.scenario }} + shell: bash + working-directory: ${{ gitea.workspace }} + env: + MOLECULE_TEST_OS: ${{ matrix.test_os }} diff --git a/roles/ednxzu.manage_apt_packages/.github/workflows/publish.yml b/roles/ednxzu.manage_apt_packages/.github/workflows/publish.yml new file mode 100644 index 0000000..784f2c9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/.github/workflows/publish.yml @@ -0,0 +1,18 @@ +--- +name: publish +on: + push: + branches: + - main + +jobs: + publish: + name: Publish to galaxy + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Publish + uses: ednxzu/galaxy-import-role@v1 + with: + galaxy-api-key: ${{ secrets.GALAXY_API_TOKEN }} diff --git a/roles/ednxzu.manage_apt_packages/.gitignore b/roles/ednxzu.manage_apt_packages/.gitignore new file mode 100644 index 0000000..bccf235 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/.gitignore @@ -0,0 +1,3 @@ +# ignore molecule/testinfra pycache +**/__pycache__ +.vscode \ No newline at end of file diff --git a/roles/ednxzu.manage_apt_packages/.yamllint b/roles/ednxzu.manage_apt_packages/.yamllint new file mode 100644 index 0000000..24fdec5 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/.yamllint @@ -0,0 +1,40 @@ +--- +# Based on ansible-lint config +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + comments: enable + comments-indentation: disable + document-start: enable + empty-lines: + max: 3 + level: error + hyphens: + level: error + indentation: enable + key-duplicates: enable + line-length: + max: 80 + level: warning + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + allowed-values: + - 'true' + - 'false' + - 'yes' + - 'no' diff --git a/roles/ednxzu.manage_apt_packages/LICENSE b/roles/ednxzu.manage_apt_packages/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/ednxzu.manage_apt_packages/README.md b/roles/ednxzu.manage_apt_packages/README.md new file mode 100644 index 0000000..64991d9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/README.md @@ -0,0 +1,62 @@ +manage_apt_packages +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role enables you to manage packages on **debian-based** distributions. It can be used on its own , or be called by other roles the install/remove packages on demand. + +Requirements +------------ + +None. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/manage_apt_packages.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +manage_apt_packages_list: # by default, not defined + - name: nginx + version: latest # Leaving empty or setting '' will be considered as latest + state: absent + - name: ... +``` +This variable is a list of packages, with their name, desired version and state. Note that the role allows version rollbacks, so unless you absolutely need a specific version, it is usualy advised to keep the version on `latest` or empty (which is considered the same). + +Dependencies +------------ + +None. + +Example Playbook +---------------- + +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.manage_apt_packages +``` + +```yaml +# calling the role inside a playbook and injecting variables (in another role for example) +- hosts: servers + tasks: + - name: "Install consul package" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: + - name: consul + version: 1.13.1-1 + state: present +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/ednxzu.manage_apt_packages/defaults/main.yml b/roles/ednxzu.manage_apt_packages/defaults/main.yml new file mode 100644 index 0000000..ea36c77 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/defaults/main.yml @@ -0,0 +1,6 @@ +--- +# defaults file for manage_apt_packages +manage_apt_packages_list: + - name: vim + version: latest + state: present diff --git a/roles/ednxzu.manage_apt_packages/defaults/manage_apt_packages.yml.sample b/roles/ednxzu.manage_apt_packages/defaults/manage_apt_packages.yml.sample new file mode 100644 index 0000000..b059b4b --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/defaults/manage_apt_packages.yml.sample @@ -0,0 +1,11 @@ +--- +# manage_apt_packages_list: +# - name: nginx +# version: 1.18.0-6ubuntu14 +# state: present +# - name: apache2 +# version: 2.4.52-1ubuntu4.4 +# state: present +# - name: +# version: +# state: diff --git a/roles/ednxzu.manage_apt_packages/handlers/main.yml b/roles/ednxzu.manage_apt_packages/handlers/main.yml new file mode 100644 index 0000000..a8e24d1 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/handlers/main.yml @@ -0,0 +1,6 @@ +--- +# handlers file for manage_apt_packages +- name: "Remove unnecessary dependencies" + ansible.builtin.apt: + autoremove: yes + listen: "apt-autoremove" diff --git a/roles/ednxzu.manage_apt_packages/meta/.galaxy_install_info b/roles/ednxzu.manage_apt_packages/meta/.galaxy_install_info new file mode 100644 index 0000000..1f054b2 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: 'Fri 15 Dec 2023 05:25:26 PM ' +version: main diff --git a/roles/ednxzu.manage_apt_packages/meta/main.yml b/roles/ednxzu.manage_apt_packages/meta/main.yml new file mode 100644 index 0000000..a87f209 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/meta/main.yml @@ -0,0 +1,24 @@ +--- +# meta file for manage_repositories +galaxy_info: + namespace: 'ednxzu' + role_name: 'manage_apt_packages' + author: 'Bertrand Lanson' + description: 'Package management for debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'packages' + +dependencies: [] diff --git a/roles/ednxzu.manage_apt_packages/molecule/default/converge.yml b/roles/ednxzu.manage_apt_packages/molecule/default/converge.yml new file mode 100644 index 0000000..f6d30d9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.manage_apt_packages" + ansible.builtin.include_role: + name: "ednxzu.manage_apt_packages" diff --git a/roles/ednxzu.manage_apt_packages/molecule/default/molecule.yml b/roles/ednxzu.manage_apt_packages/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_apt_packages/molecule/default/requirements.yml b/roles/ednxzu.manage_apt_packages/molecule/default/requirements.yml new file mode 100644 index 0000000..e9320f9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default/requirements.yml @@ -0,0 +1,3 @@ +--- +# requirements file for molecule +roles: [] diff --git a/roles/ednxzu.manage_apt_packages/molecule/default/verify.yml b/roles/ednxzu.manage_apt_packages/molecule/default/verify.yml new file mode 100644 index 0000000..1a5c0f3 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default/verify.yml @@ -0,0 +1,16 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: package vim" + block: + - name: "Get packages facts" + ansible.builtin.package_facts: + manager: auto + + - name: "Verify package vim" + ansible.builtin.assert: + that: + - "ansible_facts.packages['vim'][0]['name'] == 'vim'" diff --git a/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/converge.yml b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..f6d30d9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.manage_apt_packages" + ansible.builtin.include_role: + name: "ednxzu.manage_apt_packages" diff --git a/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/molecule.yml b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/requirements.yml b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..e9320f9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/requirements.yml @@ -0,0 +1,3 @@ +--- +# requirements file for molecule +roles: [] diff --git a/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/verify.yml b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..1a5c0f3 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/default_vagrant/verify.yml @@ -0,0 +1,16 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: package vim" + block: + - name: "Get packages facts" + ansible.builtin.package_facts: + manager: auto + + - name: "Verify package vim" + ansible.builtin.assert: + that: + - "ansible_facts.packages['vim'][0]['name'] == 'vim'" diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/converge.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/converge.yml new file mode 100644 index 0000000..f6d30d9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.manage_apt_packages" + ansible.builtin.include_role: + name: "ednxzu.manage_apt_packages" diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/group_vars/all.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/group_vars/all.yml new file mode 100644 index 0000000..faede6d --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/group_vars/all.yml @@ -0,0 +1,11 @@ +--- +manage_apt_packages_list: + - name: mariadb-server + version: latest + state: present + - name: apache2 + version: latest + state: present + - name: consul + version: 1.13.1-1 + state: present diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/molecule.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/molecule.yml new file mode 100644 index 0000000..30f7b0f --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_packages + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/prepare.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/prepare.yml new file mode 100644 index 0000000..274da39 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/prepare.yml @@ -0,0 +1,22 @@ +--- +- name: Prepare + hosts: all + tasks: + - name: "Include manage_repositories" + ansible.builtin.include_role: + name: "ednxzu.manage_repositories" + vars: + manage_repositories_enable_default_repo: true + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/requirements.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/requirements.yml new file mode 100644 index 0000000..0456e03 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/verify.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/verify.yml new file mode 100644 index 0000000..30fe0f3 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages/verify.yml @@ -0,0 +1,19 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: packages mariadb-server, apache2, consul:1.13.1-1" + block: + - name: "Get packages facts" + ansible.builtin.package_facts: + manager: auto + + - name: "Verify packages mariadb-server, apache2, consul:1.13.1-1" + ansible.builtin.assert: + that: + - "ansible_facts.packages['mariadb-server'][0]['name'] == 'mariadb-server'" + - "ansible_facts.packages['apache2'][0]['name'] == 'apache2'" + - "ansible_facts.packages['consul'][0]['name'] == 'consul'" + - "ansible_facts.packages['consul'][0]['version'] == '1.13.1-1'" diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/converge.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/converge.yml new file mode 100644 index 0000000..f6d30d9 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.manage_apt_packages" + ansible.builtin.include_role: + name: "ednxzu.manage_apt_packages" diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/group_vars/all.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/group_vars/all.yml new file mode 100644 index 0000000..faede6d --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/group_vars/all.yml @@ -0,0 +1,11 @@ +--- +manage_apt_packages_list: + - name: mariadb-server + version: latest + state: present + - name: apache2 + version: latest + state: present + - name: consul + version: 1.13.1-1 + state: present diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/molecule.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/molecule.yml new file mode 100644 index 0000000..2478c4d --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/molecule.yml @@ -0,0 +1,36 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 + #machine_virtual_size: 50 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_packages_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/prepare.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/prepare.yml new file mode 100644 index 0000000..274da39 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/prepare.yml @@ -0,0 +1,22 @@ +--- +- name: Prepare + hosts: all + tasks: + - name: "Include manage_repositories" + ansible.builtin.include_role: + name: "ednxzu.manage_repositories" + vars: + manage_repositories_enable_default_repo: true + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/requirements.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/requirements.yml new file mode 100644 index 0000000..0456e03 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories diff --git a/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/verify.yml b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/verify.yml new file mode 100644 index 0000000..30fe0f3 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/molecule/with_custom_packages_vagrant/verify.yml @@ -0,0 +1,19 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: packages mariadb-server, apache2, consul:1.13.1-1" + block: + - name: "Get packages facts" + ansible.builtin.package_facts: + manager: auto + + - name: "Verify packages mariadb-server, apache2, consul:1.13.1-1" + ansible.builtin.assert: + that: + - "ansible_facts.packages['mariadb-server'][0]['name'] == 'mariadb-server'" + - "ansible_facts.packages['apache2'][0]['name'] == 'apache2'" + - "ansible_facts.packages['consul'][0]['name'] == 'consul'" + - "ansible_facts.packages['consul'][0]['version'] == '1.13.1-1'" diff --git a/roles/ednxzu.manage_apt_packages/tasks/main.yml b/roles/ednxzu.manage_apt_packages/tasks/main.yml new file mode 100644 index 0000000..ec72f81 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# task/main file for manage_apt_packages +- name: "Update apt caches" + ansible.builtin.apt: + update_cache: yes + cache_valid_time: "{{ manage_apt_packages_apt_cache_time }}" + +- name: "Install/remove required apt packages" + ansible.builtin.apt: + name: "{{ item.name }}{% if item.version not in [None, '', 'latest'] %}={{ item.version }}{% endif %}" + state: "{{ item.state }}" + allow_downgrade: true + loop: "{{ manage_apt_packages_list }}" + when: manage_apt_packages_list is defined + and manage_apt_packages_list not in [None, ''] + notify: "apt-autoremove" diff --git a/roles/ednxzu.manage_apt_packages/vars/main.yml b/roles/ednxzu.manage_apt_packages/vars/main.yml new file mode 100644 index 0000000..22364e1 --- /dev/null +++ b/roles/ednxzu.manage_apt_packages/vars/main.yml @@ -0,0 +1,3 @@ +--- +# vars file for manage_apt_packages +manage_apt_packages_apt_cache_time: 3600 diff --git a/roles/ednxzu.manage_repositories/.ansible-lint b/roles/ednxzu.manage_repositories/.ansible-lint new file mode 100644 index 0000000..0d93798 --- /dev/null +++ b/roles/ednxzu.manage_repositories/.ansible-lint @@ -0,0 +1,8 @@ +--- +warn_list: + - experimental # all rules tagged as experimental + - yaml # violations reported by yamllint + - meta-no-info + +skip_list: + - jinja[spacing] # Rule that looks inside jinja2 templates. diff --git a/roles/ednxzu.manage_repositories/.gitea/workflows/test.yml b/roles/ednxzu.manage_repositories/.gitea/workflows/test.yml new file mode 100644 index 0000000..ff995ef --- /dev/null +++ b/roles/ednxzu.manage_repositories/.gitea/workflows/test.yml @@ -0,0 +1,52 @@ +--- +name: test +on: [push] + +jobs: + lint: + name: Linting + runs-on: ubuntu-latest + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Ansible lint" + run: ansible-lint --force-color + working-directory: ${{ gitea.workspace }} + + - name: "YAML lint" + run: yamllint . -f colored -c .yamllint + working-directory: ${{ gitea.workspace }} + + molecule-test: + name: Molecule tests + runs-on: ubuntu-latest + needs: lint + container: + image: git.ednz.fr/container-factory/ansible-runner:act-latest + credentials: + username: ${{ secrets.ACTIONS_USER }} + password: ${{ secrets.ACTIONS_TOKEN }} + strategy: + matrix: + test_os: [debian11, debian12, ubuntu2004, ubuntu2204] + scenario: [default, with_custom_repo] + env: + ANSIBLE_HOST_KEY_CHECKING: 'false' + ANSIBLE_FORCE_COLOR: 'true' + ANSIBLE_PYTHON_INTERPRETER: /usr/bin/python3 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: "Molecule test" + run: molecule test -s ${{ matrix.scenario }} + shell: bash + working-directory: ${{ gitea.workspace }} + env: + MOLECULE_TEST_OS: ${{ matrix.test_os }} diff --git a/roles/ednxzu.manage_repositories/.github/workflows/publish.yml b/roles/ednxzu.manage_repositories/.github/workflows/publish.yml new file mode 100644 index 0000000..784f2c9 --- /dev/null +++ b/roles/ednxzu.manage_repositories/.github/workflows/publish.yml @@ -0,0 +1,18 @@ +--- +name: publish +on: + push: + branches: + - main + +jobs: + publish: + name: Publish to galaxy + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Publish + uses: ednxzu/galaxy-import-role@v1 + with: + galaxy-api-key: ${{ secrets.GALAXY_API_TOKEN }} diff --git a/roles/ednxzu.manage_repositories/.gitignore b/roles/ednxzu.manage_repositories/.gitignore new file mode 100644 index 0000000..bccf235 --- /dev/null +++ b/roles/ednxzu.manage_repositories/.gitignore @@ -0,0 +1,3 @@ +# ignore molecule/testinfra pycache +**/__pycache__ +.vscode \ No newline at end of file diff --git a/roles/ednxzu.manage_repositories/.yamllint b/roles/ednxzu.manage_repositories/.yamllint new file mode 100644 index 0000000..24fdec5 --- /dev/null +++ b/roles/ednxzu.manage_repositories/.yamllint @@ -0,0 +1,40 @@ +--- +# Based on ansible-lint config +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + comments: enable + comments-indentation: disable + document-start: enable + empty-lines: + max: 3 + level: error + hyphens: + level: error + indentation: enable + key-duplicates: enable + line-length: + max: 80 + level: warning + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + allowed-values: + - 'true' + - 'false' + - 'yes' + - 'no' diff --git a/roles/ednxzu.manage_repositories/LICENSE b/roles/ednxzu.manage_repositories/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/ednxzu.manage_repositories/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/ednxzu.manage_repositories/README.md b/roles/ednxzu.manage_repositories/README.md new file mode 100644 index 0000000..fe12c6b --- /dev/null +++ b/roles/ednxzu.manage_repositories/README.md @@ -0,0 +1,97 @@ +manage_repositories +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role enables you to manage repositories on **debian-based** distributions. It can be used on its own , or be called by other roles the configure repositories on demand. + +Requirements +------------ + +None. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/manage_repositories.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +manage_repositories_enable_default_repo: true # by default, set to true +``` +This variable enable or disable the configuration of the main distribution repositories (useful when calling this role to configure repo for another role like installing docker). + +```yaml +manage_repositories_enable_custom_repo: false # by default, set to false +``` +This variable enable of disable the configuration of custom repositories + +```yaml +manage_repositories_main_repo_uri: # by default, this variable has the following values + ubuntu: "http://fr.archive.ubuntu.com/ubuntu" + debian: "http://deb.debian.org/debian" +``` +This variable sets the mirror URLs for the main repositories. You can optionally remove the distribution you don't want (ex. `remove manage_repositories_main_repo_uri[debian]` if you're only using ubuntu). + +```yaml +manage_repositories_custom_repo: # by default, this variable is not defined + - name: docker + uri: "https://download.docker.com/linux/{{ ansible_distribution|lower }}" + comments: "{{ ansible_distribution|lower }} docker repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - stable + options: + Signed-By: "https://download.docker.com/linux/{{ ansible_distribution|lower }}/gpg" + - name: ... +``` +This variable contains a list (1 to N) of custom repositories to install. IT HAS TO BE SET if `manage_repositories_enable_custom_repo == true`, or else the role might fail. The `options` entries are optional, and you can add pretty much all standard options. The `Signed-By` option expects a URL to download the gpg key. If no options are needed, the `options` key can be removed completely. + +Dependencies +------------ + +None. + +Example Playbook +---------------- + +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.manage_repositories +``` + +```yaml +# calling the role inside a playbook and injecting variables (in another role for example) +- hosts: servers + tasks: + - name: "Configure hashicorp repository" + ansible.builtin.include_role: + name: ednxzu.manage_repositories + vars: + manage_repositories_enable_default_repo: false + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: + - name: docker + uri: "https://download.docker.com/linux/{{ ansible_distribution|lower }}" + comments: "{{ ansible_distribution|lower }} docker repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - stable + options: + Signed-By: "https://download.docker.com/linux/{{ ansible_distribution|lower }}/gpg" +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/ednxzu.manage_repositories/defaults/main.yml b/roles/ednxzu.manage_repositories/defaults/main.yml new file mode 100644 index 0000000..059bbc0 --- /dev/null +++ b/roles/ednxzu.manage_repositories/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# defaults file for manage_repositories +manage_repositories_enable_default_repo: true +manage_repositories_enable_custom_repo: false +manage_repositories_main_repo_uri: + ubuntu: "http://fr.archive.ubuntu.com/ubuntu" + debian: "http://deb.debian.org/debian" diff --git a/roles/ednxzu.manage_repositories/defaults/manage_repositories.yml.sample b/roles/ednxzu.manage_repositories/defaults/manage_repositories.yml.sample new file mode 100644 index 0000000..749a3ef --- /dev/null +++ b/roles/ednxzu.manage_repositories/defaults/manage_repositories.yml.sample @@ -0,0 +1,29 @@ +--- +# manage_repositories_enable_default_repo: true +# manage_repositories_enable_custom_repo: false +# manage_repositories_main_repo_uri: +# ubuntu: "http://fr.archive.ubuntu.com/ubuntu" +# debian: "http://deb.debian.org/debian" +# manage_repositories_custom_repo: +# - name: docker +# uri: "https://download.docker.com/linux/{{ ansible_distribution|lower }}" +# comments: "{{ ansible_distribution|lower }} docker repository" +# types: +# - deb +# suites: +# - "{{ ansible_distribution_release }}" +# components: +# - stable +# options: +# Signed-By: "https://download.docker.com/linux/{{ ansible_distribution|lower }}/gpg" +# - name: hashicorp +# uri: "https://apt.releases.hashicorp.com" +# comments: "hashicorp repository" +# types: +# - deb +# suites: +# - "{{ ansible_distribution_release }}" +# components: +# - main +# options: +# Signed-By: "https://apt.releases.hashicorp.com/gpg" \ No newline at end of file diff --git a/roles/ednxzu.manage_repositories/handlers/main.yml b/roles/ednxzu.manage_repositories/handlers/main.yml new file mode 100644 index 0000000..0366a00 --- /dev/null +++ b/roles/ednxzu.manage_repositories/handlers/main.yml @@ -0,0 +1,6 @@ +--- +# handlers file for manage_repositories +- name: "Update repositories caches" + ansible.builtin.apt: + update_cache: true + listen: "debian-based-cache-update" diff --git a/roles/ednxzu.manage_repositories/meta/.galaxy_install_info b/roles/ednxzu.manage_repositories/meta/.galaxy_install_info new file mode 100644 index 0000000..877976a --- /dev/null +++ b/roles/ednxzu.manage_repositories/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: 'Fri 15 Dec 2023 05:25:25 PM ' +version: main diff --git a/roles/ednxzu.manage_repositories/meta/main.yml b/roles/ednxzu.manage_repositories/meta/main.yml new file mode 100644 index 0000000..9312771 --- /dev/null +++ b/roles/ednxzu.manage_repositories/meta/main.yml @@ -0,0 +1,25 @@ +--- +# meta file for manage_repositories +galaxy_info: + namespace: 'ednxzu' + role_name: 'manage_repositories' + author: 'Bertrand Lanson' + description: 'Repository management for debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'repositories' + - 'packages' + +dependencies: [] diff --git a/roles/ednxzu.manage_repositories/molecule/default/converge.yml b/roles/ednxzu.manage_repositories/molecule/default/converge.yml new file mode 100644 index 0000000..8374463 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include manage_repositories" + ansible.builtin.include_role: + name: "ednxzu.manage_repositories" diff --git a/roles/ednxzu.manage_repositories/molecule/default/molecule.yml b/roles/ednxzu.manage_repositories/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_repositories/molecule/default/requirements.yml b/roles/ednxzu.manage_repositories/molecule/default/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.manage_repositories/molecule/default/verify.yml b/roles/ednxzu.manage_repositories/molecule/default/verify.yml new file mode 100644 index 0000000..1444489 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default/verify.yml @@ -0,0 +1,74 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/apt/sources.list" + block: + - name: "Stat file /etc/apt/sources.list" + ansible.builtin.stat: + path: "/etc/apt/sources.list" + register: stat_etc_apt_sources_list + + - name: "Slurp file /etc/apt/sources.list" + ansible.builtin.slurp: + src: "/etc/apt/sources.list" + register: slurp_etc_apt_sources_list + + - name: "Verify file /etc/apt/sources.list" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list.stat.exists + - stat_etc_apt_sources_list.stat.isreg + - stat_etc_apt_sources_list.stat.pw_name == 'root' + - stat_etc_apt_sources_list.stat.gr_name == 'root' + - stat_etc_apt_sources_list.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list" + vars: + expected_source_list_content: | + # See /etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list.content|b64decode) == expected_source_list_content" + + - name: "Test: file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + block: + - name: "Stat /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.stat: + path: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: stat_etc_apt_sources_list_d + + - name: "Slurp file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.slurp: + src: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: slurp_etc_apt_sources_list_d + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list_d.stat.exists + - stat_etc_apt_sources_list_d.stat.isreg + - stat_etc_apt_sources_list_d.stat.pw_name == 'root' + - stat_etc_apt_sources_list_d.stat.gr_name == 'root' + - stat_etc_apt_sources_list_d.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + vars: + expected_source_list_content: + ubuntu: | + X-Repolib-Name: ubuntu + Types: deb + URIs: http://fr.archive.ubuntu.com/ubuntu + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-security {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main restricted universe multiverse + debian: | + X-Repolib-Name: debian + Types: deb + URIs: http://deb.debian.org/debian + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list_d.content|b64decode) == expected_source_list_content[ansible_distribution|lower]" diff --git a/roles/ednxzu.manage_repositories/molecule/default_vagrant/converge.yml b/roles/ednxzu.manage_repositories/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..8d9e40b --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.manage_repositories" + ansible.builtin.include_role: + name: "ednxzu.manage_repositories" diff --git a/roles/ednxzu.manage_repositories/molecule/default_vagrant/molecule.yml b/roles/ednxzu.manage_repositories/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_repositories/molecule/default_vagrant/requirements.yml b/roles/ednxzu.manage_repositories/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default_vagrant/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.manage_repositories/molecule/default_vagrant/verify.yml b/roles/ednxzu.manage_repositories/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..1444489 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/default_vagrant/verify.yml @@ -0,0 +1,74 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/apt/sources.list" + block: + - name: "Stat file /etc/apt/sources.list" + ansible.builtin.stat: + path: "/etc/apt/sources.list" + register: stat_etc_apt_sources_list + + - name: "Slurp file /etc/apt/sources.list" + ansible.builtin.slurp: + src: "/etc/apt/sources.list" + register: slurp_etc_apt_sources_list + + - name: "Verify file /etc/apt/sources.list" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list.stat.exists + - stat_etc_apt_sources_list.stat.isreg + - stat_etc_apt_sources_list.stat.pw_name == 'root' + - stat_etc_apt_sources_list.stat.gr_name == 'root' + - stat_etc_apt_sources_list.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list" + vars: + expected_source_list_content: | + # See /etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list.content|b64decode) == expected_source_list_content" + + - name: "Test: file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + block: + - name: "Stat /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.stat: + path: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: stat_etc_apt_sources_list_d + + - name: "Slurp file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.slurp: + src: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: slurp_etc_apt_sources_list_d + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list_d.stat.exists + - stat_etc_apt_sources_list_d.stat.isreg + - stat_etc_apt_sources_list_d.stat.pw_name == 'root' + - stat_etc_apt_sources_list_d.stat.gr_name == 'root' + - stat_etc_apt_sources_list_d.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + vars: + expected_source_list_content: + ubuntu: | + X-Repolib-Name: ubuntu + Types: deb + URIs: http://fr.archive.ubuntu.com/ubuntu + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-security {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main restricted universe multiverse + debian: | + X-Repolib-Name: debian + Types: deb + URIs: http://deb.debian.org/debian + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list_d.content|b64decode) == expected_source_list_content[ansible_distribution|lower]" diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo/converge.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/converge.yml new file mode 100644 index 0000000..8374463 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include manage_repositories" + ansible.builtin.include_role: + name: "ednxzu.manage_repositories" diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo/group_vars/all.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/group_vars/all.yml new file mode 100644 index 0000000..8137599 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/group_vars/all.yml @@ -0,0 +1,26 @@ +--- +manage_repositories_enable_default_repo: true +manage_repositories_enable_custom_repo: true +manage_repositories_custom_repo: + - name: docker + uri: "https://download.docker.com/linux/{{ ansible_distribution|lower }}" + comments: "{{ ansible_distribution|lower }} docker repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - stable + options: + Signed-By: "https://download.docker.com/linux/{{ ansible_distribution|lower }}/gpg" + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo/molecule.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/molecule.yml new file mode 100644 index 0000000..15f1eae --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_repo + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo/requirements.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo/verify.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/verify.yml new file mode 100644 index 0000000..31a04ba --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo/verify.yml @@ -0,0 +1,138 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/apt/sources.list" + block: + - name: "Stat file /etc/apt/sources.list" + ansible.builtin.stat: + path: "/etc/apt/sources.list" + register: stat_etc_apt_sources_list + + - name: "Slurp file /etc/apt/sources.list" + ansible.builtin.slurp: + src: "/etc/apt/sources.list" + register: slurp_etc_apt_sources_list + + - name: "Verify file /etc/apt/sources.list" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list.stat.exists + - stat_etc_apt_sources_list.stat.isreg + - stat_etc_apt_sources_list.stat.pw_name == 'root' + - stat_etc_apt_sources_list.stat.gr_name == 'root' + - stat_etc_apt_sources_list.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list" + vars: + expected_source_list_content: | + # See /etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list.content|b64decode) == expected_source_list_content" + + - name: "Test: file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + block: + - name: "Stat /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.stat: + path: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: stat_etc_apt_sources_list_d + + - name: "Slurp file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.slurp: + src: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: slurp_etc_apt_sources_list_d + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list_d.stat.exists + - stat_etc_apt_sources_list_d.stat.isreg + - stat_etc_apt_sources_list_d.stat.pw_name == 'root' + - stat_etc_apt_sources_list_d.stat.gr_name == 'root' + - stat_etc_apt_sources_list_d.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + vars: + expected_source_list_content: + ubuntu: | + X-Repolib-Name: ubuntu + Types: deb + URIs: http://fr.archive.ubuntu.com/ubuntu + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-security {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main restricted universe multiverse + debian: | + X-Repolib-Name: debian + Types: deb + URIs: http://deb.debian.org/debian + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list_d.content|b64decode) == expected_source_list_content[ansible_distribution|lower]" + + - name: "Test: directory /etc/apt/sources.list.d" + block: + - name: "Find in directory /etc/apt/sources.list.d" + ansible.builtin.find: + paths: /etc/apt/sources.list.d + file_type: file + register: find_etc_apt_sources_list_d + + - name: "Stat in directory /etc/apt/sources.list.d" + ansible.builtin.stat: + path: "{{ item.path }}" + loop: "{{ find_etc_apt_sources_list_d.files }}" + register: stat_etc_apt_sources_list_d + + - name: "Slurp in directory /etc/apt/sources.list.d" + ansible.builtin.slurp: + src: "{{ item.path }}" + loop: "{{ find_etc_apt_sources_list_d.files }}" + register: slurp_etc_apt_sources_list_d + + - name: "Verify file /etc/apt/sources.list.d/docker.list" + vars: + expected_source_list_docker_content: | + # Ansible managed: Do NOT edit this file manually! + + # {{ ansible_distribution|lower }} docker repository + X-Repolib-Name: docker + Types: deb + URIs: https://download.docker.com/linux/{{ ansible_distribution|lower }} + Suites: {{ ansible_distribution_release }} + Components: stable + Signed-By: /usr/share/keyrings/docker-archive-keyring.asc + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'root' + - item.item.gr_name == 'root' + - item.item.mode == '0644' + - "(item.content|b64decode) == expected_source_list_docker_content" + loop: "{{ slurp_etc_apt_sources_list_d.results }}" + when: (item.item.path | basename | splitext | first) == 'docker' + + - name: "Verify file /etc/apt/sources.list.d/hashicorp.list" + vars: + expected_source_list_hashicorp_content: | + # Ansible managed: Do NOT edit this file manually! + + # hashicorp repository + X-Repolib-Name: hashicorp + Types: deb + URIs: https://apt.releases.hashicorp.com + Suites: {{ ansible_distribution_release }} + Components: main + Signed-By: /usr/share/keyrings/hashicorp-archive-keyring.asc + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'root' + - item.item.gr_name == 'root' + - item.item.mode == '0644' + - "(item.content|b64decode) == expected_source_list_hashicorp_content" + loop: "{{ slurp_etc_apt_sources_list_d.results }}" + when: (item.item.path | basename | splitext | first) == 'hashicorp' diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/converge.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/converge.yml new file mode 100644 index 0000000..8ebfc23 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + tasks: + - name: "Include ednxzu.manage_repositories" + ansible.builtin.include_role: + name: "ednxzu.manage_repositories" diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/group_vars/all.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/group_vars/all.yml new file mode 100644 index 0000000..8137599 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/group_vars/all.yml @@ -0,0 +1,26 @@ +--- +manage_repositories_enable_default_repo: true +manage_repositories_enable_custom_repo: true +manage_repositories_custom_repo: + - name: docker + uri: "https://download.docker.com/linux/{{ ansible_distribution|lower }}" + comments: "{{ ansible_distribution|lower }} docker repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - stable + options: + Signed-By: "https://download.docker.com/linux/{{ ansible_distribution|lower }}/gpg" + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/molecule.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/molecule.yml new file mode 100644 index 0000000..c4a3658 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_repo_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/requirements.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/verify.yml b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/verify.yml new file mode 100644 index 0000000..31a04ba --- /dev/null +++ b/roles/ednxzu.manage_repositories/molecule/with_custom_repo_vagrant/verify.yml @@ -0,0 +1,138 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: file /etc/apt/sources.list" + block: + - name: "Stat file /etc/apt/sources.list" + ansible.builtin.stat: + path: "/etc/apt/sources.list" + register: stat_etc_apt_sources_list + + - name: "Slurp file /etc/apt/sources.list" + ansible.builtin.slurp: + src: "/etc/apt/sources.list" + register: slurp_etc_apt_sources_list + + - name: "Verify file /etc/apt/sources.list" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list.stat.exists + - stat_etc_apt_sources_list.stat.isreg + - stat_etc_apt_sources_list.stat.pw_name == 'root' + - stat_etc_apt_sources_list.stat.gr_name == 'root' + - stat_etc_apt_sources_list.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list" + vars: + expected_source_list_content: | + # See /etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list.content|b64decode) == expected_source_list_content" + + - name: "Test: file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + block: + - name: "Stat /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.stat: + path: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: stat_etc_apt_sources_list_d + + - name: "Slurp file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.slurp: + src: "/etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources" + register: slurp_etc_apt_sources_list_d + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + ansible.builtin.assert: + that: + - stat_etc_apt_sources_list_d.stat.exists + - stat_etc_apt_sources_list_d.stat.isreg + - stat_etc_apt_sources_list_d.stat.pw_name == 'root' + - stat_etc_apt_sources_list_d.stat.gr_name == 'root' + - stat_etc_apt_sources_list_d.stat.mode == '0644' + + - name: "Verify file /etc/apt/sources.list.d/{{ ansible_distribution|lower }}" + vars: + expected_source_list_content: + ubuntu: | + X-Repolib-Name: ubuntu + Types: deb + URIs: http://fr.archive.ubuntu.com/ubuntu + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-security {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main restricted universe multiverse + debian: | + X-Repolib-Name: debian + Types: deb + URIs: http://deb.debian.org/debian + Suites: {{ ansible_distribution_release }} {{ ansible_distribution_release }}-updates {{ ansible_distribution_release }}-backports + Components: main + ansible.builtin.assert: + that: + - "(slurp_etc_apt_sources_list_d.content|b64decode) == expected_source_list_content[ansible_distribution|lower]" + + - name: "Test: directory /etc/apt/sources.list.d" + block: + - name: "Find in directory /etc/apt/sources.list.d" + ansible.builtin.find: + paths: /etc/apt/sources.list.d + file_type: file + register: find_etc_apt_sources_list_d + + - name: "Stat in directory /etc/apt/sources.list.d" + ansible.builtin.stat: + path: "{{ item.path }}" + loop: "{{ find_etc_apt_sources_list_d.files }}" + register: stat_etc_apt_sources_list_d + + - name: "Slurp in directory /etc/apt/sources.list.d" + ansible.builtin.slurp: + src: "{{ item.path }}" + loop: "{{ find_etc_apt_sources_list_d.files }}" + register: slurp_etc_apt_sources_list_d + + - name: "Verify file /etc/apt/sources.list.d/docker.list" + vars: + expected_source_list_docker_content: | + # Ansible managed: Do NOT edit this file manually! + + # {{ ansible_distribution|lower }} docker repository + X-Repolib-Name: docker + Types: deb + URIs: https://download.docker.com/linux/{{ ansible_distribution|lower }} + Suites: {{ ansible_distribution_release }} + Components: stable + Signed-By: /usr/share/keyrings/docker-archive-keyring.asc + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'root' + - item.item.gr_name == 'root' + - item.item.mode == '0644' + - "(item.content|b64decode) == expected_source_list_docker_content" + loop: "{{ slurp_etc_apt_sources_list_d.results }}" + when: (item.item.path | basename | splitext | first) == 'docker' + + - name: "Verify file /etc/apt/sources.list.d/hashicorp.list" + vars: + expected_source_list_hashicorp_content: | + # Ansible managed: Do NOT edit this file manually! + + # hashicorp repository + X-Repolib-Name: hashicorp + Types: deb + URIs: https://apt.releases.hashicorp.com + Suites: {{ ansible_distribution_release }} + Components: main + Signed-By: /usr/share/keyrings/hashicorp-archive-keyring.asc + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'root' + - item.item.gr_name == 'root' + - item.item.mode == '0644' + - "(item.content|b64decode) == expected_source_list_hashicorp_content" + loop: "{{ slurp_etc_apt_sources_list_d.results }}" + when: (item.item.path | basename | splitext | first) == 'hashicorp' diff --git a/roles/ednxzu.manage_repositories/tasks/custom_repositories.yml b/roles/ednxzu.manage_repositories/tasks/custom_repositories.yml new file mode 100644 index 0000000..2d4995a --- /dev/null +++ b/roles/ednxzu.manage_repositories/tasks/custom_repositories.yml @@ -0,0 +1,24 @@ +--- +# task/custom_repositories file for manage_repositories +- name: "Download gpg key for custom repositories" + ansible.builtin.get_url: + url: "{{ item.options['Signed-By'] }}" + dest: "{{ manage_repositories_signing_keys_location }}/{{ item.name }}-archive-keyring.asc" + mode: '0644' + loop: "{{ manage_repositories_custom_repo }}" + when: item.options is defined + and item.options['Signed-By'] is defined + and item.options['Signed-By'] not in [None, ''] + +- name: "Configure custom repositories" + vars: + repository: "{{ item }}" + ansible.builtin.template: + src: "repo.sources.j2" + dest: "{{ manage_repositories_repo_location }}/{{ item.name }}.sources" + mode: '0644' + owner: root + group: root + loop: "{{ manage_repositories_custom_repo }}" + notify: + - "debian-based-cache-update" diff --git a/roles/ednxzu.manage_repositories/tasks/main.yml b/roles/ednxzu.manage_repositories/tasks/main.yml new file mode 100644 index 0000000..1031fc5 --- /dev/null +++ b/roles/ednxzu.manage_repositories/tasks/main.yml @@ -0,0 +1,19 @@ +--- +# task/main file for manage_repositories +- name: "Load variables" + ansible.builtin.include_vars: + file: "{{ ansible_distribution|lower }}.yml" + +- name: "Import prerequisites.yml" + ansible.builtin.include_tasks: prerequisites.yml + +- name: "Import main repositories for {{ ansible_distribution|lower }}" + ansible.builtin.include_tasks: "main_repositories.yml" + when: manage_repositories_enable_default_repo + +- name: "Import custom_repositories.yml" + ansible.builtin.include_tasks: custom_repositories.yml + when: manage_repositories_enable_custom_repo + +- name: "Update apt caches" + ansible.builtin.meta: flush_handlers diff --git a/roles/ednxzu.manage_repositories/tasks/main_repositories.yml b/roles/ednxzu.manage_repositories/tasks/main_repositories.yml new file mode 100644 index 0000000..af3e60c --- /dev/null +++ b/roles/ednxzu.manage_repositories/tasks/main_repositories.yml @@ -0,0 +1,44 @@ +--- +# task/main_repositories file for manage_repositories +- name: "Emtpy /etc/apt/sources.list" + block: + - name: "Read the current content of source.list" + ansible.builtin.slurp: + src: "{{ manage_repositories_sources_list_location }}" + register: sources_list_current_content + ignore_errors: true + + - name: "Convert sources.list current content to string" + ansible.builtin.set_fact: + sources_list_current_content_str: "{{ (sources_list_current_content.content | default('')) | b64decode }}" + + - name: "Define sources.list new content" + ansible.builtin.set_fact: + sources_list_new_content: "{{ manage_repositories_sources_list_message }}" + + - name: "Create file /etc/apt/sources.list" + ansible.builtin.file: + path: "{{ manage_repositories_sources_list_location }}" + state: touch + owner: root + group: root + mode: '0644' + when: sources_list_current_content_str == '' + + - name: "Replace content of /etc/apt/sources.list" + ansible.builtin.replace: + path: "{{ manage_repositories_sources_list_location }}" + regexp: "{{ sources_list_current_content_str | regex_escape }}" + replace: "{{ sources_list_new_content }}" + when: sources_list_current_content_str != sources_list_new_content + +- name: "Configure main repositories into sources.list.d for {{ ansible_distribution|lower }} " + ansible.builtin.deb822_repository: + name: "{{ item.name }}" + types: "{{item.types}}" + uris: "{{ item.uri }}" + suites: "{{ item.suites | join(' ') }}" + components: "{{ item.components }}" + loop: "{{ manage_repositories_default_repo }}" + notify: + - "debian-based-cache-update" diff --git a/roles/ednxzu.manage_repositories/tasks/prerequisites.yml b/roles/ednxzu.manage_repositories/tasks/prerequisites.yml new file mode 100644 index 0000000..6e851f1 --- /dev/null +++ b/roles/ednxzu.manage_repositories/tasks/prerequisites.yml @@ -0,0 +1,7 @@ +--- +# task/prerequisites file for manage_repositories +- name: "Install python dependencies" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ manage_repositories_required_packages }}" diff --git a/roles/ednxzu.manage_repositories/templates/repo.sources.j2 b/roles/ednxzu.manage_repositories/templates/repo.sources.j2 new file mode 100644 index 0000000..79dae38 --- /dev/null +++ b/roles/ednxzu.manage_repositories/templates/repo.sources.j2 @@ -0,0 +1,17 @@ +# {{ ansible_managed }} + +# {{ repository.comments}} +X-Repolib-Name: {{ repository.name }} +Types: {{ repository.types | join(' ') }} +URIs: {{ repository.uri }} +Suites: {{ repository.suites | join(' ') }} +Components: {{ repository.components | join(' ') }} +{% if (repository.options is defined) and repository.options %} +{% for option in repository.options %} +{% if option == "Signed-By" %} +{{ option }}: {{ manage_repositories_signing_keys_location + "/" + item.name + "-archive-keyring.asc" }} +{% else %} +{{ option }}: {{ repository.options[option] }} +{% endif %} +{% endfor %} +{% endif %} diff --git a/roles/ednxzu.manage_repositories/vars/debian.yml b/roles/ednxzu.manage_repositories/vars/debian.yml new file mode 100644 index 0000000..aa099c6 --- /dev/null +++ b/roles/ednxzu.manage_repositories/vars/debian.yml @@ -0,0 +1,23 @@ +--- +# vars file for manage_repositories +manage_repositories_default_repo: + - name: debian + uri: "{{ manage_repositories_main_repo_uri[ansible_distribution|lower] }}" + comments: "debian main repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + - "{{ ansible_distribution_release }}-updates" + - "{{ ansible_distribution_release }}-backports" + components: + - main + - name: debian-security + uri: "{{ manage_repositories_main_repo_uri[ansible_distribution|lower] }}-security" + comments: "debian main repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}-security" + components: + - main diff --git a/roles/ednxzu.manage_repositories/vars/main.yml b/roles/ednxzu.manage_repositories/vars/main.yml new file mode 100644 index 0000000..d6c9648 --- /dev/null +++ b/roles/ednxzu.manage_repositories/vars/main.yml @@ -0,0 +1,10 @@ +--- +# vars file for manage_repositories +manage_repositories_sources_list_location: /etc/apt/sources.list +manage_repositories_repo_location: /etc/apt/sources.list.d +manage_repositories_signing_keys_location: /usr/share/keyrings +manage_repositories_sources_list_message: "# See /etc/apt/sources.list.d/{{ ansible_distribution|lower }}.sources\\n" +manage_repositories_required_packages: + - name: python3-debian + version: latest + state: present diff --git a/roles/ednxzu.manage_repositories/vars/ubuntu.yml b/roles/ednxzu.manage_repositories/vars/ubuntu.yml new file mode 100644 index 0000000..8bb0bf8 --- /dev/null +++ b/roles/ednxzu.manage_repositories/vars/ubuntu.yml @@ -0,0 +1,18 @@ +--- +# vars file for manage_repositories +manage_repositories_default_repo: + - name: ubuntu + uri: "{{ manage_repositories_main_repo_uri[ansible_distribution|lower] }}" + comments: "ubuntu main repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + - "{{ ansible_distribution_release }}-security" + - "{{ ansible_distribution_release }}-updates" + - "{{ ansible_distribution_release }}-backports" + components: + - main + - restricted + - universe + - multiverse diff --git a/roles/hashicorp_consul/LICENSE b/roles/hashicorp_consul/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/hashicorp_consul/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/hashicorp_consul/README.md b/roles/hashicorp_consul/README.md new file mode 100644 index 0000000..e349875 --- /dev/null +++ b/roles/hashicorp_consul/README.md @@ -0,0 +1,106 @@ +hashicorp_consul +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role install and configure consul on **debian-based** distributions. + +Requirements +------------ + +None. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/hashicorp_consul.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +hashi_consul_install: true # by default, set to true +``` +This variable defines if the consul package is to be installed or not before configuring. If you install consul using another task, you can set this to `false`. + +```yaml +hashi_consul_auto_update: false # by default, set to false +``` +This variable allows you to choose to automatically update consul if a newer version is available. Updating consul is usually pretty safe if done on a regular basis, but for better control over the upgrade process, see `hashi_consul_version`. + +```yaml +hashi_consul_start_service: true +``` +This variable defines if the consul service should be started once it has been configured. This is usefull in case you're using this role to build golden images, in which case you might want to only enable the service, to have it start on the next boot (when the image is launched) + +```yaml +hashi_consul_version: latest # by default, set to latest +``` +This variable specifies the version of consul to install when `hashi_consul_install` is set to `true`. The version to specify is the version of the package on the hashicorp repository (`1.14.1-1` for example). This can be found by running `apt-cache madison consul` on a machine with the repository installed. + +```yaml +hashi_consul_deploy_method: host # by default, set to host +``` +This variable defines the method of deployment of consul. The `host` method installs the binary directly on the host, and runs consul as a systemd service. The `docker` method install consul as a docker container. +> Currently, only the `host` method is available, the `docker` method will be added later. + +```yaml +hashi_consul_env_variables: # by default, set to {} + env_var: value +``` +This value is a list of key/value that will populate the `consul.env` file. You do not have to capitalize the KEYS, as it will be done automatically. + +```yaml +hashi_consul_data_dir: "/opt/consul" # by default, set to /opt/consul +``` +This value defines the path where consul data will be stored on the node. Defaults to `/opt/consul`. + +```yaml +hashi_consul_extra_files: false # by default, set to false +``` +This variable defines whether or not there is extra configuration files to copy to the target. If there are, these extra files are expected to be jinja2 templates located all in the same directory, and will be copied to the specified directory on the target machine. + +```yaml +hashi_consul_extra_files_src: /tmp/extra_files # by default, set to /tmp/extra_files +``` +This variable defines the source directory (without the trailing /) for the extra files to be copied in case there are some. + +```yaml +hashi_consul_extra_files_dst: /etc/consul.d/extra_files # by default, set to /etc/consul.d/extra_files +``` +This variable defines the destination directory (without the trailing /) for the extra files to be copied. + +```yaml +hashi_consul_envoy_install: false # by default, set to false +``` +This variable allows you to install the envoy binary on the consul node, in case you need to deploy connect proxies. This feature is usefull when deploying consul agents that will handle services in the service mesh. It is NOT required on server nodes (since they most likely wont have services running in service mesh). +```yaml +hashi_consul_envoy_version: latest # by default, set to latest +``` +This variable defines which version of envoy to install in case `hashi_consul_envoy_install` is set to true. **IMPORTANT:** The `latest` version set by default is not guaranteed to work, please refer to the [documentation](https://developer.hashicorp.com/consul/docs/connect/proxies/envoy#supported-versions) for informations about the support matrix for consul and envoy. + +```yaml +hashi_consul_configuration: {} # by default, set to a simple configuration +``` +This variable sets all of the configuration parameters for consul. For more information on all of them, please check the [documentation](https://developer.hashicorp.com/consul/docs/agent/config/config-files). This variable is parsed and converted to json format to create the config file, so each key and value should be set according to the documentation. This method of passing configuration allows for compatibility with every configuration parameters that consul has to offer. The defaults are simply here to deploy a simple, single-node consul server without much configuration, and should NOT be used in production. You will want to edit this to deploy production-ready clusters. + +Dependencies +------------ + +`ednxzu.manage_repositories` to configure the hashicorp apt repository. +`ednxzu.manage_apt_packages` to install consul. + +Example Playbook +---------------- + +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.hashicorp_consul +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/hashicorp_consul/defaults/hashicorp_consul.yml.sample b/roles/hashicorp_consul/defaults/hashicorp_consul.yml.sample new file mode 100644 index 0000000..c644129 --- /dev/null +++ b/roles/hashicorp_consul/defaults/hashicorp_consul.yml.sample @@ -0,0 +1,69 @@ +--- +# hashi_consul_install: true +# hashi_consul_auto_update: false +# hashi_consul_start_service: true +# hashi_consul_version: latest +# hashi_consul_deploy_method: host # deployment method, either host or docker. +# hashi_consul_env_variables: {} +# hashi_consul_data_dir: "/opt/consul" +# hashi_consul_extra_files: false +# hashi_consul_extra_files_src: /tmp/extra_files +# hashi_consul_extra_files_dst: /etc/consul.d/extra_files +# hashi_consul_envoy_install: false +# hashi_consul_envoy_version: latest +# #! consul configuration +# hashi_consul_configuration: +# domain: consul +# datacenter: dc1 +# primary_datacenter: dc1 +# client_addr: "0.0.0.0" +# bind_addr: "{{ ansible_default_ipv4.address }}" +# advertise_addr: "{{ ansible_default_ipv4.address }}" +# data_dir: "{{ hashi_consul_data_dir }}" +# encrypt: "{{ 'mysupersecretgossipencryptionkey'|b64encode }}" +# server: true +# bootstrap_expect: 1 +# retry_join: +# - "{{ ansible_default_ipv4.address }}" +# ui_config: +# enabled: true +# connect: +# enabled: false +# leave_on_terminate: true +# rejoin_after_leave: true +# enable_script_checks: true +# enable_syslog: true +# log_level: INFO +# acl: +# enabled: false +# default_policy: "allow" +# enable_token_persistence: true +# tokens: +# initial_management: "" +# agent: "" +# dns_config: +# allow_stale: true +# enable_truncate: true +# only_passing: true +# ports: +# dns: 8600 +# http: 8500 +# https: -1 +# grpc: 8502 +# grpc_tls: 8503 +# server: 8300 +# serf_lan: 8301 +# serf_wan: 8302 +# sidecar_min_port: 21000 +# sidecar_max_port: 21255 +# expose_min_port: 21500 +# expose_max_port: 21755 +# # tls: +# # defaults: +# # ca_file: "{{ hashi_consul_data_dir }}/tls/ca.pem" +# # cert_file: "{{ hashi_consul_data_dir }}/tls/cert.pem" +# # key_file: "{{ hashi_consul_data_dir }}/tls/key.pem" +# # verify_incoming: false +# # verify_outgoing: true +# # grpc: {} +# # https: {} diff --git a/roles/hashicorp_consul/defaults/main.yml b/roles/hashicorp_consul/defaults/main.yml new file mode 100644 index 0000000..6a35bca --- /dev/null +++ b/roles/hashicorp_consul/defaults/main.yml @@ -0,0 +1,70 @@ +--- +# defaults file for hashicorp_consul +hashi_consul_install: true +hashi_consul_auto_update: false +hashi_consul_start_service: true +hashi_consul_version: latest +hashi_consul_deploy_method: host # deployment method, either host or docker. +hashi_consul_env_variables: {} +hashi_consul_data_dir: "/opt/consul" +hashi_consul_extra_files: false +hashi_consul_extra_files_src: /tmp/extra_files +hashi_consul_extra_files_dst: /etc/consul.d/extra_files +hashi_consul_envoy_install: false +hashi_consul_envoy_version: latest +#! consul configuration +hashi_consul_configuration: + domain: consul + datacenter: dc1 + primary_datacenter: dc1 + client_addr: "0.0.0.0" + bind_addr: "{{ ansible_default_ipv4.address }}" + advertise_addr: "{{ ansible_default_ipv4.address }}" + data_dir: "{{ hashi_consul_data_dir }}" + encrypt: "{{ 'mysupersecretgossipencryptionkey'|b64encode }}" + server: true + bootstrap_expect: 1 + retry_join: + - "{{ ansible_default_ipv4.address }}" + ui_config: + enabled: true + connect: + enabled: false + leave_on_terminate: true + rejoin_after_leave: true + enable_script_checks: true + enable_syslog: true + log_level: INFO + acl: + enabled: false + default_policy: "allow" + enable_token_persistence: true + tokens: + initial_management: "" + agent: "" + dns_config: + allow_stale: true + enable_truncate: true + only_passing: true + ports: + dns: 8600 + http: 8500 + https: -1 + grpc: 8502 + grpc_tls: 8503 + server: 8300 + serf_lan: 8301 + serf_wan: 8302 + sidecar_min_port: 21000 + sidecar_max_port: 21255 + expose_min_port: 21500 + expose_max_port: 21755 + # tls: + # defaults: + # ca_file: "{{ hashi_consul_data_dir }}/tls/ca.pem" + # cert_file: "{{ hashi_consul_data_dir }}/tls/cert.pem" + # key_file: "{{ hashi_consul_data_dir }}/tls/key.pem" + # verify_incoming: false + # verify_outgoing: true + # grpc: {} + # https: {} diff --git a/roles/hashicorp_consul/files/.gitkeep b/roles/hashicorp_consul/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/roles/hashicorp_consul/handlers/main.yml b/roles/hashicorp_consul/handlers/main.yml new file mode 100644 index 0000000..bbf20d9 --- /dev/null +++ b/roles/hashicorp_consul/handlers/main.yml @@ -0,0 +1,20 @@ +--- +# handlers file for hashicorp_consul +- name: "Reload systemd file" + ansible.builtin.systemd: + daemon_reload: true + listen: "systemctl-daemon-reload" + +- name: "Enable consul service" + ansible.builtin.service: + name: consul + enabled: true + listen: "systemctl-enable-consul" + +- name: "Start consul service" + ansible.builtin.service: + name: consul + state: restarted + listen: "systemctl-restart-consul" + throttle: 1 + when: hashi_consul_start_service diff --git a/roles/hashicorp_consul/meta/main.yml b/roles/hashicorp_consul/meta/main.yml new file mode 100644 index 0000000..92a54a8 --- /dev/null +++ b/roles/hashicorp_consul/meta/main.yml @@ -0,0 +1,25 @@ +--- +# meta file for hashicorp_consul +galaxy_info: + namespace: 'ednxzu' + role_name: 'hashicorp_consul' + author: 'Bertrand Lanson' + description: 'Install and configure hashicorp consul for debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'hashicorp' + - 'consul' + +dependencies: [] diff --git a/roles/hashicorp_consul/molecule/default/converge.yml b/roles/hashicorp_consul/molecule/default/converge.yml new file mode 100644 index 0000000..836464f --- /dev/null +++ b/roles/hashicorp_consul/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_consul" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_consul" diff --git a/roles/hashicorp_consul/molecule/default/molecule.yml b/roles/hashicorp_consul/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/hashicorp_consul/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_consul/molecule/default/requirements.yml b/roles/hashicorp_consul/molecule/default/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_consul/molecule/default/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_consul/molecule/default/verify.yml b/roles/hashicorp_consul/molecule/default/verify.yml new file mode 100644 index 0000000..762ae27 --- /dev/null +++ b/roles/hashicorp_consul/molecule/default/verify.yml @@ -0,0 +1,146 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: consul user and group" + block: + - name: "Getent user consul" + ansible.builtin.getent: + database: passwd + key: consul + register: consul_user + + - name: "Getent group consul" + ansible.builtin.getent: + database: group + key: consul + register: consul_group + + - name: "Verify consul user and group" + ansible.builtin.assert: + that: + - not consul_user.failed + - not consul_group.failed + - "'consul' in consul_user.ansible_facts.getent_passwd.keys()" + - "'/home/consul' in consul_user.ansible_facts.getent_passwd['consul']" + - "'/bin/false' in consul_user.ansible_facts.getent_passwd['consul']" + - "'consul' in consul_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/consul.d" + block: + - name: "Stat directory /etc/consul.d" + ansible.builtin.stat: + path: "/etc/consul.d" + register: stat_etc_consul_d + + - name: "Stat file /etc/consul.d/consul.env" + ansible.builtin.stat: + path: "/etc/consul.d/consul.env" + register: stat_etc_consul_d_consul_env + + - name: "Stat file /etc/consul.d/consul.json" + ansible.builtin.stat: + path: "/etc/consul.d/consul.json" + register: stat_etc_consul_d_consul_json + + - name: "Slurp file /etc/consul.d/consul.json" + ansible.builtin.slurp: + src: "/etc/consul.d/consul.json" + register: slurp_etc_consul_d_consul_json + + - name: "Verify directory /etc/consul.d" + ansible.builtin.assert: + that: + - stat_etc_consul_d.stat.exists + - stat_etc_consul_d.stat.isdir + - stat_etc_consul_d.stat.pw_name == 'consul' + - stat_etc_consul_d.stat.gr_name == 'consul' + - stat_etc_consul_d.stat.mode == '0755' + - stat_etc_consul_d_consul_env.stat.exists + - stat_etc_consul_d_consul_env.stat.isreg + - stat_etc_consul_d_consul_env.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_env.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_env.stat.mode == '0600' + - stat_etc_consul_d_consul_json.stat.exists + - stat_etc_consul_d_consul_json.stat.isreg + - stat_etc_consul_d_consul_json.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_json.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_json.stat.mode == '0600' + - slurp_etc_consul_d_consul_json.content != '' + + - name: "Test: directory /opt/consul" + block: + - name: "Stat directory /opt/consul" + ansible.builtin.stat: + path: "/opt/consul" + register: stat_opt_consul + + - name: "Verify directory /opt/consul" + ansible.builtin.assert: + that: + - stat_opt_consul.stat.exists + - stat_opt_consul.stat.isdir + - stat_opt_consul.stat.pw_name == 'consul' + - stat_opt_consul.stat.gr_name == 'consul' + - stat_opt_consul.stat.mode == '0755' + + - name: "Test: service consul" + block: + - name: "Get service consul" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul.service" + register: stat_etc_systemd_system_consul_service + + - name: "Slurp file /etc/systemd/system/consul.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul.service" + register: slurp_etc_systemd_system_consul_service + + - name: "Verify service consul" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_service.stat.exists + - stat_etc_systemd_system_consul_service.stat.isreg + - stat_etc_systemd_system_consul_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_service.content != '' + - ansible_facts.services['consul.service'] is defined + - ansible_facts.services['consul.service']['source'] == 'systemd' + - ansible_facts.services['consul.service']['state'] == 'running' + - ansible_facts.services['consul.service']['status'] == 'enabled' + + - name: "Test: interaction consul" + block: + - name: "Command consul kv put" + ansible.builtin.command: "consul kv put foo bar" + changed_when: false + register: consul_kv_put + + - name: "Command consul kv get" + ansible.builtin.command: "consul kv get foo" + changed_when: false + register: consul_kv_get + + - name: "Command consul kv delete" + ansible.builtin.command: "consul kv delete foo" + changed_when: false + register: consul_kv_delete + + - name: "Command consul members" + ansible.builtin.command: "consul members" + changed_when: false + register: consul_members + + - name: "Verify consul interaction" + ansible.builtin.assert: + that: + - "'instance' in consul_members.stdout" + - consul_kv_put.stdout == 'Success! Data written to: foo' + - consul_kv_get.stdout == 'bar' + - consul_kv_delete.stdout == 'Success! Deleted key: foo' diff --git a/roles/hashicorp_consul/molecule/default_vagrant/converge.yml b/roles/hashicorp_consul/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..836464f --- /dev/null +++ b/roles/hashicorp_consul/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_consul" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_consul" diff --git a/roles/hashicorp_consul/molecule/default_vagrant/molecule.yml b/roles/hashicorp_consul/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/hashicorp_consul/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_consul/molecule/default_vagrant/requirements.yml b/roles/hashicorp_consul/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_consul/molecule/default_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_consul/molecule/default_vagrant/verify.yml b/roles/hashicorp_consul/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..762ae27 --- /dev/null +++ b/roles/hashicorp_consul/molecule/default_vagrant/verify.yml @@ -0,0 +1,146 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: consul user and group" + block: + - name: "Getent user consul" + ansible.builtin.getent: + database: passwd + key: consul + register: consul_user + + - name: "Getent group consul" + ansible.builtin.getent: + database: group + key: consul + register: consul_group + + - name: "Verify consul user and group" + ansible.builtin.assert: + that: + - not consul_user.failed + - not consul_group.failed + - "'consul' in consul_user.ansible_facts.getent_passwd.keys()" + - "'/home/consul' in consul_user.ansible_facts.getent_passwd['consul']" + - "'/bin/false' in consul_user.ansible_facts.getent_passwd['consul']" + - "'consul' in consul_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/consul.d" + block: + - name: "Stat directory /etc/consul.d" + ansible.builtin.stat: + path: "/etc/consul.d" + register: stat_etc_consul_d + + - name: "Stat file /etc/consul.d/consul.env" + ansible.builtin.stat: + path: "/etc/consul.d/consul.env" + register: stat_etc_consul_d_consul_env + + - name: "Stat file /etc/consul.d/consul.json" + ansible.builtin.stat: + path: "/etc/consul.d/consul.json" + register: stat_etc_consul_d_consul_json + + - name: "Slurp file /etc/consul.d/consul.json" + ansible.builtin.slurp: + src: "/etc/consul.d/consul.json" + register: slurp_etc_consul_d_consul_json + + - name: "Verify directory /etc/consul.d" + ansible.builtin.assert: + that: + - stat_etc_consul_d.stat.exists + - stat_etc_consul_d.stat.isdir + - stat_etc_consul_d.stat.pw_name == 'consul' + - stat_etc_consul_d.stat.gr_name == 'consul' + - stat_etc_consul_d.stat.mode == '0755' + - stat_etc_consul_d_consul_env.stat.exists + - stat_etc_consul_d_consul_env.stat.isreg + - stat_etc_consul_d_consul_env.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_env.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_env.stat.mode == '0600' + - stat_etc_consul_d_consul_json.stat.exists + - stat_etc_consul_d_consul_json.stat.isreg + - stat_etc_consul_d_consul_json.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_json.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_json.stat.mode == '0600' + - slurp_etc_consul_d_consul_json.content != '' + + - name: "Test: directory /opt/consul" + block: + - name: "Stat directory /opt/consul" + ansible.builtin.stat: + path: "/opt/consul" + register: stat_opt_consul + + - name: "Verify directory /opt/consul" + ansible.builtin.assert: + that: + - stat_opt_consul.stat.exists + - stat_opt_consul.stat.isdir + - stat_opt_consul.stat.pw_name == 'consul' + - stat_opt_consul.stat.gr_name == 'consul' + - stat_opt_consul.stat.mode == '0755' + + - name: "Test: service consul" + block: + - name: "Get service consul" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul.service" + register: stat_etc_systemd_system_consul_service + + - name: "Slurp file /etc/systemd/system/consul.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul.service" + register: slurp_etc_systemd_system_consul_service + + - name: "Verify service consul" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_service.stat.exists + - stat_etc_systemd_system_consul_service.stat.isreg + - stat_etc_systemd_system_consul_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_service.content != '' + - ansible_facts.services['consul.service'] is defined + - ansible_facts.services['consul.service']['source'] == 'systemd' + - ansible_facts.services['consul.service']['state'] == 'running' + - ansible_facts.services['consul.service']['status'] == 'enabled' + + - name: "Test: interaction consul" + block: + - name: "Command consul kv put" + ansible.builtin.command: "consul kv put foo bar" + changed_when: false + register: consul_kv_put + + - name: "Command consul kv get" + ansible.builtin.command: "consul kv get foo" + changed_when: false + register: consul_kv_get + + - name: "Command consul kv delete" + ansible.builtin.command: "consul kv delete foo" + changed_when: false + register: consul_kv_delete + + - name: "Command consul members" + ansible.builtin.command: "consul members" + changed_when: false + register: consul_members + + - name: "Verify consul interaction" + ansible.builtin.assert: + that: + - "'instance' in consul_members.stdout" + - consul_kv_put.stdout == 'Success! Data written to: foo' + - consul_kv_get.stdout == 'bar' + - consul_kv_delete.stdout == 'Success! Deleted key: foo' diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled/converge.yml b/roles/hashicorp_consul/molecule/with_acl_enabled/converge.yml new file mode 100644 index 0000000..836464f --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_consul" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_consul" diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled/group_vars/all.yml b/roles/hashicorp_consul/molecule/with_acl_enabled/group_vars/all.yml new file mode 100644 index 0000000..bdb7324 --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled/group_vars/all.yml @@ -0,0 +1,69 @@ +--- +hashi_consul_install: true +hashi_consul_auto_update: true +hashi_consul_start_service: true +hashi_consul_version: latest +hashi_consul_deploy_method: host # deployment method, either host or docker. +hashi_consul_env_variables: {} +hashi_consul_data_dir: "/opt/consul" +hashi_consul_extra_files: false +hashi_consul_extra_files_src: /tmp/extra_files +hashi_consul_extra_files_dst: /etc/consul.d/extra_files +hashi_consul_envoy_install: true +hashi_consul_envoy_version: v1.26.3 +#! consul configuration +hashi_consul_configuration: + domain: consul + datacenter: dc1 + primary_datacenter: dc1 + client_addr: "0.0.0.0" + bind_addr: "{{ ansible_default_ipv4.address }}" + advertise_addr: "{{ ansible_default_ipv4.address }}" + data_dir: "{{ hashi_consul_data_dir }}" + encrypt: "{{ 'mysupersecretgossipencryptionkey'|b64encode }}" + server: true + bootstrap_expect: 1 + retry_join: + - "{{ ansible_default_ipv4.address }}" + ui_config: + enabled: true + connect: + enabled: false + leave_on_terminate: true + rejoin_after_leave: true + enable_script_checks: true + enable_syslog: true + log_level: INFO + acl: + enabled: true + default_policy: "deny" + enable_token_persistence: true + tokens: + initial_management: "1a1f2ce5-3730-47de-9a9c-89e037376bab" + agent: "1a1f2ce5-3730-47de-9a9c-89e037376bab" + dns_config: + allow_stale: true + enable_truncate: true + only_passing: true + ports: + dns: 8600 + http: 8500 + https: -1 + grpc: 8502 + grpc_tls: 8503 + server: 8300 + serf_lan: 8301 + serf_wan: 8302 + sidecar_min_port: 21000 + sidecar_max_port: 21255 + expose_min_port: 21500 + expose_max_port: 21755 + # tls: + # defaults: + # ca_file: "{{ hashi_consul_data_dir }}/tls/ca.pem" + # cert_file: "{{ hashi_consul_data_dir }}/tls/cert.pem" + # key_file: "{{ hashi_consul_data_dir }}/tls/key.pem" + # verify_incoming: false + # verify_outgoing: true + # grpc: {} + # https: {} diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled/molecule.yml b/roles/hashicorp_consul/molecule/with_acl_enabled/molecule.yml new file mode 100644 index 0000000..59630f1 --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_acl_enabled + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled/requirements.yml b/roles/hashicorp_consul/molecule/with_acl_enabled/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled/verify.yml b/roles/hashicorp_consul/molecule/with_acl_enabled/verify.yml new file mode 100644 index 0000000..2ec5eea --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled/verify.yml @@ -0,0 +1,156 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: consul user and group" + block: + - name: "Getent user consul" + ansible.builtin.getent: + database: passwd + key: consul + register: consul_user + + - name: "Getent group consul" + ansible.builtin.getent: + database: group + key: consul + register: consul_group + + - name: "Verify consul user and group" + ansible.builtin.assert: + that: + - not consul_user.failed + - not consul_group.failed + - "'consul' in consul_user.ansible_facts.getent_passwd.keys()" + - "'/home/consul' in consul_user.ansible_facts.getent_passwd['consul']" + - "'/bin/false' in consul_user.ansible_facts.getent_passwd['consul']" + - "'consul' in consul_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/consul.d" + block: + - name: "Stat directory /etc/consul.d" + ansible.builtin.stat: + path: "/etc/consul.d" + register: stat_etc_consul_d + + - name: "Stat file /etc/consul.d/consul.env" + ansible.builtin.stat: + path: "/etc/consul.d/consul.env" + register: stat_etc_consul_d_consul_env + + - name: "Stat file /etc/consul.d/consul.json" + ansible.builtin.stat: + path: "/etc/consul.d/consul.json" + register: stat_etc_consul_d_consul_json + + - name: "Slurp file /etc/consul.d/consul.json" + ansible.builtin.slurp: + src: "/etc/consul.d/consul.json" + register: slurp_etc_consul_d_consul_json + + - name: "Verify directory /etc/consul.d" + ansible.builtin.assert: + that: + - stat_etc_consul_d.stat.exists + - stat_etc_consul_d.stat.isdir + - stat_etc_consul_d.stat.pw_name == 'consul' + - stat_etc_consul_d.stat.gr_name == 'consul' + - stat_etc_consul_d.stat.mode == '0755' + - stat_etc_consul_d_consul_env.stat.exists + - stat_etc_consul_d_consul_env.stat.isreg + - stat_etc_consul_d_consul_env.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_env.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_env.stat.mode == '0600' + - stat_etc_consul_d_consul_json.stat.exists + - stat_etc_consul_d_consul_json.stat.isreg + - stat_etc_consul_d_consul_json.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_json.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_json.stat.mode == '0600' + - slurp_etc_consul_d_consul_json.content != '' + + - name: "Test: directory /opt/consul" + block: + - name: "Stat directory /opt/consul" + ansible.builtin.stat: + path: "/opt/consul" + register: stat_opt_consul + + - name: "Verify directory /opt/consul" + ansible.builtin.assert: + that: + - stat_opt_consul.stat.exists + - stat_opt_consul.stat.isdir + - stat_opt_consul.stat.pw_name == 'consul' + - stat_opt_consul.stat.gr_name == 'consul' + - stat_opt_consul.stat.mode == '0755' + + - name: "Test: service consul" + block: + - name: "Get service consul" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul.service" + register: stat_etc_systemd_system_consul_service + + - name: "Slurp file /etc/systemd/system/consul.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul.service" + register: slurp_etc_systemd_system_consul_service + + - name: "Verify service consul" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_service.stat.exists + - stat_etc_systemd_system_consul_service.stat.isreg + - stat_etc_systemd_system_consul_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_service.content != '' + - ansible_facts.services['consul.service'] is defined + - ansible_facts.services['consul.service']['source'] == 'systemd' + - ansible_facts.services['consul.service']['state'] == 'running' + - ansible_facts.services['consul.service']['status'] == 'enabled' + + - name: "Test: interaction consul" + vars: + acl_token: "1a1f2ce5-3730-47de-9a9c-89e037376bab" + block: + - name: "Command consul kv put" + ansible.builtin.command: "consul kv put foo bar" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_kv_put + + - name: "Command consul kv get" + ansible.builtin.command: "consul kv get foo" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_kv_get + + - name: "Command consul kv delete" + ansible.builtin.command: "consul kv delete foo" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_kv_delete + + - name: "Command consul members" + ansible.builtin.command: "consul members" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_members + + - name: "Verify consul interaction" + ansible.builtin.assert: + that: + - "'instance' in consul_members.stdout" + - consul_kv_put.stdout == 'Success! Data written to: foo' + - consul_kv_get.stdout == 'bar' + - consul_kv_delete.stdout == 'Success! Deleted key: foo' diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/converge.yml b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/converge.yml new file mode 100644 index 0000000..836464f --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_consul" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_consul" diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/group_vars/all.yml b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/group_vars/all.yml new file mode 100644 index 0000000..bdb7324 --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/group_vars/all.yml @@ -0,0 +1,69 @@ +--- +hashi_consul_install: true +hashi_consul_auto_update: true +hashi_consul_start_service: true +hashi_consul_version: latest +hashi_consul_deploy_method: host # deployment method, either host or docker. +hashi_consul_env_variables: {} +hashi_consul_data_dir: "/opt/consul" +hashi_consul_extra_files: false +hashi_consul_extra_files_src: /tmp/extra_files +hashi_consul_extra_files_dst: /etc/consul.d/extra_files +hashi_consul_envoy_install: true +hashi_consul_envoy_version: v1.26.3 +#! consul configuration +hashi_consul_configuration: + domain: consul + datacenter: dc1 + primary_datacenter: dc1 + client_addr: "0.0.0.0" + bind_addr: "{{ ansible_default_ipv4.address }}" + advertise_addr: "{{ ansible_default_ipv4.address }}" + data_dir: "{{ hashi_consul_data_dir }}" + encrypt: "{{ 'mysupersecretgossipencryptionkey'|b64encode }}" + server: true + bootstrap_expect: 1 + retry_join: + - "{{ ansible_default_ipv4.address }}" + ui_config: + enabled: true + connect: + enabled: false + leave_on_terminate: true + rejoin_after_leave: true + enable_script_checks: true + enable_syslog: true + log_level: INFO + acl: + enabled: true + default_policy: "deny" + enable_token_persistence: true + tokens: + initial_management: "1a1f2ce5-3730-47de-9a9c-89e037376bab" + agent: "1a1f2ce5-3730-47de-9a9c-89e037376bab" + dns_config: + allow_stale: true + enable_truncate: true + only_passing: true + ports: + dns: 8600 + http: 8500 + https: -1 + grpc: 8502 + grpc_tls: 8503 + server: 8300 + serf_lan: 8301 + serf_wan: 8302 + sidecar_min_port: 21000 + sidecar_max_port: 21255 + expose_min_port: 21500 + expose_max_port: 21755 + # tls: + # defaults: + # ca_file: "{{ hashi_consul_data_dir }}/tls/ca.pem" + # cert_file: "{{ hashi_consul_data_dir }}/tls/cert.pem" + # key_file: "{{ hashi_consul_data_dir }}/tls/key.pem" + # verify_incoming: false + # verify_outgoing: true + # grpc: {} + # https: {} diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/molecule.yml b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/molecule.yml new file mode 100644 index 0000000..0e6b593 --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_acl_enabled_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/requirements.yml b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/verify.yml b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/verify.yml new file mode 100644 index 0000000..2ec5eea --- /dev/null +++ b/roles/hashicorp_consul/molecule/with_acl_enabled_vagrant/verify.yml @@ -0,0 +1,156 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: consul user and group" + block: + - name: "Getent user consul" + ansible.builtin.getent: + database: passwd + key: consul + register: consul_user + + - name: "Getent group consul" + ansible.builtin.getent: + database: group + key: consul + register: consul_group + + - name: "Verify consul user and group" + ansible.builtin.assert: + that: + - not consul_user.failed + - not consul_group.failed + - "'consul' in consul_user.ansible_facts.getent_passwd.keys()" + - "'/home/consul' in consul_user.ansible_facts.getent_passwd['consul']" + - "'/bin/false' in consul_user.ansible_facts.getent_passwd['consul']" + - "'consul' in consul_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/consul.d" + block: + - name: "Stat directory /etc/consul.d" + ansible.builtin.stat: + path: "/etc/consul.d" + register: stat_etc_consul_d + + - name: "Stat file /etc/consul.d/consul.env" + ansible.builtin.stat: + path: "/etc/consul.d/consul.env" + register: stat_etc_consul_d_consul_env + + - name: "Stat file /etc/consul.d/consul.json" + ansible.builtin.stat: + path: "/etc/consul.d/consul.json" + register: stat_etc_consul_d_consul_json + + - name: "Slurp file /etc/consul.d/consul.json" + ansible.builtin.slurp: + src: "/etc/consul.d/consul.json" + register: slurp_etc_consul_d_consul_json + + - name: "Verify directory /etc/consul.d" + ansible.builtin.assert: + that: + - stat_etc_consul_d.stat.exists + - stat_etc_consul_d.stat.isdir + - stat_etc_consul_d.stat.pw_name == 'consul' + - stat_etc_consul_d.stat.gr_name == 'consul' + - stat_etc_consul_d.stat.mode == '0755' + - stat_etc_consul_d_consul_env.stat.exists + - stat_etc_consul_d_consul_env.stat.isreg + - stat_etc_consul_d_consul_env.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_env.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_env.stat.mode == '0600' + - stat_etc_consul_d_consul_json.stat.exists + - stat_etc_consul_d_consul_json.stat.isreg + - stat_etc_consul_d_consul_json.stat.pw_name == 'consul' + - stat_etc_consul_d_consul_json.stat.gr_name == 'consul' + - stat_etc_consul_d_consul_json.stat.mode == '0600' + - slurp_etc_consul_d_consul_json.content != '' + + - name: "Test: directory /opt/consul" + block: + - name: "Stat directory /opt/consul" + ansible.builtin.stat: + path: "/opt/consul" + register: stat_opt_consul + + - name: "Verify directory /opt/consul" + ansible.builtin.assert: + that: + - stat_opt_consul.stat.exists + - stat_opt_consul.stat.isdir + - stat_opt_consul.stat.pw_name == 'consul' + - stat_opt_consul.stat.gr_name == 'consul' + - stat_opt_consul.stat.mode == '0755' + + - name: "Test: service consul" + block: + - name: "Get service consul" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul.service" + register: stat_etc_systemd_system_consul_service + + - name: "Slurp file /etc/systemd/system/consul.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul.service" + register: slurp_etc_systemd_system_consul_service + + - name: "Verify service consul" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_service.stat.exists + - stat_etc_systemd_system_consul_service.stat.isreg + - stat_etc_systemd_system_consul_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_service.content != '' + - ansible_facts.services['consul.service'] is defined + - ansible_facts.services['consul.service']['source'] == 'systemd' + - ansible_facts.services['consul.service']['state'] == 'running' + - ansible_facts.services['consul.service']['status'] == 'enabled' + + - name: "Test: interaction consul" + vars: + acl_token: "1a1f2ce5-3730-47de-9a9c-89e037376bab" + block: + - name: "Command consul kv put" + ansible.builtin.command: "consul kv put foo bar" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_kv_put + + - name: "Command consul kv get" + ansible.builtin.command: "consul kv get foo" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_kv_get + + - name: "Command consul kv delete" + ansible.builtin.command: "consul kv delete foo" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_kv_delete + + - name: "Command consul members" + ansible.builtin.command: "consul members" + environment: + CONSUL_HTTP_TOKEN: "{{ acl_token }}" + changed_when: false + register: consul_members + + - name: "Verify consul interaction" + ansible.builtin.assert: + that: + - "'instance' in consul_members.stdout" + - consul_kv_put.stdout == 'Success! Data written to: foo' + - consul_kv_get.stdout == 'bar' + - consul_kv_delete.stdout == 'Success! Deleted key: foo' diff --git a/roles/hashicorp_consul/tasks/configure.yml b/roles/hashicorp_consul/tasks/configure.yml new file mode 100644 index 0000000..479f447 --- /dev/null +++ b/roles/hashicorp_consul/tasks/configure.yml @@ -0,0 +1,46 @@ +--- +# task/configure file for hashicorp_consul +- name: "Ensure default consul.hcl is removed" + ansible.builtin.file: + path: /etc/consul.d/consul.hcl + state: absent + +- name: "Copy consul.json template" + ansible.builtin.template: + src: consul.json.j2 + dest: "{{ hashi_consul_config_dir }}/consul.json" + owner: "{{ hashi_consul_user }}" + group: "{{ hashi_consul_group }}" + mode: '0600' + notify: + - "systemctl-enable-consul" + - "systemctl-restart-consul" + +- name: "Create consul.env" + ansible.builtin.template: + src: consul.env.j2 + dest: "{{ hashi_consul_config_dir }}/consul.env" + owner: "{{ hashi_consul_user }}" + group: "{{ hashi_consul_group }}" + mode: '0600' + +- name: "Copy extra configuration files" + when: hashi_consul_extra_files + block: + - name: "Create directory {{ hashi_consul_extra_files_dst }}" + ansible.builtin.file: + path: "{{ hashi_consul_extra_files_dst }}" + state: directory + owner: "{{ hashi_consul_user }}" + group: "{{ hashi_consul_group }}" + mode: '0755' + + - name: "Copy extra configuration files" + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ hashi_consul_extra_files_dst }}/{{ (item | basename).split('.')[:-1] | join('.')}}" + owner: "{{ hashi_consul_user }}" + group: "{{ hashi_consul_group }}" + mode: '0600' + with_fileglob: + - "{{ hashi_consul_extra_files_src }}/*" diff --git a/roles/hashicorp_consul/tasks/install.yml b/roles/hashicorp_consul/tasks/install.yml new file mode 100644 index 0000000..0fa8b09 --- /dev/null +++ b/roles/hashicorp_consul/tasks/install.yml @@ -0,0 +1,25 @@ +--- +# task/install file for hashicorp_consul +- name: "Configure hashicorp repository" + ansible.builtin.include_role: + name: ednxzu.manage_repositories + vars: + manage_repositories_enable_default_repo: false + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: "{{ hashi_consul_repository }}" + +- name: "Install consul:{{ hashi_consul_version }}" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ hashi_consul_packages }}" + +- name: "Copy systemd service file for consul" + ansible.builtin.template: + src: "consul.service.j2" + dest: "/etc/systemd/system/consul.service" + owner: root + group: root + mode: '0644' + notify: + - "systemctl-daemon-reload" diff --git a/roles/hashicorp_consul/tasks/install_envoy.yml b/roles/hashicorp_consul/tasks/install_envoy.yml new file mode 100644 index 0000000..89a085a --- /dev/null +++ b/roles/hashicorp_consul/tasks/install_envoy.yml @@ -0,0 +1,66 @@ +--- +# task/install_envoy file for hashicorp_consul +- name: "Get release for envoy:{{ hashi_consul_envoy_version }}" + vars: + _envoy_url_ext: "{% if hashi_consul_envoy_version == 'latest'%}releases{% else %}releases/tags{% endif %}" + ansible.builtin.uri: + url: "{{ hashi_consul_envoy_github_api }}/{{ _envoy_url_ext }}/{{ hashi_consul_envoy_version }}" + return_content: true + register: _envoy_new_release + +- name: "Check if envoy is already installed" + ansible.builtin.stat: + path: "{{ hashi_consul_data_dir }}/envoy/version" + changed_when: false + check_mode: false + register: _envoy_is_installed + + +- name: "Check current envoy version" + ansible.builtin.command: "cat {{ hashi_consul_data_dir }}/envoy/version" + changed_when: false + check_mode: false + register: _envoy_old_release + when: _envoy_is_installed.stat.exists + +- name: "Set facts for wanted envoy release" + ansible.builtin.set_fact: + hashi_consul_envoy_wanted_version: "{{ _envoy_new_release.json['tag_name']|regex_replace('v', '') }}" + when: _envoy_new_release.json is defined + and (_envoy_new_release.json | length > 0) + +- name: "Set facts for current envoy release" + ansible.builtin.set_fact: + hashi_consul_envoy_current_version: "{{ _envoy_old_release.stdout | regex_replace('v', '') }}" + when: _envoy_old_release.stdout is defined + and (_envoy_old_release.stdout | length > 0) + +- name: "Create envoy directory" + ansible.builtin.file: + path: "{{ hashi_consul_data_dir }}/envoy" + state: directory + mode: "0775" + +- name: "Install envoy" + when: hashi_consul_envoy_current_version is not defined + or hashi_consul_envoy_wanted_version not in hashi_consul_envoy_current_version + block: + - name: "Remove old compose binary if different" + ansible.builtin.file: + path: "{{ hashi_consul_envoy_path }}" + state: absent + register: _envoy_binary_removed + + - name: "Download and install envoy version:{{ hashi_consul_envoy_version }}" + ansible.builtin.get_url: + url: "{{ hashi_consul_envoy_github_url }}/releases/download/v{{ hashi_consul_envoy_wanted_version }}/envoy-{{ hashi_consul_envoy_wanted_version }}-linux-{{ hashi_consul_envoy_arch }} " + dest: "{{ hashi_consul_envoy_path }}" + owner: root + group: root + mode: '0755' + + - name: "Update version file" + ansible.builtin.copy: + content: "{{ hashi_consul_envoy_wanted_version }}" + dest: "{{ hashi_consul_data_dir }}/envoy/version" + mode: "0600" diff --git a/roles/hashicorp_consul/tasks/main.yml b/roles/hashicorp_consul/tasks/main.yml new file mode 100644 index 0000000..a26499e --- /dev/null +++ b/roles/hashicorp_consul/tasks/main.yml @@ -0,0 +1,14 @@ +--- +# task/main file for hashicorp_consul +- name: "Import prerequisites.yml" + ansible.builtin.include_tasks: prerequisites.yml + +- name: "Import install.yml" + ansible.builtin.include_tasks: install.yml + +- name: "Import install_envoy.yml" + ansible.builtin.include_tasks: install_envoy.yml + when: hashi_consul_envoy_install + +- name: "Import configure.yml" + ansible.builtin.include_tasks: configure.yml diff --git a/roles/hashicorp_consul/tasks/prerequisites.yml b/roles/hashicorp_consul/tasks/prerequisites.yml new file mode 100644 index 0000000..7d37263 --- /dev/null +++ b/roles/hashicorp_consul/tasks/prerequisites.yml @@ -0,0 +1,29 @@ +--- +# task/prerequisites file for hashicorp_consul +- name: "Create group {{ hashi_consul_group }}" + ansible.builtin.group: + name: "{{ hashi_consul_group }}" + state: present + +- name: "Create user {{ hashi_consul_user }}" + ansible.builtin.user: + name: "{{ hashi_consul_user }}" + group: "{{ hashi_consul_group }}" + shell: /bin/false + state: present + +- name: "Create directory {{ hashi_consul_config_dir }}" + ansible.builtin.file: + path: "{{ hashi_consul_config_dir }}" + state: directory + owner: "{{ hashi_consul_user }}" + group: "{{ hashi_consul_group }}" + mode: '0755' + +- name: "Create directory {{ hashi_consul_data_dir}}" + ansible.builtin.file: + path: "{{ hashi_consul_data_dir }}" + state: directory + owner: "{{ hashi_consul_user }}" + group: "{{ hashi_consul_group }}" + mode: '0755' diff --git a/roles/hashicorp_consul/templates/consul.env.j2 b/roles/hashicorp_consul/templates/consul.env.j2 new file mode 100644 index 0000000..3acc2ff --- /dev/null +++ b/roles/hashicorp_consul/templates/consul.env.j2 @@ -0,0 +1,4 @@ +# {{ ansible_managed }} +{% for item in hashi_consul_env_variables %} +{{ item|upper }}="{{ hashi_consul_env_variables[item] }}" +{% endfor %} \ No newline at end of file diff --git a/roles/hashicorp_consul/templates/consul.json.j2 b/roles/hashicorp_consul/templates/consul.json.j2 new file mode 100644 index 0000000..7cf757d --- /dev/null +++ b/roles/hashicorp_consul/templates/consul.json.j2 @@ -0,0 +1 @@ +{{ hashi_consul_configuration|to_nice_json }} diff --git a/roles/hashicorp_consul/templates/consul.service.j2 b/roles/hashicorp_consul/templates/consul.service.j2 new file mode 100644 index 0000000..86dea55 --- /dev/null +++ b/roles/hashicorp_consul/templates/consul.service.j2 @@ -0,0 +1,20 @@ +[Unit] +Description=Consul +Documentation=https://developer.hashicorp.com/consul/docs +Requires=network-online.target +After=network-online.target +ConditionFileNotEmpty={{ hashi_consul_config_dir }}/consul.json + +[Service] +EnvironmentFile=-{{ hashi_consul_config_dir }}/consul.env +User={{ hashi_consul_user }} +Group={{ hashi_consul_group }} +ExecStart=/usr/bin/consul agent -config-dir={{ hashi_consul_config_dir }} +ExecReload=/bin/kill --signal HUP $MAINPID +KillMode=process +KillSignal=SIGTERM +Restart=on-failure +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/hashicorp_consul/vars/main.yml b/roles/hashicorp_consul/vars/main.yml new file mode 100644 index 0000000..e9a6b51 --- /dev/null +++ b/roles/hashicorp_consul/vars/main.yml @@ -0,0 +1,28 @@ +--- +# vars file for hashicorp_consul +hashi_consul_user: consul +hashi_consul_group: consul +hashi_consul_config_dir: "/etc/consul.d" +hashi_consul_envoy_github_api: https://api.github.com/repos/envoyproxy/envoy +hashi_consul_envoy_github_url: https://github.com/envoyproxy/envoy +hashi_consul_envoy_path: "/usr/local/bin/envoy" +hashi_consul_envoy_arch_map: + x86_64: 'x86_64' + aarch64: 'aarch64' +hashi_consul_envoy_arch: "{{ hashi_consul_envoy_arch_map[ansible_architecture] | default(ansible_architecture) }}" +hashi_consul_repository: + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" +hashi_consul_packages: + - name: consul + version: "{{ hashi_consul_version }}" + state: "{% if hashi_consul_auto_update %}latest{% else %}present{% endif %}" diff --git a/roles/hashicorp_nomad/LICENSE b/roles/hashicorp_nomad/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/hashicorp_nomad/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/hashicorp_nomad/README.md b/roles/hashicorp_nomad/README.md new file mode 100644 index 0000000..79ab3ed --- /dev/null +++ b/roles/hashicorp_nomad/README.md @@ -0,0 +1,107 @@ +hashicorp_nomad +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role install and configure nomad on **debian-based** distributions. + +Requirements +------------ + +None. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/hashicorp_nomad.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +hashi_nomad_install: true # by default, set to true +``` +This variable defines if the nomad package is to be installed or not before configuring. If you install nomad using another task, you can set this to `false`. + +```yaml +hashi_nomad_auto_update: false # by default, set to false +``` +This variable allows you to choose to automatically update nomad if a newer version is available. Updating nomad is usually pretty safe if done on a regular basis, but for better control over the upgrade process, see `hashi_nomad_version`. + +```yaml +hashi_nomad_cni_plugins_install: true # by default, set to true +``` +This variable defines whether or not to install the CNI plugins on the host. Defaults to `true`. + +```yaml +hashi_nomad_start_service: true +``` +This variable defines if the nomad service should be started once it has been configured. This is usefull in case you're using this role to build golden images, in which case you might want to only enable the service, to have it start on the next boot (when the image is launched) + +```yaml +hashi_nomad_cni_plugins_version: latest # by default, set to latest +``` +This variable defines the version of the CNI plugins to install. + +```yaml +hashi_nomad_cni_plugins_install_path: /opt/cni/bin +``` +This variable defines where to install the CNI plugins. Note that it should be referenced in the nomad configuration. + +```yaml +hashi_nomad_version: latest # by default, set to latest +``` +This variable specifies the version of nomad to install when `hashi_nomad_install` is set to `true`. The version to specify is the version of the package on the hashicorp repository (`1.5.1-1` for example). This can be found by running `apt-cache madison consul` on a machine with the repository installed. + +```yaml +hashi_nomad_deploy_method: host # by default, set to host +``` +This variable defines the method of deployment of nomad. The `host` method installs the binary directly on the host, and runs nomad as a systemd service. The `docker` method install nomad as a docker container. +> Currently, only the `host` method is available, the `docker` method will be added later. + +```yaml +hashi_nomad_env_variables: # by default, set to empty + env_var: value +``` +This value is a list of key/value that will populate the `nomad.env` file. You do not have to capitalize the KEYS, as it will be done automatically. + +```yaml +hashi_nomad_extra_files: false # by default, set to false +``` +This variable defines whether or not there is extra configuration files to copy to the target. If there are, these extra files are expected to be jinja2 templates located all in the same directory, and will be copied to the specified directory on the target machine. + +```yaml +hashi_nomad_extra_files_src: /tmp/extra_files # by default, set to /tmp/extra_files +``` +This variable defines the source directory (without the trailing /) for the extra files to be copied in case there are some. + +```yaml +hashi_nomad_extra_files_dst: /etc/nomad.d/extra_files # by default, set to /etc/nomad.d/extra_files +``` +This variable defines the destination directory (without the trailing /) for the extra files to be copied. + +```yaml +hashi_nomad_configuration: {} # by default, set to a simple configuration +``` +This variable sets all of the configuration parameters for nomad. For more information on all of them, please check the [documentation](https://developer.hashicorp.com/nomad/docs/configuration). This variable is parsed and converted to json format to create the config file, so each key and value should be set according to the documentation. This method of passing configuration allows for compatibility with every configuration parameters that nomad has to offer. The defaults are simply here to deploy a simple, single-node nomad server without much configuration, and should NOT be used in production. You will want to edit this to deploy production-ready clusters. + +Dependencies +------------ + +`ednxzu.manage_repositories` to configure the hashicorp apt repository. +`ednxzu.manage_apt_packages` to install nomad. + +Example Playbook +---------------- + +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.hashicorp_nomad +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/hashicorp_nomad/defaults/hashicorp_nomad.yml.sample b/roles/hashicorp_nomad/defaults/hashicorp_nomad.yml.sample new file mode 100644 index 0000000..86f54db --- /dev/null +++ b/roles/hashicorp_nomad/defaults/hashicorp_nomad.yml.sample @@ -0,0 +1,86 @@ +--- +# hashi_nomad_install: true +# hashi_nomad_auto_update: false +# hashi_nomad_cni_plugins_install: true +# hashi_nomad_start_service: true +# hashi_nomad_cni_plugins_version: latest +# hashi_nomad_cni_plugins_install_path: "/opt/cni/bin" +# hashi_nomad_version: latest +# hashi_nomad_deploy_method: host # deployment method, either host or docker +# hashi_nomad_env_variables: {} +# hashi_nomad_data_dir: /opt/nomad +# hashi_nomad_extra_files: false +# hashi_nomad_extra_files_src: /tmp/extra_files +# hashi_nomad_extra_files_dst: /etc/nomad.d/extra_files +# #! nomad configuration +# hashi_nomad_configuration: +# bind_addr: "0.0.0.0" +# datacenter: dc1 +# log_level: INFO +# leave_on_terminate: false +# data_dir: "{{ hashi_nomad_data_dir }}" +# advertise: +# http: "{{ ansible_default_ipv4.address }}" +# rpc: "{{ ansible_default_ipv4.address }}" +# serf: "{{ ansible_default_ipv4.address }}" +# server: +# enabled: true +# bootstrap_expect: 1 +# server_join: +# retry_join: +# - "{{ ansible_default_ipv4.address }}" +# client: +# enabled: false +# node_class: default +# reserved: +# cpu: 500 +# memory: 300 +# cni_path: "{{ hashi_nomad_cni_plugins_install_path }}" +# bridge_network_name: nomad +# bridge_network_subnet: "172.26.64.0/20" +# ui: +# enabled: true +# acl: +# enabled: false +# token_ttl: 30s +# policy_ttl: 30s +# role_ttl: 30s +# token_min_expiration_ttl: 30s +# token_max_expiration_ttl: 24h +# telemetry: +# collection_interval: 1s +# disable_hostname: false +# use_node_name: false +# publish_allocation_metrics: false +# publish_node_metrics: false +# prefix_filter: [] +# disable_dispatched_job_summary_metrics: false +# prometheus_metrics: false +# # tls: +# # http: false +# # rpc: false +# # ca_file: "{{ hashi_nomad_data_dir }}/tls/ca.pem" +# # cert_file: "{{ hashi_nomad_data_dir }}/tls/cert.pem" +# # key_file: "{{ hashi_nomad_data_dir }}/tls/key.pem" +# # plugin: +# # docker: +# # config: +# # endpoint: "unix:///var/run/docker.sock" +# # allow_privileged: false +# # allow_caps: ["all"] +# # volumes: +# # enabled: true +# # consul: +# # address: "127.0.0.1:8500" +# # token: "" +# # auto_advertise: true +# # vault: +# # address: http://vault.service.consul:8200 +# # token: "" +# # create_from_role: nomad-cluster +# # plugin: +# # docker: +# # endpoint: "unix:///var/run/docker.sock" +# # allow_privileged: false +# # allow_caps: ["all"] +# # volumes_enabled: true diff --git a/roles/hashicorp_nomad/defaults/main.yml b/roles/hashicorp_nomad/defaults/main.yml new file mode 100644 index 0000000..badedb1 --- /dev/null +++ b/roles/hashicorp_nomad/defaults/main.yml @@ -0,0 +1,87 @@ +--- +# defaults file for hashicorp_nomad +hashi_nomad_install: true +hashi_nomad_auto_update: false +hashi_nomad_cni_plugins_install: true +hashi_nomad_start_service: true +hashi_nomad_cni_plugins_version: latest +hashi_nomad_cni_plugins_install_path: /opt/cni/bin +hashi_nomad_version: latest +hashi_nomad_deploy_method: host # deployment method, either host or docker +hashi_nomad_env_variables: {} +hashi_nomad_data_dir: /opt/nomad +hashi_nomad_extra_files: false +hashi_nomad_extra_files_src: /tmp/extra_files +hashi_nomad_extra_files_dst: /etc/nomad.d/extra_files +#! nomad configuration +hashi_nomad_configuration: + bind_addr: "0.0.0.0" + datacenter: dc1 + log_level: INFO + leave_on_terminate: false + data_dir: "{{ hashi_nomad_data_dir }}" + advertise: + http: "{{ ansible_default_ipv4.address }}" + rpc: "{{ ansible_default_ipv4.address }}" + serf: "{{ ansible_default_ipv4.address }}" + server: + enabled: true + bootstrap_expect: 1 + server_join: + retry_join: + - "{{ ansible_default_ipv4.address }}" + client: + enabled: false + node_class: default + reserved: + cpu: 500 + memory: 300 + cni_path: "{{ hashi_nomad_cni_plugins_install_path }}" + bridge_network_name: nomad + bridge_network_subnet: "172.26.64.0/20" + ui: + enabled: true + acl: + enabled: false + token_ttl: 30s + policy_ttl: 30s + role_ttl: 30s + token_min_expiration_ttl: 30s + token_max_expiration_ttl: 24h + telemetry: + collection_interval: 1s + disable_hostname: false + use_node_name: false + publish_allocation_metrics: false + publish_node_metrics: false + prefix_filter: [] + disable_dispatched_job_summary_metrics: false + prometheus_metrics: false + # tls: + # http: false + # rpc: false + # ca_file: "{{ hashi_nomad_data_dir }}/tls/ca.pem" + # cert_file: "{{ hashi_nomad_data_dir }}/tls/cert.pem" + # key_file: "{{ hashi_nomad_data_dir }}/tls/key.pem" + # plugin: + # docker: + # config: + # endpoint: "unix:///var/run/docker.sock" + # allow_privileged: false + # allow_caps: ["all"] + # volumes: + # enabled: true + # consul: + # address: "127.0.0.1:8500" + # token: "" + # auto_advertise: true + # vault: + # address: http://vault.service.consul:8200 + # token: "" + # create_from_role: nomad-cluster + # plugin: + # docker: + # endpoint: "unix:///var/run/docker.sock" + # allow_privileged: false + # allow_caps: ["all"] + # volumes_enabled: true diff --git a/roles/hashicorp_nomad/handlers/main.yml b/roles/hashicorp_nomad/handlers/main.yml new file mode 100644 index 0000000..d093dd6 --- /dev/null +++ b/roles/hashicorp_nomad/handlers/main.yml @@ -0,0 +1,20 @@ +--- +# handlers file for hashicorp_nomad +- name: "Reload systemd file" + ansible.builtin.systemd: + daemon_reload: true + listen: "systemctl-daemon-reload" + +- name: "Enable nomad service" + ansible.builtin.service: + name: nomad + enabled: true + listen: "systemctl-enable-nomad" + +- name: "Start nomad service" + ansible.builtin.service: + name: nomad + state: restarted + listen: "systemctl-restart-nomad" + throttle: 1 + when: hashi_nomad_start_service diff --git a/roles/hashicorp_nomad/meta/main.yml b/roles/hashicorp_nomad/meta/main.yml new file mode 100644 index 0000000..7f31c31 --- /dev/null +++ b/roles/hashicorp_nomad/meta/main.yml @@ -0,0 +1,25 @@ +--- +# meta file for hashicorp_nomad +galaxy_info: + namespace: 'ednxzu' + role_name: 'hashicorp_nomad' + author: 'Bertrand Lanson' + description: 'Install and configure hashicorp nomad for debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'hashicorp' + - 'nomad' + +dependencies: [] diff --git a/roles/hashicorp_nomad/molecule/default/converge.yml b/roles/hashicorp_nomad/molecule/default/converge.yml new file mode 100644 index 0000000..4dfaa5b --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_nomad" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_nomad" diff --git a/roles/hashicorp_nomad/molecule/default/molecule.yml b/roles/hashicorp_nomad/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_nomad/molecule/default/requirements.yml b/roles/hashicorp_nomad/molecule/default/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_nomad/molecule/default/verify.yml b/roles/hashicorp_nomad/molecule/default/verify.yml new file mode 100644 index 0000000..6b173a9 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default/verify.yml @@ -0,0 +1,146 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: nomad user and group" + block: + - name: "Getent user nomad" + ansible.builtin.getent: + database: passwd + key: nomad + register: nomad_user + + - name: "Getent group nomad" + ansible.builtin.getent: + database: group + key: nomad + register: nomad_group + + - name: "Verify nomad user and group" + ansible.builtin.assert: + that: + - not nomad_user.failed + - not nomad_group.failed + - "'nomad' in nomad_user.ansible_facts.getent_passwd.keys()" + - "'/home/nomad' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'/bin/false' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'nomad' in nomad_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/nomad.d" + block: + - name: "Stat directory /etc/nomad.d" + ansible.builtin.stat: + path: "/etc/nomad.d" + register: stat_etc_nomad_d + + - name: "Stat file /etc/nomad.d/nomad.env" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.env" + register: stat_etc_nomad_d_nomad_env + + - name: "Stat file /etc/nomad.d/nomad.json" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.json" + register: stat_etc_nomad_d_nomad_json + + - name: "Slurp file /etc/nomad.d/nomad.json" + ansible.builtin.slurp: + src: "/etc/nomad.d/nomad.json" + register: slurp_etc_nomad_d_nomad_json + + - name: "Verify directory /etc/nomad.d" + ansible.builtin.assert: + that: + - stat_etc_nomad_d.stat.exists + - stat_etc_nomad_d.stat.isdir + - stat_etc_nomad_d.stat.pw_name == 'nomad' + - stat_etc_nomad_d.stat.gr_name == 'nomad' + - stat_etc_nomad_d.stat.mode == '0755' + - stat_etc_nomad_d_nomad_env.stat.exists + - stat_etc_nomad_d_nomad_env.stat.isreg + - stat_etc_nomad_d_nomad_env.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.mode == '0600' + - stat_etc_nomad_d_nomad_json.stat.exists + - stat_etc_nomad_d_nomad_json.stat.isreg + - stat_etc_nomad_d_nomad_json.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.mode == '0600' + - slurp_etc_nomad_d_nomad_json.content != '' + + - name: "Test: directory /opt/nomad" + block: + - name: "Stat directory /opt/nomad" + ansible.builtin.stat: + path: "/opt/nomad" + register: stat_opt_nomad + + - name: "Verify directory /opt/nomad" + ansible.builtin.assert: + that: + - stat_opt_nomad.stat.exists + - stat_opt_nomad.stat.isdir + - stat_opt_nomad.stat.pw_name == 'nomad' + - stat_opt_nomad.stat.gr_name == 'nomad' + - stat_opt_nomad.stat.mode == '0755' + + - name: "Test: service nomad" + block: + - name: "Get service nomad" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nomad.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nomad.service" + register: stat_etc_systemd_system_nomad_service + + - name: "Slurp file /etc/systemd/system/nomad.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nomad.service" + register: slurp_etc_systemd_system_nomad_service + + - name: "Verify service nomad" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nomad_service.stat.exists + - stat_etc_systemd_system_nomad_service.stat.isreg + - stat_etc_systemd_system_nomad_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.mode == '0644' + - slurp_etc_systemd_system_nomad_service.content != '' + - ansible_facts.services['nomad.service'] is defined + - ansible_facts.services['nomad.service']['source'] == 'systemd' + - ansible_facts.services['nomad.service']['state'] == 'running' + - ansible_facts.services['nomad.service']['status'] == 'enabled' + + - name: "Test: interaction nomad" + block: + - name: "Command nomad var put" + ansible.builtin.command: "nomad var put secret/foobar foo=bar" + changed_when: false + register: nomad_var_put + + - name: "Command nomad var get" + ansible.builtin.command: "nomad var get secret/foobar" + changed_when: false + register: nomad_var_get + + - name: "Command nomad var purge" + ansible.builtin.command: "nomad var purge secret/foobar" + changed_when: false + register: nomad_var_purge + + - name: "Command nomad server members" + ansible.builtin.command: "nomad server members" + changed_when: false + register: nomad_server_members + + - name: "Verify nomad interaction" + ansible.builtin.assert: + that: + - "'instance.global' in nomad_server_members.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_put.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_get.stdout" + - nomad_var_purge.stdout == 'Successfully purged variable \"secret/foobar\"!' diff --git a/roles/hashicorp_nomad/molecule/default_vagrant/converge.yml b/roles/hashicorp_nomad/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..4dfaa5b --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_nomad" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_nomad" diff --git a/roles/hashicorp_nomad/molecule/default_vagrant/molecule.yml b/roles/hashicorp_nomad/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_nomad/molecule/default_vagrant/requirements.yml b/roles/hashicorp_nomad/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_nomad/molecule/default_vagrant/verify.yml b/roles/hashicorp_nomad/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..6b173a9 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/default_vagrant/verify.yml @@ -0,0 +1,146 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: nomad user and group" + block: + - name: "Getent user nomad" + ansible.builtin.getent: + database: passwd + key: nomad + register: nomad_user + + - name: "Getent group nomad" + ansible.builtin.getent: + database: group + key: nomad + register: nomad_group + + - name: "Verify nomad user and group" + ansible.builtin.assert: + that: + - not nomad_user.failed + - not nomad_group.failed + - "'nomad' in nomad_user.ansible_facts.getent_passwd.keys()" + - "'/home/nomad' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'/bin/false' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'nomad' in nomad_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/nomad.d" + block: + - name: "Stat directory /etc/nomad.d" + ansible.builtin.stat: + path: "/etc/nomad.d" + register: stat_etc_nomad_d + + - name: "Stat file /etc/nomad.d/nomad.env" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.env" + register: stat_etc_nomad_d_nomad_env + + - name: "Stat file /etc/nomad.d/nomad.json" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.json" + register: stat_etc_nomad_d_nomad_json + + - name: "Slurp file /etc/nomad.d/nomad.json" + ansible.builtin.slurp: + src: "/etc/nomad.d/nomad.json" + register: slurp_etc_nomad_d_nomad_json + + - name: "Verify directory /etc/nomad.d" + ansible.builtin.assert: + that: + - stat_etc_nomad_d.stat.exists + - stat_etc_nomad_d.stat.isdir + - stat_etc_nomad_d.stat.pw_name == 'nomad' + - stat_etc_nomad_d.stat.gr_name == 'nomad' + - stat_etc_nomad_d.stat.mode == '0755' + - stat_etc_nomad_d_nomad_env.stat.exists + - stat_etc_nomad_d_nomad_env.stat.isreg + - stat_etc_nomad_d_nomad_env.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.mode == '0600' + - stat_etc_nomad_d_nomad_json.stat.exists + - stat_etc_nomad_d_nomad_json.stat.isreg + - stat_etc_nomad_d_nomad_json.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.mode == '0600' + - slurp_etc_nomad_d_nomad_json.content != '' + + - name: "Test: directory /opt/nomad" + block: + - name: "Stat directory /opt/nomad" + ansible.builtin.stat: + path: "/opt/nomad" + register: stat_opt_nomad + + - name: "Verify directory /opt/nomad" + ansible.builtin.assert: + that: + - stat_opt_nomad.stat.exists + - stat_opt_nomad.stat.isdir + - stat_opt_nomad.stat.pw_name == 'nomad' + - stat_opt_nomad.stat.gr_name == 'nomad' + - stat_opt_nomad.stat.mode == '0755' + + - name: "Test: service nomad" + block: + - name: "Get service nomad" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nomad.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nomad.service" + register: stat_etc_systemd_system_nomad_service + + - name: "Slurp file /etc/systemd/system/nomad.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nomad.service" + register: slurp_etc_systemd_system_nomad_service + + - name: "Verify service nomad" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nomad_service.stat.exists + - stat_etc_systemd_system_nomad_service.stat.isreg + - stat_etc_systemd_system_nomad_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.mode == '0644' + - slurp_etc_systemd_system_nomad_service.content != '' + - ansible_facts.services['nomad.service'] is defined + - ansible_facts.services['nomad.service']['source'] == 'systemd' + - ansible_facts.services['nomad.service']['state'] == 'running' + - ansible_facts.services['nomad.service']['status'] == 'enabled' + + - name: "Test: interaction nomad" + block: + - name: "Command nomad var put" + ansible.builtin.command: "nomad var put secret/foobar foo=bar" + changed_when: false + register: nomad_var_put + + - name: "Command nomad var get" + ansible.builtin.command: "nomad var get secret/foobar" + changed_when: false + register: nomad_var_get + + - name: "Command nomad var purge" + ansible.builtin.command: "nomad var purge secret/foobar" + changed_when: false + register: nomad_var_purge + + - name: "Command nomad server members" + ansible.builtin.command: "nomad server members" + changed_when: false + register: nomad_server_members + + - name: "Verify nomad interaction" + ansible.builtin.assert: + that: + - "'instance.global' in nomad_server_members.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_put.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_get.stdout" + - nomad_var_purge.stdout == 'Successfully purged variable \"secret/foobar\"!' diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled/converge.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled/converge.yml new file mode 100644 index 0000000..4dfaa5b --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_nomad" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_nomad" diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled/group_vars/all.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled/group_vars/all.yml new file mode 100644 index 0000000..2ca2b54 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled/group_vars/all.yml @@ -0,0 +1,86 @@ +--- +hashi_nomad_install: true +hashi_nomad_auto_update: true +hashi_nomad_cni_plugins_install: true +hashi_nomad_start_service: true +hashi_nomad_cni_plugins_version: latest +hashi_nomad_cni_plugins_install_path: "/opt/cni/bin" +hashi_nomad_version: latest +hashi_nomad_deploy_method: host # deployment method, either host or docker +hashi_nomad_env_variables: {} +hashi_nomad_data_dir: /opt/nomad +hashi_nomad_extra_files: true +hashi_nomad_extra_files_src: /tmp/extra_files +hashi_nomad_extra_files_dst: /etc/nomad.d/extra_files +#! nomad configuration +hashi_nomad_configuration: + bind_addr: "0.0.0.0" + datacenter: dc1 + log_level: INFO + leave_on_terminate: false + data_dir: "{{ hashi_nomad_data_dir }}" + advertise: + http: "{{ ansible_default_ipv4.address }}" + rpc: "{{ ansible_default_ipv4.address }}" + serf: "{{ ansible_default_ipv4.address }}" + server: + enabled: true + bootstrap_expect: 1 + server_join: + retry_join: + - "{{ ansible_default_ipv4.address }}" + client: + enabled: false + node_class: default + reserved: + cpu: 500 + memory: 300 + cni_path: "{{ hashi_nomad_cni_plugins_install_path }}" + bridge_network_name: nomad + bridge_network_subnet: "172.26.64.0/20" + ui: + enabled: true + acl: + enabled: true + token_ttl: 30s + policy_ttl: 30s + role_ttl: 30s + token_min_expiration_ttl: 30s + token_max_expiration_ttl: 24h + telemetry: + collection_interval: 1s + disable_hostname: false + use_node_name: false + publish_allocation_metrics: false + publish_node_metrics: false + prefix_filter: [] + disable_dispatched_job_summary_metrics: false + prometheus_metrics: false + # tls: + # http: false + # rpc: false + # ca_file: "{{ hashi_nomad_data_dir }}/tls/ca.pem" + # cert_file: "{{ hashi_nomad_data_dir }}/tls/cert.pem" + # key_file: "{{ hashi_nomad_data_dir }}/tls/key.pem" + # plugin: + # docker: + # config: + # endpoint: "unix:///var/run/docker.sock" + # allow_privileged: false + # allow_caps: ["all"] + # volumes: + # enabled: true + # consul: + # address: "127.0.0.1:8500" + # token: "" + # auto_advertise: true + # vault: + # address: http://vault.service.consul:8200 + # token: "" + # create_from_role: nomad-cluster + # plugin: + # docker: + # endpoint: "unix:///var/run/docker.sock" + # allow_privileged: false + # allow_caps: ["all"] + # volumes_enabled: true diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled/molecule.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled/molecule.yml new file mode 100644 index 0000000..59630f1 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_acl_enabled + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled/requirements.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled/verify.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled/verify.yml new file mode 100644 index 0000000..71ad567 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled/verify.yml @@ -0,0 +1,163 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: nomad user and group" + block: + - name: "Getent user nomad" + ansible.builtin.getent: + database: passwd + key: nomad + register: nomad_user + + - name: "Getent group nomad" + ansible.builtin.getent: + database: group + key: nomad + register: nomad_group + + - name: "Verify nomad user and group" + ansible.builtin.assert: + that: + - not nomad_user.failed + - not nomad_group.failed + - "'nomad' in nomad_user.ansible_facts.getent_passwd.keys()" + - "'/home/nomad' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'/bin/false' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'nomad' in nomad_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/nomad.d" + block: + - name: "Stat directory /etc/nomad.d" + ansible.builtin.stat: + path: "/etc/nomad.d" + register: stat_etc_nomad_d + + - name: "Stat file /etc/nomad.d/nomad.env" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.env" + register: stat_etc_nomad_d_nomad_env + + - name: "Stat file /etc/nomad.d/nomad.json" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.json" + register: stat_etc_nomad_d_nomad_json + + - name: "Slurp file /etc/nomad.d/nomad.json" + ansible.builtin.slurp: + src: "/etc/nomad.d/nomad.json" + register: slurp_etc_nomad_d_nomad_json + + - name: "Verify directory /etc/nomad.d" + ansible.builtin.assert: + that: + - stat_etc_nomad_d.stat.exists + - stat_etc_nomad_d.stat.isdir + - stat_etc_nomad_d.stat.pw_name == 'nomad' + - stat_etc_nomad_d.stat.gr_name == 'nomad' + - stat_etc_nomad_d.stat.mode == '0755' + - stat_etc_nomad_d_nomad_env.stat.exists + - stat_etc_nomad_d_nomad_env.stat.isreg + - stat_etc_nomad_d_nomad_env.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.mode == '0600' + - stat_etc_nomad_d_nomad_json.stat.exists + - stat_etc_nomad_d_nomad_json.stat.isreg + - stat_etc_nomad_d_nomad_json.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.mode == '0600' + - slurp_etc_nomad_d_nomad_json.content != '' + + - name: "Test: directory /opt/nomad" + block: + - name: "Stat directory /opt/nomad" + ansible.builtin.stat: + path: "/opt/nomad" + register: stat_opt_nomad + + - name: "Verify directory /opt/nomad" + ansible.builtin.assert: + that: + - stat_opt_nomad.stat.exists + - stat_opt_nomad.stat.isdir + - stat_opt_nomad.stat.pw_name == 'nomad' + - stat_opt_nomad.stat.gr_name == 'nomad' + - stat_opt_nomad.stat.mode == '0755' + + - name: "Test: service nomad" + block: + - name: "Get service nomad" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nomad.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nomad.service" + register: stat_etc_systemd_system_nomad_service + + - name: "Slurp file /etc/systemd/system/nomad.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nomad.service" + register: slurp_etc_systemd_system_nomad_service + + - name: "Verify service nomad" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nomad_service.stat.exists + - stat_etc_systemd_system_nomad_service.stat.isreg + - stat_etc_systemd_system_nomad_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.mode == '0644' + - slurp_etc_systemd_system_nomad_service.content != '' + - ansible_facts.services['nomad.service'] is defined + - ansible_facts.services['nomad.service']['source'] == 'systemd' + - ansible_facts.services['nomad.service']['state'] == 'running' + - ansible_facts.services['nomad.service']['status'] == 'enabled' + + - name: "Test: bootstrap acl nomad" + block: + - name: "Command nomad acl bootstrap" + ansible.builtin.command: "nomad acl bootstrap -json" + changed_when: false + register: nomad_acl_bootstrap + + - name: "Test: interaction nomad" + vars: + acl_token: "{{ nomad_acl_bootstrap.stdout|from_json|json_query('SecretID') }}" + block: + - name: "Command nomad var put" + ansible.builtin.command: "nomad var put secret/foobar foo=bar" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_var_put + + - name: "Command nomad var get" + ansible.builtin.command: "nomad var get secret/foobar" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_var_get + + - name: "Command nomad var purge" + ansible.builtin.command: "nomad var purge secret/foobar" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_var_purge + + - name: "Command nomad server members" + ansible.builtin.command: "nomad server members" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_server_members + + - name: "Verify nomad interaction" + ansible.builtin.assert: + that: + - "'instance.global' in nomad_server_members.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_put.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_get.stdout" + - nomad_var_purge.stdout == 'Successfully purged variable \"secret/foobar\"!' diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/converge.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/converge.yml new file mode 100644 index 0000000..4dfaa5b --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_nomad" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_nomad" diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/group_vars/all.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/group_vars/all.yml new file mode 100644 index 0000000..2ca2b54 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/group_vars/all.yml @@ -0,0 +1,86 @@ +--- +hashi_nomad_install: true +hashi_nomad_auto_update: true +hashi_nomad_cni_plugins_install: true +hashi_nomad_start_service: true +hashi_nomad_cni_plugins_version: latest +hashi_nomad_cni_plugins_install_path: "/opt/cni/bin" +hashi_nomad_version: latest +hashi_nomad_deploy_method: host # deployment method, either host or docker +hashi_nomad_env_variables: {} +hashi_nomad_data_dir: /opt/nomad +hashi_nomad_extra_files: true +hashi_nomad_extra_files_src: /tmp/extra_files +hashi_nomad_extra_files_dst: /etc/nomad.d/extra_files +#! nomad configuration +hashi_nomad_configuration: + bind_addr: "0.0.0.0" + datacenter: dc1 + log_level: INFO + leave_on_terminate: false + data_dir: "{{ hashi_nomad_data_dir }}" + advertise: + http: "{{ ansible_default_ipv4.address }}" + rpc: "{{ ansible_default_ipv4.address }}" + serf: "{{ ansible_default_ipv4.address }}" + server: + enabled: true + bootstrap_expect: 1 + server_join: + retry_join: + - "{{ ansible_default_ipv4.address }}" + client: + enabled: false + node_class: default + reserved: + cpu: 500 + memory: 300 + cni_path: "{{ hashi_nomad_cni_plugins_install_path }}" + bridge_network_name: nomad + bridge_network_subnet: "172.26.64.0/20" + ui: + enabled: true + acl: + enabled: true + token_ttl: 30s + policy_ttl: 30s + role_ttl: 30s + token_min_expiration_ttl: 30s + token_max_expiration_ttl: 24h + telemetry: + collection_interval: 1s + disable_hostname: false + use_node_name: false + publish_allocation_metrics: false + publish_node_metrics: false + prefix_filter: [] + disable_dispatched_job_summary_metrics: false + prometheus_metrics: false + # tls: + # http: false + # rpc: false + # ca_file: "{{ hashi_nomad_data_dir }}/tls/ca.pem" + # cert_file: "{{ hashi_nomad_data_dir }}/tls/cert.pem" + # key_file: "{{ hashi_nomad_data_dir }}/tls/key.pem" + # plugin: + # docker: + # config: + # endpoint: "unix:///var/run/docker.sock" + # allow_privileged: false + # allow_caps: ["all"] + # volumes: + # enabled: true + # consul: + # address: "127.0.0.1:8500" + # token: "" + # auto_advertise: true + # vault: + # address: http://vault.service.consul:8200 + # token: "" + # create_from_role: nomad-cluster + # plugin: + # docker: + # endpoint: "unix:///var/run/docker.sock" + # allow_privileged: false + # allow_caps: ["all"] + # volumes_enabled: true diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/molecule.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/molecule.yml new file mode 100644 index 0000000..0e6b593 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_acl_enabled_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/requirements.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/verify.yml b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/verify.yml new file mode 100644 index 0000000..71ad567 --- /dev/null +++ b/roles/hashicorp_nomad/molecule/with_acl_enabled_vagrant/verify.yml @@ -0,0 +1,163 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: nomad user and group" + block: + - name: "Getent user nomad" + ansible.builtin.getent: + database: passwd + key: nomad + register: nomad_user + + - name: "Getent group nomad" + ansible.builtin.getent: + database: group + key: nomad + register: nomad_group + + - name: "Verify nomad user and group" + ansible.builtin.assert: + that: + - not nomad_user.failed + - not nomad_group.failed + - "'nomad' in nomad_user.ansible_facts.getent_passwd.keys()" + - "'/home/nomad' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'/bin/false' in nomad_user.ansible_facts.getent_passwd['nomad']" + - "'nomad' in nomad_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/nomad.d" + block: + - name: "Stat directory /etc/nomad.d" + ansible.builtin.stat: + path: "/etc/nomad.d" + register: stat_etc_nomad_d + + - name: "Stat file /etc/nomad.d/nomad.env" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.env" + register: stat_etc_nomad_d_nomad_env + + - name: "Stat file /etc/nomad.d/nomad.json" + ansible.builtin.stat: + path: "/etc/nomad.d/nomad.json" + register: stat_etc_nomad_d_nomad_json + + - name: "Slurp file /etc/nomad.d/nomad.json" + ansible.builtin.slurp: + src: "/etc/nomad.d/nomad.json" + register: slurp_etc_nomad_d_nomad_json + + - name: "Verify directory /etc/nomad.d" + ansible.builtin.assert: + that: + - stat_etc_nomad_d.stat.exists + - stat_etc_nomad_d.stat.isdir + - stat_etc_nomad_d.stat.pw_name == 'nomad' + - stat_etc_nomad_d.stat.gr_name == 'nomad' + - stat_etc_nomad_d.stat.mode == '0755' + - stat_etc_nomad_d_nomad_env.stat.exists + - stat_etc_nomad_d_nomad_env.stat.isreg + - stat_etc_nomad_d_nomad_env.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_env.stat.mode == '0600' + - stat_etc_nomad_d_nomad_json.stat.exists + - stat_etc_nomad_d_nomad_json.stat.isreg + - stat_etc_nomad_d_nomad_json.stat.pw_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.gr_name == 'nomad' + - stat_etc_nomad_d_nomad_json.stat.mode == '0600' + - slurp_etc_nomad_d_nomad_json.content != '' + + - name: "Test: directory /opt/nomad" + block: + - name: "Stat directory /opt/nomad" + ansible.builtin.stat: + path: "/opt/nomad" + register: stat_opt_nomad + + - name: "Verify directory /opt/nomad" + ansible.builtin.assert: + that: + - stat_opt_nomad.stat.exists + - stat_opt_nomad.stat.isdir + - stat_opt_nomad.stat.pw_name == 'nomad' + - stat_opt_nomad.stat.gr_name == 'nomad' + - stat_opt_nomad.stat.mode == '0755' + + - name: "Test: service nomad" + block: + - name: "Get service nomad" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/nomad.service" + ansible.builtin.stat: + path: "/etc/systemd/system/nomad.service" + register: stat_etc_systemd_system_nomad_service + + - name: "Slurp file /etc/systemd/system/nomad.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/nomad.service" + register: slurp_etc_systemd_system_nomad_service + + - name: "Verify service nomad" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_nomad_service.stat.exists + - stat_etc_systemd_system_nomad_service.stat.isreg + - stat_etc_systemd_system_nomad_service.stat.pw_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.gr_name == 'root' + - stat_etc_systemd_system_nomad_service.stat.mode == '0644' + - slurp_etc_systemd_system_nomad_service.content != '' + - ansible_facts.services['nomad.service'] is defined + - ansible_facts.services['nomad.service']['source'] == 'systemd' + - ansible_facts.services['nomad.service']['state'] == 'running' + - ansible_facts.services['nomad.service']['status'] == 'enabled' + + - name: "Test: bootstrap acl nomad" + block: + - name: "Command nomad acl bootstrap" + ansible.builtin.command: "nomad acl bootstrap -json" + changed_when: false + register: nomad_acl_bootstrap + + - name: "Test: interaction nomad" + vars: + acl_token: "{{ nomad_acl_bootstrap.stdout|from_json|json_query('SecretID') }}" + block: + - name: "Command nomad var put" + ansible.builtin.command: "nomad var put secret/foobar foo=bar" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_var_put + + - name: "Command nomad var get" + ansible.builtin.command: "nomad var get secret/foobar" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_var_get + + - name: "Command nomad var purge" + ansible.builtin.command: "nomad var purge secret/foobar" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_var_purge + + - name: "Command nomad server members" + ansible.builtin.command: "nomad server members" + environment: + NOMAD_TOKEN: "{{ acl_token }}" + changed_when: false + register: nomad_server_members + + - name: "Verify nomad interaction" + ansible.builtin.assert: + that: + - "'instance.global' in nomad_server_members.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_put.stdout" + - "'\"Items\": {\n \"foo\": \"bar\"\n }' in nomad_var_get.stdout" + - nomad_var_purge.stdout == 'Successfully purged variable \"secret/foobar\"!' diff --git a/roles/hashicorp_nomad/tasks/cni_install.yml b/roles/hashicorp_nomad/tasks/cni_install.yml new file mode 100644 index 0000000..442bbb3 --- /dev/null +++ b/roles/hashicorp_nomad/tasks/cni_install.yml @@ -0,0 +1,73 @@ +--- +# task/cni_install file for hashicorp_nomad +- name: "Get release for cni_plugins:{{ hashi_nomad_cni_plugins_version }}" + vars: + _cni_plugins_url_ext: "{% if hashi_nomad_cni_plugins_version == 'latest'%}releases{% else %}releases/tags{% endif %}" + ansible.builtin.uri: + url: "{{ hashi_nomad_cni_plugins_github_api }}/{{ _cni_plugins_url_ext }}/{{ hashi_nomad_cni_plugins_version }}" + return_content: true + register: _cni_plugins_new_release + +- name: "Check if cni plugin is already installed" + ansible.builtin.stat: + path: "{{ hashi_nomad_cni_plugins_install_path }}/version" + changed_when: false + check_mode: false + register: _cni_plugins_is_installed + +- name: "Check current cni plugin version" + ansible.builtin.command: "cat {{ hashi_nomad_cni_plugins_install_path }}/version" + changed_when: false + check_mode: false + register: _cni_plugins_old_release + when: _cni_plugins_is_installed.stat.exists + +- name: "Set facts for wanted cni plugins release" + ansible.builtin.set_fact: + hashi_nomad_cni_plugins_wanted_version: "{{ _cni_plugins_new_release.json['tag_name']|regex_replace('v', '') }}" + when: _cni_plugins_new_release.json is defined + and (_cni_plugins_new_release.json | length > 0) + +- name: "Set facts for current cni plugins release" + ansible.builtin.set_fact: + hashi_nomad_cni_plugins_current_version: "{{ _cni_plugins_old_release.stdout | regex_replace('v', '') }}" + when: _cni_plugins_old_release.stdout is defined + and (_cni_plugins_old_release.stdout | length > 0) + +- name: "Create cni directory" + ansible.builtin.file: + path: "{{ hashi_nomad_cni_plugins_install_path }}" + state: directory + mode: "0775" + +- name: "Install cni plugins" + when: hashi_nomad_cni_plugins_current_version is not defined + or hashi_nomad_cni_plugins_wanted_version not in hashi_nomad_cni_plugins_current_version + block: + - name: "Install cni plugins version:{{ hashi_nomad_cni_plugins_version }}" + ansible.builtin.get_url: + url: "{{ hashi_nomad_cni_plugins_github_url }}/releases/download/v{{ hashi_nomad_cni_plugins_wanted_version }}/cni-plugins-linux-{{ hashi_nomad_cni_plugins_arch }}-v{{ hashi_nomad_cni_plugins_wanted_version }}.tgz" + dest: "/tmp/cni_plugin.tgz" + mode: "0644" + register: _cni_plugins_download_archive + until: _cni_plugins_download_archive is succeeded + retries: 5 + delay: 2 + check_mode: false + + - name: "Unpack cni plugins" + ansible.builtin.unarchive: + src: "/tmp/cni_plugin.tgz" + dest: "{{ hashi_nomad_cni_plugins_install_path }}" + remote_src: true + + - name: "Remove temporary archive" + ansible.builtin.file: + path: "/tmp/cni_plugin.tgz" + state: absent + + - name: "Update version file" + ansible.builtin.copy: + content: "{{ hashi_nomad_cni_plugins_wanted_version }}" + dest: "{{ hashi_nomad_cni_plugins_install_path }}/version" + mode: "0600" diff --git a/roles/hashicorp_nomad/tasks/configure.yml b/roles/hashicorp_nomad/tasks/configure.yml new file mode 100644 index 0000000..5be74a5 --- /dev/null +++ b/roles/hashicorp_nomad/tasks/configure.yml @@ -0,0 +1,46 @@ +--- +# task/configure file for hashicorp_nomad +- name: "Ensure default nomad.hcl is removed" + ansible.builtin.file: + path: /etc/nomad.d/nomad.hcl + state: absent + +- name: "Copy nomad.json template" + ansible.builtin.template: + src: nomad.json.j2 + dest: "{{ hashi_nomad_config_dir }}/nomad.json" + owner: "{{ hashi_nomad_user }}" + group: "{{ hashi_nomad_group }}" + mode: '0600' + notify: + - "systemctl-enable-nomad" + - "systemctl-restart-nomad" + +- name: "Create nomad.env" + ansible.builtin.template: + src: nomad.env.j2 + dest: "{{ hashi_nomad_config_dir }}/nomad.env" + owner: "{{ hashi_nomad_user }}" + group: "{{ hashi_nomad_group }}" + mode: '0600' + +- name: "Copy extra configuration files" + when: hashi_nomad_extra_files + block: + - name: "Create directory {{ hashi_nomad_extra_files_dst }}" + ansible.builtin.file: + path: "{{ hashi_nomad_extra_files_dst }}" + state: directory + owner: "{{ hashi_nomad_user }}" + group: "{{ hashi_nomad_group }}" + mode: '0755' + + - name: "Copy extra configuration files" + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ hashi_nomad_extra_files_dst }}/{{ (item | basename).split('.')[:-1] | join('.')}}" + owner: "{{ hashi_nomad_user }}" + group: "{{ hashi_nomad_group }}" + mode: '0600' + with_fileglob: + - "{{ hashi_nomad_extra_files_src }}/*" diff --git a/roles/hashicorp_nomad/tasks/install.yml b/roles/hashicorp_nomad/tasks/install.yml new file mode 100644 index 0000000..71f308b --- /dev/null +++ b/roles/hashicorp_nomad/tasks/install.yml @@ -0,0 +1,25 @@ +--- +# task/install file for hashicorp_nomad +- name: "Configure hashicorp repository" + ansible.builtin.include_role: + name: ednxzu.manage_repositories + vars: + manage_repositories_enable_default_repo: false + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: "{{ hashi_nomad_repository }}" + +- name: "Install nomad:{{ hashi_nomad_version }}" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ hashi_nomad_packages }}" + +- name: "Copy systemd service file for nomad" + ansible.builtin.template: + src: "nomad.service.j2" + dest: "/etc/systemd/system/nomad.service" + owner: root + group: root + mode: '0644' + notify: + - "systemctl-daemon-reload" diff --git a/roles/hashicorp_nomad/tasks/main.yml b/roles/hashicorp_nomad/tasks/main.yml new file mode 100644 index 0000000..c997106 --- /dev/null +++ b/roles/hashicorp_nomad/tasks/main.yml @@ -0,0 +1,15 @@ +--- +# task/main file for hashicorp_nomad +- name: "Import prerequisites.yml" + ansible.builtin.include_tasks: prerequisites.yml + +- name: "Import install.yml" + ansible.builtin.include_tasks: install.yml + when: hashi_nomad_install + +- name: "Import cni_install.yml" + ansible.builtin.include_tasks: cni_install.yml + when: hashi_nomad_cni_plugins_install + +- name: "Import configure.yml" + ansible.builtin.include_tasks: configure.yml diff --git a/roles/hashicorp_nomad/tasks/prerequisites.yml b/roles/hashicorp_nomad/tasks/prerequisites.yml new file mode 100644 index 0000000..a78d51a --- /dev/null +++ b/roles/hashicorp_nomad/tasks/prerequisites.yml @@ -0,0 +1,29 @@ +--- +# task/prerequisites file for hashicorp_nomad +- name: "Create group {{ hashi_nomad_group }}" + ansible.builtin.group: + name: "{{ hashi_nomad_user }}" + state: present + +- name: "Create user {{ hashi_nomad_user }}" + ansible.builtin.user: + name: "{{ hashi_nomad_user }}" + group: "{{ hashi_nomad_group }}" + shell: /bin/false + state: present + +- name: "Create directory {{ hashi_nomad_config_dir }}" + ansible.builtin.file: + path: "{{ hashi_nomad_config_dir }}" + state: directory + owner: "{{ hashi_nomad_user }}" + group: "{{ hashi_nomad_group }}" + mode: '0755' + +- name: "Create directory {{ hashi_nomad_data_dir }}" + ansible.builtin.file: + path: "{{ hashi_nomad_data_dir }}" + state: directory + owner: "{{ hashi_nomad_user }}" + group: "{{ hashi_nomad_group }}" + mode: '0755' diff --git a/roles/hashicorp_nomad/templates/nomad.env.j2 b/roles/hashicorp_nomad/templates/nomad.env.j2 new file mode 100644 index 0000000..60459d3 --- /dev/null +++ b/roles/hashicorp_nomad/templates/nomad.env.j2 @@ -0,0 +1,4 @@ +# {{ ansible_managed }} +{% for item in hashi_nomad_env_variables %} +{{ item|upper }}="{{ hashi_nomad_env_variables[item] }}" +{% endfor %} \ No newline at end of file diff --git a/roles/hashicorp_nomad/templates/nomad.json.j2 b/roles/hashicorp_nomad/templates/nomad.json.j2 new file mode 100644 index 0000000..2aae039 --- /dev/null +++ b/roles/hashicorp_nomad/templates/nomad.json.j2 @@ -0,0 +1 @@ +{{ hashi_nomad_configuration|to_nice_json }} diff --git a/roles/hashicorp_nomad/templates/nomad.service.j2 b/roles/hashicorp_nomad/templates/nomad.service.j2 new file mode 100644 index 0000000..70741c3 --- /dev/null +++ b/roles/hashicorp_nomad/templates/nomad.service.j2 @@ -0,0 +1,33 @@ +[Unit] +Description=Nomad +Documentation=https://developer.hashicorp.com/nomad/docs +Wants=network-online.target +After=network-online.target +ConditionFileNotEmpty={{ hashi_nomad_config_dir }}/nomad.json +{% if hashi_nomad_configuration.consul.address is defined %} +Wants=consul.service +After=consul.service +{% endif %} + +[Service] +EnvironmentFile=-{{ hashi_nomad_config_dir }}/nomad.env +{% if not (hashi_nomad_configuration.client.enabled is defined and hashi_nomad_configuration.client.enabled) %} +User={{ hashi_nomad_user }} +Group={{ hashi_nomad_group }} +{% else %} +User=root +Group=root +{% endif %} +ExecStart=/usr/bin/nomad agent -config {{ hashi_nomad_config_dir }}/nomad.json +ExecReload=/bin/kill -HUP $MAINPID +KillMode=process +KillSignal=SIGINT +Restart=on-failure +LimitNOFILE=65536 +LimitNPROC=infinity +RestartSec=2 +TasksMax=infinity +OOMScoreAdjust=-1000 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/hashicorp_nomad/vars/main.yml b/roles/hashicorp_nomad/vars/main.yml new file mode 100644 index 0000000..394bb5b --- /dev/null +++ b/roles/hashicorp_nomad/vars/main.yml @@ -0,0 +1,30 @@ +--- +# vars file for hashicorp_nomad +hashi_nomad_user: nomad +hashi_nomad_group: nomad +hashi_nomad_config_dir: "/etc/nomad.d" +hashi_nomad_cni_plugins_arch_map: + i386: '386' + x86_64: 'amd64' + aarch64: 'arm' + armv7l: 'arm' + armv6l: 'arm' +hashi_nomad_cni_plugins_arch: "{{ hashi_nomad_cni_plugins_arch_map[ansible_architecture] | default(ansible_architecture) }}" +hashi_nomad_cni_plugins_github_api: https://api.github.com/repos/containernetworking/plugins +hashi_nomad_cni_plugins_github_url: https://github.com/containernetworking/plugins +hashi_nomad_repository: + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" +hashi_nomad_packages: + - name: nomad + version: "{{ hashi_nomad_version }}" + state: "{% if hashi_nomad_auto_update %}latest{% else %}present{% endif %}" diff --git a/roles/hashicorp_vault/LICENSE b/roles/hashicorp_vault/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/hashicorp_vault/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/hashicorp_vault/README.md b/roles/hashicorp_vault/README.md new file mode 100644 index 0000000..1fac717 --- /dev/null +++ b/roles/hashicorp_vault/README.md @@ -0,0 +1,98 @@ +hashicorp_vault +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role install and configure vault on **debian-based** distributions. + +Requirements +------------ + +None. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/hashicorp_vault.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +hashi_vault_install: true # by default, set to true +``` +This variable defines if the vault package is to be installed or not before configuring. If you install vault using another task, you can set this to `false`. + +```yaml +hashi_vault_auto_update: false # by default, set to false +``` +This variable allows you to choose to automatically update vault if a newer version is available. Updating vault is usually pretty safe if done on a regular basis, but for better control over the upgrade process, see `hashi_vault_version`. + +```yaml +hashi_vault_start_service: true +``` +This variable defines if the vault service should be started once it has been configured. This is usefull in case you're using this role to build golden images, in which case you might want to only enable the service, to have it start on the next boot (when the image is launched) + +```yaml +hashi_vault_version: latest # by default, set to latest +``` +This variable specifies the version of vault to install when `hashi_vault_install` is set to `true`. The version to specify is the version of the package on the hashicorp repository (`1.10.1-1` for example). This can be found by running `apt-cache madison vault` on a machine with the repository installed. + +```yaml +hashi_vault_deploy_method: host # by default, set to host +``` +This variable defines the method of deployment of vault. The `host` method installs the binary directly on the host, and runs vault as a systemd service. The `docker` method install vault as a docker container. +> Currently, only the `host` method is available, the `docker` method will be added later. + +```yaml +hashi_vault_env_variables: # by default, set to {} + env_var: value +``` +This value is a list of key/value that will populate the `vault.env` file. You do not have to capitalize the KEYS, as it will be done automatically. + +```yaml +hashi_vault_data_dir: "/opt/vault" # by default, set to /opt/vault +``` +This value defines the path where consul data will be stored on the node. Defaults to `/opt/consul`. + +```yaml +hashi_vault_extra_files: false # by default, set to false +``` +This variable defines whether or not there is extra configuration files to copy to the target. If there are, these extra files are expected to be jinja2 templates located all in the same directory, and will be copied to the specified directory on the target machine. + +```yaml +hashi_vault_extra_files_src: /tmp/extra_files # by default, set to /tmp/extra_files +``` +This variable defines the source directory (without the trailing /) for the extra files to be copied in case there are some. + +```yaml +hashi_vault_extra_files_dst: /etc/vault.d/extra_files # by default, set to /etc/vault.d/extra_files +``` +This variable defines the destination directory (without the trailing /) for the extra files to be copied. + +```yaml +hashi_vault_configuration: {} # by default, set to a simple configuration +``` +This variable sets all of the configuration parameters for vault. For more information on all of them, please check the [documentation](https://developer.hashicorp.com/vault/docs/configuration). This variable is parsed and converted to json format to create the config file, so each key and value should be set according to the documentation. This method of passing configuration allows for compatibility with every configuration parameters that vault has to offer. The defaults are simply here to deploy a simple, single-node vault server without much configuration, and should NOT be used in production. You will want to edit this to deploy production-ready clusters. + +Dependencies +------------ + +`ednxzu.manage_repositories` to configure the hashicorp apt repository. +`ednxzu.manage_apt_packages` to install vault. + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.hashicorp_vault +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/hashicorp_vault/defaults/hashicorp_vault.yml.sample b/roles/hashicorp_vault/defaults/hashicorp_vault.yml.sample new file mode 100644 index 0000000..46b9522 --- /dev/null +++ b/roles/hashicorp_vault/defaults/hashicorp_vault.yml.sample @@ -0,0 +1,46 @@ +--- +# hashi_vault_install: true +# hashi_vault_auto_update: false +# hashi_vault_start_service: true +# hashi_vault_version: latest +# hashi_vault_deploy_method: host # deployment method, either host or docker +# hashi_vault_env_variables: {} +# hashi_vault_data_dir: "/opt/vault" +# hashi_vault_extra_files: false +# hashi_vault_extra_files_src: /tmp/extra_files +# hashi_vault_extra_files_dst: /etc/vault.d/extra_files +# #! vault configuration +# hashi_vault_configuration: +# cluster_name: vault +# cluster_addr: "https://127.0.0.1:8201" +# api_addr: "https://127.0.0.1:8200" +# ui: true +# disable_mlock: false +# disable_cache: false +# listener: +# tcp: +# address: "127.0.0.1:8200" +# cluster_address: "127.0.0.1:8201" +# tls_disable: 0 +# tls_disable_client_certs: false +# tls_cert_file: "{{ hashi_vault_data_dir }}/tls/tls.crt" # this use the autogenerated TLS certificates +# tls_key_file: "{{ hashi_vault_data_dir }}/tls/tls.key" # this use the autogenerated TLS certificates +# storage: +# file: +# path: "{{ hashi_vault_data_dir }}/data" +# # service_registration: +# # consul: +# # address: 127.0.0.1:8500 +# # scheme: https +# # token: someUUIDforconsul +# telemetry: +# usage_gauge_period: 10m +# maximum_gauge_cardinality: 500 +# disable_hostname: false +# enable_hostname_label: false +# lease_metrics_epsilon: 1h +# num_lease_metrics_buckets: 168 +# add_lease_metrics_namespace_labels: false +# filter_default: true +# prefix_filter: [] +# prometheus_retention_time: 24h diff --git a/roles/hashicorp_vault/defaults/main.yml b/roles/hashicorp_vault/defaults/main.yml new file mode 100644 index 0000000..6c8e571 --- /dev/null +++ b/roles/hashicorp_vault/defaults/main.yml @@ -0,0 +1,47 @@ +--- +# defaults file for hashicorp_vault +hashi_vault_install: true +hashi_vault_auto_update: false +hashi_vault_start_service: true +hashi_vault_version: latest +hashi_vault_deploy_method: host # deployment method, either host or docker +hashi_vault_env_variables: {} +hashi_vault_data_dir: "/opt/vault" +hashi_vault_extra_files: false +hashi_vault_extra_files_src: /tmp/extra_files +hashi_vault_extra_files_dst: /etc/vault.d/extra_files +#! vault configuration +hashi_vault_configuration: + cluster_name: vault + cluster_addr: "https://127.0.0.1:8201" + api_addr: "https://127.0.0.1:8200" + ui: true + disable_mlock: false + disable_cache: false + listener: + tcp: + address: "127.0.0.1:8200" + cluster_address: "127.0.0.1:8201" + tls_disable: 0 + tls_disable_client_certs: false + tls_cert_file: "{{ hashi_vault_data_dir }}/tls/tls.crt" # this use the autogenerated TLS certificates + tls_key_file: "{{ hashi_vault_data_dir }}/tls/tls.key" # this use the autogenerated TLS certificates + storage: + file: + path: "{{ hashi_vault_data_dir }}/data" + # service_registration: + # consul: + # address: 127.0.0.1:8500 + # scheme: https + # token: someUUIDforconsul + telemetry: + usage_gauge_period: 10m + maximum_gauge_cardinality: 500 + disable_hostname: false + enable_hostname_label: false + lease_metrics_epsilon: 1h + num_lease_metrics_buckets: 168 + add_lease_metrics_namespace_labels: false + filter_default: true + prefix_filter: [] + prometheus_retention_time: 24h diff --git a/roles/hashicorp_vault/handlers/main.yml b/roles/hashicorp_vault/handlers/main.yml new file mode 100644 index 0000000..22ad3a1 --- /dev/null +++ b/roles/hashicorp_vault/handlers/main.yml @@ -0,0 +1,20 @@ +--- +# handlers file for hashicorp_vault +- name: "Reload systemd file" + ansible.builtin.systemd: + daemon_reload: true + listen: "systemctl-daemon-reload" + +- name: "Enable vault service" + ansible.builtin.service: + name: vault + enabled: true + listen: "systemctl-enable-vault" + +- name: "Start vault service" + ansible.builtin.service: + name: vault + state: restarted + listen: "systemctl-restart-vault" + throttle: 1 + when: hashi_vault_start_service diff --git a/roles/hashicorp_vault/meta/main.yml b/roles/hashicorp_vault/meta/main.yml new file mode 100644 index 0000000..3e001d3 --- /dev/null +++ b/roles/hashicorp_vault/meta/main.yml @@ -0,0 +1,25 @@ +--- +# meta file for hashicorp_vault +galaxy_info: + namespace: 'ednxzu' + role_name: 'hashicorp_vault' + author: 'Bertrand Lanson' + description: 'Install and configure hashicorp vault for debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'hashicorp' + - 'vault' + +dependencies: [] diff --git a/roles/hashicorp_vault/molecule/default/converge.yml b/roles/hashicorp_vault/molecule/default/converge.yml new file mode 100644 index 0000000..96ffa3c --- /dev/null +++ b/roles/hashicorp_vault/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_vault" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_vault" diff --git a/roles/hashicorp_vault/molecule/default/molecule.yml b/roles/hashicorp_vault/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/hashicorp_vault/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_vault/molecule/default/requirements.yml b/roles/hashicorp_vault/molecule/default/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_vault/molecule/default/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_vault/molecule/default/verify.yml b/roles/hashicorp_vault/molecule/default/verify.yml new file mode 100644 index 0000000..5a577f5 --- /dev/null +++ b/roles/hashicorp_vault/molecule/default/verify.yml @@ -0,0 +1,162 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: vault user and group" + block: + - name: "Getent user vault" + ansible.builtin.getent: + database: passwd + key: vault + register: vault_user + + - name: "Getent group vault" + ansible.builtin.getent: + database: group + key: vault + register: vault_group + + - name: "Verify vault user and group" + ansible.builtin.assert: + that: + - not vault_user.failed + - not vault_group.failed + - "'vault' in vault_user.ansible_facts.getent_passwd.keys()" + - "'/home/vault' in vault_user.ansible_facts.getent_passwd['vault']" + - "'/bin/false' in vault_user.ansible_facts.getent_passwd['vault']" + - "'vault' in vault_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/vault.d" + block: + - name: "Stat directory /etc/vault.d" + ansible.builtin.stat: + path: "/etc/vault.d" + register: stat_etc_vault_d + + - name: "Stat file /etc/vault.d/vault.env" + ansible.builtin.stat: + path: "/etc/vault.d/vault.env" + register: stat_etc_vault_d_vault_env + + - name: "Stat file /etc/vault.d/vault.json" + ansible.builtin.stat: + path: "/etc/vault.d/vault.json" + register: stat_etc_vault_d_vault_json + + - name: "Slurp file /etc/vault.d/vault.json" + ansible.builtin.slurp: + src: "/etc/vault.d/vault.json" + register: slurp_etc_vault_d_vault_json + + - name: "Verify directory /etc/vault.d" + ansible.builtin.assert: + that: + - stat_etc_vault_d.stat.exists + - stat_etc_vault_d.stat.isdir + - stat_etc_vault_d.stat.pw_name == 'vault' + - stat_etc_vault_d.stat.gr_name == 'vault' + - stat_etc_vault_d.stat.mode == '0755' + - stat_etc_vault_d_vault_env.stat.exists + - stat_etc_vault_d_vault_env.stat.isreg + - stat_etc_vault_d_vault_env.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_env.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_env.stat.mode == '0600' + - stat_etc_vault_d_vault_json.stat.exists + - stat_etc_vault_d_vault_json.stat.isreg + - stat_etc_vault_d_vault_json.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_json.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_json.stat.mode == '0600' + - slurp_etc_vault_d_vault_json.content != '' + + - name: "Test: directory /opt/vault" + block: + - name: "Stat directory /opt/vault" + ansible.builtin.stat: + path: "/opt/vault" + register: stat_opt_vault + + - name: "Verify directory /opt/vault" + ansible.builtin.assert: + that: + - stat_opt_vault.stat.exists + - stat_opt_vault.stat.isdir + - stat_opt_vault.stat.pw_name == 'vault' + - stat_opt_vault.stat.gr_name == 'vault' + - stat_opt_vault.stat.mode == '0755' + + - name: "Test: service vault" + block: + - name: "Get service vault" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/vault.service" + ansible.builtin.stat: + path: "/etc/systemd/system/vault.service" + register: stat_etc_systemd_system_vault_service + + - name: "Slurp file /etc/systemd/system/vault.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/vault.service" + register: slurp_etc_systemd_system_vault_service + + - name: "Verify service vault" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_vault_service.stat.exists + - stat_etc_systemd_system_vault_service.stat.isreg + - stat_etc_systemd_system_vault_service.stat.pw_name == 'root' + - stat_etc_systemd_system_vault_service.stat.gr_name == 'root' + - stat_etc_systemd_system_vault_service.stat.mode == '0644' + - slurp_etc_systemd_system_vault_service.content != '' + - ansible_facts.services['vault.service'] is defined + - ansible_facts.services['vault.service']['source'] == 'systemd' + - ansible_facts.services['vault.service']['state'] == 'running' + - ansible_facts.services['vault.service']['status'] == 'enabled' + + - name: "Test: bootstrap vault cluster" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator init -non-interactive -key-shares=3 -key-threshold=2 -tls-skip-verify -format=json" + changed_when: false + register: vault_operator_init + + - name: "Test: unseal vault cluster" + vars: + vault_unseal_keys: "{{ vault_operator_init.stdout|from_json|json_query('unseal_keys_hex') }}" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[0] }}" + changed_when: false + register: vault_operator_unseal_0 + + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[1] }}" + changed_when: false + register: vault_operator_unseal_1 + + - name: "Verify vault operator unseal" + vars: + vault_seal_state_0: "{{ vault_operator_unseal_0.stdout|from_json|json_query('sealed') }}" + vault_seal_state_1: "{{ vault_operator_unseal_1.stdout|from_json|json_query('sealed') }}" + ansible.builtin.assert: + that: + - vault_seal_state_0 + - not vault_seal_state_1 + + - name: "Test: vault interaction" + vars: + root_token: "{{ vault_operator_init.stdout|from_json|json_query('root_token') }}" + block: + - name: "Command vault secret enable" + ansible.builtin.command: "vault secrets enable -version=1 -tls-skip-verify kv" + environment: + VAULT_TOKEN: "{{ root_token }}" + changed_when: false + register: vault_secret_enable + + - name: "Verify vault interaction" + ansible.builtin.assert: + that: + - vault_secret_enable.stdout == 'Success! Enabled the kv secrets engine at: kv/' diff --git a/roles/hashicorp_vault/molecule/default_vagrant/converge.yml b/roles/hashicorp_vault/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..96ffa3c --- /dev/null +++ b/roles/hashicorp_vault/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_vault" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_vault" diff --git a/roles/hashicorp_vault/molecule/default_vagrant/molecule.yml b/roles/hashicorp_vault/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/hashicorp_vault/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_vault/molecule/default_vagrant/requirements.yml b/roles/hashicorp_vault/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_vault/molecule/default_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_vault/molecule/default_vagrant/verify.yml b/roles/hashicorp_vault/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..5a577f5 --- /dev/null +++ b/roles/hashicorp_vault/molecule/default_vagrant/verify.yml @@ -0,0 +1,162 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: vault user and group" + block: + - name: "Getent user vault" + ansible.builtin.getent: + database: passwd + key: vault + register: vault_user + + - name: "Getent group vault" + ansible.builtin.getent: + database: group + key: vault + register: vault_group + + - name: "Verify vault user and group" + ansible.builtin.assert: + that: + - not vault_user.failed + - not vault_group.failed + - "'vault' in vault_user.ansible_facts.getent_passwd.keys()" + - "'/home/vault' in vault_user.ansible_facts.getent_passwd['vault']" + - "'/bin/false' in vault_user.ansible_facts.getent_passwd['vault']" + - "'vault' in vault_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/vault.d" + block: + - name: "Stat directory /etc/vault.d" + ansible.builtin.stat: + path: "/etc/vault.d" + register: stat_etc_vault_d + + - name: "Stat file /etc/vault.d/vault.env" + ansible.builtin.stat: + path: "/etc/vault.d/vault.env" + register: stat_etc_vault_d_vault_env + + - name: "Stat file /etc/vault.d/vault.json" + ansible.builtin.stat: + path: "/etc/vault.d/vault.json" + register: stat_etc_vault_d_vault_json + + - name: "Slurp file /etc/vault.d/vault.json" + ansible.builtin.slurp: + src: "/etc/vault.d/vault.json" + register: slurp_etc_vault_d_vault_json + + - name: "Verify directory /etc/vault.d" + ansible.builtin.assert: + that: + - stat_etc_vault_d.stat.exists + - stat_etc_vault_d.stat.isdir + - stat_etc_vault_d.stat.pw_name == 'vault' + - stat_etc_vault_d.stat.gr_name == 'vault' + - stat_etc_vault_d.stat.mode == '0755' + - stat_etc_vault_d_vault_env.stat.exists + - stat_etc_vault_d_vault_env.stat.isreg + - stat_etc_vault_d_vault_env.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_env.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_env.stat.mode == '0600' + - stat_etc_vault_d_vault_json.stat.exists + - stat_etc_vault_d_vault_json.stat.isreg + - stat_etc_vault_d_vault_json.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_json.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_json.stat.mode == '0600' + - slurp_etc_vault_d_vault_json.content != '' + + - name: "Test: directory /opt/vault" + block: + - name: "Stat directory /opt/vault" + ansible.builtin.stat: + path: "/opt/vault" + register: stat_opt_vault + + - name: "Verify directory /opt/vault" + ansible.builtin.assert: + that: + - stat_opt_vault.stat.exists + - stat_opt_vault.stat.isdir + - stat_opt_vault.stat.pw_name == 'vault' + - stat_opt_vault.stat.gr_name == 'vault' + - stat_opt_vault.stat.mode == '0755' + + - name: "Test: service vault" + block: + - name: "Get service vault" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/vault.service" + ansible.builtin.stat: + path: "/etc/systemd/system/vault.service" + register: stat_etc_systemd_system_vault_service + + - name: "Slurp file /etc/systemd/system/vault.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/vault.service" + register: slurp_etc_systemd_system_vault_service + + - name: "Verify service vault" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_vault_service.stat.exists + - stat_etc_systemd_system_vault_service.stat.isreg + - stat_etc_systemd_system_vault_service.stat.pw_name == 'root' + - stat_etc_systemd_system_vault_service.stat.gr_name == 'root' + - stat_etc_systemd_system_vault_service.stat.mode == '0644' + - slurp_etc_systemd_system_vault_service.content != '' + - ansible_facts.services['vault.service'] is defined + - ansible_facts.services['vault.service']['source'] == 'systemd' + - ansible_facts.services['vault.service']['state'] == 'running' + - ansible_facts.services['vault.service']['status'] == 'enabled' + + - name: "Test: bootstrap vault cluster" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator init -non-interactive -key-shares=3 -key-threshold=2 -tls-skip-verify -format=json" + changed_when: false + register: vault_operator_init + + - name: "Test: unseal vault cluster" + vars: + vault_unseal_keys: "{{ vault_operator_init.stdout|from_json|json_query('unseal_keys_hex') }}" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[0] }}" + changed_when: false + register: vault_operator_unseal_0 + + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[1] }}" + changed_when: false + register: vault_operator_unseal_1 + + - name: "Verify vault operator unseal" + vars: + vault_seal_state_0: "{{ vault_operator_unseal_0.stdout|from_json|json_query('sealed') }}" + vault_seal_state_1: "{{ vault_operator_unseal_1.stdout|from_json|json_query('sealed') }}" + ansible.builtin.assert: + that: + - vault_seal_state_0 + - not vault_seal_state_1 + + - name: "Test: vault interaction" + vars: + root_token: "{{ vault_operator_init.stdout|from_json|json_query('root_token') }}" + block: + - name: "Command vault secret enable" + ansible.builtin.command: "vault secrets enable -version=1 -tls-skip-verify kv" + environment: + VAULT_TOKEN: "{{ root_token }}" + changed_when: false + register: vault_secret_enable + + - name: "Verify vault interaction" + ansible.builtin.assert: + that: + - vault_secret_enable.stdout == 'Success! Enabled the kv secrets engine at: kv/' diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled/converge.yml b/roles/hashicorp_vault/molecule/with_raft_enabled/converge.yml new file mode 100644 index 0000000..96ffa3c --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_vault" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_vault" diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled/group_vars/all.yml b/roles/hashicorp_vault/molecule/with_raft_enabled/group_vars/all.yml new file mode 100644 index 0000000..8689496 --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled/group_vars/all.yml @@ -0,0 +1,52 @@ +--- +# defaults file for hashicorp_vault +hashi_vault_install: true +hashi_vault_auto_update: true +hashi_vault_start_service: true +hashi_vault_version: latest +hashi_vault_deploy_method: host # deployment method, either host or docker +hashi_vault_env_variables: {} +hashi_vault_data_dir: "/opt/vault" +hashi_vault_extra_files: false +hashi_vault_extra_files_src: /tmp/extra_files +hashi_vault_extra_files_dst: /etc/vault.d/extra_files +#! vault configuration +hashi_vault_configuration: + cluster_name: vault + cluster_addr: "http://127.0.0.1:8201" + api_addr: "http://127.0.0.1:8200" + ui: true + disable_mlock: false + disable_cache: false + listener: + tcp: + address: "127.0.0.1:8200" + cluster_address: "127.0.0.1:8201" + tls_disable: 1 + tls_disable_client_certs: false + tls_cert_file: "{{ hashi_vault_data_dir }}/tls/tls.crt" # this use the autogenerated TLS certificates + tls_key_file: "{{ hashi_vault_data_dir }}/tls/tls.key" # this use the autogenerated TLS certificates + storage: + raft: + path: "{{ hashi_vault_data_dir }}/data" + node_id: "{{ ansible_hostname }}" + retry_join: + - leader_api_addr: "http://127.0.0.1:8200" + - leader_api_addr: "http://127.0.0.2:8200" + - leader_api_addr: "http://127.0.0.3:8200" + # service_registration: + # consul: + # address: 127.0.0.1:8500 + # scheme: https + # token: someUUIDforconsul + telemetry: + usage_gauge_period: 10m + maximum_gauge_cardinality: 500 + disable_hostname: false + enable_hostname_label: false + lease_metrics_epsilon: 1h + num_lease_metrics_buckets: 168 + add_lease_metrics_namespace_labels: false + filter_default: true + prefix_filter: [] + prometheus_retention_time: 24h diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled/molecule.yml b/roles/hashicorp_vault/molecule/with_raft_enabled/molecule.yml new file mode 100644 index 0000000..fe9d010 --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_raft_enabled + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled/requirements.yml b/roles/hashicorp_vault/molecule/with_raft_enabled/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled/verify.yml b/roles/hashicorp_vault/molecule/with_raft_enabled/verify.yml new file mode 100644 index 0000000..d1c06e8 --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled/verify.yml @@ -0,0 +1,169 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: vault user and group" + block: + - name: "Getent user vault" + ansible.builtin.getent: + database: passwd + key: vault + register: vault_user + + - name: "Getent group vault" + ansible.builtin.getent: + database: group + key: vault + register: vault_group + + - name: "Verify vault user and group" + ansible.builtin.assert: + that: + - not vault_user.failed + - not vault_group.failed + - "'vault' in vault_user.ansible_facts.getent_passwd.keys()" + - "'/home/vault' in vault_user.ansible_facts.getent_passwd['vault']" + - "'/bin/false' in vault_user.ansible_facts.getent_passwd['vault']" + - "'vault' in vault_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/vault.d" + block: + - name: "Stat directory /etc/vault.d" + ansible.builtin.stat: + path: "/etc/vault.d" + register: stat_etc_vault_d + + - name: "Stat file /etc/vault.d/vault.env" + ansible.builtin.stat: + path: "/etc/vault.d/vault.env" + register: stat_etc_vault_d_vault_env + + - name: "Stat file /etc/vault.d/vault.json" + ansible.builtin.stat: + path: "/etc/vault.d/vault.json" + register: stat_etc_vault_d_vault_json + + - name: "Slurp file /etc/vault.d/vault.json" + ansible.builtin.slurp: + src: "/etc/vault.d/vault.json" + register: slurp_etc_vault_d_vault_json + + - name: "Verify directory /etc/vault.d" + ansible.builtin.assert: + that: + - stat_etc_vault_d.stat.exists + - stat_etc_vault_d.stat.isdir + - stat_etc_vault_d.stat.pw_name == 'vault' + - stat_etc_vault_d.stat.gr_name == 'vault' + - stat_etc_vault_d.stat.mode == '0755' + - stat_etc_vault_d_vault_env.stat.exists + - stat_etc_vault_d_vault_env.stat.isreg + - stat_etc_vault_d_vault_env.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_env.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_env.stat.mode == '0600' + - stat_etc_vault_d_vault_json.stat.exists + - stat_etc_vault_d_vault_json.stat.isreg + - stat_etc_vault_d_vault_json.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_json.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_json.stat.mode == '0600' + - slurp_etc_vault_d_vault_json.content != '' + + - name: "Test: directory /opt/vault" + block: + - name: "Stat directory /opt/vault" + ansible.builtin.stat: + path: "/opt/vault" + register: stat_opt_vault + + - name: "Verify directory /opt/vault" + ansible.builtin.assert: + that: + - stat_opt_vault.stat.exists + - stat_opt_vault.stat.isdir + - stat_opt_vault.stat.pw_name == 'vault' + - stat_opt_vault.stat.gr_name == 'vault' + - stat_opt_vault.stat.mode == '0755' + + - name: "Test: service vault" + block: + - name: "Get service vault" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/vault.service" + ansible.builtin.stat: + path: "/etc/systemd/system/vault.service" + register: stat_etc_systemd_system_vault_service + + - name: "Slurp file /etc/systemd/system/vault.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/vault.service" + register: slurp_etc_systemd_system_vault_service + + - name: "Verify service vault" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_vault_service.stat.exists + - stat_etc_systemd_system_vault_service.stat.isreg + - stat_etc_systemd_system_vault_service.stat.pw_name == 'root' + - stat_etc_systemd_system_vault_service.stat.gr_name == 'root' + - stat_etc_systemd_system_vault_service.stat.mode == '0644' + - slurp_etc_systemd_system_vault_service.content != '' + - ansible_facts.services['vault.service'] is defined + - ansible_facts.services['vault.service']['source'] == 'systemd' + - ansible_facts.services['vault.service']['state'] == 'running' + - ansible_facts.services['vault.service']['status'] == 'enabled' + + - name: "Test: bootstrap vault cluster" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator init -non-interactive -key-shares=3 -key-threshold=2 -tls-skip-verify -format=json" + environment: + VAULT_ADDR: "http://localhost:8200" + changed_when: false + register: vault_operator_init + + - name: "Test: unseal vault cluster" + vars: + vault_unseal_keys: "{{ vault_operator_init.stdout|from_json|json_query('unseal_keys_hex') }}" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[0] }}" + environment: + VAULT_ADDR: "http://localhost:8200" + changed_when: false + register: vault_operator_unseal_0 + + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[1] }}" + environment: + VAULT_ADDR: "http://localhost:8200" + changed_when: false + register: vault_operator_unseal_1 + + - name: "Verify vault operator unseal" + vars: + vault_seal_state_0: "{{ vault_operator_unseal_0.stdout|from_json|json_query('sealed') }}" + vault_seal_state_1: "{{ vault_operator_unseal_1.stdout|from_json|json_query('sealed') }}" + ansible.builtin.assert: + that: + - vault_seal_state_0 + - not vault_seal_state_1 + + - name: "Test: vault interaction" + vars: + root_token: "{{ vault_operator_init.stdout|from_json|json_query('root_token') }}" + block: + - name: "Command vault secret enable" + ansible.builtin.command: "vault secrets enable -version=1 -tls-skip-verify kv" + environment: + VAULT_ADDR: "http://localhost:8200" + VAULT_TOKEN: "{{ root_token }}" + changed_when: false + register: vault_secret_enable + + - name: "Verify vault interaction" + ansible.builtin.assert: + that: + - vault_secret_enable.stdout == 'Success! Enabled the kv secrets engine at: kv/' diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/converge.yml b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/converge.yml new file mode 100644 index 0000000..96ffa3c --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.hashicorp_vault" + ansible.builtin.include_role: + name: "ednxzu.hashicorp_vault" diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/group_vars/all.yml b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/group_vars/all.yml new file mode 100644 index 0000000..8689496 --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/group_vars/all.yml @@ -0,0 +1,52 @@ +--- +# defaults file for hashicorp_vault +hashi_vault_install: true +hashi_vault_auto_update: true +hashi_vault_start_service: true +hashi_vault_version: latest +hashi_vault_deploy_method: host # deployment method, either host or docker +hashi_vault_env_variables: {} +hashi_vault_data_dir: "/opt/vault" +hashi_vault_extra_files: false +hashi_vault_extra_files_src: /tmp/extra_files +hashi_vault_extra_files_dst: /etc/vault.d/extra_files +#! vault configuration +hashi_vault_configuration: + cluster_name: vault + cluster_addr: "http://127.0.0.1:8201" + api_addr: "http://127.0.0.1:8200" + ui: true + disable_mlock: false + disable_cache: false + listener: + tcp: + address: "127.0.0.1:8200" + cluster_address: "127.0.0.1:8201" + tls_disable: 1 + tls_disable_client_certs: false + tls_cert_file: "{{ hashi_vault_data_dir }}/tls/tls.crt" # this use the autogenerated TLS certificates + tls_key_file: "{{ hashi_vault_data_dir }}/tls/tls.key" # this use the autogenerated TLS certificates + storage: + raft: + path: "{{ hashi_vault_data_dir }}/data" + node_id: "{{ ansible_hostname }}" + retry_join: + - leader_api_addr: "http://127.0.0.1:8200" + - leader_api_addr: "http://127.0.0.2:8200" + - leader_api_addr: "http://127.0.0.3:8200" + # service_registration: + # consul: + # address: 127.0.0.1:8500 + # scheme: https + # token: someUUIDforconsul + telemetry: + usage_gauge_period: 10m + maximum_gauge_cardinality: 500 + disable_hostname: false + enable_hostname_label: false + lease_metrics_epsilon: 1h + num_lease_metrics_buckets: 168 + add_lease_metrics_namespace_labels: false + filter_default: true + prefix_filter: [] + prometheus_retention_time: 24h diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/molecule.yml b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/molecule.yml new file mode 100644 index 0000000..bb8d9b1 --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_raft_enabled_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/requirements.yml b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/verify.yml b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/verify.yml new file mode 100644 index 0000000..d1c06e8 --- /dev/null +++ b/roles/hashicorp_vault/molecule/with_raft_enabled_vagrant/verify.yml @@ -0,0 +1,169 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: vault user and group" + block: + - name: "Getent user vault" + ansible.builtin.getent: + database: passwd + key: vault + register: vault_user + + - name: "Getent group vault" + ansible.builtin.getent: + database: group + key: vault + register: vault_group + + - name: "Verify vault user and group" + ansible.builtin.assert: + that: + - not vault_user.failed + - not vault_group.failed + - "'vault' in vault_user.ansible_facts.getent_passwd.keys()" + - "'/home/vault' in vault_user.ansible_facts.getent_passwd['vault']" + - "'/bin/false' in vault_user.ansible_facts.getent_passwd['vault']" + - "'vault' in vault_group.ansible_facts.getent_group.keys()" + + - name: "Test: directory /etc/vault.d" + block: + - name: "Stat directory /etc/vault.d" + ansible.builtin.stat: + path: "/etc/vault.d" + register: stat_etc_vault_d + + - name: "Stat file /etc/vault.d/vault.env" + ansible.builtin.stat: + path: "/etc/vault.d/vault.env" + register: stat_etc_vault_d_vault_env + + - name: "Stat file /etc/vault.d/vault.json" + ansible.builtin.stat: + path: "/etc/vault.d/vault.json" + register: stat_etc_vault_d_vault_json + + - name: "Slurp file /etc/vault.d/vault.json" + ansible.builtin.slurp: + src: "/etc/vault.d/vault.json" + register: slurp_etc_vault_d_vault_json + + - name: "Verify directory /etc/vault.d" + ansible.builtin.assert: + that: + - stat_etc_vault_d.stat.exists + - stat_etc_vault_d.stat.isdir + - stat_etc_vault_d.stat.pw_name == 'vault' + - stat_etc_vault_d.stat.gr_name == 'vault' + - stat_etc_vault_d.stat.mode == '0755' + - stat_etc_vault_d_vault_env.stat.exists + - stat_etc_vault_d_vault_env.stat.isreg + - stat_etc_vault_d_vault_env.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_env.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_env.stat.mode == '0600' + - stat_etc_vault_d_vault_json.stat.exists + - stat_etc_vault_d_vault_json.stat.isreg + - stat_etc_vault_d_vault_json.stat.pw_name == 'vault' + - stat_etc_vault_d_vault_json.stat.gr_name == 'vault' + - stat_etc_vault_d_vault_json.stat.mode == '0600' + - slurp_etc_vault_d_vault_json.content != '' + + - name: "Test: directory /opt/vault" + block: + - name: "Stat directory /opt/vault" + ansible.builtin.stat: + path: "/opt/vault" + register: stat_opt_vault + + - name: "Verify directory /opt/vault" + ansible.builtin.assert: + that: + - stat_opt_vault.stat.exists + - stat_opt_vault.stat.isdir + - stat_opt_vault.stat.pw_name == 'vault' + - stat_opt_vault.stat.gr_name == 'vault' + - stat_opt_vault.stat.mode == '0755' + + - name: "Test: service vault" + block: + - name: "Get service vault" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/vault.service" + ansible.builtin.stat: + path: "/etc/systemd/system/vault.service" + register: stat_etc_systemd_system_vault_service + + - name: "Slurp file /etc/systemd/system/vault.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/vault.service" + register: slurp_etc_systemd_system_vault_service + + - name: "Verify service vault" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_vault_service.stat.exists + - stat_etc_systemd_system_vault_service.stat.isreg + - stat_etc_systemd_system_vault_service.stat.pw_name == 'root' + - stat_etc_systemd_system_vault_service.stat.gr_name == 'root' + - stat_etc_systemd_system_vault_service.stat.mode == '0644' + - slurp_etc_systemd_system_vault_service.content != '' + - ansible_facts.services['vault.service'] is defined + - ansible_facts.services['vault.service']['source'] == 'systemd' + - ansible_facts.services['vault.service']['state'] == 'running' + - ansible_facts.services['vault.service']['status'] == 'enabled' + + - name: "Test: bootstrap vault cluster" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator init -non-interactive -key-shares=3 -key-threshold=2 -tls-skip-verify -format=json" + environment: + VAULT_ADDR: "http://localhost:8200" + changed_when: false + register: vault_operator_init + + - name: "Test: unseal vault cluster" + vars: + vault_unseal_keys: "{{ vault_operator_init.stdout|from_json|json_query('unseal_keys_hex') }}" + block: + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[0] }}" + environment: + VAULT_ADDR: "http://localhost:8200" + changed_when: false + register: vault_operator_unseal_0 + + - name: "Command vault operator init" + ansible.builtin.command: "vault operator unseal -format=json -tls-skip-verify {{ vault_unseal_keys[1] }}" + environment: + VAULT_ADDR: "http://localhost:8200" + changed_when: false + register: vault_operator_unseal_1 + + - name: "Verify vault operator unseal" + vars: + vault_seal_state_0: "{{ vault_operator_unseal_0.stdout|from_json|json_query('sealed') }}" + vault_seal_state_1: "{{ vault_operator_unseal_1.stdout|from_json|json_query('sealed') }}" + ansible.builtin.assert: + that: + - vault_seal_state_0 + - not vault_seal_state_1 + + - name: "Test: vault interaction" + vars: + root_token: "{{ vault_operator_init.stdout|from_json|json_query('root_token') }}" + block: + - name: "Command vault secret enable" + ansible.builtin.command: "vault secrets enable -version=1 -tls-skip-verify kv" + environment: + VAULT_ADDR: "http://localhost:8200" + VAULT_TOKEN: "{{ root_token }}" + changed_when: false + register: vault_secret_enable + + - name: "Verify vault interaction" + ansible.builtin.assert: + that: + - vault_secret_enable.stdout == 'Success! Enabled the kv secrets engine at: kv/' diff --git a/roles/hashicorp_vault/tasks/configure.yml b/roles/hashicorp_vault/tasks/configure.yml new file mode 100644 index 0000000..f114db1 --- /dev/null +++ b/roles/hashicorp_vault/tasks/configure.yml @@ -0,0 +1,46 @@ +--- +# task/configure file for hashicorp_vault +- name: "Ensure default vault.hcl is removed" + ansible.builtin.file: + path: /etc/vault.d/vault.hcl + state: absent + +- name: "Copy vault.json template" + ansible.builtin.template: + src: vault.json.j2 + dest: "{{ hashi_vault_config_dir }}/vault.json" + owner: "{{ hashi_vault_user }}" + group: "{{ hashi_vault_group }}" + mode: '0600' + notify: + - "systemctl-enable-vault" + - "systemctl-restart-vault" + +- name: "Create vault.env" + ansible.builtin.template: + src: vault.env.j2 + dest: "{{ hashi_vault_config_dir }}/vault.env" + owner: "{{ hashi_vault_user }}" + group: "{{ hashi_vault_group }}" + mode: '0600' + +- name: "Copy extra configuration files" + when: hashi_vault_extra_files + block: + - name: "Create directory {{ hashi_vault_extra_files_dst }}" + ansible.builtin.file: + path: "{{ hashi_vault_extra_files_dst }}" + state: directory + owner: "{{ hashi_vault_user }}" + group: "{{ hashi_vault_group }}" + mode: '0755' + + - name: "Copy extra configuration files" + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ hashi_vault_extra_files_dst }}/{{ (item | basename).split('.')[:-1] | join('.')}}" + owner: "{{ hashi_vault_user }}" + group: "{{ hashi_vault_group }}" + mode: '0600' + with_fileglob: + - "{{ hashi_vault_extra_files_src }}/*" diff --git a/roles/hashicorp_vault/tasks/install.yml b/roles/hashicorp_vault/tasks/install.yml new file mode 100644 index 0000000..cbf7f96 --- /dev/null +++ b/roles/hashicorp_vault/tasks/install.yml @@ -0,0 +1,25 @@ +--- +# task/install file for hashicorp_vault +- name: "Configure hashicorp repository" + ansible.builtin.include_role: + name: ednxzu.manage_repositories + vars: + manage_repositories_enable_default_repo: false + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: "{{ hashi_vault_repository }}" + +- name: "Install vault:{{ hashi_vault_version }}" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ hashi_vault_packages }}" + +- name: "Copy systemd service file for vault" + ansible.builtin.template: + src: "vault.service.j2" + dest: "/etc/systemd/system/vault.service" + owner: root + group: root + mode: '0644' + notify: + - "systemctl-daemon-reload" diff --git a/roles/hashicorp_vault/tasks/main.yml b/roles/hashicorp_vault/tasks/main.yml new file mode 100644 index 0000000..f7db3e8 --- /dev/null +++ b/roles/hashicorp_vault/tasks/main.yml @@ -0,0 +1,11 @@ +--- +# task/main file for hashicorp_vault +- name: "Import prerequisites.yml" + ansible.builtin.include_tasks: prerequisites.yml + +- name: "Import install.yml" + ansible.builtin.include_tasks: install.yml + when: hashi_vault_install + +- name: "Import configure.yml" + ansible.builtin.include_tasks: configure.yml diff --git a/roles/hashicorp_vault/tasks/prerequisites.yml b/roles/hashicorp_vault/tasks/prerequisites.yml new file mode 100644 index 0000000..4874dd8 --- /dev/null +++ b/roles/hashicorp_vault/tasks/prerequisites.yml @@ -0,0 +1,29 @@ +--- +# task/prerequisites file for hashicorp_vault +- name: "Create group {{ hashi_vault_group }}" + ansible.builtin.group: + name: "{{ hashi_vault_user }}" + state: present + +- name: "Create user {{ hashi_vault_user }}" + ansible.builtin.user: + name: "{{ hashi_vault_user }}" + group: "{{ hashi_vault_group }}" + shell: /bin/false + state: present + +- name: "Create directory {{ hashi_vault_config_dir }}" + ansible.builtin.file: + path: "{{ hashi_vault_config_dir }}" + state: directory + owner: "{{ hashi_vault_user }}" + group: "{{ hashi_vault_group }}" + mode: '0755' + +- name: "Create directory {{ hashi_vault_data_dir }}" + ansible.builtin.file: + path: "{{ hashi_vault_data_dir }}" + state: directory + owner: "{{ hashi_vault_user }}" + group: "{{ hashi_vault_group }}" + mode: '0755' diff --git a/roles/hashicorp_vault/templates/vault.env.j2 b/roles/hashicorp_vault/templates/vault.env.j2 new file mode 100644 index 0000000..73c6327 --- /dev/null +++ b/roles/hashicorp_vault/templates/vault.env.j2 @@ -0,0 +1,4 @@ +# {{ ansible_managed }} +{% for item in hashi_vault_env_variables %} +{{ item|upper }}="{{ hashi_vault_env_variables[item] }}" +{% endfor %} \ No newline at end of file diff --git a/roles/hashicorp_vault/templates/vault.json.j2 b/roles/hashicorp_vault/templates/vault.json.j2 new file mode 100644 index 0000000..b0964d6 --- /dev/null +++ b/roles/hashicorp_vault/templates/vault.json.j2 @@ -0,0 +1 @@ +{{ hashi_vault_configuration|to_nice_json }} \ No newline at end of file diff --git a/roles/hashicorp_vault/templates/vault.service.j2 b/roles/hashicorp_vault/templates/vault.service.j2 new file mode 100644 index 0000000..b2eb09d --- /dev/null +++ b/roles/hashicorp_vault/templates/vault.service.j2 @@ -0,0 +1,38 @@ +[Unit] +Description="HashiCorp Vault - A tool for managing secrets" +Documentation=https://www.vaultproject.io/docs/ +Requires=network-online.target +After=network-online.target +ConditionFileNotEmpty={{ hashi_vault_config_dir }}/vault.json +StartLimitIntervalSec=60 +StartLimitBurst=3 +{% if hashi_vault_configuration.storage.consul is defined or hashi_vault_configuration.service_registration.consul is defined %} +Wants=consul.service +After=consul.service +{% endif %} + +[Service] +Type=notify +EnvironmentFile=-{{ hashi_vault_config_dir }}/vault.env +User={{ hashi_vault_user }} +Group={{ hashi_vault_group }} +ProtectSystem=full +ProtectHome=read-only +PrivateTmp=yes +PrivateDevices=yes +SecureBits=keep-caps +AmbientCapabilities=CAP_IPC_LOCK +CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK +NoNewPrivileges=yes +ExecStart=/usr/bin/vault server -config={{ hashi_vault_config_dir }} +ExecReload=/bin/kill --signal HUP $MAINPID +KillMode=process +KillSignal=SIGINT +Restart=on-failure +RestartSec=5 +TimeoutStopSec=30 +LimitNOFILE=65536 +LimitMEMLOCK=infinity + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/hashicorp_vault/vars/main.yml b/roles/hashicorp_vault/vars/main.yml new file mode 100644 index 0000000..bfcf3d3 --- /dev/null +++ b/roles/hashicorp_vault/vars/main.yml @@ -0,0 +1,21 @@ +--- +# vars file for hashicorp_vault +hashi_vault_user: vault +hashi_vault_group: vault +hashi_vault_config_dir: "/etc/vault.d" +hashi_vault_repository: + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" +hashi_vault_packages: + - name: vault + version: "{{ hashi_vault_version }}" + state: "{% if hashi_vault_auto_update %}latest{% else %}present{% endif %}" diff --git a/roles/import_vault_root_ca/LICENSE b/roles/import_vault_root_ca/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/import_vault_root_ca/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/import_vault_root_ca/README.md b/roles/import_vault_root_ca/README.md new file mode 100644 index 0000000..1d5dd6a --- /dev/null +++ b/roles/import_vault_root_ca/README.md @@ -0,0 +1,51 @@ +import_vault_root_ca +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role imports root CA certificates from Vault to the trust store on **debian-based** distributions. + +Requirements +------------ + +None. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/import_vault_root_ca.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +import_vault_root_ca_certificate_force_download: false # by default, set to false +``` +This variable defines whether the role should always download the provided certificate even if it already exists. This can be useful if you want to replace an existing CA, but note that **it breaks idempotence**. + +```yaml +import_vault_root_ca_certificate_list: [] # by default, set to an empty dict + - url: + cert_name: +``` +This variable defines which CA certificate to install on the machine, it is only tested with CA from Hashicorp Vault pki engine, but should work with any CA that can be downloaded from a webserver. + +Dependencies +------------ + +`ednxzu.manage_apt_packages` to install consul-template. + +Example Playbook +---------------- + +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.import_vault_root_ca +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/import_vault_root_ca/defaults/main.yml b/roles/import_vault_root_ca/defaults/main.yml new file mode 100644 index 0000000..d36169d --- /dev/null +++ b/roles/import_vault_root_ca/defaults/main.yml @@ -0,0 +1,4 @@ +--- +# defaults file for import_vault_root_ca +import_vault_root_ca_certificate_force_download: false +import_vault_root_ca_certificate_list: [] diff --git a/roles/import_vault_root_ca/handlers/main.yml b/roles/import_vault_root_ca/handlers/main.yml new file mode 100644 index 0000000..c35ea85 --- /dev/null +++ b/roles/import_vault_root_ca/handlers/main.yml @@ -0,0 +1,6 @@ +--- +# handlers file for import_vault_root_ca +- name: "Update the trust store" + ansible.builtin.command: update-ca-certificates + changed_when: false + listen: "update-ca-certificates" diff --git a/roles/import_vault_root_ca/meta/main.yml b/roles/import_vault_root_ca/meta/main.yml new file mode 100644 index 0000000..c5bebf8 --- /dev/null +++ b/roles/import_vault_root_ca/meta/main.yml @@ -0,0 +1,27 @@ +--- +# meta file for hashicorp_nomad +galaxy_info: + namespace: 'ednxzu' + role_name: 'import_vault_root_ca' + author: 'Bertrand Lanson' + description: 'Imports root CA certificates from Vault to the trust store on debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'vault' + - 'openssl' + - 'store' + - 'certificate' + +dependencies: [] diff --git a/roles/import_vault_root_ca/molecule/default/converge.yml b/roles/import_vault_root_ca/molecule/default/converge.yml new file mode 100644 index 0000000..6a07ee9 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.import_vault_root_ca" + ansible.builtin.include_role: + name: "ednxzu.import_vault_root_ca" diff --git a/roles/import_vault_root_ca/molecule/default/molecule.yml b/roles/import_vault_root_ca/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/import_vault_root_ca/molecule/default/requirements.yml b/roles/import_vault_root_ca/molecule/default/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/import_vault_root_ca/molecule/default/verify.yml b/roles/import_vault_root_ca/molecule/default/verify.yml new file mode 100644 index 0000000..55097ef --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default/verify.yml @@ -0,0 +1,28 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /usr/local/share/ca-certificates" + block: + - name: "Stat directory /usr/local/share/ca-certificates" + ansible.builtin.stat: + path: "/usr/local/share/ca-certificates" + register: usr_local_share_ca_certificates + + - name: "Find files in directory /usr/local/share/ca-certificates" + ansible.builtin.find: + paths: "/usr/local/share/ca-certificates" + file_type: file + register: usr_local_share_ca_certificates_ls + + - name: "Verify directory /usr/local/share/ca-certificates" + ansible.builtin.assert: + that: + - usr_local_share_ca_certificates.stat.exists + - usr_local_share_ca_certificates.stat.isdir + - usr_local_share_ca_certificates.stat.pw_name == 'root' + - usr_local_share_ca_certificates.stat.gr_name == 'root' + - usr_local_share_ca_certificates.stat.mode == '0755' + - (usr_local_share_ca_certificates_ls.files|length) == 0 diff --git a/roles/import_vault_root_ca/molecule/default_vagrant/converge.yml b/roles/import_vault_root_ca/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..6a07ee9 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.import_vault_root_ca" + ansible.builtin.include_role: + name: "ednxzu.import_vault_root_ca" diff --git a/roles/import_vault_root_ca/molecule/default_vagrant/molecule.yml b/roles/import_vault_root_ca/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/import_vault_root_ca/molecule/default_vagrant/requirements.yml b/roles/import_vault_root_ca/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default_vagrant/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/import_vault_root_ca/molecule/default_vagrant/verify.yml b/roles/import_vault_root_ca/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..55097ef --- /dev/null +++ b/roles/import_vault_root_ca/molecule/default_vagrant/verify.yml @@ -0,0 +1,28 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /usr/local/share/ca-certificates" + block: + - name: "Stat directory /usr/local/share/ca-certificates" + ansible.builtin.stat: + path: "/usr/local/share/ca-certificates" + register: usr_local_share_ca_certificates + + - name: "Find files in directory /usr/local/share/ca-certificates" + ansible.builtin.find: + paths: "/usr/local/share/ca-certificates" + file_type: file + register: usr_local_share_ca_certificates_ls + + - name: "Verify directory /usr/local/share/ca-certificates" + ansible.builtin.assert: + that: + - usr_local_share_ca_certificates.stat.exists + - usr_local_share_ca_certificates.stat.isdir + - usr_local_share_ca_certificates.stat.pw_name == 'root' + - usr_local_share_ca_certificates.stat.gr_name == 'root' + - usr_local_share_ca_certificates.stat.mode == '0755' + - (usr_local_share_ca_certificates_ls.files|length) == 0 diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca/converge.yml b/roles/import_vault_root_ca/molecule/with_custom_ca/converge.yml new file mode 100644 index 0000000..6a07ee9 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.import_vault_root_ca" + ansible.builtin.include_role: + name: "ednxzu.import_vault_root_ca" diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca/group_vars/all.yml b/roles/import_vault_root_ca/molecule/with_custom_ca/group_vars/all.yml new file mode 100644 index 0000000..805668d --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca/group_vars/all.yml @@ -0,0 +1,5 @@ +--- +import_vault_root_ca_certificate_force_download: false +import_vault_root_ca_certificate_list: + - url: "https://letsencrypt.org/certs/isrg-root-x2.pem" + cert_name: "isrg_root" diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca/molecule.yml b/roles/import_vault_root_ca/molecule/with_custom_ca/molecule.yml new file mode 100644 index 0000000..7150297 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_ca + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca/requirements.yml b/roles/import_vault_root_ca/molecule/with_custom_ca/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca/verify.yml b/roles/import_vault_root_ca/molecule/with_custom_ca/verify.yml new file mode 100644 index 0000000..f25fa2f --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca/verify.yml @@ -0,0 +1,53 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /usr/local/share/ca-certificates" + block: + - name: "Stat directory /usr/local/share/ca-certificates" + ansible.builtin.stat: + path: "/usr/local/share/ca-certificates" + register: usr_local_share_ca_certificates + + - name: "Find files in directory /usr/local/share/ca-certificates" + ansible.builtin.find: + paths: "/usr/local/share/ca-certificates" + file_type: file + register: usr_local_share_ca_certificates_ls + + - name: "Verify directory /usr/local/share/ca-certificates" + ansible.builtin.assert: + that: + - usr_local_share_ca_certificates.stat.exists + - usr_local_share_ca_certificates.stat.isdir + - usr_local_share_ca_certificates.stat.pw_name == 'root' + - usr_local_share_ca_certificates.stat.gr_name == 'root' + - usr_local_share_ca_certificates.stat.mode == '0755' + - (usr_local_share_ca_certificates_ls.files|length) == 1 + - (usr_local_share_ca_certificates_ls.files[0].path|basename) == 'isrg_root.crt' + + - name: "Test: certificate isrg_root.crt" + block: + - name: "Stat file /usr/local/share/ca-certificates/isrg_root.crt" + ansible.builtin.stat: + path: "/usr/local/share/ca-certificates/isrg_root.crt" + register: isrg_root_file + + - name: "Get certificate info" + community.crypto.x509_certificate_info: + path: "/usr/local/share/ca-certificates/isrg_root.crt" + register: isrg_root_pem + + - name: "Verify certificate is readable" + ansible.builtin.assert: + that: + - isrg_root_file.stat.exists + - isrg_root_file.stat.isreg + - isrg_root_file.stat.pw_name == 'root' + - isrg_root_file.stat.gr_name == 'root' + - isrg_root_file.stat.mode == '0644' + - not isrg_root_pem.failed + - not isrg_root_pem.expired + - isrg_root_pem.issuer == isrg_root_pem.subject diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/converge.yml b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/converge.yml new file mode 100644 index 0000000..6a07ee9 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.import_vault_root_ca" + ansible.builtin.include_role: + name: "ednxzu.import_vault_root_ca" diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/group_vars/all.yml b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/group_vars/all.yml new file mode 100644 index 0000000..805668d --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/group_vars/all.yml @@ -0,0 +1,5 @@ +--- +import_vault_root_ca_certificate_force_download: false +import_vault_root_ca_certificate_list: + - url: "https://letsencrypt.org/certs/isrg-root-x2.pem" + cert_name: "isrg_root" diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/molecule.yml b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/molecule.yml new file mode 100644 index 0000000..263943e --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_ca_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/requirements.yml b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/requirements.yml new file mode 100644 index 0000000..ca250b7 --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/requirements.yml @@ -0,0 +1,4 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_apt_packages diff --git a/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/verify.yml b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/verify.yml new file mode 100644 index 0000000..f25fa2f --- /dev/null +++ b/roles/import_vault_root_ca/molecule/with_custom_ca_vagrant/verify.yml @@ -0,0 +1,53 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /usr/local/share/ca-certificates" + block: + - name: "Stat directory /usr/local/share/ca-certificates" + ansible.builtin.stat: + path: "/usr/local/share/ca-certificates" + register: usr_local_share_ca_certificates + + - name: "Find files in directory /usr/local/share/ca-certificates" + ansible.builtin.find: + paths: "/usr/local/share/ca-certificates" + file_type: file + register: usr_local_share_ca_certificates_ls + + - name: "Verify directory /usr/local/share/ca-certificates" + ansible.builtin.assert: + that: + - usr_local_share_ca_certificates.stat.exists + - usr_local_share_ca_certificates.stat.isdir + - usr_local_share_ca_certificates.stat.pw_name == 'root' + - usr_local_share_ca_certificates.stat.gr_name == 'root' + - usr_local_share_ca_certificates.stat.mode == '0755' + - (usr_local_share_ca_certificates_ls.files|length) == 1 + - (usr_local_share_ca_certificates_ls.files[0].path|basename) == 'isrg_root.crt' + + - name: "Test: certificate isrg_root.crt" + block: + - name: "Stat file /usr/local/share/ca-certificates/isrg_root.crt" + ansible.builtin.stat: + path: "/usr/local/share/ca-certificates/isrg_root.crt" + register: isrg_root_file + + - name: "Get certificate info" + community.crypto.x509_certificate_info: + path: "/usr/local/share/ca-certificates/isrg_root.crt" + register: isrg_root_pem + + - name: "Verify certificate is readable" + ansible.builtin.assert: + that: + - isrg_root_file.stat.exists + - isrg_root_file.stat.isreg + - isrg_root_file.stat.pw_name == 'root' + - isrg_root_file.stat.gr_name == 'root' + - isrg_root_file.stat.mode == '0644' + - not isrg_root_pem.failed + - not isrg_root_pem.expired + - isrg_root_pem.issuer == isrg_root_pem.subject diff --git a/roles/import_vault_root_ca/tasks/import.yml b/roles/import_vault_root_ca/tasks/import.yml new file mode 100644 index 0000000..19596dd --- /dev/null +++ b/roles/import_vault_root_ca/tasks/import.yml @@ -0,0 +1,27 @@ +--- +# task/import file for import_vault_root_ca +- name: "Download certificate file" + ansible.builtin.get_url: + url: "{{ item.url }}" + validate_certs: false + force: "{{ import_vault_root_ca_certificate_force_download }}" + dest: "/tmp/{{ item.cert_name }}.tmp" + mode: '0644' + loop: "{{ import_vault_root_ca_certificate_list }}" + register: download_results + +- name: "Check certificate format" + ansible.builtin.command: > + openssl x509 -inform PEM -noout -in {{ item.dest }} + loop: "{{ download_results.results }}" + register: cert_format_results + changed_when: false + failed_when: false + +- name: "Make sure certificate is in PEM format" + ansible.builtin.command: + cmd: openssl x509 -inform {{ 'PEM' if item.rc == 0 else 'DER' }} -in {{ item.item.dest }} -out {{ import_vault_root_ca_cert_dir }}/{{ item.item.item.cert_name }}.crt -outform pem + creates: "{{ import_vault_root_ca_cert_dir }}/{{ item.item.item.cert_name }}.crt" + loop: "{{ cert_format_results.results }}" + notify: + - update-ca-certificates diff --git a/roles/import_vault_root_ca/tasks/main.yml b/roles/import_vault_root_ca/tasks/main.yml new file mode 100644 index 0000000..9adbc03 --- /dev/null +++ b/roles/import_vault_root_ca/tasks/main.yml @@ -0,0 +1,7 @@ +--- +# task/main file for import_vault_root_ca +- name: "Import prerequisites.yml" + ansible.builtin.include_tasks: prerequisites.yml + +- name: "Import import.yml" + ansible.builtin.include_tasks: import.yml diff --git a/roles/import_vault_root_ca/tasks/prerequisites.yml b/roles/import_vault_root_ca/tasks/prerequisites.yml new file mode 100644 index 0000000..c890667 --- /dev/null +++ b/roles/import_vault_root_ca/tasks/prerequisites.yml @@ -0,0 +1,15 @@ +--- +# task/prerequisites file for import_vault_root_ca +- name: "Install dependencies" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ import_vault_root_ca_packages }}" + +- name: "Create directory {{ import_vault_root_ca_cert_dir }}" + ansible.builtin.file: + path: "{{ import_vault_root_ca_cert_dir }}" + state: directory + owner: "root" + group: "root" + mode: '0755' diff --git a/roles/import_vault_root_ca/vars/main.yml b/roles/import_vault_root_ca/vars/main.yml new file mode 100644 index 0000000..fa7eee6 --- /dev/null +++ b/roles/import_vault_root_ca/vars/main.yml @@ -0,0 +1,10 @@ +--- +# vars file for import_vault_root_ca +import_vault_root_ca_cert_dir: /usr/local/share/ca-certificates +import_vault_root_ca_packages: + - name: openssl + version: latest + state: present + - name: ca-certificates + version: latest + state: present diff --git a/roles/renew_consul_certificates/LICENSE b/roles/renew_consul_certificates/LICENSE new file mode 100644 index 0000000..c9a37e5 --- /dev/null +++ b/roles/renew_consul_certificates/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bertrand Lanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/roles/renew_consul_certificates/README.md b/roles/renew_consul_certificates/README.md new file mode 100644 index 0000000..5a89774 --- /dev/null +++ b/roles/renew_consul_certificates/README.md @@ -0,0 +1,123 @@ +renew_consul_certificates +========= +> This repository is only a mirror. Development and testing is done on a private gitea server. + +This role install consul-template and configure a service to automate renewal of TLS certificates for Hashicorp Consul on **debian-based** distributions. + +Requirements +------------ + +This role assume that you already have installed a consul server on the host, and is only here to assist in automating the certificate renewal process. + +Role Variables +-------------- +Available variables are listed below, along with default values. A sample file for the default values is available in `default/renew_consul_certificates.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. + +```yaml +renew_consul_certificates_config_dir: /etc/consul-template.d/consul # by default, set to /etc/consul-template.d/consul +``` +This variable defines where the files for the role are stored (consul-template configuration + templates). + +```yaml +renew_consul_certificates_consul_user: consul # by default, set to consul +``` +This variable defines the user that'll be running the certificate renewal service. Defaults to `consul`, and should be present on the host prior to playing this role (ideally when installing consul). + +```yaml +renew_consul_certificates_consul_group: consul # by default, set to consul +``` +This variable defines the group that'll be running the certificate renewal service. Defaults to `consul`, and should be present on the host prior to playing this role (ideally when installing consul). + +```yaml +renew_consul_certificates_service_env_variables: + consul_http_addr: http://127.0.0.1:8500 + # consul_http_token: +``` +This variable sets the environment variables for the consul-certs services (notably the address and token to use for the `consul reload` command). + +```yaml +renew_consul_certificates_vault_addr: https://vault.example.com # by default, set to https://vault.example.com +``` +This variable defines the address the consul-template service will query to get the new certificates. Defaults to localhost, but can be changed if vault isnt reachable on localhost. + +```yaml +renew_consul_certificates_vault_token: mysupersecretvaulttokenthatyoushouldchange # by default, set to a dummy string +``` +This variable defines the vault token top use to access vault and renew the certificate. Default is a dummy string to pass unit tests. + +```yaml +renew_consul_certificates_vault_token_unwrap: false # by default, set to false +``` +Defines whether or not the token is wrapped and should be unwrapped (this is an enterprise-only feature of vault at the moment). + +```yaml +renew_consul_certificates_vault_token_renew: true # by default, set to true +``` +This variable defines whether or not to renew the vault token. It should probably be `true`, and you should have a periodic token to handle this. + +```yaml +renew_consul_certificates_ca_dest: /opt/consul/tls/ca.pem # by default, set to /opt/consul/tls/ca.pem +``` +This variable defines where to copy the certificate authority upon renewal. Default to `/opt/consul/tls/ca.pem` but should be changed depending on where you store the certificate authority. + +```yaml +renew_consul_certificates_cert_dest: /opt/consul/tls/cert.pem # by default, set to /opt/consul/tls/cert.pem +``` +This variable defines where to copy the certificates upon renewal. Default to `/opt/consul/tls/cert.pem` but should be changed depending on where you store the certificates. + +```yaml +renew_consul_certificates_key_dest: /opt/consul/tls/key.pem # by default, set to /opt/consul/tls/cert.pem +``` +This variable defines where to copy the private keys upon renewal. Default to `/opt/consul/tls/key.pem` but should be changed depending on where you store the keys. + +```yaml +renew_consul_certificates_info: # by default, set to: + issuer_path: pki/issue/your-issuer + common_name: consul01.example.com + ttl: 90d + is_server: false + include_consul_service: false +``` +This variable defines the path on vault to retrieve the certificates, as well as the common name and TTL to use for it. It can also include consul aliases in case you have registered consul services in itself (`consul.service.consul`). It also handles whether or not to append the server.yourdc.consul SAN, in case you're enforcing hostname checking. + +```yaml +renew_consul_certificates_consul_dc_name: dc1.consul # by default, set to dc1.consul +``` +In case you enforce hostname checking, set this variable to your desired dc and consul domain. This is used to forge the SAN that will be checked by consul to only allow specific nodes to be managers. + +```yaml +renew_consul_certificates_consul_service_name: consul.service.consul # by default, set to consul.service.consul +``` +This variable defines the consul service name in consul. Default is `consul.service.consul` + +```yaml +renew_consul_certificates_start_service: false +``` +This variable defines whether or not to start the service after creating it. By default, it is only enabled, but not started, in case you're building golden images (in which case you probably don't want a certificate generated during the build process). + +Dependencies +------------ + +`ednxzu.manage_repositories` to configure hashicorp apt repository. +`ednxzu.manage_apt_packages` to install consul-template. + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: +```yaml +# calling the role inside a playbook with either the default or group_vars/host_vars +- hosts: servers + roles: + - ednxzu.renew_consul_certificates +``` + +License +------- + +MIT / BSD + +Author Information +------------------ + +This role was created by Bertrand Lanson in 2023. diff --git a/roles/renew_consul_certificates/defaults/main.yml b/roles/renew_consul_certificates/defaults/main.yml new file mode 100644 index 0000000..a5a13ea --- /dev/null +++ b/roles/renew_consul_certificates/defaults/main.yml @@ -0,0 +1,24 @@ +--- +# defaults file for renew_consul_certificates +renew_consul_certificates_config_dir: /etc/consul-template.d/consul +renew_consul_certificates_consul_user: consul +renew_consul_certificates_consul_group: consul +renew_consul_certificates_service_env_variables: + consul_http_addr: http://127.0.0.1:8500 + # consul_http_token: +renew_consul_certificates_vault_addr: "https://vault.example.com" +renew_consul_certificates_vault_token: mysupersecretconsultokenthatyoushouldchange +renew_consul_certificates_vault_token_unwrap: false +renew_consul_certificates_vault_token_renew: true +renew_consul_certificates_ca_dest: /opt/consul/tls/ca.pem +renew_consul_certificates_cert_dest: /opt/consul/tls/cert.pem +renew_consul_certificates_key_dest: /opt/consul/tls/key.pem +renew_consul_certificates_info: + issuer_path: pki/issue/your-issuer + common_name: consul01.example.com + ttl: 90d + is_server: false + include_consul_service: false +renew_consul_certificates_consul_dc_name: dc1.consul +renew_consul_certificates_consul_service_name: consul.service.consul +renew_consul_certificates_start_service: false diff --git a/roles/renew_consul_certificates/defaults/renew_consul_certificates.yml.sample b/roles/renew_consul_certificates/defaults/renew_consul_certificates.yml.sample new file mode 100644 index 0000000..e289122 --- /dev/null +++ b/roles/renew_consul_certificates/defaults/renew_consul_certificates.yml.sample @@ -0,0 +1,23 @@ +--- +# renew_consul_certificates_config_dir: /etc/consul-template.d/consul +# renew_consul_certificates_consul_user: consul +# renew_consul_certificates_consul_group: consul +# renew_consul_certificates_service_env_variables: +# consul_http_addr: http://127.0.0.1:8500 +# # consul_http_token: +# renew_consul_certificates_vault_addr: "https://consul.example.com" +# renew_consul_certificates_vault_token: mysupersecretconsultokenthatyoushouldchange +# renew_consul_certificates_vault_token_unwrap: false +# renew_consul_certificates_vault_token_renew: true +# renew_consul_certificates_ca_dest: /opt/consul/tls/ca.pem +# renew_consul_certificates_cert_dest: /opt/consul/tls/cert.pem +# renew_consul_certificates_key_dest: /opt/consul/tls/key.pem +# renew_consul_certificates_info: +# issuer_path: pki/issue/your-issuer +# common_name: consul01.example.com +# ttl: 90d +# is_server: false +# include_consul_service: false +# renew_consul_certificates_consul_dc_name: dc1.consul +# renew_consul_certificates_consul_service_name: consul.service.consul +# renew_consul_certificates_start_service: false diff --git a/roles/renew_consul_certificates/handlers/main.yml b/roles/renew_consul_certificates/handlers/main.yml new file mode 100644 index 0000000..6c9f41b --- /dev/null +++ b/roles/renew_consul_certificates/handlers/main.yml @@ -0,0 +1,19 @@ +--- +# handlers file for renew_consul_certificates +- name: "Reload service file" + ansible.builtin.systemd: + daemon_reload: true + listen: "systemctl-daemon-reload" + +- name: "Enable consul-certs service" + ansible.builtin.service: + name: consul-certs + enabled: true + listen: "systemctl-enable-consul-certs" + +- name: "Start consul-certs service" + ansible.builtin.service: + name: consul-certs + state: restarted + listen: "systemctl-restart-consul-certs" + when: renew_consul_certificates_start_service diff --git a/roles/renew_consul_certificates/meta/main.yml b/roles/renew_consul_certificates/meta/main.yml new file mode 100644 index 0000000..800445b --- /dev/null +++ b/roles/renew_consul_certificates/meta/main.yml @@ -0,0 +1,25 @@ +--- +# meta file for renew_consul_certificates +galaxy_info: + namespace: 'ednxzu' + role_name: 'renew_consul_certificates' + author: 'Bertrand Lanson' + description: 'Install and configure consul-template to renew consul TLS certificates for debian-based distros.' + license: 'license (BSD, MIT)' + min_ansible_version: '2.10' + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - 'ubuntu' + - 'debian' + - 'hashicorp' + - 'consul' + +dependencies: [] diff --git a/roles/renew_consul_certificates/molecule/default/converge.yml b/roles/renew_consul_certificates/molecule/default/converge.yml new file mode 100644 index 0000000..c1e3e1e --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.renew_consul_certificates" + ansible.builtin.include_role: + name: "ednxzu.renew_consul_certificates" diff --git a/roles/renew_consul_certificates/molecule/default/molecule.yml b/roles/renew_consul_certificates/molecule/default/molecule.yml new file mode 100644 index 0000000..49efc7f --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/renew_consul_certificates/molecule/default/prepare.yml b/roles/renew_consul_certificates/molecule/default/prepare.yml new file mode 100644 index 0000000..f2e71c5 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default/prepare.yml @@ -0,0 +1,16 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: + - name: "Create group consul" + ansible.builtin.group: + name: "consul" + state: present + + - name: "Create user consul" + ansible.builtin.user: + name: "consul" + group: "consul" + shell: /bin/false + state: present diff --git a/roles/renew_consul_certificates/molecule/default/requirements.yml b/roles/renew_consul_certificates/molecule/default/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/renew_consul_certificates/molecule/default/verify.yml b/roles/renew_consul_certificates/molecule/default/verify.yml new file mode 100644 index 0000000..7338f39 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default/verify.yml @@ -0,0 +1,140 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /etc/consul-template.d/consul" + block: + - name: "Stat directory /etc/consul-template.d/consul" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul" + register: stat_etc_consul_template_d_nomad + + - name: "Stat file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/consul_config.hcl" + register: stat_etc_consul_template_d_nomad_nomad_config_hcl + + - name: "Slurp file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.slurp: + src: "/etc/consul-template.d/consul/consul_config.hcl" + register: slurp_etc_consul_template_d_consul_consul_config_hcl + + - name: "Verify directory /etc/consul-template.d/consul" + ansible.builtin.assert: + that: + - stat_etc_consul_template_d_nomad.stat.exists + - stat_etc_consul_template_d_nomad.stat.isdir + - stat_etc_consul_template_d_nomad.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.mode == '0755' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.exists + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.isreg + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.mode == '0600' + - slurp_etc_consul_template_d_consul_consul_config_hcl.content != '' + + - name: "Test: directory /etc/consul-template.d/consul/templates" + block: + - name: "Stat directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/templates" + register: stat_etc_consul_template_d_consul_templates + + - name: "Find in directory /etc/consul-template.d/consul/templates" + ansible.builtin.find: + paths: "/etc/consul-template.d/consul/templates" + file_type: file + register: find_etc_consul_template_d_consul_templates + + - name: "Stat in directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: stat_etc_consul_template_d_consul_templates + + - name: "Slurp in directory /etc/consul-template.d/consul/templates" + ansible.builtin.slurp: + src: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: slurp_etc_consul_template_d_nomad_templates + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_ca.pem.tpl" + vars: + consul_ca_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_ca_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_ca.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_cert.pem.tpl" + vars: + consul_cert_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }} + {{ .Data.certificate }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_cert_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_cert.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_key.pem.tpl" + vars: + consul_key_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }} + {{ .Data.private_key }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_key_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_key.pem.tpl' + + - name: "Test: service consul-certs" + block: + - name: "Get service consul-certs" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul-certs.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul-certs.service" + register: stat_etc_systemd_system_consul_certs_service + + - name: "Slurp file /etc/systemd/system/consul-certs.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul-certs.service" + register: slurp_etc_systemd_system_consul_certs_service + + - name: "Verify service consul-certs" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_certs_service.stat.exists + - stat_etc_systemd_system_consul_certs_service.stat.isreg + - stat_etc_systemd_system_consul_certs_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_certs_service.content != '' + - ansible_facts.services['consul-certs.service'] is defined + - ansible_facts.services['consul-certs.service']['source'] == 'systemd' + - ansible_facts.services['consul-certs.service']['state'] == 'stopped' + - ansible_facts.services['consul-certs.service']['status'] == 'enabled' diff --git a/roles/renew_consul_certificates/molecule/default_vagrant/converge.yml b/roles/renew_consul_certificates/molecule/default_vagrant/converge.yml new file mode 100644 index 0000000..c1e3e1e --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.renew_consul_certificates" + ansible.builtin.include_role: + name: "ednxzu.renew_consul_certificates" diff --git a/roles/renew_consul_certificates/molecule/default_vagrant/molecule.yml b/roles/renew_consul_certificates/molecule/default_vagrant/molecule.yml new file mode 100644 index 0000000..2b02360 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: default_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/renew_consul_certificates/molecule/default_vagrant/prepare.yml b/roles/renew_consul_certificates/molecule/default_vagrant/prepare.yml new file mode 100644 index 0000000..f2e71c5 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default_vagrant/prepare.yml @@ -0,0 +1,16 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: + - name: "Create group consul" + ansible.builtin.group: + name: "consul" + state: present + + - name: "Create user consul" + ansible.builtin.user: + name: "consul" + group: "consul" + shell: /bin/false + state: present diff --git a/roles/renew_consul_certificates/molecule/default_vagrant/requirements.yml b/roles/renew_consul_certificates/molecule/default_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/renew_consul_certificates/molecule/default_vagrant/verify.yml b/roles/renew_consul_certificates/molecule/default_vagrant/verify.yml new file mode 100644 index 0000000..7338f39 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/default_vagrant/verify.yml @@ -0,0 +1,140 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /etc/consul-template.d/consul" + block: + - name: "Stat directory /etc/consul-template.d/consul" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul" + register: stat_etc_consul_template_d_nomad + + - name: "Stat file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/consul_config.hcl" + register: stat_etc_consul_template_d_nomad_nomad_config_hcl + + - name: "Slurp file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.slurp: + src: "/etc/consul-template.d/consul/consul_config.hcl" + register: slurp_etc_consul_template_d_consul_consul_config_hcl + + - name: "Verify directory /etc/consul-template.d/consul" + ansible.builtin.assert: + that: + - stat_etc_consul_template_d_nomad.stat.exists + - stat_etc_consul_template_d_nomad.stat.isdir + - stat_etc_consul_template_d_nomad.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.mode == '0755' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.exists + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.isreg + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.mode == '0600' + - slurp_etc_consul_template_d_consul_consul_config_hcl.content != '' + + - name: "Test: directory /etc/consul-template.d/consul/templates" + block: + - name: "Stat directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/templates" + register: stat_etc_consul_template_d_consul_templates + + - name: "Find in directory /etc/consul-template.d/consul/templates" + ansible.builtin.find: + paths: "/etc/consul-template.d/consul/templates" + file_type: file + register: find_etc_consul_template_d_consul_templates + + - name: "Stat in directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: stat_etc_consul_template_d_consul_templates + + - name: "Slurp in directory /etc/consul-template.d/consul/templates" + ansible.builtin.slurp: + src: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: slurp_etc_consul_template_d_nomad_templates + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_ca.pem.tpl" + vars: + consul_ca_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_ca_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_ca.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_cert.pem.tpl" + vars: + consul_cert_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }} + {{ .Data.certificate }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_cert_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_cert.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_key.pem.tpl" + vars: + consul_key_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }} + {{ .Data.private_key }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_key_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_key.pem.tpl' + + - name: "Test: service consul-certs" + block: + - name: "Get service consul-certs" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul-certs.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul-certs.service" + register: stat_etc_systemd_system_consul_certs_service + + - name: "Slurp file /etc/systemd/system/consul-certs.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul-certs.service" + register: slurp_etc_systemd_system_consul_certs_service + + - name: "Verify service consul-certs" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_certs_service.stat.exists + - stat_etc_systemd_system_consul_certs_service.stat.isreg + - stat_etc_systemd_system_consul_certs_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_certs_service.content != '' + - ansible_facts.services['consul-certs.service'] is defined + - ansible_facts.services['consul-certs.service']['source'] == 'systemd' + - ansible_facts.services['consul-certs.service']['state'] == 'stopped' + - ansible_facts.services['consul-certs.service']['status'] == 'enabled' diff --git a/roles/renew_consul_certificates/molecule/with_custom_config/converge.yml b/roles/renew_consul_certificates/molecule/with_custom_config/converge.yml new file mode 100644 index 0000000..c1e3e1e --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.renew_consul_certificates" + ansible.builtin.include_role: + name: "ednxzu.renew_consul_certificates" diff --git a/roles/renew_consul_certificates/molecule/with_custom_config/group_vars/all.yml b/roles/renew_consul_certificates/molecule/with_custom_config/group_vars/all.yml new file mode 100644 index 0000000..945a562 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config/group_vars/all.yml @@ -0,0 +1,23 @@ +--- +renew_consul_certificates_config_dir: /etc/consul-template.d/consul +renew_consul_certificates_consul_user: consul +renew_consul_certificates_consul_group: consul +renew_consul_certificates_service_env_variables: + consul_http_addr: http://127.0.0.1:8500 + # consul_http_token: +renew_consul_certificates_vault_addr: "https://consul.example.com" +renew_consul_certificates_vault_token: mysupersecretconsultokenthatyoushouldchange +renew_consul_certificates_vault_token_unwrap: false +renew_consul_certificates_vault_token_renew: true +renew_consul_certificates_ca_dest: /opt/consul/tls/ca.pem +renew_consul_certificates_cert_dest: /opt/consul/tls/cert.pem +renew_consul_certificates_key_dest: /opt/consul/tls/key.pem +renew_consul_certificates_info: + issuer_path: pki/issue/your-issuer + common_name: consul01.example.com + ttl: 90d + is_server: true + include_consul_service: true +renew_consul_certificates_consul_dc_name: dc1.consul +renew_consul_certificates_consul_service_name: consul.service.consul +renew_consul_certificates_start_service: false diff --git a/roles/renew_consul_certificates/molecule/with_custom_config/molecule.yml b/roles/renew_consul_certificates/molecule/with_custom_config/molecule.yml new file mode 100644 index 0000000..4df62e9 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config/molecule.yml @@ -0,0 +1,37 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: docker +platforms: + - name: instance + image: geerlingguy/docker-${MOLECULE_TEST_OS}-ansible + command: "" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_config + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/renew_consul_certificates/molecule/with_custom_config/prepare.yml b/roles/renew_consul_certificates/molecule/with_custom_config/prepare.yml new file mode 100644 index 0000000..f2e71c5 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config/prepare.yml @@ -0,0 +1,16 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: + - name: "Create group consul" + ansible.builtin.group: + name: "consul" + state: present + + - name: "Create user consul" + ansible.builtin.user: + name: "consul" + group: "consul" + shell: /bin/false + state: present diff --git a/roles/renew_consul_certificates/molecule/with_custom_config/requirements.yml b/roles/renew_consul_certificates/molecule/with_custom_config/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/renew_consul_certificates/molecule/with_custom_config/verify.yml b/roles/renew_consul_certificates/molecule/with_custom_config/verify.yml new file mode 100644 index 0000000..3056cd2 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config/verify.yml @@ -0,0 +1,140 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /etc/consul-template.d/consul" + block: + - name: "Stat directory /etc/consul-template.d/consul" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul" + register: stat_etc_consul_template_d_nomad + + - name: "Stat file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/consul_config.hcl" + register: stat_etc_consul_template_d_nomad_nomad_config_hcl + + - name: "Slurp file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.slurp: + src: "/etc/consul-template.d/consul/consul_config.hcl" + register: slurp_etc_consul_template_d_consul_consul_config_hcl + + - name: "Verify directory /etc/consul-template.d/consul" + ansible.builtin.assert: + that: + - stat_etc_consul_template_d_nomad.stat.exists + - stat_etc_consul_template_d_nomad.stat.isdir + - stat_etc_consul_template_d_nomad.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.mode == '0755' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.exists + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.isreg + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.mode == '0600' + - slurp_etc_consul_template_d_consul_consul_config_hcl.content != '' + + - name: "Test: directory /etc/consul-template.d/consul/templates" + block: + - name: "Stat directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/templates" + register: stat_etc_consul_template_d_consul_templates + + - name: "Find in directory /etc/consul-template.d/consul/templates" + ansible.builtin.find: + paths: "/etc/consul-template.d/consul/templates" + file_type: file + register: find_etc_consul_template_d_consul_templates + + - name: "Stat in directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: stat_etc_consul_template_d_consul_templates + + - name: "Slurp in directory /etc/consul-template.d/consul/templates" + ansible.builtin.slurp: + src: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: slurp_etc_consul_template_d_nomad_templates + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_ca.pem.tpl" + vars: + consul_ca_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_ca_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_ca.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_cert.pem.tpl" + vars: + consul_cert_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }} + {{ .Data.certificate }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_cert_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_cert.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_key.pem.tpl" + vars: + consul_key_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }} + {{ .Data.private_key }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_key_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_key.pem.tpl' + + - name: "Test: service consul-certs" + block: + - name: "Get service consul-certs" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul-certs.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul-certs.service" + register: stat_etc_systemd_system_consul_certs_service + + - name: "Slurp file /etc/systemd/system/consul-certs.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul-certs.service" + register: slurp_etc_systemd_system_consul_certs_service + + - name: "Verify service consul-certs" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_certs_service.stat.exists + - stat_etc_systemd_system_consul_certs_service.stat.isreg + - stat_etc_systemd_system_consul_certs_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_certs_service.content != '' + - ansible_facts.services['consul-certs.service'] is defined + - ansible_facts.services['consul-certs.service']['source'] == 'systemd' + - ansible_facts.services['consul-certs.service']['state'] == 'stopped' + - ansible_facts.services['consul-certs.service']['status'] == 'enabled' diff --git a/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/converge.yml b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/converge.yml new file mode 100644 index 0000000..c1e3e1e --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: "Include ednxzu.renew_consul_certificates" + ansible.builtin.include_role: + name: "ednxzu.renew_consul_certificates" diff --git a/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/group_vars/all.yml b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/group_vars/all.yml new file mode 100644 index 0000000..945a562 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/group_vars/all.yml @@ -0,0 +1,23 @@ +--- +renew_consul_certificates_config_dir: /etc/consul-template.d/consul +renew_consul_certificates_consul_user: consul +renew_consul_certificates_consul_group: consul +renew_consul_certificates_service_env_variables: + consul_http_addr: http://127.0.0.1:8500 + # consul_http_token: +renew_consul_certificates_vault_addr: "https://consul.example.com" +renew_consul_certificates_vault_token: mysupersecretconsultokenthatyoushouldchange +renew_consul_certificates_vault_token_unwrap: false +renew_consul_certificates_vault_token_renew: true +renew_consul_certificates_ca_dest: /opt/consul/tls/ca.pem +renew_consul_certificates_cert_dest: /opt/consul/tls/cert.pem +renew_consul_certificates_key_dest: /opt/consul/tls/key.pem +renew_consul_certificates_info: + issuer_path: pki/issue/your-issuer + common_name: consul01.example.com + ttl: 90d + is_server: true + include_consul_service: true +renew_consul_certificates_consul_dc_name: dc1.consul +renew_consul_certificates_consul_service_name: consul.service.consul +renew_consul_certificates_start_service: false diff --git a/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/molecule.yml b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/molecule.yml new file mode 100644 index 0000000..890cdd0 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/molecule.yml @@ -0,0 +1,35 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: instance + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 4096 +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: with_custom_config_vagrant + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/prepare.yml b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/prepare.yml new file mode 100644 index 0000000..f2e71c5 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/prepare.yml @@ -0,0 +1,16 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: + - name: "Create group consul" + ansible.builtin.group: + name: "consul" + state: present + + - name: "Create user consul" + ansible.builtin.user: + name: "consul" + group: "consul" + shell: /bin/false + state: present diff --git a/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/requirements.yml b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/requirements.yml new file mode 100644 index 0000000..0a4a9fb --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/requirements.yml @@ -0,0 +1,5 @@ +--- +# requirements file for molecule +roles: + - name: ednxzu.manage_repositories + - name: ednxzu.manage_apt_packages diff --git a/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/verify.yml b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/verify.yml new file mode 100644 index 0000000..3056cd2 --- /dev/null +++ b/roles/renew_consul_certificates/molecule/with_custom_config_vagrant/verify.yml @@ -0,0 +1,140 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: + - name: "Test: directory /etc/consul-template.d/consul" + block: + - name: "Stat directory /etc/consul-template.d/consul" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul" + register: stat_etc_consul_template_d_nomad + + - name: "Stat file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/consul_config.hcl" + register: stat_etc_consul_template_d_nomad_nomad_config_hcl + + - name: "Slurp file /etc/consul-template.d/consul/consul_config.hcl" + ansible.builtin.slurp: + src: "/etc/consul-template.d/consul/consul_config.hcl" + register: slurp_etc_consul_template_d_consul_consul_config_hcl + + - name: "Verify directory /etc/consul-template.d/consul" + ansible.builtin.assert: + that: + - stat_etc_consul_template_d_nomad.stat.exists + - stat_etc_consul_template_d_nomad.stat.isdir + - stat_etc_consul_template_d_nomad.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad.stat.mode == '0755' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.exists + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.isreg + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.pw_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.gr_name == 'consul' + - stat_etc_consul_template_d_nomad_nomad_config_hcl.stat.mode == '0600' + - slurp_etc_consul_template_d_consul_consul_config_hcl.content != '' + + - name: "Test: directory /etc/consul-template.d/consul/templates" + block: + - name: "Stat directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "/etc/consul-template.d/consul/templates" + register: stat_etc_consul_template_d_consul_templates + + - name: "Find in directory /etc/consul-template.d/consul/templates" + ansible.builtin.find: + paths: "/etc/consul-template.d/consul/templates" + file_type: file + register: find_etc_consul_template_d_consul_templates + + - name: "Stat in directory /etc/consul-template.d/consul/templates" + ansible.builtin.stat: + path: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: stat_etc_consul_template_d_consul_templates + + - name: "Slurp in directory /etc/consul-template.d/consul/templates" + ansible.builtin.slurp: + src: "{{ item.path }}" + loop: "{{ find_etc_consul_template_d_consul_templates.files }}" + register: slurp_etc_consul_template_d_nomad_templates + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_ca.pem.tpl" + vars: + consul_ca_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_ca_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_ca.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_cert.pem.tpl" + vars: + consul_cert_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }} + {{ .Data.certificate }} + {{ .Data.issuing_ca }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_cert_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_cert.pem.tpl' + + - name: "Verify file /etc/consul-template.d/consul/templates/consul_key.pem.tpl" + vars: + consul_key_file: | + {% raw %}{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }} + {{ .Data.private_key }} + {{ end }}{% endraw %} + ansible.builtin.assert: + that: + - item.item.isreg + - item.item.pw_name == 'consul' + - item.item.gr_name == 'consul' + - item.item.mode == '0600' + - "(item.content|b64decode) == consul_key_file" + loop: "{{ slurp_etc_consul_template_d_nomad_templates.results }}" + when: (item.item.path | basename) == 'consul_key.pem.tpl' + + - name: "Test: service consul-certs" + block: + - name: "Get service consul-certs" + ansible.builtin.service_facts: + + - name: "Stat file /etc/systemd/system/consul-certs.service" + ansible.builtin.stat: + path: "/etc/systemd/system/consul-certs.service" + register: stat_etc_systemd_system_consul_certs_service + + - name: "Slurp file /etc/systemd/system/consul-certs.service" + ansible.builtin.slurp: + src: "/etc/systemd/system/consul-certs.service" + register: slurp_etc_systemd_system_consul_certs_service + + - name: "Verify service consul-certs" + ansible.builtin.assert: + that: + - stat_etc_systemd_system_consul_certs_service.stat.exists + - stat_etc_systemd_system_consul_certs_service.stat.isreg + - stat_etc_systemd_system_consul_certs_service.stat.pw_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.gr_name == 'root' + - stat_etc_systemd_system_consul_certs_service.stat.mode == '0644' + - slurp_etc_systemd_system_consul_certs_service.content != '' + - ansible_facts.services['consul-certs.service'] is defined + - ansible_facts.services['consul-certs.service']['source'] == 'systemd' + - ansible_facts.services['consul-certs.service']['state'] == 'stopped' + - ansible_facts.services['consul-certs.service']['status'] == 'enabled' diff --git a/roles/renew_consul_certificates/tasks/configure.yml b/roles/renew_consul_certificates/tasks/configure.yml new file mode 100644 index 0000000..7ef5491 --- /dev/null +++ b/roles/renew_consul_certificates/tasks/configure.yml @@ -0,0 +1,58 @@ +--- +# task/configure file for renew_consul_certificates +- name: "Configure files for consul certificate renewal" + notify: + - "systemctl-enable-consul-certs" + - "systemctl-restart-consul-certs" + block: + - name: "Copy consul_config.hcl template" + ansible.builtin.template: + src: consul_config.hcl.j2 + dest: "{{ renew_consul_certificates_config_dir }}/consul_config.hcl" + owner: "{{ renew_consul_certificates_consul_user }}" + group: "{{ renew_consul_certificates_consul_group }}" + mode: '0600' + + - name: "Copy consul_ca.pem.tpl template" + ansible.builtin.template: + src: consul_ca.pem.tpl.j2 + dest: "{{ renew_consul_certificates_config_dir }}/templates/consul_ca.pem.tpl" + owner: "{{ renew_consul_certificates_consul_user }}" + group: "{{ renew_consul_certificates_consul_group }}" + mode: '0600' + + - name: "Copy consul_cert.pem.tpl template" + ansible.builtin.template: + src: consul_cert.pem.tpl.j2 + dest: "{{ renew_consul_certificates_config_dir }}/templates/consul_cert.pem.tpl" + owner: "{{ renew_consul_certificates_consul_user }}" + group: "{{ renew_consul_certificates_consul_group }}" + mode: '0600' + + - name: "Copy consul_cert.key.tpl template" + ansible.builtin.template: + src: consul_key.pem.tpl.j2 + dest: "{{ renew_consul_certificates_config_dir }}/templates/consul_key.pem.tpl" + owner: "{{ renew_consul_certificates_consul_user }}" + group: "{{ renew_consul_certificates_consul_group }}" + mode: '0600' + +- name: "Configure consul-certs systemd service" + notify: + - "systemctl-daemon-reload" + block: + - name: "Configure consul-certs env file" + ansible.builtin.template: + src: consul-certs.env.j2 + dest: "{{ renew_consul_certificates_config_dir }}/consul-certs.env" + owner: root + group: root + mode: '0644' + + - name: "Configure consul-certs systemd service" + ansible.builtin.template: + src: consul-certs.service.j2 + dest: /etc/systemd/system/consul-certs.service + owner: root + group: root + mode: '0644' diff --git a/roles/renew_consul_certificates/tasks/install.yml b/roles/renew_consul_certificates/tasks/install.yml new file mode 100644 index 0000000..b559f50 --- /dev/null +++ b/roles/renew_consul_certificates/tasks/install.yml @@ -0,0 +1,15 @@ +--- +# task/install file for renew_consul_certificates +- name: "Configure hashicorp repository" + ansible.builtin.include_role: + name: ednxzu.manage_repositories + vars: + manage_repositories_enable_default_repo: false + manage_repositories_enable_custom_repo: true + manage_repositories_custom_repo: "{{ renew_consul_certificates_repository }}" + +- name: "Install consul-template" + ansible.builtin.include_role: + name: ednxzu.manage_apt_packages + vars: + manage_apt_packages_list: "{{ renew_consul_certificates_packages }}" diff --git a/roles/renew_consul_certificates/tasks/main.yml b/roles/renew_consul_certificates/tasks/main.yml new file mode 100644 index 0000000..088dca8 --- /dev/null +++ b/roles/renew_consul_certificates/tasks/main.yml @@ -0,0 +1,10 @@ +--- +# task/main file for renew_consul_certificates +- name: "Import prerequisites.yml" + ansible.builtin.include_tasks: prerequisites.yml + +- name: "Import install.yml" + ansible.builtin.include_tasks: install.yml + +- name: "Import configure.yml" + ansible.builtin.include_tasks: configure.yml diff --git a/roles/renew_consul_certificates/tasks/prerequisites.yml b/roles/renew_consul_certificates/tasks/prerequisites.yml new file mode 100644 index 0000000..32d7c20 --- /dev/null +++ b/roles/renew_consul_certificates/tasks/prerequisites.yml @@ -0,0 +1,29 @@ +--- +# task/prerequisites file for renew_consul_certificates +- name: "Create directory {{ renew_consul_certificates_config_dir }}" + ansible.builtin.file: + path: "{{ renew_consul_certificates_config_dir }}" + state: directory + owner: "{{ renew_consul_certificates_consul_user }}" + group: "{{ renew_consul_certificates_consul_group }}" + mode: '0755' + +- name: "Create directory templates directory in {{ renew_consul_certificates_config_dir }}" + ansible.builtin.file: + path: "{{ renew_consul_certificates_config_dir }}/templates" + state: directory + owner: "{{ renew_consul_certificates_consul_user }}" + group: "{{ renew_consul_certificates_consul_group }}" + mode: '0755' + +- name: "Ensure certificate/key directory(ies) exist(s)" + ansible.builtin.file: + path: "{{item | dirname }}" + state: directory + owner: "{{ renew_consul_certificates_consul_user }}" + group: "{{ renew_consul_certificates_consul_group }}" + mode: '0755' + loop: + - "{{ renew_consul_certificates_cert_dest }}" + - "{{ renew_consul_certificates_key_dest }}" + - "{{ renew_consul_certificates_ca_dest }}" diff --git a/roles/renew_consul_certificates/templates/consul-certs.env.j2 b/roles/renew_consul_certificates/templates/consul-certs.env.j2 new file mode 100644 index 0000000..0303f37 --- /dev/null +++ b/roles/renew_consul_certificates/templates/consul-certs.env.j2 @@ -0,0 +1,4 @@ +# {{ ansible_managed }} +{% for item in renew_consul_certificates_service_env_variables %} +{{ item|upper }}="{{ renew_consul_certificates_service_env_variables[item] }}" +{% endfor %} \ No newline at end of file diff --git a/roles/renew_consul_certificates/templates/consul-certs.service.j2 b/roles/renew_consul_certificates/templates/consul-certs.service.j2 new file mode 100644 index 0000000..987b365 --- /dev/null +++ b/roles/renew_consul_certificates/templates/consul-certs.service.j2 @@ -0,0 +1,17 @@ +[Unit] +Description=Automatic renewal of consul certificate using consul-template +Requires=network-online.target +After=network-online.target consul.service +ConditionFileNotEmpty={{ renew_consul_certificates_config_dir }}/consul_config.hcl + +[Service] +EnvironmentFile=-{{ renew_consul_certificates_config_dir }}/consul-certs.env +User={{ renew_consul_certificates_consul_user }} +Group={{ renew_consul_certificates_consul_group }} +ExecStart=/usr/bin/consul-template $OPTIONS -config={{ renew_consul_certificates_config_dir }}/consul_config.hcl +ExecReload=/bin/kill --signal HUP $MAINPID +KillSignal=SIGINT +Restart=on-failure + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/renew_consul_certificates/templates/consul_ca.pem.tpl.j2 b/roles/renew_consul_certificates/templates/consul_ca.pem.tpl.j2 new file mode 100644 index 0000000..65e4826 --- /dev/null +++ b/roles/renew_consul_certificates/templates/consul_ca.pem.tpl.j2 @@ -0,0 +1,5 @@ +{% raw %}{{ with secret {% endraw %}"{{ renew_consul_certificates_info['issuer_path'] }}" "common_name={{ renew_consul_certificates_info['common_name'] }}" "ttl={{ renew_consul_certificates_info['ttl'] }}" "alt_names=localhost{% if renew_consul_certificates_info['is_server'] %},server.{{ renew_consul_certificates_consul_dc_name }}{% endif %}{% if renew_consul_certificates_info['include_consul_service']%},{{ renew_consul_certificates_consul_service_name }}{% endif %}" "ip_sans=127.0.0.1"{% raw %} }}{% endraw %} + +{% raw %}{{ .Data.issuing_ca }}{% endraw %} + +{% raw %}{{ end }}{% endraw %} diff --git a/roles/renew_consul_certificates/templates/consul_cert.pem.tpl.j2 b/roles/renew_consul_certificates/templates/consul_cert.pem.tpl.j2 new file mode 100644 index 0000000..b45ded2 --- /dev/null +++ b/roles/renew_consul_certificates/templates/consul_cert.pem.tpl.j2 @@ -0,0 +1,7 @@ +{% raw %}{{ with secret {% endraw %}"{{ renew_consul_certificates_info['issuer_path'] }}" "common_name={{ renew_consul_certificates_info['common_name'] }}" "ttl={{ renew_consul_certificates_info['ttl'] }}" "alt_names=localhost{% if renew_consul_certificates_info['is_server'] %},server.{{ renew_consul_certificates_consul_dc_name }}{% endif %}{% if renew_consul_certificates_info['include_consul_service']%},{{ renew_consul_certificates_consul_service_name }}{% endif %}" "ip_sans=127.0.0.1"{% raw %} }}{% endraw %} + +{% raw %}{{ .Data.certificate }}{% endraw %} + +{% raw %}{{ .Data.issuing_ca }}{% endraw %} + +{% raw %}{{ end }}{% endraw %} diff --git a/roles/renew_consul_certificates/templates/consul_config.hcl.j2 b/roles/renew_consul_certificates/templates/consul_config.hcl.j2 new file mode 100644 index 0000000..cf34570 --- /dev/null +++ b/roles/renew_consul_certificates/templates/consul_config.hcl.j2 @@ -0,0 +1,33 @@ +vault { + address = "{{ renew_consul_certificates_vault_addr }}" + token = "{{ renew_consul_certificates_vault_token }}" + unwrap_token = {{ renew_consul_certificates_vault_token_unwrap|lower }} + renew_token = {{ renew_consul_certificates_vault_token_renew|lower }} +} + +template { + source = "{{ renew_consul_certificates_config_dir }}/templates/consul_ca.pem.tpl" + destination = "{{ renew_consul_certificates_ca_dest }}" + perms = 0700 + user = "{{ renew_consul_certificates_consul_user }}" + group = "{{ renew_consul_certificates_consul_group }}" + command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && consul reload '" +} + +template { + source = "{{ renew_consul_certificates_config_dir }}/templates/consul_cert.pem.tpl" + destination = "{{ renew_consul_certificates_cert_dest }}" + perms = 0700 + user = "{{ renew_consul_certificates_consul_user }}" + group = "{{ renew_consul_certificates_consul_group }}" + command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && consul reload '" +} + +template { + source = "{{ renew_consul_certificates_config_dir }}/templates/consul_key.pem.tpl" + destination = "{{ renew_consul_certificates_key_dest }}" + perms = 0700 + user = "{{ renew_consul_certificates_consul_user }}" + group = "{{ renew_consul_certificates_consul_group }}" + command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && consul reload '" +} diff --git a/roles/renew_consul_certificates/templates/consul_key.pem.tpl.j2 b/roles/renew_consul_certificates/templates/consul_key.pem.tpl.j2 new file mode 100644 index 0000000..234de6c --- /dev/null +++ b/roles/renew_consul_certificates/templates/consul_key.pem.tpl.j2 @@ -0,0 +1,5 @@ +{% raw %}{{ with secret {% endraw %}"{{ renew_consul_certificates_info['issuer_path'] }}" "common_name={{ renew_consul_certificates_info['common_name'] }}" "ttl={{ renew_consul_certificates_info['ttl'] }}" "alt_names=localhost{% if renew_consul_certificates_info['is_server'] %},server.{{ renew_consul_certificates_consul_dc_name }}{% endif %}{% if renew_consul_certificates_info['include_consul_service']%},{{ renew_consul_certificates_consul_service_name }}{% endif %}" "ip_sans=127.0.0.1"{% raw %} }}{% endraw %} + +{% raw %}{{ .Data.private_key }}{% endraw %} + +{% raw %}{{ end }}{% endraw %} diff --git a/roles/renew_consul_certificates/vars/main.yml b/roles/renew_consul_certificates/vars/main.yml new file mode 100644 index 0000000..9ec775b --- /dev/null +++ b/roles/renew_consul_certificates/vars/main.yml @@ -0,0 +1,18 @@ +--- +# vars file for renew_consul_certificates +renew_consul_certificates_repository: + - name: hashicorp + uri: "https://apt.releases.hashicorp.com" + comments: "hashicorp repository" + types: + - deb + suites: + - "{{ ansible_distribution_release }}" + components: + - main + options: + Signed-By: "https://apt.releases.hashicorp.com/gpg" +renew_consul_certificates_packages: + - name: consul-template + version: latest + state: present