From 7fec0b69a082aaeec72fee0612766aa42f6b1b4d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 18 Apr 2024 07:52:35 +0200 Subject: Merging upstream version 9.4.0+dfsg. Signed-off-by: Daniel Baumann --- .../actions/docker-image-versions/action.yml | 3 +- .../actions/docker-image-versions/versions.py | 13 +- .../community/hashi_vault/.github/dependabot.yml | 9 + .../.github/workflows/ansible-builder.yml | 7 +- .../hashi_vault/.github/workflows/ansible-test.yml | 181 +- .../.github/workflows/github-release.yml | 12 +- .../community/hashi_vault/CHANGELOG.md | 828 ++++++++++ .../community/hashi_vault/CHANGELOG.rst | 97 +- .../community/hashi_vault/FILES.json | 1731 ++++++++++++++++---- .../community/hashi_vault/MANIFEST.json | 4 +- .../community/hashi_vault/README.md | 14 +- .../hashi_vault/changelogs/changelog.yaml | 121 ++ .../community/hashi_vault/changelogs/config.yaml | 1 + .../hashi_vault/docs/docsite/rst/CHANGELOG.rst | 97 +- .../hashi_vault/docs/docsite/rst/user_guide.rst | 11 +- .../community/hashi_vault/meta/ee-requirements.txt | 2 +- .../community/hashi_vault/meta/runtime.yml | 16 +- .../hashi_vault/plugins/doc_fragments/auth.py | 6 + .../hashi_vault/plugins/lookup/hashi_vault.py | 5 +- .../plugins/lookup/vault_token_create.py | 2 +- .../hashi_vault/plugins/lookup/vault_write.py | 19 +- .../plugins/module_utils/_auth_method_token.py | 2 +- .../plugins/module_utils/_connection_options.py | 8 +- .../plugins/module_utils/_hashi_vault_common.py | 50 +- .../modules/vault_database_connection_configure.py | 193 +++ .../modules/vault_database_connection_delete.py | 146 ++ .../modules/vault_database_connection_read.py | 162 ++ .../modules/vault_database_connection_reset.py | 145 ++ .../modules/vault_database_connections_list.py | 176 ++ .../plugins/modules/vault_database_role_create.py | 207 +++ .../plugins/modules/vault_database_role_delete.py | 146 ++ .../plugins/modules/vault_database_role_read.py | 175 ++ .../plugins/modules/vault_database_roles_list.py | 173 ++ .../vault_database_rotate_root_credentials.py | 150 ++ .../modules/vault_database_static_role_create.py | 188 +++ .../vault_database_static_role_get_credentials.py | 167 ++ .../modules/vault_database_static_role_read.py | 171 ++ ...ault_database_static_role_rotate_credentials.py | 152 ++ .../modules/vault_database_static_roles_list.py | 174 ++ .../hashi_vault/plugins/modules/vault_write.py | 19 +- .../plugin_utils/_hashi_vault_lookup_base.py | 7 +- .../hashi_vault/tests/integration/constraints.txt | 64 + .../hashi_vault/tests/integration/requirements.txt | 20 +- .../auth_approle/tasks/approle_test_controller.yml | 2 +- .../auth_approle/tasks/approle_test_target.yml | 4 +- .../targets/auth_approle/tasks/main.yml | 2 +- .../auth_aws_iam/tasks/aws_iam_test_target.yml | 2 +- .../targets/auth_aws_iam/tasks/main.yml | 2 +- .../targets/auth_azure/tasks/azure_test_target.yml | 4 +- .../integration/targets/auth_azure/tasks/main.yml | 2 +- .../targets/auth_cert/tasks/cert_test_target.yml | 2 +- .../integration/targets/auth_cert/tasks/main.yml | 2 +- .../targets/auth_jwt/tasks/jwt_test_target.yml | 2 +- .../integration/targets/auth_jwt/tasks/main.yml | 2 +- .../targets/auth_ldap/tasks/ldap_test_target.yml | 2 +- .../integration/targets/auth_ldap/tasks/main.yml | 2 +- .../integration/targets/auth_token/tasks/main.yml | 4 +- .../auth_token/tasks/token_test_controller.yml | 2 +- .../targets/auth_token/tasks/token_test_target.yml | 2 +- .../targets/auth_userpass/tasks/main.yml | 2 +- .../auth_userpass/tasks/userpass_test_target.yml | 2 +- .../connection_options/tasks/controller.yml | 16 +- .../targets/connection_options/tasks/target.yml | 14 +- .../lookup_hashi_vault/tasks/lookup_test.yml | 33 +- .../tasks/lookup_vault_write_test.yml | 3 + .../aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...e_vault_database_connection_configure_setup.yml | 9 + ...le_vault_database_connection_configure_test.yml | 192 +++ .../aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...dule_vault_database_connection_delete_setup.yml | 36 + ...odule_vault_database_connection_delete_test.yml | 84 + .../module_vault_database_connection_read/aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...module_vault_database_connection_read_setup.yml | 9 + .../module_vault_database_connection_read_test.yml | 134 ++ .../module_vault_database_connection_reset/aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...odule_vault_database_connection_reset_setup.yml | 9 + ...module_vault_database_connection_reset_test.yml | 84 + .../module_vault_database_connections_list/aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...module_vault_database_connection_list_setup.yml | 9 + .../module_vault_database_connection_list_test.yml | 72 + .../module_vault_database_role_create/aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + .../module_vault_database_role_create_setup.yml | 13 + .../module_vault_database_role_create_test.yml | 92 ++ .../module_vault_database_role_delete/aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + .../module_vault_database_role_delete_setup.yml | 34 + .../module_vault_database_role_delete_test.yml | 75 + .../module_vault_database_role_read/aliases | 1 + .../module_vault_database_role_read/meta/main.yml | 4 + .../module_vault_database_role_read/tasks/main.yml | 3 + .../module_vault_database_role_read_setup.yml | 9 + .../tasks/module_vault_database_role_read_test.yml | 126 ++ .../module_vault_database_roles_list/aliases | 1 + .../module_vault_database_roles_list/meta/main.yml | 4 + .../tasks/main.yml | 3 + .../module_vault_database_roles_list_setup.yml | 9 + .../module_vault_database_roles_list_test.yml | 65 + .../aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 10 + .../module_vault_db_rotate_root_creds_cleanup.yml | 12 + .../module_vault_db_rotate_root_creds_setup.yml | 46 + .../module_vault_db_rotate_root_creds_test.yml | 132 ++ .../aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...ule_vault_database_static_role_create_setup.yml | 13 + ...dule_vault_database_static_role_create_test.yml | 130 ++ .../aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ..._database_static_role_get_credentials_setup.yml | 13 + ...t_database_static_role_get_credentials_test.yml | 114 ++ .../module_vault_database_static_role_read/aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...odule_vault_database_static_role_read_setup.yml | 9 + ...module_vault_database_static_role_read_test.yml | 123 ++ .../aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 8 + ...ule_vault_db_static_role_rotate_creds_setup.yml | 23 + ...dule_vault_db_static_role_rotate_creds_test.yml | 120 ++ .../aliases | 1 + .../meta/main.yml | 4 + .../tasks/main.yml | 3 + ...dule_vault_database_static_roles_list_setup.yml | 9 + ...odule_vault_database_static_roles_list_test.yml | 91 + .../tasks/module_vault_login_test.yml | 2 +- .../tasks/module_vault_write_test.yml | 14 +- .../setup_localenv_docker/defaults/main.yml | 12 + .../files/playbooks/vault_docker.yml | 2 +- .../files/requirements/constraints.txt | 5 +- .../files/requirements/requirements.txt | 1 - .../setup_localenv_docker/files/sql/init.sql | 16 + .../targets/setup_localenv_docker/tasks/main.yml | 31 +- .../templates/docker-compose.yml.j2 | 17 +- .../targets/setup_localenv_docker/vars/main.yml | 5 + .../setup_localenv_gha/files/playbooks/gha.yml | 2 +- .../setup_vault_configure_database/README.md | 2 + .../targets/setup_vault_configure_database/aliases | 2 + .../setup_vault_configure_database/meta/main.yml | 3 + .../tasks/configure.yml | 48 + .../setup_vault_configure_database/tasks/main.yml | 17 + .../setup_vault_configure_database/vars/main.yml | 27 + .../community/hashi_vault/tests/unit/conftest.py | 10 + .../hashi_vault/tests/unit/constraints.txt | 64 + .../database_connection_read_response.json | 20 + .../database_connections_list_response.json | 21 + .../unit/fixtures/database_role_read_response.json | 22 + .../fixtures/database_roles_list_response.json | 21 + ...abase_static_role_get_credentials_response.json | 25 + .../database_static_role_read_response.json | 18 + .../database_static_roles_list_response.json | 21 + .../unit/plugins/lookup/test_vault_token_create.py | 13 +- .../tests/unit/plugins/lookup/test_vault_write.py | 47 +- .../authentication/test_auth_aws_iam.py | 2 +- .../module_utils/authentication/test_auth_azure.py | 12 +- .../module_utils/authentication/test_auth_token.py | 6 +- .../test_hashi_vault_auth_method_base.py | 14 +- .../test_hashi_vault_option_adapter.py | 74 +- .../test_hashi_vault_connection_options.py | 4 +- .../module_utils/test_hashi_vault_helper.py | 10 - .../test_vault_database_connection_configure.py | 195 +++ .../test_vault_database_connection_delete.py | 181 ++ .../modules/test_vault_database_connection_read.py | 200 +++ .../test_vault_database_connection_reset.py | 181 ++ .../test_vault_database_connections_list.py | 228 +++ .../modules/test_vault_database_role_create.py | 197 +++ .../modules/test_vault_database_role_delete.py | 180 ++ .../modules/test_vault_database_role_read.py | 200 +++ .../modules/test_vault_database_roles_list.py | 228 +++ .../test_vault_database_rotate_root_credentials.py | 197 +++ .../test_vault_database_static_role_create.py | 192 +++ ...t_vault_database_static_role_get_credentials.py | 202 +++ .../test_vault_database_static_role_read.py | 200 +++ ...ault_database_static_role_rotate_credentials.py | 199 +++ .../test_vault_database_static_roles_list.py | 228 +++ .../modules/test_vault_pki_generate_certificate.py | 2 +- .../tests/unit/plugins/modules/test_vault_write.py | 58 +- .../plugin_utils/authentication/conftest.py | 10 - .../plugin_utils/authentication/test_auth_token.py | 54 - .../base/test_hashi_vault_lookup_base.py | 16 +- .../plugin_utils/option_adapter/conftest.py | 29 +- .../test_hashi_vault_option_adapter.py | 2 +- .../test_hashi_vault_common_stringify.py | 48 - .../plugin_utils/test_hashi_vault_helper.py | 58 - .../hashi_vault/tests/unit/requirements.txt | 18 +- .../hashi_vault/tests/utils/constraints.txt | 62 - 202 files changed, 11074 insertions(+), 911 deletions(-) create mode 100644 ansible_collections/community/hashi_vault/.github/dependabot.yml create mode 100644 ansible_collections/community/hashi_vault/CHANGELOG.md create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py create mode 100644 ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py create mode 100644 ansible_collections/community/hashi_vault/tests/integration/constraints.txt create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml create mode 100644 ansible_collections/community/hashi_vault/tests/unit/constraints.txt create mode 100644 ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json create mode 100644 ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json create mode 100644 ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json create mode 100644 ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json create mode 100644 ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json create mode 100644 ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json create mode 100644 ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py create mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py delete mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/conftest.py delete mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py delete mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py delete mode 100644 ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py delete mode 100644 ansible_collections/community/hashi_vault/tests/utils/constraints.txt (limited to 'ansible_collections/community/hashi_vault') diff --git a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml index 766067df7..d2503deaa 100644 --- a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml +++ b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml @@ -8,8 +8,7 @@ outputs: inputs: image: description: The docker image name. - required: false - default: vault + required: true num_major_versions: description: Number of unique major versions to return. required: false diff --git a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py index 9d7fcea2d..d73680f8c 100755 --- a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py +++ b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py @@ -21,7 +21,7 @@ from warnings import warn from packaging import version -TAG_URI = 'https://registry.hub.docker.com/v2/repositories/library/%s/tags?page_size=1024' +TAG_URI = 'https://registry.hub.docker.com/v2/repositories/%s/%s/tags?page_size=1024' class WarningRetry(Retry): @@ -49,7 +49,7 @@ def main(argv): for opt, arg in opts: if opt == '--image': - image = arg + image = image_name = arg elif opt == '--num_major_versions': num_major_versions = int(arg) elif opt == '--num_minor_versions': @@ -64,7 +64,12 @@ def main(argv): if image is None: raise ValueError('image must be supplied.') - tag_url = TAG_URI % image + if '/' in image: + org, image_name = image.split('/') + else: + org = 'library' + + tag_url = TAG_URI % (org, image_name) sess = requests.Session() retry = WarningRetry(total=5, backoff_factor=0.2, respect_retry_after_header=False) @@ -112,7 +117,7 @@ def main(argv): keep.append(str(ver)) - with open(os.environ['GITHUB_OUTPUT'], 'a') as f: + with open(os.environ.get('GITHUB_OUTPUT', '/dev/stdout'), 'a') as f: f.write('versions=') json.dump(keep, f) diff --git a/ansible_collections/community/hashi_vault/.github/dependabot.yml b/ansible_collections/community/hashi_vault/.github/dependabot.yml new file mode 100644 index 000000000..969b36fe0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/.github/dependabot.yml @@ -0,0 +1,9 @@ +--- +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml b/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml index 10aeb5c2d..a3a849c46 100644 --- a/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml +++ b/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml @@ -24,14 +24,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: + show-progress: false path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }} - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: 3.11 - name: Install ansible-builder run: pip install ansible-builder diff --git a/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml b/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml index 25857dadb..b1b079817 100644 --- a/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml +++ b/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml @@ -2,6 +2,8 @@ name: CI on: # Run CI against all pushes (direct commits, also merged PRs), Pull Requests push: + branches-ignore: + - 'dependabot/**' paths-ignore: - 'docs/**' - '.github/workflows/_shared-*' @@ -31,17 +33,16 @@ jobs: name: Sanity (Ⓐ${{ matrix.ansible }}) runs-on: ${{ matrix.runner }} strategy: + fail-fast: false matrix: runner: - ubuntu-latest test_container: - default ansible: - - stable-2.11 - - stable-2.12 - - stable-2.13 - stable-2.14 - stable-2.15 + - stable-2.16 - devel steps: @@ -55,22 +56,23 @@ jobs: TEST_INVOCATION="sanity --docker ${{ matrix.test_container }} -v --color ${{ github.event_name != 'schedule' && '--coverage' || '' }}" - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: + show-progress: false path: ${{ env.COLLECTION_PATH }} - name: Link to .github # easier access to local actions run: ln -s "${COLLECTION_PATH}/.github" .github - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: # it is just required to run that once as "ansible-test sanity" in the docker image # will run on all python versions it supports. - python-version: 3.9 + python-version: '3.11' # Install the head of the given branch (devel, stable-2.14) - - name: Install ansible-base (${{ matrix.ansible }}) + - name: Install ansible-core (${{ matrix.ansible }}) run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check - name: Pull Ansible test images @@ -95,7 +97,7 @@ jobs: - name: Upload ${{ github.job }} coverage reports if: ${{ github.event_name != 'schedule' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=data path: ${{ env.COLLECTION_PATH }}/tests/output/reports/ @@ -107,19 +109,16 @@ jobs: runs-on: ${{ matrix.runner }} name: Units (Ⓐ${{ matrix.ansible }}) strategy: - # As soon as the first unit test fails, cancel the others to free up the CI queue - fail-fast: true + fail-fast: false matrix: runner: - ubuntu-latest test_container: - default ansible: - - stable-2.11 - - stable-2.12 - - stable-2.13 - stable-2.14 - stable-2.15 + - stable-2.16 - devel steps: @@ -131,21 +130,22 @@ jobs: TEST_INVOCATION="units --color --docker ${{ matrix.test_container }} ${{ github.event_name != 'schedule' && '--coverage' || '' }}" - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: + show-progress: false path: ${{ env.COLLECTION_PATH }} - name: Link to .github # easier access to local actions run: ln -s "${COLLECTION_PATH}/.github" .github - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: # it is just required to run that once as "ansible-test units" in the docker image # will run on all python versions it supports. - python-version: 3.9 + python-version: '3.11' - - name: Install ansible-base (${{ matrix.ansible }}) + - name: Install ansible-core (${{ matrix.ansible }}) run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check - name: Pull Ansible test images @@ -168,7 +168,7 @@ jobs: - name: Upload ${{ github.job }} coverage reports if: ${{ github.event_name != 'schedule' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=data path: ${{ env.COLLECTION_PATH }}/tests/output/reports/ @@ -182,7 +182,7 @@ jobs: integration: runs-on: ${{ matrix.runner }} - name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) + name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}+V[-${{ matrix.vault_minus }}]) strategy: fail-fast: false matrix: @@ -190,12 +190,13 @@ jobs: - ubuntu-latest test_container: - default + vault_minus: + - 0 + - 1 ansible: - - stable-2.11 - - stable-2.12 - - stable-2.13 - stable-2.14 - stable-2.15 + - stable-2.16 - devel python: - '3.6' @@ -204,29 +205,36 @@ jobs: - '3.9' - '3.10' - '3.11' + - '3.12' exclude: # https://docs.ansible.com/ansible/devel/installation_guide/intro_installation.html#control-node-requirements # https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix - - ansible: 'stable-2.11' - python: '3.10' - - ansible: 'stable-2.11' - python: '3.11' - - ansible: 'stable-2.12' - python: '3.11' - - ansible: 'stable-2.13' - python: '3.11' - - ansible: 'stable-2.15' + - ansible: 'devel' python: '3.6' - - ansible: 'stable-2.15' + - ansible: 'devel' python: '3.7' - - ansible: 'stable-2.15' + - ansible: 'devel' python: '3.8' - ansible: 'devel' + python: '3.9' + - ansible: 'stable-2.16' python: '3.6' - - ansible: 'devel' + - ansible: 'stable-2.16' python: '3.7' - - ansible: 'devel' + - ansible: 'stable-2.16' + python: '3.8' + - ansible: 'stable-2.16' + python: '3.9' + - ansible: 'stable-2.15' + python: '3.6' + - ansible: 'stable-2.15' + python: '3.7' + - ansible: 'stable-2.15' + python: '3.12' + - ansible: 'stable-2.15' python: '3.8' + - ansible: 'stable-2.14' + python: '3.12' steps: - name: Initialize env vars @@ -239,29 +247,36 @@ jobs: TEST_INVOCATION="integration -v --color --retry-on-error --continue-on-error --python ${{ matrix.python }} --docker ${{ matrix.test_container }} ${{ github.event_name != 'schedule' && '--coverage' || '' }} --docker-network hashi_vault_default" - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: + show-progress: false path: ${{ env.COLLECTION_PATH }} - name: Link to .github # easier access to local actions run: ln -s "${COLLECTION_PATH}/.github" .github - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: '3.11' - name: Get Vault versions id: vault_versions uses: ./.github/actions/docker-image-versions with: + image: hashicorp/vault num_major_versions: 1 num_minor_versions: 2 num_micro_versions: 1 - - name: Install ansible-base (${{ matrix.ansible }}) + - name: Install ansible-core (${{ matrix.ansible }}) run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + - name: Install community.postgresql + uses: ./.github/actions/collection-via-git + with: + collection: community.postgresql + - name: Pull Ansible test images timeout-minutes: 5 continue-on-error: true @@ -270,23 +285,10 @@ jobs: working-directory: ${{ env.COLLECTION_PATH }} ansible-test-invocation: ${{ env.TEST_INVOCATION }} - - name: Set Vault Version (older) + - name: Set Vault Version uses: briantist/ezenv@v1 with: - env: VAULT_VERSION=${{ fromJSON(steps.vault_versions.outputs.versions)[1] }} - - - name: Prepare docker dependencies (Vault ${{ env.VAULT_VERSION }}) - run: ./setup.sh -e vault_version=${VAULT_VERSION} - working-directory: ${{ env.COLLECTION_INTEGRATION_TARGETS }}/setup_localenv_gha - - - name: Run integration test (Vault ${{ env.VAULT_VERSION }}) - run: ansible-test ${{ env.TEST_INVOCATION }} - working-directory: ${{ env.COLLECTION_PATH }} - - - name: Set Vault Version (newer) - uses: briantist/ezenv@v1 - with: - env: VAULT_VERSION=${{ fromJSON(steps.vault_versions.outputs.versions)[0] }} + env: VAULT_VERSION=${{ fromJSON(steps.vault_versions.outputs.versions)[matrix.vault_minus] }} - name: Prepare docker dependencies (Vault ${{ env.VAULT_VERSION }}) run: ./setup.sh -e vault_version=${VAULT_VERSION} @@ -304,9 +306,9 @@ jobs: - name: Upload ${{ github.job }} coverage reports if: ${{ github.event_name != 'schedule' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=data + name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=vault_minus_${{ matrix.vault_minus }}=data path: ${{ env.COLLECTION_PATH }}/tests/output/reports/ if-no-files-found: error retention-days: 1 @@ -318,14 +320,22 @@ jobs: fail-fast: false matrix: ansible: - - stable-2.15 + - stable-2.16 - devel + delete_canaries: + - true + - false python: - - 3.9 + - '3.12' runner: - ubuntu-latest test_container: - default + exclude: + - ansible: devel + delete_canaries: false + - ansible: stable-2.16 + delete_canaries: true steps: - name: Initialize env vars @@ -338,19 +348,20 @@ jobs: DOCKER_TEST_INVOCATION="integration -v --color --retry-on-error --continue-on-error --controller docker:${{ matrix.test_container }},python=${{ matrix.python }} ${{ github.event_name != 'schedule' && '--coverage' || '' }}" - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: + show-progress: false path: ${{ env.COLLECTION_PATH }} - name: Link to .github # easier access to local actions run: ln -s "${COLLECTION_PATH}/.github" .github - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - - name: Install ansible-base (${{ matrix.ansible }}) + - name: Install ansible-core (${{ matrix.ansible }}) run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check - name: Install community.crypto @@ -363,6 +374,11 @@ jobs: with: collection: community.docker + - name: Install community.postgresql + uses: ./.github/actions/collection-via-git + with: + collection: community.postgresql + - name: Pull Ansible test images timeout-minutes: 5 continue-on-error: true @@ -374,6 +390,10 @@ jobs: - name: localenv_docker - setup run: | pwd + pip install --upgrade pip setuptools build wheel + pip install "Cython<3.0" "pyyaml<6" --no-build-isolation + # ^ https://github.com/yaml/pyyaml/issues/601 + # ^ https://github.com/docker/compose/issues/10836 pip install -r files/requirements/requirements.txt -c files/requirements/constraints.txt ./setup.sh working-directory: ${{ env.COLLECTION_INTEGRATION_TARGETS }}/setup_localenv_docker @@ -383,13 +403,9 @@ jobs: ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default working-directory: ${{ env.COLLECTION_PATH }} - - name: Run integration again (ensure tests do not break against still-running containers) - run: | - ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default - working-directory: ${{ env.COLLECTION_PATH }} - #TODO add capability in the Ansible side once vault_list and vault_delete exist - - name: Run a third time, but delete Vault's cubbyhole contents first + - name: Delete Vault's cubbyhole contents (ensure test setup is idempotent) + if: matrix.delete_canaries working-directory: ${{ env.COLLECTION_PATH }} env: VAULT_TOKEN: 47542cbc-6bf8-4fba-8eda-02e0a0d29a0a @@ -398,8 +414,11 @@ jobs: echo 'vault list cubbyhole \ | tail -n +3 \ | xargs -I{} -n 1 vault delete cubbyhole/{}' \ - | docker run --rm --network hashi_vault_default -e VAULT_TOKEN -e VAULT_ADDR -i vault sh + | docker run --rm --network hashi_vault_default -e VAULT_TOKEN -e VAULT_ADDR -i hashicorp/vault sh + - name: Run integration again (ensure tests do not break against still-running containers) + working-directory: ${{ env.COLLECTION_PATH }} + run: | ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default # ansible-test support producing code coverage data @@ -410,7 +429,7 @@ jobs: - name: Upload ${{ github.job }} coverage reports if: ${{ github.event_name != 'schedule' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: coverage=${{ github.job }}=${{ matrix.runner }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=data path: ${{ env.COLLECTION_PATH }}/tests/output/reports/ @@ -430,31 +449,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 + with: + show-progress: false - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: ./cov - # Before Ansible 2.12, units always used a "target" of "units", and we don't want a flag of "target_units". - # After 2.12, target can be "controller" or "module_utils" and we'll preserve them for now. - # If we decide that those targets are not helpful, we can simplify processing by removing this run block - # and just having two ansible-codecov calls, one for units (that excludes target) and one for integration. - # That change would also make integration processing faster because we can hardcode the integration flag as an additional flag. - - name: Move Ansible pre-2.12 units - run: | - mkdir ./cov-units-pre2.12 - mv ./cov/coverage=units=ansible_stable-2.11=data ./cov-units-pre2.12 - - - name: Upload Ansible pre-2.12 unit coverage reports to Codecov - uses: ./.github/actions/ansible-codecov - with: - directory: ./cov-units-pre2.12 - additional-flags: units - file-flag-pattern: coverage=units=units={env_%}.xml - directory-flag-pattern: =ansible_{ansible-%}= - # See the reports at https://codecov.io/gh/ansible-collections/community.hashi_vault - name: Upload coverage reports to Codecov uses: ./.github/actions/ansible-codecov diff --git a/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml b/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml index 6fce7d2e6..4a2a2418e 100644 --- a/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml +++ b/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml @@ -15,18 +15,20 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + with: + show-progress: false - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: 3.12 - name: Install PyYaml - run: pip install pyyaml + run: pip install pyyaml ansible-core - name: Validate version is published to Galaxy - run: curl --head -s -f -o /dev/null https://galaxy.ansible.com/download/community-hashi_vault-${{ github.event.inputs.version }}.tar.gz + run: ansible-galaxy collection download -vvv -p /tmp 'community.hashi_vault:==${{ github.event.inputs.version }}' - name: Build release description shell: python diff --git a/ansible_collections/community/hashi_vault/CHANGELOG.md b/ansible_collections/community/hashi_vault/CHANGELOG.md new file mode 100644 index 000000000..87ac6d4e0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/CHANGELOG.md @@ -0,0 +1,828 @@ +# community\.hashi\_vault Release Notes + +**Topics** + +- v6\.2\.0 + - Release Summary + - Minor Changes + - New Modules +- v6\.1\.0 + - Release Summary + - Major Changes +- v6\.0\.0 + - Release Summary + - Breaking Changes / Porting Guide + - Removed Features \(previously deprecated\) +- v5\.0\.1 + - Release Summary + - Bugfixes +- v5\.0\.0 + - Release Summary + - Breaking Changes / Porting Guide +- v4\.2\.1 + - Release Summary +- v4\.2\.0 + - Release Summary + - Deprecated Features + - Bugfixes + - New Modules +- v4\.1\.0 + - Release Summary + - Deprecated Features + - New Plugins + - Lookup + - New Modules +- v4\.0\.0 + - Release Summary + - Minor Changes + - Breaking Changes / Porting Guide +- v3\.4\.0 + - Release Summary + - Minor Changes + - Bugfixes + - New Modules +- v3\.3\.1 + - Release Summary +- v3\.3\.0 + - Release Summary + - Minor Changes +- v3\.2\.0 + - Release Summary + - Minor Changes + - Bugfixes +- v3\.1\.0 + - Release Summary + - Deprecated Features + - Bugfixes +- v3\.0\.0 + - Release Summary + - Deprecated Features + - Removed Features \(previously deprecated\) +- v2\.5\.0 + - Release Summary + - Minor Changes + - Deprecated Features + - New Plugins + - Lookup + - New Modules +- v2\.4\.0 + - Release Summary + - New Plugins + - Lookup + - New Modules +- v2\.3\.0 + - Release Summary + - New Plugins + - Lookup + - New Modules +- v2\.2\.0 + - Release Summary + - Minor Changes + - New Plugins + - Filter + - Lookup + - New Modules +- v2\.1\.0 + - Release Summary + - Deprecated Features + - Removed Features \(previously deprecated\) +- v2\.0\.0 + - Release Summary + - Breaking Changes / Porting Guide + - Removed Features \(previously deprecated\) +- v1\.5\.0 + - Release Summary + - Minor Changes +- v1\.4\.1 + - Release Summary + - Bugfixes +- v1\.4\.0 + - Release Summary + - Minor Changes + - Deprecated Features + - Bugfixes + - New Plugins + - Lookup + - New Modules +- v1\.3\.2 + - Release Summary + - Minor Changes + - Deprecated Features +- v1\.3\.1 + - Release Summary +- v1\.3\.0 + - Release Summary + - Minor Changes +- v1\.2\.0 + - Release Summary + - Minor Changes + - Deprecated Features +- v1\.1\.3 + - Release Summary + - Bugfixes +- v1\.1\.2 + - Release Summary +- v1\.1\.1 + - Release Summary + - Bugfixes +- v1\.1\.0 + - Release Summary + - Minor Changes +- v1\.0\.0 + - Release Summary + - Breaking Changes / Porting Guide +- v0\.2\.0 + - Release Summary + - Minor Changes + - Deprecated Features + - Bugfixes +- v0\.1\.0 + - Release Summary + + +## v6\.2\.0 + + +### Release Summary + +This release contains a dozen\+ new modules for working with Vault\'s database secrets engine and some new vars entries for specifying public and private keys in cert auth\. + + +### Minor Changes + +* cert auth \- add option to set the cert\_auth\_public\_key and cert\_auth\_private\_key parameters using the variables ansible\_hashi\_vault\_cert\_auth\_public\_key and ansible\_hashi\_vault\_cert\_auth\_private\_key \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/428](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/428)\)\. + + +### New Modules + +* vault\_database\_connection\_configure \- Configures the database engine +* vault\_database\_connection\_delete \- Delete a Database Connection +* vault\_database\_connection\_read \- Returns the configuration settings for a O\(connection\_name\) +* vault\_database\_connection\_reset \- Closes a O\(connection\_name\) and its underlying plugin and restarts it with the configuration stored +* vault\_database\_connections\_list \- Returns a list of available connections +* vault\_database\_role\_create \- Creates or updates a \(dynamic\) role definition +* vault\_database\_role\_delete \- Delete a role definition +* vault\_database\_role\_read \- Queries a dynamic role definition +* vault\_database\_roles\_list \- Returns a list of available \(dynamic\) roles +* vault\_database\_rotate\_root\_credentials \- Rotates the root credentials stored for the database connection\. This user must have permissions to update its own password\. +* vault\_database\_static\_role\_create \- Create or update a static role +* vault\_database\_static\_role\_get\_credentials \- Returns the current credentials based on the named static role +* vault\_database\_static\_role\_read \- Queries a static role definition +* vault\_database\_static\_role\_rotate\_credentials \- Trigger the credential rotation for a static role +* vault\_database\_static\_roles\_list \- Returns a list of available static roles + + +## v6\.1\.0 + + +### Release Summary + +This release addresses some breaking changes in core that were backported\. + + +### Major Changes + +* requirements \- the requests package which is required by hvac now has a more restrictive range for this collection in certain use cases due to breaking security changes in ansible\-core that were backported \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/416](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/416)\)\. + + +## v6\.0\.0 + + +### Release Summary + +This major version of the collection has no functional changes from the previous version\, however the minimum versions of hvac and ansible\-core have been raised\. While the collection may still work with those earlier versions\, future changes will not test against them\. + + +### Breaking Changes / Porting Guide + +* The minimum required version of hvac is now 1\.2\.1 \([https\://docs\.ansible\.com/ansible/devel/collections/community/hashi\_vault/docsite/user\_guide\.html\#hvac\-version\-specifics](https\://docs\.ansible\.com/ansible/devel/collections/community/hashi\_vault/docsite/user\_guide\.html\#hvac\-version\-specifics)\)\. + + +### Removed Features \(previously deprecated\) + +* The minimum supported version of ansible\-core is now 2\.14\, support for 2\.13 has been dropped \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/403](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/403)\)\. + + +## v5\.0\.1 + + +### Release Summary + +This release fixes a bug in vault\_write ahead of the collection\'s next major release\. + + +### Bugfixes + +* vault\_write \- the vault\_write lookup and module were not able to write data containing keys named path or wrap\_ttl due to a bug in the hvac library\. These plugins have now been updated to take advantage of fixes in hvac\>\=1\.2 to address this \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/389](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/389)\)\. + + +## v5\.0\.0 + + +### Release Summary + +This version makes some relatively minor but technically breaking changes\. Support for ansible\-core versions 2\.11 and 2\.12 have been dropped\, and there is now a minimum supported version of hvac which will be updated over time\. A warning in the hashi\_vault lookup on duplicate option specifications in the term string has been changed to a fatal error\. + + +### Breaking Changes / Porting Guide + +* Support for ansible\-core 2\.11 and 2\.12 has been removed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340)\)\. +* The minimum version of hvac for community\.hashi\_vault is now 1\.1\.0 \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324)\)\. +* hashi\_vault lookup \- duplicate option entries in the term string now raises an exception instead of a warning \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356)\)\. + + +## v4\.2\.1 + + +### Release Summary + +This patch version updates the documentation for the vault\_kv2\_write module\. There are no functional changes\. + + +## v4\.2\.0 + + +### Release Summary + +This release contains a new module for KVv2 writes\, and a new warning for duplicated term string options in the hashi\_vault lookup\. + + +### Deprecated Features + +* hashi\_vault lookup \- in v5\.0\.0 duplicate term string options will raise an exception instead of showing a warning \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356)\)\. + + +### Bugfixes + +* hashi\_vault lookup \- a term string with duplicate options would silently use the last value\. The lookup now shows a warning on option duplication \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/349](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/349)\)\. + + +### New Modules + +* vault\_kv2\_write \- Perform a write operation against a KVv2 secret in HashiCorp Vault + + +## v4\.1\.0 + + +### Release Summary + +This release brings new generic vault\_list plugins from a new contributor\! +There are also some deprecation notices for the next major version\, and some updates to documentation attributes\. + + +### Deprecated Features + +* ansible\-core \- support for ansible\-core versions 2\.11 and 2\.12 will be dropped in collection version 5\.0\.0\, making 2\.13 the minimum supported version of ansible\-core \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340)\)\. +* hvac \- the minimum version of hvac to be supported in collection version 5\.0\.0 will be at least 1\.0\.2\; this minimum may be raised before 5\.0\.0 is released\, so please subscribe to the linked issue and look out for new notices in the changelog \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324)\)\. + + +### New Plugins + + +#### Lookup + +* vault\_list \- Perform a list operation against HashiCorp Vault + + +### New Modules + +* vault\_list \- Perform a list operation against HashiCorp Vault + + +## v4\.0\.0 + + +### Release Summary + +The next major version of the collection includes previously announced breaking changes to some default values\, and improvements to module documentation with attributes that describe the use of action groups and check mode support\. + + +### Minor Changes + +* modules \- all modules now document their action group and support for check mode in their attributes documentation \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/197](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/197)\)\. + + +### Breaking Changes / Porting Guide + +* auth \- the default value for token\_validate has changed from true to false\, as previously announced \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248)\)\. +* vault\_kv2\_get lookup \- as previously announced\, the default value for engine\_mount\_point in the vault\_kv2\_get lookup has changed from kv to secret \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279)\)\. + + +## v3\.4\.0 + + +### Release Summary + +This release includes a new module\, fixes \(another\) requests header issue\, and updates some inaccurate documentation\. +This is the last planned release before v4\.0\.0\. + + +### Minor Changes + +* vault\_pki\_generate\_certificate \- the documentation has been updated to match the argspec for the default values of options alt\_names\, ip\_sans\, other\_sans\, and uri\_sans \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/318](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/318)\)\. + + +### Bugfixes + +* connection options \- the namespace connection option will be forced into a string to ensure cmpatibility with recent requests versions \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/309](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/309)\)\. + + +### New Modules + +* vault\_kv2\_delete \- Delete one or more versions of a secret from HashiCorp Vault\'s KV version 2 secret store + + +## v3\.3\.1 + + +### Release Summary + +No functional changes in this release\, this provides updated filter documentation for the public docsite\. + + +## v3\.3\.0 + + +### Release Summary + +With the release of hvac version 1\.0\.0\, we needed to update vault\_token\_create\'s support for orphan tokens\. +The collection\'s changelog is now viewable in the Ansible documentation site\. + + +### Minor Changes + +* vault\_token\_create \- creation or orphan tokens uses hvac\'s new v1 method for creating orphans\, or falls back to the v0 method if needed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/301](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/301)\)\. + + +## v3\.2\.0 + + +### Release Summary + +This release brings support for the azure auth method\, adds 412 to the default list of HTTP status codes to be retried\, and fixes a bug that causes failures in token auth with requests\>\=2\.28\.0\. + + +### Minor Changes + +* community\.hashi\_vault collection \- add support for azure auth method\, for Azure service principal\, managed identity\, or plain JWT access token \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/293](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/293)\)\. +* community\.hashi\_vault retries \- [HTTP status code 412](https\://www\.vaultproject\.io/api\-docs\#412) has been added to the default list of codes to be retried\, for the new [Server Side Consistent Token feature](https\://www\.vaultproject\.io/docs/faq/ssct\#q\-is\-there\-anything\-else\-i\-need\-to\-consider\-to\-achieve\-consistency\-besides\-upgrading\-to\-vault\-1\-10) in Vault Enterprise \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/290](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/290)\)\. + + +### Bugfixes + +* community\.hashi\_vault plugins \- tokens will be cast to a string type before being sent to hvac to prevent errors in requests when values are AnsibleUnsafe \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/289](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/289)\)\. +* modules \- fix a \"variable used before assignment\" that cannot be reached but causes sanity test failures \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/296](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/296)\)\. + + +## v3\.1\.0 + + +### Release Summary + +A default value that was set incorrectly will be corrected in 4\.0\.0\. +A deprecation warning will be shown until then if the value is not specified explicitly\. +This version also includes some fixes and improvements to the licensing in the collection\, which does not affect any functionality\. + + +### Deprecated Features + +* vault\_kv2\_get lookup \- the engine\_mount\_point option in the vault\_kv2\_get lookup only will change its default from kv to secret in community\.hashi\_vault version 4\.0\.0 \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279)\)\. + + +### Bugfixes + +* Add SPDX license headers to individual files \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/282](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/282)\)\. +* Add missing BSD\-2\-Clause\.txt file for BSD licensed content \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/275](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/275)\)\. +* Use the correct GPL license for plugin\_utils \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/276](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/276)\)\. + + +## v3\.0\.0 + + +### Release Summary + +Version 3\.0\.0 of community\.hashi\_vault drops support for Ansible 2\.9 and ansible\-base 2\.10\. +Several deprecated features have been removed\. See the changelog for the full list\. + + +### Deprecated Features + +* token\_validate options \- the shared auth option token\_validate will change its default from true to false in community\.hashi\_vault version 4\.0\.0\. The vault\_login lookup and module will keep the default value of true \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248)\)\. + + +### Removed Features \(previously deprecated\) + +* aws\_iam auth \- the deprecated alias aws\_iam\_login for the aws\_iam value of the auth\_method option has been removed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/194](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/194)\)\. +* community\.hashi\_vault collection \- support for Ansible 2\.9 and ansible\-base 2\.10 has been removed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189)\)\. +* hashi\_vault lookup \- the deprecated \[lookup\_hashi\_vault\] INI config section has been removed in favor of the collection\-wide \[hashi\_vault\_collection\] section \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/179](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/179)\)\. + + +## v2\.5\.0 + + +### Release Summary + +This release finally contains dedicated KV plugins and modules\, and an exciting new lookup to help use plugin values in module calls\. +With that\, we also have a guide in the collection docsite for migrating away from the hashi\_vault lookup toward dedicated content\. +We are also announcing that the token\_validate option will change its default value in version 4\.0\.0\. +This is the last planned release before 3\.0\.0\. See the porting guide for breaking changes and removed features in the next version\. + + +### Minor Changes + +* vault\_login module \& lookup \- no friendly error message was given when hvac was missing \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257)\)\. +* vault\_pki\_certificate \- add vault\_pki\_certificate to the community\.hashi\_vault\.vault action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251)\)\. +* vault\_read module \& lookup \- no friendly error message was given when hvac was missing \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257)\)\. +* vault\_token\_create \- add vault\_token\_create to the community\.hashi\_vault\.vault action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251)\)\. +* vault\_token\_create module \& lookup \- no friendly error message was given when hvac was missing \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257)\)\. +* vault\_write \- add vault\_write to the community\.hashi\_vault\.vault action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251)\)\. + + +### Deprecated Features + +* token\_validate options \- the shared auth option token\_validate will change its default from True to False in community\.hashi\_vault version 4\.0\.0\. The vault\_login lookup and module will keep the default value of True \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248)\)\. + + +### New Plugins + + +#### Lookup + +* vault\_ansible\_settings \- Returns plugin settings \(options\) +* vault\_kv1\_get \- Get a secret from HashiCorp Vault\'s KV version 1 secret store +* vault\_kv2\_get \- Get a secret from HashiCorp Vault\'s KV version 2 secret store + + +### New Modules + +* vault\_kv1\_get \- Get a secret from HashiCorp Vault\'s KV version 1 secret store +* vault\_kv2\_get \- Get a secret from HashiCorp Vault\'s KV version 2 secret store + + +## v2\.4\.0 + + +### Release Summary + +Our first content for writing to Vault is now live\. + + +### New Plugins + + +#### Lookup + +* vault\_write \- Perform a write operation against HashiCorp Vault + + +### New Modules + +* vault\_write \- Perform a write operation against HashiCorp Vault + + +## v2\.3\.0 + + +### Release Summary + +This release contains new plugins and modules for creating tokens and for generating certificates with Vault\'s PKI secrets engine\. + + +### New Plugins + + +#### Lookup + +* vault\_token\_create \- Create a HashiCorp Vault token + + +### New Modules + +* vault\_pki\_generate\_certificate \- Generates a new set of credentials \(private key and certificate\) using HashiCorp Vault PKI +* vault\_token\_create \- Create a HashiCorp Vault token + + +## v2\.2\.0 + + +### Release Summary + +This release contains a new lookup/module combo for logging in to Vault\, and includes our first filter plugin\. + + +### Minor Changes + +* The Filter guide has been added to the collection\'s docsite\. + + +### New Plugins + + +#### Filter + +* vault\_login\_token \- Extracts the client token from a Vault login response + + +#### Lookup + +* vault\_login \- Perform a login operation against HashiCorp Vault + + +### New Modules + +* vault\_login \- Perform a login operation against HashiCorp Vault + + +## v2\.1\.0 + + +### Release Summary + +The most important change in this release is renaming the aws\_iam\_login auth method to aws\_iam and deprecating the old name\. This release also announces the deprecation of Ansible 2\.9 and ansible\-base 2\.10 support in 3\.0\.0\. + + +### Deprecated Features + +* Support for Ansible 2\.9 and ansible\-base 2\.10 is deprecated\, and will be removed in the next major release \(community\.hashi\_vault 3\.0\.0\) next spring \([https\://github\.com/ansible\-community/community\-topics/issues/50](https\://github\.com/ansible\-community/community\-topics/issues/50)\, [https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189)\)\. +* aws\_iam\_login auth method \- the aws\_iam\_login method has been renamed to aws\_iam\. The old name will be removed in collection version 3\.0\.0\. Until then both names will work\, and a warning will be displayed when using the old name \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/193](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/193)\)\. + + +### Removed Features \(previously deprecated\) + +* the \"legacy\" integration test setup has been removed\; this does not affect end users and is only relevant to contributors \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/191](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/191)\)\. + + +## v2\.0\.0 + + +### Release Summary + +Version 2\.0\.0 of the collection drops support for Python 2 \& Python 3\.5\, making Python 3\.6 the minimum supported version\. +Some deprecated features and settings have been removed as well\. + + +### Breaking Changes / Porting Guide + +* connection options \- there is no longer a default value for the url option \(the Vault address\)\, so a value must be supplied \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/83](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/83)\)\. + + +### Removed Features \(previously deprecated\) + +* drop support for Python 2 and Python 3\.5 \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81)\)\. +* support for the following deprecated environment variables has been removed\: VAULT\_AUTH\_METHOD\, VAULT\_TOKEN\_PATH\, VAULT\_TOKEN\_FILE\, VAULT\_ROLE\_ID\, VAULT\_SECRET\_ID \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/173](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/173)\)\. + + +## v1\.5\.0 + + +### Release Summary + +This release includes a new action group for use with module\_defaults\, and additional ways of specifying the mount\_point option for plugins\. +This will be the last 1\.x release\. + + +### Minor Changes + +* add the community\.hashi\_vault\.vault action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/172](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/172)\)\. +* auth methods \- Add support for configuring the mount\_point auth method option in plugins via the ANSIBLE\_HASHI\_VAULT\_MOUNT\_POINT environment variable\, ansible\_hashi\_vault\_mount\_point ansible variable\, or mount\_point INI section \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/171](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/171)\)\. + + +## v1\.4\.1 + + +### Release Summary + +This release contains a bugfix for aws\_iam\_login authentication\. + + +### Bugfixes + +* aws\_iam\_login auth method \- fix incorrect use of boto3/botocore that prevented proper loading of AWS IAM role credentials \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/167](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/167)\)\. + + +## v1\.4\.0 + + +### Release Summary + +This release includes bugfixes\, a new auth method \(cert\)\, and the first new content since the collection\'s formation\, the vault\_read module and lookup plugin\. +We\'re also announcing the deprecation of the \[lookup\_hashi\_vault\] INI section \(which will continue working up until its removal only for the hashi\_vault lookup\)\, to be replaced by the \[hashi\_vault\_collection\] section that will apply to all plugins in the collection\. + + +### Minor Changes + +* community\.hashi\_vault collection \- add cert auth method \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/159](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/159)\)\. + + +### Deprecated Features + +* lookup hashi\_vault \- the \[lookup\_hashi\_vault\] section in the ansible\.cfg file is deprecated and will be removed in collection version 3\.0\.0\. Instead\, the section \[hashi\_vault\_collection\] can be used\, which will apply to all plugins in the collection going forward \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/144](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/144)\)\. + + +### Bugfixes + +* aws\_iam\_login auth \- the aws\_security\_token option was not used\, causing assumed role credentials to fail \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/160](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/160)\)\. +* hashi\_vault collection \- a fallback import supporting the retries option for urllib3 via requests\.packages\.urllib3 was not correctly formed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/116](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/116)\)\. +* hashi\_vault collection \- unhandled exception with token auth when token\_file exists but is a directory \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/152](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/152)\)\. + + +### New Plugins + + +#### Lookup + +* vault\_read \- Perform a read operation against HashiCorp Vault + + +### New Modules + +* vault\_read \- Perform a read operation against HashiCorp Vault + + +## v1\.3\.2 + + +### Release Summary + +This release adds requirements detection support for Ansible Execution Environments\. It also updates and adds new guides in our [collection docsite](https\://docs\.ansible\.com/ansible/devel/collections/community/hashi\_vault)\. +This release also announces the dropping of Python 3\.5 support in version 2\.0\.0 of the collection\, alongside the previous announcement dropping Python 2\.x in 2\.0\.0\. + + +### Minor Changes + +* hashi\_vault collection \- add execution\-environment\.yml and a python requirements file to better support ansible\-builder \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/105](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/105)\)\. + + +### Deprecated Features + +* hashi\_vault collection \- support for Python 3\.5 will be dropped in version 2\.0\.0 of community\.hashi\_vault \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81)\)\. + + +## v1\.3\.1 + + +### Release Summary + +This release fixes an error in the documentation\. No functionality is changed so it\'s not necessary to upgrade from 1\.3\.0\. + + +## v1\.3\.0 + + +### Release Summary + +This release adds two connection\-based options for controlling timeouts and retrying failed Vault requests\. + + +### Minor Changes + +* hashi\_vault lookup \- add retries and retry\_action to enable built\-in retry on failure \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/71](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/71)\)\. +* hashi\_vault lookup \- add timeout option to control connection timeouts \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/100](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/100)\)\. + + +## v1\.2\.0 + + +### Release Summary + +This release brings several new ways of accessing options\, like using Ansible vars\, and addng new environment variables and INI config entries\. +A special none auth type is also added\, for working with certain Vault Agent configurations\. +This release also announces the deprecation of Python 2 support in version 2\.0\.0 of the collection\. + + +### Minor Changes + +* hashi\_vault lookup \- add ANSIBLE\_HASHI\_VAULT\_CA\_CERT env var \(with VAULT\_CACERT low\-precedence fallback\) for ca\_cert option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97)\)\. +* hashi\_vault lookup \- add ANSIBLE\_HASHI\_VAULT\_PASSWORD env var and ansible\_hashi\_vault\_password ansible var for password option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96)\)\. +* hashi\_vault lookup \- add ANSIBLE\_HASHI\_VAULT\_USERNAME env var and ansible\_hashi\_vault\_username ansible var for username option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_auth\_method Ansible vars entry to the proxies option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_ca\_cert ansible var for ca\_cert option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_namespace Ansible vars entry to the namespace option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_proxies Ansible vars entry to the proxies option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_role\_id Ansible vars entry to the proxies option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_secret\_id Ansible vars entry to the proxies option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_token\_file Ansible vars entry to the token\_file option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_token\_path Ansible vars entry to the token\_path option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_token\_validate Ansible vars entry to the proxies option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_token Ansible vars entry to the proxies option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_url and ansible\_hashi\_vault\_addr Ansible vars entries to the url option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\. +* hashi\_vault lookup \- add ansible\_hashi\_vault\_validate\_certs Ansible vars entry to the validate\_certs option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95)\)\. +* hashi\_vault lookup \- add ca\_cert INI config file key ca\_cert option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97)\)\. +* hashi\_vault lookup \- add none auth type which allows for passive auth via a Vault agent \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/80](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/80)\)\. + + +### Deprecated Features + +* hashi\_vault collection \- support for Python 2 will be dropped in version 2\.0\.0 of community\.hashi\_vault \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81)\)\. + + +## v1\.1\.3 + + +### Release Summary + +This release fixes a bug with userpass authentication and hvac versions 0\.9\.6 and higher\. + + +### Bugfixes + +* hashi\_vault \- userpass authentication did not work with hvac 0\.9\.6 or higher \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/68](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/68)\)\. + + +## v1\.1\.2 + + +### Release Summary + +This release contains the same functionality as 1\.1\.1\. The only change is to mark some code as internal to the collection\. If you are already using 1\.1\.1 as an end user you do not need to update\. + + +## v1\.1\.1 + + +### Release Summary + +This bugfix release restores the use of the VAULT\_ADDR environment variable for setting the url option\. +See the PR linked from the changelog entry for details and workarounds if you cannot upgrade\. + + +### Bugfixes + +* hashi\_vault \- restore use of VAULT\_ADDR environment variable as a low preference env var \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/61](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/61)\)\. + + +## v1\.1\.0 + + +### Release Summary + +This release contains a new proxies option for the hashi\_vault lookup\. + + +### Minor Changes + +* hashi\_vault \- add proxies option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/50](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/50)\)\. + + +## v1\.0\.0 + + +### Release Summary + +Our first major release contains a single breaking change that will affect only a small subset of users\. No functionality is removed\. See the details in the changelog to determine if you\'re affected and if so how to transition to remediate\. + + +### Breaking Changes / Porting Guide + +* hashi\_vault \- the VAULT\_ADDR environment variable is now checked last for the url parameter\. For details on which use cases are impacted\, see \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8)\)\. + + +## v0\.2\.0 + + +### Release Summary + +Several backwards\-compatible bugfixes and enhancements in this release\. +Some environment variables are deprecated and have standardized replacements\. + + +### Minor Changes + +* Add optional aws\_iam\_server\_id parameter as the value for X\-Vault\-AWS\-IAM\-Server\-ID header \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/27](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/27)\)\. +* hashi\_vault \- ANSIBLE\_HASHI\_VAULT\_ADDR environment variable added for option url \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8)\)\. +* hashi\_vault \- ANSIBLE\_HASHI\_VAULT\_AUTH\_METHOD environment variable added for option auth\_method \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17)\)\. +* hashi\_vault \- ANSIBLE\_HASHI\_VAULT\_ROLE\_ID environment variable added for option role\_id \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\. +* hashi\_vault \- ANSIBLE\_HASHI\_VAULT\_SECRET\_ID environment variable added for option secret\_id \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\. +* hashi\_vault \- ANSIBLE\_HASHI\_VAULT\_TOKEN\_FILE environment variable added for option token\_file \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\. +* hashi\_vault \- ANSIBLE\_HASHI\_VAULT\_TOKEN\_PATH environment variable added for option token\_path \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\. +* hashi\_vault \- namespace parameter can be specified in INI or via env vars ANSIBLE\_HASHI\_VAULT\_NAMESPACE \(new\) and VAULT\_NAMESPACE \(lower preference\) \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/14](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/14)\)\. +* hashi\_vault \- token parameter can now be specified via ANSIBLE\_HASHI\_VAULT\_TOKEN as well as via VAULT\_TOKEN \(the latter with lower preference\) \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/16](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/16)\)\. +* hashi\_vault \- add token\_validate option to control token validation \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/24](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/24)\)\. +* hashi\_vault \- uses new AppRole method in hvac 0\.10\.6 with fallback to deprecated method with warning \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33)\)\. + + +### Deprecated Features + +* hashi\_vault \- VAULT\_ADDR environment variable for option url will have its precedence lowered in 1\.0\.0\; use ANSIBLE\_HASHI\_VAULT\_ADDR to intentionally override a config value \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8)\)\. +* hashi\_vault \- VAULT\_AUTH\_METHOD environment variable for option auth\_method will be removed in 2\.0\.0\, use ANSIBLE\_HASHI\_VAULT\_AUTH\_METHOD instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17)\)\. +* hashi\_vault \- VAULT\_ROLE\_ID environment variable for option role\_id will be removed in 2\.0\.0\, use ANSIBLE\_HASHI\_VAULT\_ROLE\_ID instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\. +* hashi\_vault \- VAULT\_SECRET\_ID environment variable for option secret\_id will be removed in 2\.0\.0\, use ANSIBLE\_HASHI\_VAULT\_SECRET\_ID instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\. +* hashi\_vault \- VAULT\_TOKEN\_FILE environment variable for option token\_file will be removed in 2\.0\.0\, use ANSIBLE\_HASHI\_VAULT\_TOKEN\_FILE instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\. +* hashi\_vault \- VAULT\_TOKEN\_PATH environment variable for option token\_path will be removed in 2\.0\.0\, use ANSIBLE\_HASHI\_VAULT\_TOKEN\_PATH instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\. + + +### Bugfixes + +* hashi\_vault \- mount\_point parameter did not work with aws\_iam\_login auth method \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/7](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/7)\) +* hashi\_vault \- fallback logic for handling deprecated style of auth in hvac was not implemented correctly \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33)\)\. +* hashi\_vault \- parameter mount\_point does not work with JWT auth \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/29](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/29)\)\. +* hashi\_vault \- tokens without lookup\-self ability can\'t be used because of validation \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/18](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/18)\)\. + + +## v0\.1\.0 + + +### Release Summary + +Our first release matches the hashi\_vault lookup functionality provided by community\.general version 1\.3\.0\. diff --git a/ansible_collections/community/hashi_vault/CHANGELOG.rst b/ansible_collections/community/hashi_vault/CHANGELOG.rst index 5223d4a97..4362dc7f0 100644 --- a/ansible_collections/community/hashi_vault/CHANGELOG.rst +++ b/ansible_collections/community/hashi_vault/CHANGELOG.rst @@ -1,9 +1,99 @@ -=================================== -community.hashi_vault Release Notes -=================================== +==================================== +community.hashi\_vault Release Notes +==================================== .. contents:: Topics +v6.2.0 +====== + +Release Summary +--------------- + +This release contains a dozen+ new modules for working with Vault's database secrets engine and some new ``vars`` entries for specifying public and private keys in ``cert`` auth. + +Minor Changes +------------- + +- cert auth - add option to set the ``cert_auth_public_key`` and ``cert_auth_private_key`` parameters using the variables ``ansible_hashi_vault_cert_auth_public_key`` and ``ansible_hashi_vault_cert_auth_private_key`` (https://github.com/ansible-collections/community.hashi_vault/issues/428). + +New Modules +----------- + +- vault_database_connection_configure - Configures the database engine +- vault_database_connection_delete - Delete a Database Connection +- vault_database_connection_read - Returns the configuration settings for a O(connection_name) +- vault_database_connection_reset - Closes a O(connection_name) and its underlying plugin and restarts it with the configuration stored +- vault_database_connections_list - Returns a list of available connections +- vault_database_role_create - Creates or updates a (dynamic) role definition +- vault_database_role_delete - Delete a role definition +- vault_database_role_read - Queries a dynamic role definition +- vault_database_roles_list - Returns a list of available (dynamic) roles +- vault_database_rotate_root_credentials - Rotates the root credentials stored for the database connection. This user must have permissions to update its own password. +- vault_database_static_role_create - Create or update a static role +- vault_database_static_role_get_credentials - Returns the current credentials based on the named static role +- vault_database_static_role_read - Queries a static role definition +- vault_database_static_role_rotate_credentials - Trigger the credential rotation for a static role +- vault_database_static_roles_list - Returns a list of available static roles + +v6.1.0 +====== + +Release Summary +--------------- + +This release addresses some breaking changes in core that were backported. + +Major Changes +------------- + +- requirements - the ``requests`` package which is required by ``hvac`` now has a more restrictive range for this collection in certain use cases due to breaking security changes in ``ansible-core`` that were backported (https://github.com/ansible-collections/community.hashi_vault/pull/416). + +v6.0.0 +====== + +Release Summary +--------------- + +This major version of the collection has no functional changes from the previous version, however the minimum versions of ``hvac`` and ``ansible-core`` have been raised. While the collection may still work with those earlier versions, future changes will not test against them. + +Breaking Changes / Porting Guide +-------------------------------- + +- The minimum required version of ``hvac`` is now ``1.2.1`` (https://docs.ansible.com/ansible/devel/collections/community/hashi_vault/docsite/user_guide.html#hvac-version-specifics). + +Removed Features (previously deprecated) +---------------------------------------- + +- The minimum supported version of ``ansible-core`` is now ``2.14``, support for ``2.13`` has been dropped (https://github.com/ansible-collections/community.hashi_vault/pull/403). + +v5.0.1 +====== + +Release Summary +--------------- + +This release fixes a bug in ``vault_write`` ahead of the collection's next major release. + +Bugfixes +-------- + +- vault_write - the ``vault_write`` lookup and module were not able to write data containing keys named ``path`` or ``wrap_ttl`` due to a bug in the ``hvac`` library. These plugins have now been updated to take advantage of fixes in ``hvac>=1.2`` to address this (https://github.com/ansible-collections/community.hashi_vault/issues/389). + +v5.0.0 +====== + +Release Summary +--------------- + +This version makes some relatively minor but technically breaking changes. Support for ``ansible-core`` versions ``2.11`` and ``2.12`` have been dropped, and there is now a minimum supported version of ``hvac`` which will be updated over time. A warning in the ``hashi_vault`` lookup on duplicate option specifications in the term string has been changed to a fatal error. + +Breaking Changes / Porting Guide +-------------------------------- + +- Support for ``ansible-core`` 2.11 and 2.12 has been removed (https://github.com/ansible-collections/community.hashi_vault/issues/340). +- The minimum version of ``hvac`` for ``community.hashi_vault`` is now ``1.1.0`` (https://github.com/ansible-collections/community.hashi_vault/issues/324). +- hashi_vault lookup - duplicate option entries in the term string now raises an exception instead of a warning (https://github.com/ansible-collections/community.hashi_vault/issues/356). v4.2.1 ====== @@ -601,4 +691,3 @@ Release Summary --------------- Our first release matches the ``hashi_vault`` lookup functionality provided by ``community.general`` version ``1.3.0``. - diff --git a/ansible_collections/community/hashi_vault/FILES.json b/ansible_collections/community/hashi_vault/FILES.json index a64ed5bf0..504a3d407 100644 --- a/ansible_collections/community/hashi_vault/FILES.json +++ b/ansible_collections/community/hashi_vault/FILES.json @@ -67,7 +67,7 @@ "name": ".github/actions/docker-image-versions/action.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "84f0cc9401479ea5de42f11f78b581b9e230a0676bbc6e79f2672f1a72f47912", + "chksum_sha256": "ed473f398e597fd8b0a9d7c8417ce59a2e1d3184b7adc3d92bed87caae970cf8", "format": 1 }, { @@ -81,7 +81,7 @@ "name": ".github/actions/docker-image-versions/versions.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "959b408cc5a5c6a8276906db11846cc1b5a0b73ff5761036cbfa92b410e73eee", + "chksum_sha256": "5002feb4c7cc3aebfc5e7e7a2eecd3f05bd75c0a151342f61eb1e49ef7dba2df", "format": 1 }, { @@ -109,14 +109,14 @@ "name": ".github/workflows/ansible-builder.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "09b7434235b6c0eafa5ec2649fcb3f7121917e9f18723ca0af3c239d1bc644c7", + "chksum_sha256": "60e927ce638ba122eb6524e00a8c85c83d8f49572e3a85bfbf1529901a90652e", "format": 1 }, { "name": ".github/workflows/ansible-test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "442c8de42766184549bbc6e8f1687a80b488e71f7072d3aee57d9851c296b4d3", + "chksum_sha256": "f58b5fd09fea3c4f0bdf17685f636a3f0e56535c0c89a72ba130a42aa0363539", "format": 1 }, { @@ -137,7 +137,14 @@ "name": ".github/workflows/github-release.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "cebad181da6db6c618d2e698942a868e8e4ef90ad977465ebf2396ae2947d4b7", + "chksum_sha256": "52d9ec1fe024e9fc8f646e9fb9afc25788c61caf9ee772bc683a890cf6c19dbd", + "format": 1 + }, + { + "name": ".github/dependabot.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6e34ab713019e08cae0c4c50295b17c904ee6f0c7ed1e8cf8d08213cb2772142", "format": 1 }, { @@ -186,14 +193,14 @@ "name": "changelogs/changelog.yaml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "a854ea29e391bde2c6bcd8c45e7081d746daff404d3f4221af5f43c7e320a142", + "chksum_sha256": "42eccc5898ab651d29158d22b590a0638259d6de081adda969b0bae8e6ede1fc", "format": 1 }, { "name": "changelogs/config.yaml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "630354cc2146c9705841870850c9a5b3b8f61775452e45f056f3a5f84c6e5f20", + "chksum_sha256": "9453f4ca84464e45eb811ed5a71bb973a59ea6cc906f0e851a774a055e31f0d8", "format": 1 }, { @@ -221,7 +228,7 @@ "name": "docs/docsite/rst/CHANGELOG.rst", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "79bab511c63a4f5ffdffbf0deb76f4b6aed0db672e46dc34413030f308cbba4a", + "chksum_sha256": "9b52d95bfa031a3b374b7a519ea045b63a7ee696cf74af9d6bf70039a5ef4816", "format": 1 }, { @@ -270,7 +277,7 @@ "name": "docs/docsite/rst/user_guide.rst", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "0cd48bf54449f41af3ccf83fec27be2554b3774b4bc76d7a7755a856b24b3244", + "chksum_sha256": "9b4394996585d6f8c236d6729c7721a785a6f69a462d31673491548d13debade", "format": 1 }, { @@ -354,7 +361,7 @@ "name": "meta/ee-requirements.txt", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "21886d56af804293670e040b8dd722757ec0247cee26caec659e667991efc556", + "chksum_sha256": "59961a1cc5447ff1ad70a7d2d415543e1e8e17f7e242b10e1e2a792abfbe5d2b", "format": 1 }, { @@ -368,7 +375,7 @@ "name": "meta/runtime.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "94f270496ec3a6415ee18ae1e586e8038b1b3f43d4b03eef6d5ba764259a0724", + "chksum_sha256": "62ad2fcfb7ad737b4038c9e73025c96640f371bc9cdd08c8b429a53397748683", "format": 1 }, { @@ -396,7 +403,7 @@ "name": "plugins/doc_fragments/auth.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "d983c9c2ffec0153202c74cb4d003562e2d3272e75920097bcd0dee4bf08cc12", + "chksum_sha256": "2f0f0a8c928449d457d100c90a60fc5c284bcd86eaa31d24062188303aea8fec", "format": 1 }, { @@ -459,7 +466,7 @@ "name": "plugins/lookup/hashi_vault.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "1f9913f0e357c356b80860ddc23e77d435fe7bbd33caa5b907fddb42aff365b2", + "chksum_sha256": "fc1e9d356b44254568ecb59bc2f617c1d87122f7af2853bd0e1744a228a739f0", "format": 1 }, { @@ -508,14 +515,14 @@ "name": "plugins/lookup/vault_token_create.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9c208d252553cf150234f240d5898c40521627fe9f8db60330cae1fed7b7cd65", + "chksum_sha256": "9c1841d0c54c7fc2de3b2024e14dc28e1cbde3a7f932390f6d54699cc09980b8", "format": 1 }, { "name": "plugins/lookup/vault_write.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "d8fd10b5075f0bdc34e8b1ea0f7707acc1e198bd2d7e5acf22033ad39646564e", + "chksum_sha256": "5e12bc31541e63c459eb7a84419759823eb04cdfcc2f5795bac2a749649e8500", "format": 1 }, { @@ -578,7 +585,7 @@ "name": "plugins/module_utils/_auth_method_token.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "f88bf860fbb14a5163dd30f0e03b629e4c7b8b83acfdb24f3783d8cc93a867c3", + "chksum_sha256": "5131dceee53f54144c2fd4c9965d165b8773df9a6ee9c04935fde99f0686623d", "format": 1 }, { @@ -599,14 +606,14 @@ "name": "plugins/module_utils/_connection_options.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "1c30d05a0fb24f6fa0d22f8837620101366b8fa761e89dcd7828d429537031e3", + "chksum_sha256": "d7a219f8af7237d09429f4aacda1539adb2c300f5d39aba9ca96956b0e20d08b", "format": 1 }, { "name": "plugins/module_utils/_hashi_vault_common.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "5ab33ef2f123fce48c13ea200a22ee06a45c565cdc147e4403f879ef585ff725", + "chksum_sha256": "e5785f7c5ea98d8a899908ba96353c3e667a7c591ac93bf0ed96f96491594d36", "format": 1 }, { @@ -623,6 +630,111 @@ "chksum_sha256": null, "format": 1 }, + { + "name": "plugins/modules/vault_database_connection_configure.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "09785e357b9fb8b2c1200ca2b99179b754a1f6e7faff983f3266f8d7301c9e39", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_connection_delete.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "02a090ab539e27374c76c084e3ff9bb24a0fc5e30636a3368059ae24a3fd3ff8", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_connection_read.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "719567425b8da7eb28bcb4ca7034df09d590b935c4704a774fa70498ac9cfc8c", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_connection_reset.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6336e36134104d48498ab30023e631617b51e2cdebb1028246c13a9f18b81d54", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_connections_list.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "61ac9eb1f1da102140ba6e115a53deb71f1919f23704da27e5a230a9968a1c97", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_role_create.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cb7b14e64b789feb1e493b0a2401cc4cde7c155ed105ac483d0164c1f3f0a99c", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_role_delete.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95c294c9cfacc0fb31e2d3db558161ecc1062a0b66bff2cbb809687609fbf4fc", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_role_read.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2ccb57f6d005b02a0afb90aaa5bea494eee9c7c36e7b8c62bd9878d997561a6f", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_roles_list.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bdb86ab286581c84af4d5d06cb72bfd566be38c7b750c20599d00099549b193d", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_rotate_root_credentials.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d8b0a1de9116f4af09767079a0731dd58134c6733f3a12445ed61e47cdb1572f", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_static_role_create.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "15504a6219ca74129bdffcc05fa77d58d0dcfc76a5cbb9a4bdafced8a27a454f", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_static_role_get_credentials.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8a89ccbc40df8450ffa3cd1b0f2a75c2269e73f3a7648cd4d54aadb5986932b2", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_static_role_read.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ffbb4b47d7cfb2d8a523850e1191e8510b3c89449f8979e72b0ff59d9710b935", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_static_role_rotate_credentials.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ef159236af51471ef9150f262778d8fd9e971554e282a0eb956fd8662765537f", + "format": 1 + }, + { + "name": "plugins/modules/vault_database_static_roles_list.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c76eefd9c2345648c5e333b3d006e3d2b85a8deded214d6d19ce2afbef06a7ef", + "format": 1 + }, { "name": "plugins/modules/vault_kv1_get.py", "ftype": "file", @@ -690,7 +802,7 @@ "name": "plugins/modules/vault_write.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "c17d015dff130769b05357cb3496b2b32acdbc4f1b4f84d2f0b24f31bfd51ae6", + "chksum_sha256": "ef53b13f68730379e4c1c662e8ca1a2acafd196f97b009e3ccc8e27a5975184a", "format": 1 }, { @@ -704,7 +816,7 @@ "name": "plugins/plugin_utils/_hashi_vault_lookup_base.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "8bacb7aeaf9aefb8a7b750c70c8a01a5d3970a326711c1579deaeff4de3fbd9e", + "chksum_sha256": "980e337f86c244b851f8c7d78c7728185904fb4f7f49bc04a688d8dcbea7b9ca", "format": 1 }, { @@ -788,21 +900,21 @@ "name": "tests/integration/targets/auth_approle/tasks/approle_test_controller.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "db2c8d9bffe8900e52fca26547274879ea6f0f9082aa63a0fa5afbf061951b30", + "chksum_sha256": "6652903cfaf08fd637f3d54cfa1438b9844f537dea99a6098cc1e7b432b9a441", "format": 1 }, { "name": "tests/integration/targets/auth_approle/tasks/approle_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "1901a0c244201493787e3a9b4191d7de38f3d78fb4119a25f71f61e6386bf8c1", + "chksum_sha256": "349fce896f65460b122adebbd9a7684084c3bcde6a0966d49493f82a657eb0c0", "format": 1 }, { "name": "tests/integration/targets/auth_approle/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e6afe86da906899d4cbb718e4ceee48d3fd935a77cc5503b69add5cf940bb9ef", + "chksum_sha256": "a20931f5d629f3689e5cccbc7f8e663c21fec701ab967fd16c0de4d2afa05c8f", "format": 1 }, { @@ -865,14 +977,14 @@ "name": "tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "91cb21963bca9ecfa4ecd1dc21fec09685e95e9df8d702057cc390295f7422c0", + "chksum_sha256": "bb9f349ede884884ae6ffdb1059019d3ff391574afd956abd75153e66572888b", "format": 1 }, { "name": "tests/integration/targets/auth_aws_iam/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9f8e209e859c00c8caf7898bb8fb2d35ddf6866c8e0074ce2c58d39296439f02", + "chksum_sha256": "e3836386fd357e44042bb492c90d43bf7ed676cc29528af72d80f23c244af426", "format": 1 }, { @@ -935,14 +1047,14 @@ "name": "tests/integration/targets/auth_azure/tasks/azure_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "da5435958d587f7bb1eb774b6bda26390ea05c0a1c0a4ba57c9e7fd824f2ffda", + "chksum_sha256": "d35ddc8bb68b74eaeecefabea6c57425bc2fac10df55dd784671bf1711fb4e90", "format": 1 }, { "name": "tests/integration/targets/auth_azure/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "03882c949782ad0a1cbe23a0be8b849d7c6b85f7b5700b756c379fb7d2800cff", + "chksum_sha256": "52ec210f89111e200e34c28486fb3ff5800aff1188b9b061c633fc4d0f9421e2", "format": 1 }, { @@ -1047,14 +1159,14 @@ "name": "tests/integration/targets/auth_cert/tasks/cert_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "94bd3b77ebd5c339f00b7a68e9221bdadc48fe00d217e50e3042c50743f6d63f", + "chksum_sha256": "3a1043a944c79adde84f9c2e3d556853438085f34d1468b04e394d42539857a7", "format": 1 }, { "name": "tests/integration/targets/auth_cert/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "ee0782baf3cc65d16b1159db751f29d817968fc6fe705ed541259afd3f58c618", + "chksum_sha256": "1fbe3a23da9c63df523935d1d6d7aabaeec21da75db2a3279934d3eb318c549c", "format": 1 }, { @@ -1159,14 +1271,14 @@ "name": "tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "1b1eba5701d38b6eff7de7547d24420d7d81ac86827c0aca044b5e41e14fade8", + "chksum_sha256": "c5265a06d2e60d8f52a4af2dcb791d2aa22d24d0c9049e8a8fe80b053759fadd", "format": 1 }, { "name": "tests/integration/targets/auth_jwt/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "00aca2ae191aa626d9818d9f279a30e8ccf1172f31f77c683fe5ffaccd4deb40", + "chksum_sha256": "b7fd3e0d2fbbd3767878ac8aeec211ff7bbfe86a64d0240fac3157adccb113d9", "format": 1 }, { @@ -1229,14 +1341,14 @@ "name": "tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "270f5d3f7ff671ea2f20a55dfd424b431aa133bff57dff5e98c556ee379bda63", + "chksum_sha256": "7d3946d44231b95d46278feeb5444731e8c0711622e25e48950e0d6bcb5d46ca", "format": 1 }, { "name": "tests/integration/targets/auth_ldap/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "5506a054b0000d291b243fdd6e3e2445377c21c3cc678cdcad1885e9921aa2f6", + "chksum_sha256": "35994f3f0d55754d16342bc38845369bc04de16c9455acfb057f4c6c4e07c07c", "format": 1 }, { @@ -1362,21 +1474,21 @@ "name": "tests/integration/targets/auth_token/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "6b0806626ea64468831efbb27c86078a7a43e94a82dcb77aef645851f67bff96", + "chksum_sha256": "946757960cb259566d15cc02cfd209bef9c4a63da7468e6c4a4ad25af3bb9d3d", "format": 1 }, { "name": "tests/integration/targets/auth_token/tasks/token_test_controller.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e135196c8e082e36f18cd35ea6e736a7d6c6c0f67f7298122c896ec4ed171353", + "chksum_sha256": "b7ca6f715fe4daf1c5586904074ba60952dc3ddd85fe49409ddd7bcc02d34f00", "format": 1 }, { "name": "tests/integration/targets/auth_token/tasks/token_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "c11eea8eba17a551373c684c7625da1e28d1f8e9072eb09bbfff48b57e2a35ed", + "chksum_sha256": "f53a1ab468d52899229a15ecee9fcb71bf635d0705042f909ededf92f0bda11e", "format": 1 }, { @@ -1432,7 +1544,7 @@ "name": "tests/integration/targets/auth_userpass/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "37c1144beac57279d2f79c9a49c2c37f8227e4f77203bf12bce1e59eeaf255a1", + "chksum_sha256": "5f5eb68962d2263743736024b160cdf50be12906c13c66e72476de70aad23f5f", "format": 1 }, { @@ -1453,7 +1565,7 @@ "name": "tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "a80bb0f3842e9ada72841ec1677e0a12703634e5d65d18a71c2f7ddcc595e30a", + "chksum_sha256": "ecbbc0696c4bb5e2238d6d1388e40781de62bccf1d924888cf0f1dacebdf3ebe", "format": 1 }, { @@ -1509,7 +1621,7 @@ "name": "tests/integration/targets/connection_options/tasks/controller.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "330ca6d4711e5e35f0b4045d6140127b7835e8d0b3e87cf66c3b98e88346b043", + "chksum_sha256": "13872e8fc01d9a542965bb1bfb4a7bc788bf751e6390afc069d39b30b530fd3a", "format": 1 }, { @@ -1523,7 +1635,7 @@ "name": "tests/integration/targets/connection_options/tasks/target.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "34a316f8f3fada71ca60d476144e2b29fb6c6eb285a21468e1a8b3405abab115", + "chksum_sha256": "c37bdfecd80f27a2783c57e771cfdb269a9f486539e39c97f4a40631d6dae868", "format": 1 }, { @@ -1600,7 +1712,7 @@ "name": "tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "763927dee00e08efaeb2f61c3f876294a97e9d6277be53351e211974937b8b2a", + "chksum_sha256": "4d53516153a79579ee12390baa5a7a5586b73f2895d2798a3f74afc7f708406b", "format": 1 }, { @@ -2048,7 +2160,7 @@ "name": "tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "cf8dcda9a6613838dbf5d38d55eb7d26a8de4c405a4a254c01d2e1863c8a30a9", + "chksum_sha256": "28cdd9d16d48d749b670df94e969a66541d075d3f4e106bc1c9a2acebea51ba5", "format": 1 }, { @@ -2066,696 +2178,1543 @@ "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get", + "name": "tests/integration/targets/module_vault_database_connection_configure", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get/meta", + "name": "tests/integration/targets/module_vault_database_connection_configure/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_configure/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get/tasks", + "name": "tests/integration/targets/module_vault_database_connection_configure/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "a7b0fcc3cf144f647e9ff812d244e9a9fa5505ee93150968b74fa3c80af3f1d2", + "chksum_sha256": "732804da077147062d10c0e3260bfddd70caab5eb0c86e71f75d6c9a83cb7d15", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get/tasks/module_vault_kv1_get_setup.yml", + "name": "tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "4d62c4e28a99a4ea4c7c852c2f9ad7f18ef5f0fa0aec6173d4d22549a258f3e7", + "chksum_sha256": "f132da412f3037b2d20ed77ced34c54b25e0f45fac918279b5444161f4ec00c2", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get/tasks/module_vault_kv1_get_test.yml", + "name": "tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "743099acae8046c0084a97e034a404a3d5ce5fd6f7d518325e6631b6fbe25100", + "chksum_sha256": "8a93b17aebe03af788005293758f8edeed48dea3b7f2ed10a4e78978599b077d", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv1_get/aliases", + "name": "tests/integration/targets/module_vault_database_connection_configure/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete", + "name": "tests/integration/targets/module_vault_database_connection_delete", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete/meta", + "name": "tests/integration/targets/module_vault_database_connection_delete/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_delete/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete/tasks", + "name": "tests/integration/targets/module_vault_database_connection_delete/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "dac8c3fdd19f0ef331541dbac0990585d56c790ac0e668c69f13aa43901f0733", + "chksum_sha256": "0c84c2923b51da9074523b92997311f516a6b0c68caa3f48cf440e22f855f602", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete/tasks/module_vault_kv2_delete_setup.yml", + "name": "tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "deb41e77ec8ab94b7e52d069ba8abc7d608fface50b04d95e519cc79862476c2", + "chksum_sha256": "00541579a7143cc99bfcbc2df6b528554a3fdddb48ba1547b4f2fae2b471cd6f", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete/tasks/module_vault_kv2_delete_test.yml", + "name": "tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "0838e8664760bdbc3c346e3a8ff6a0933669caa7b73f5bb61917200bf1a5f209", + "chksum_sha256": "aa8a1fead1fff90e5972b47d0f8bbdf1401351e758815a5bd39fe677e1e78ad9", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_delete/aliases", + "name": "tests/integration/targets/module_vault_database_connection_delete/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get", + "name": "tests/integration/targets/module_vault_database_connection_read", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get/meta", + "name": "tests/integration/targets/module_vault_database_connection_read/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_read/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get/tasks", + "name": "tests/integration/targets/module_vault_database_connection_read/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_read/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "2eb537abfb3a977dbfc8c3f9d8aa6a74bf6d847a40b534f33bb01ab39d553ece", + "chksum_sha256": "b55fc52d80a32bd15f2fa96b86bba5e1f7b7f835eb71d82826a7a2fd3027f6a3", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get/tasks/module_vault_kv2_get_setup.yml", + "name": "tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9e6a6d56b14c282646e5963cea65a65810b588b6ea031a6da9c56cb55a92274f", + "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get/tasks/module_vault_kv2_get_test.yml", + "name": "tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "522b1a08b43c5197f21ffdc3d02fae29203603bd89a2613505821f63e78a81ca", + "chksum_sha256": "7c3b8185b7475ce1ea8ae9a4418cf70721e8a21009b011190c89a47598ef73d0", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_get/aliases", + "name": "tests/integration/targets/module_vault_database_connection_read/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write", + "name": "tests/integration/targets/module_vault_database_connection_reset", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write/meta", + "name": "tests/integration/targets/module_vault_database_connection_reset/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_reset/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write/tasks", + "name": "tests/integration/targets/module_vault_database_connection_reset/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write/tasks/main.yml", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "bcffa3e2bbb00d5cfb872e44a8c434f38082ece25980f9f5893565bff6d0d47c", - "format": 1 - }, - { - "name": "tests/integration/targets/module_vault_kv2_write/tasks/setup.yml", + "name": "tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "1af47e07f72f7218b072c4c596a424322c8c3859ff36a0070fa9d6c48747f8c6", + "chksum_sha256": "061020558d2ad687e4a211905b162222302001a9502ec8a26569a77c9c2f4856", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write/tasks/test.yml", + "name": "tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "d010ebc4f545365b01b006ba74fcbba1ef9de787a464eb8b07c18cb85b127d8c", - "format": 1 - }, - { - "name": "tests/integration/targets/module_vault_kv2_write/vars", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, + "chksum_sha256": "f132da412f3037b2d20ed77ced34c54b25e0f45fac918279b5444161f4ec00c2", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write/vars/main.yml", + "name": "tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "dba69bdb30b13fd447059fe9dd9b8723a67bc07cc888072e61fe4703d8bf9209", + "chksum_sha256": "8ed2ec14914b9632684928e2b2c0e6a4a0214d9bd0a2d4cdc6ce6c12f26b020a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_kv2_write/aliases", + "name": "tests/integration/targets/module_vault_database_connection_reset/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_list", + "name": "tests/integration/targets/module_vault_database_connections_list", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_list/meta", + "name": "tests/integration/targets/module_vault_database_connections_list/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_list/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_connections_list/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_list/tasks", + "name": "tests/integration/targets/module_vault_database_connections_list/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_list/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_connections_list/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "d2bc178fdf9e58520049f8c790ab59fea46d0e0702217b09d44585d8924cfcd6", + "chksum_sha256": "3281e06eeef48bde62a10941ce28d734f475c588d3e7ff77ee4d894bb8709989", "format": 1 }, { - "name": "tests/integration/targets/module_vault_list/tasks/module_vault_list_setup.yml", + "name": "tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "da29f44ffc011d762ccce49fb56d9f92c211efc2b23e862b06250b53cfa99b4e", + "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b", "format": 1 }, { - "name": "tests/integration/targets/module_vault_list/tasks/module_vault_list_test.yml", + "name": "tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "04989cd5883e29a27e3518abf43101b3250a59ce12ab3fa211c47189ff073bc9", + "chksum_sha256": "fbdcd876556d4d40b8276d1f9f1f5276e160180f7f60a99f10359a276010f1b5", "format": 1 }, { - "name": "tests/integration/targets/module_vault_list/aliases", + "name": "tests/integration/targets/module_vault_database_connections_list/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_login", + "name": "tests/integration/targets/module_vault_database_role_create", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_login/meta", + "name": "tests/integration/targets/module_vault_database_role_create/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_login/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_role_create/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_login/tasks", + "name": "tests/integration/targets/module_vault_database_role_create/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_login/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_role_create/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "b22bf1cde572747f66c24506459ce8af2fe3eb10e7e76819a36dfdb073cac838", + "chksum_sha256": "121019ed78fec8ed9aed738f3b3f2def55991536dc1a7baf6d62f176f6e1626d", "format": 1 }, { - "name": "tests/integration/targets/module_vault_login/tasks/module_vault_login_setup.yml", + "name": "tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "4dac8d49fd0585e2c19586a49c648155603ac0586f9e4d408d542dfbe17a84c4", + "chksum_sha256": "9e2ad35c9d730c9f37b404934fad90b1bfcff67347f3c449bf78e6bba214381c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml", + "name": "tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "8c301ddad3eaf8cbcce282450509b8f97373a9eaba0f303b75bdbffa31632a7e", + "chksum_sha256": "40a8641647a29d2965c13a2d331780d89384c80d4a209a4de441c7f4d8368bd8", "format": 1 }, { - "name": "tests/integration/targets/module_vault_login/aliases", + "name": "tests/integration/targets/module_vault_database_role_create/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate", + "name": "tests/integration/targets/module_vault_database_role_delete", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate/meta", + "name": "tests/integration/targets/module_vault_database_role_delete/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_role_delete/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "f46c476164b3816ef5d5177c32e476907bb4d6f10521503f49fdd4ca7750dffd", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks", + "name": "tests/integration/targets/module_vault_database_role_delete/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_role_delete/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "4cecdc9ba4619ff50914708f6245117b193c1bd8d7cacdd3f0cc0e9d362f926a", + "chksum_sha256": "70703bfa3463815edc4d0967793fefe37a72dab1c3245af3f56d8e244114b8d7", "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks/module_vault_pki_generate_certificate_setup.yml", + "name": "tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "fe70e81bb263e06bcae2f17a416e0924b37ad5b3909a0e40af204b537118e2af", + "chksum_sha256": "5dfd1b35f4d521e5dd5e849451669db9ce7f44670e2ff91105282b2e7a59279a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks/module_vault_pki_generate_certificate_test.yml", + "name": "tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "946878cbc4ccecb274c1bec29bfe02765fa29fcd790c2633c2b69c1ecd1850d5", + "chksum_sha256": "119e9785255c90e923506cc8e0b9e276d50115eb90167c66c26c7714d58a7e4f", "format": 1 }, { - "name": "tests/integration/targets/module_vault_pki_generate_certificate/aliases", + "name": "tests/integration/targets/module_vault_database_role_delete/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_read", + "name": "tests/integration/targets/module_vault_database_role_read", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_read/meta", + "name": "tests/integration/targets/module_vault_database_role_read/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_read/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_role_read/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_read/tasks", + "name": "tests/integration/targets/module_vault_database_role_read/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_read/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_role_read/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "0dd8e3e62fa4a57db9b413e4720b557fa93f3ee3099d342dc9db5aabffc5f514", + "chksum_sha256": "454bbf70f3e1da0a05b95c6acc9561514474144eed982d7a52764f325edaed51", "format": 1 }, { - "name": "tests/integration/targets/module_vault_read/tasks/module_vault_read_setup.yml", + "name": "tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "da29f44ffc011d762ccce49fb56d9f92c211efc2b23e862b06250b53cfa99b4e", + "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b", "format": 1 }, { - "name": "tests/integration/targets/module_vault_read/tasks/module_vault_read_test.yml", + "name": "tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "64c40f5bdb50e600ff94387a0d9aae3f0df171de2548d5bdfc693a2c7fc7cafd", + "chksum_sha256": "19798f8d2a693c9109206301a56a0ea0a5df681e141dbd0647af4d7f88f24b94", "format": 1 }, { - "name": "tests/integration/targets/module_vault_read/aliases", + "name": "tests/integration/targets/module_vault_database_role_read/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create", + "name": "tests/integration/targets/module_vault_database_roles_list", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create/meta", + "name": "tests/integration/targets/module_vault_database_roles_list/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_roles_list/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create/tasks", + "name": "tests/integration/targets/module_vault_database_roles_list/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_roles_list/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "18612db702fea282a224794f73509a59be1ffc1916e90cfc55ecfa6a73f6919c", + "chksum_sha256": "3f3530c36c4f487f55b454349b72ab9fc04958ae3117ea40b4b6aed8661ed19c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create/tasks/module_vault_token_create_setup.yml", + "name": "tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "c85486c5137bd9d5b4820e08b9c2206db7cbb87fa3af2461322048dff4bdff54", + "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b", "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create/tasks/module_vault_token_create_test.yml", + "name": "tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "92960ce2f9e01c7d7bc1bc7865ffa941da04f0c6e916ff5fdc1c48b7c61c9008", + "chksum_sha256": "4b4a64ba29c5b2d1e9f1b8a94d44f8d2c9f75a17f4d99bd868ab66cc31a7cfb7", "format": 1 }, { - "name": "tests/integration/targets/module_vault_token_create/aliases", + "name": "tests/integration/targets/module_vault_database_roles_list/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/module_vault_write", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_write/meta", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_write/meta/main.yml", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "4711f4181ed51d1fd3c0912702e2e28b8429485a3ded3bbe8088b873a6ff3888", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/module_vault_write/tasks", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/module_vault_write/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "9ba8927d006f6fe47f7b07101814e2ba0380abf275893ae9f23c2f10016c57fa", + "chksum_sha256": "c810c6573a56b0f3e75d50095d9aede661faae86d10baca9689b97018cd8e9eb", "format": 1 }, { - "name": "tests/integration/targets/module_vault_write/tasks/module_vault_write_setup.yml", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "b2634aae7862e962b8e3b3d91e4c8139a3665f4594508759dbadb29b533098ac", + "chksum_sha256": "e5a5899f1dd9fffc20f1eae8176fb6271008da40308e9d8d7de641d7d0fbc248", "format": 1 }, { - "name": "tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "2c77fe22b6a2c80eab637289cd32027d3893ecab8f9e9deee8551234a3ded4ae", + "chksum_sha256": "c5f28493506637d1575dd435a5cac4392bfa793a4c1f0b09d44182ca21671819", "format": 1 }, { - "name": "tests/integration/targets/module_vault_write/aliases", + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e6e0975b9bffccf9c3f1ee819ee0f2482f1bdf9ddccfd386bacbcf3157a09cc6", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_rotate_root_creds/aliases", "ftype": "file", "chksum_type": "sha256", "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content", + "name": "tests/integration/targets/module_vault_database_static_role_create", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content/defaults", + "name": "tests/integration/targets/module_vault_database_static_role_create/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content/defaults/main.yml", + "name": "tests/integration/targets/module_vault_database_static_role_create/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "1a0680caa039fea93d79a7c029902d0bfe92fca93262c7a94d6500da1623b4ec", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content/files", + "name": "tests/integration/targets/module_vault_database_static_role_create/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content/files/.gitignore", + "name": "tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d", + "chksum_sha256": "04b41c2b6d52b73e539f227d5860f2a2d0839d8a4263404aef861c634cddd9f7", "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content/tasks", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, - "format": 1 - }, - { - "name": "tests/integration/targets/setup_cert_content/tasks/main.yml", + "name": "tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e6bedb35975e2420202e837af3950fd4511e3329961155468062619a1a38c29c", + "chksum_sha256": "9e2ad35c9d730c9f37b404934fad90b1bfcff67347f3c449bf78e6bba214381c", "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content/README.md", + "name": "tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "22f4f3c9b0922471eb243107f1c2981e078dda06b80df33a2a25cd652c5bcaae", + "chksum_sha256": "1299f12449f5c2978e936212d539000aae16bbd1dd9a889fdcca027e312b3abe", "format": 1 }, { - "name": "tests/integration/targets/setup_cert_content/aliases", + "name": "tests/integration/targets/module_vault_database_static_role_create/aliases", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e084a3683ef795d1cdbf5e9b253f2ca1f783ae0d0d6e47e419acbbc4fc80bbfa", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", "format": 1 }, { - "name": "tests/integration/targets/setup_localenv_docker", + "name": "tests/integration/targets/module_vault_database_static_role_get_creds", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/setup_localenv_docker/defaults", + "name": "tests/integration/targets/module_vault_database_static_role_get_creds/meta", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/setup_localenv_docker/defaults/main.yml", + "name": "tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e9186a70864ebe946235117d244026dff8de74ffc6185f470c947fc83aa7e046", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", "format": 1 }, { - "name": "tests/integration/targets/setup_localenv_docker/files", + "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks", "ftype": "dir", "chksum_type": null, "chksum_sha256": null, "format": 1 }, { - "name": "tests/integration/targets/setup_localenv_docker/files/.output", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, + "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5b5bc39e5d80cdeb750f6f44017ea22574d4659be6829118b976a193565cb2ed", "format": 1 }, { - "name": "tests/integration/targets/setup_localenv_docker/files/.output/.gitignore", + "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d", + "chksum_sha256": "371e13dca6e5ffdb1e7daae3a995c5bc666fb61da3d3ae7bd1424f9314821595", "format": 1 }, { - "name": "tests/integration/targets/setup_localenv_docker/files/playbooks", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, + "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "645bac53117a5a61655dd99faf04297d6d531ca279aebca771c6321885d395ee", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_get_creds/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7969c6a9f5447fae5e780d5df7c18f32ce1a33c1d1829e16c0c7a7fecead88b2", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "41bcf98396b6ad272d5915faa64fb376ce41c2289c0fb92f65a94127339309aa", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_read/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6ac85c42e2b88b0279543724956b144113d13ba1a3ad868fc0049cc53b66b6f8", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5c0bbfcabe4cf92041f3b192a02d98b24c26ec51a543f7570556d31ba3c6dbcd", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "712cd5d4150769cd5f3327038feb7dc04802e5e11f844ba2083356bb785e07d5", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b524e4c9b61fc3985a5081122446de5f372d0949fa08efc851048b5b4bb50b62", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5d4627309166e68d3b2c5ef27e63e56a62ce82634b5d924c692cd1ff9ef5ab45", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_database_static_roles_list/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a7b0fcc3cf144f647e9ff812d244e9a9fa5505ee93150968b74fa3c80af3f1d2", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get/tasks/module_vault_kv1_get_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d62c4e28a99a4ea4c7c852c2f9ad7f18ef5f0fa0aec6173d4d22549a258f3e7", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get/tasks/module_vault_kv1_get_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "743099acae8046c0084a97e034a404a3d5ce5fd6f7d518325e6631b6fbe25100", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv1_get/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dac8c3fdd19f0ef331541dbac0990585d56c790ac0e668c69f13aa43901f0733", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete/tasks/module_vault_kv2_delete_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "deb41e77ec8ab94b7e52d069ba8abc7d608fface50b04d95e519cc79862476c2", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete/tasks/module_vault_kv2_delete_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0838e8664760bdbc3c346e3a8ff6a0933669caa7b73f5bb61917200bf1a5f209", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_delete/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2eb537abfb3a977dbfc8c3f9d8aa6a74bf6d847a40b534f33bb01ab39d553ece", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get/tasks/module_vault_kv2_get_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9e6a6d56b14c282646e5963cea65a65810b588b6ea031a6da9c56cb55a92274f", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get/tasks/module_vault_kv2_get_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "522b1a08b43c5197f21ffdc3d02fae29203603bd89a2613505821f63e78a81ca", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_get/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bcffa3e2bbb00d5cfb872e44a8c434f38082ece25980f9f5893565bff6d0d47c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/tasks/setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1af47e07f72f7218b072c4c596a424322c8c3859ff36a0070fa9d6c48747f8c6", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/tasks/test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d010ebc4f545365b01b006ba74fcbba1ef9de787a464eb8b07c18cb85b127d8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dba69bdb30b13fd447059fe9dd9b8723a67bc07cc888072e61fe4703d8bf9209", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_kv2_write/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d2bc178fdf9e58520049f8c790ab59fea46d0e0702217b09d44585d8924cfcd6", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list/tasks/module_vault_list_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "da29f44ffc011d762ccce49fb56d9f92c211efc2b23e862b06250b53cfa99b4e", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list/tasks/module_vault_list_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "04989cd5883e29a27e3518abf43101b3250a59ce12ab3fa211c47189ff073bc9", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_list/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b22bf1cde572747f66c24506459ce8af2fe3eb10e7e76819a36dfdb073cac838", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login/tasks/module_vault_login_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4dac8d49fd0585e2c19586a49c648155603ac0586f9e4d408d542dfbe17a84c4", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "85463950dfa98475033d097b0d582e1706bd660b9c51f7886d1ccef0e2e95de1", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_login/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f46c476164b3816ef5d5177c32e476907bb4d6f10521503f49fdd4ca7750dffd", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4cecdc9ba4619ff50914708f6245117b193c1bd8d7cacdd3f0cc0e9d362f926a", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks/module_vault_pki_generate_certificate_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fe70e81bb263e06bcae2f17a416e0924b37ad5b3909a0e40af204b537118e2af", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate/tasks/module_vault_pki_generate_certificate_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "946878cbc4ccecb274c1bec29bfe02765fa29fcd790c2633c2b69c1ecd1850d5", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_pki_generate_certificate/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0dd8e3e62fa4a57db9b413e4720b557fa93f3ee3099d342dc9db5aabffc5f514", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read/tasks/module_vault_read_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "da29f44ffc011d762ccce49fb56d9f92c211efc2b23e862b06250b53cfa99b4e", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read/tasks/module_vault_read_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "64c40f5bdb50e600ff94387a0d9aae3f0df171de2548d5bdfc693a2c7fc7cafd", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_read/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9126d021b12eeeb4906402adad6b85a1536f4c3096b9f6864037ebaa5da25a2b", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "18612db702fea282a224794f73509a59be1ffc1916e90cfc55ecfa6a73f6919c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create/tasks/module_vault_token_create_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c85486c5137bd9d5b4820e08b9c2206db7cbb87fa3af2461322048dff4bdff54", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create/tasks/module_vault_token_create_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "92960ce2f9e01c7d7bc1bc7865ffa941da04f0c6e916ff5fdc1c48b7c61c9008", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_token_create/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4711f4181ed51d1fd3c0912702e2e28b8429485a3ded3bbe8088b873a6ff3888", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9ba8927d006f6fe47f7b07101814e2ba0380abf275893ae9f23c2f10016c57fa", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write/tasks/module_vault_write_setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b2634aae7862e962b8e3b3d91e4c8139a3665f4594508759dbadb29b533098ac", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6ecab83cd951b6761b5dccde4a65b40027269afff7ed8113b7d08172765a1c7c", + "format": 1 + }, + { + "name": "tests/integration/targets/module_vault_write/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1a0680caa039fea93d79a7c029902d0bfe92fca93262c7a94d6500da1623b4ec", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/files/.gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e6bedb35975e2420202e837af3950fd4511e3329961155468062619a1a38c29c", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "22f4f3c9b0922471eb243107f1c2981e078dda06b80df33a2a25cd652c5bcaae", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_cert_content/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e084a3683ef795d1cdbf5e9b253f2ca1f783ae0d0d6e47e419acbbc4fc80bbfa", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2d962f207d5f4bcdd85730c077130c86f81d08f8a35ff6bbe2e56ad68be33a43", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker/files/.output", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker/files/.output/.gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "240a3e0d37d2e86b614063f5347eb02d4f99ca6c254de6b82871ff8d95532a7d", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker/files/playbooks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, "format": 1 }, { "name": "tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "db75d75550fcb5334f8161ae8b591f145c6604a093247e9149f723bf26682abb", + "chksum_sha256": "0c247bf4edd24eb1c7bef49da03d59df376b5946196d58e0bf47c5003003cc4a", "format": 1 }, { @@ -2769,14 +3728,14 @@ "name": "tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "521caee2728da71f6f8c804ee6a125081b38ac1b07b0acb48d790eeeca722eeb", + "chksum_sha256": "3d00767b7ce6a17528778206e8a1a3888e8bf966f88c6dbb03608aa1d9e11f11", "format": 1 }, { "name": "tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e2af5fc6f791738b66b031c46731e8de0976265f02dc51901174af1f1be3b4e3", + "chksum_sha256": "cdc9c91d9afdb3a25f281299e50d7fb1456820f5cee294569135487c358ff57d", "format": 1 }, { @@ -2786,6 +3745,20 @@ "chksum_sha256": "be87a9d501b75b973dc2f4fe10737999d8efab083b9c6110babe06cf1cb3d502", "format": 1 }, + { + "name": "tests/integration/targets/setup_localenv_docker/files/sql", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_localenv_docker/files/sql/init.sql", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7855191e0bc7cb4a363a426e22f00cbe4d2a6714b871682345552abfa8c36ccf", + "format": 1 + }, { "name": "tests/integration/targets/setup_localenv_docker/tasks", "ftype": "dir", @@ -2804,7 +3777,7 @@ "name": "tests/integration/targets/setup_localenv_docker/tasks/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "5847657fe7ab224b6a780b62359a725f4dd8978c9fbde213bb6dd124d648ab19", + "chksum_sha256": "f53f3dc1f2059e3f97c1504c118d806f8a91940f2a5d8f09058df5ae8486d177", "format": 1 }, { @@ -2895,7 +3868,7 @@ "name": "tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "4ee4aded02dc766e59599c22e977f266fee2a4e238b5c9cb5b7ccfbd31e089e3", + "chksum_sha256": "d76a1634d00bf21830d5970775f048cd62735552fff1b21990d5be789043f76e", "format": 1 }, { @@ -2930,7 +3903,7 @@ "name": "tests/integration/targets/setup_localenv_docker/vars/main.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "ba1d50adc2585030809325a0102576dbb5cb1c5f4c1613bf5f1f4a2ce0bd6cc8", + "chksum_sha256": "91655f9dc152ab9aa50cb99bfd12aacb8a277f4d4ccd70f9509912d4c63e9ecf", "format": 1 }, { @@ -3021,7 +3994,7 @@ "name": "tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e3f4b18483da6eadf64e5ed8193d89ba648daa2ac67c61df156e7dbd9a166496", + "chksum_sha256": "41fc6c71d3aa6682059d9ea3a7f5a9cf8c84347f202564bcc2ddaebc912e0be1", "format": 1 }, { @@ -3150,6 +4123,76 @@ "chksum_sha256": "0584bb783019be77fe15aba5347fba524b641155594286366214a4647662c8e8", "format": 1 }, + { + "name": "tests/integration/targets/setup_vault_configure_database", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4711f4181ed51d1fd3c0912702e2e28b8429485a3ded3bbe8088b873a6ff3888", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/tasks/configure.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7053ed5006ed1da7dc410b149a6fef66099c4e5803d765db4446d21704aef050", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "40e459dac64ec618436d308ce3400a37b057267fbd082cc8c4cd7aea973c9eed", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "14de609ddcffdb33a72f72ea45908d7edbbaf0194e014163691d200ea603f917", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b5e48fce153278864264b27fc2162a6bbd8c789413b592a8ae4349014ee72bd6", + "format": 1 + }, + { + "name": "tests/integration/targets/setup_vault_configure_database/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0584bb783019be77fe15aba5347fba524b641155594286366214a4647662c8e8", + "format": 1 + }, { "name": "tests/integration/targets/setup_vault_configure_engine_pki", "ftype": "dir", @@ -3402,6 +4445,13 @@ "chksum_sha256": "982c0b7fe8683e818a27cf59b6a6892d91c277703c81e2db35994f63ef90e7fc", "format": 1 }, + { + "name": "tests/integration/constraints.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9dec7a581a697549468372acb1cc3a37b2cbe897ea2902878f9565f3f8b7b3fb", + "format": 1 + }, { "name": "tests/integration/integration.cfg", "ftype": "file", @@ -3420,7 +4470,7 @@ "name": "tests/integration/requirements.txt", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "b46f66680eea1291c232bd2e08db3258aa94ad4a3c5a26750203dc71046810f5", + "chksum_sha256": "caddf55f1b596b08d58b6ecf106f4321f79dacdb648d69e953184d01cd4b1755", "format": 1 }, { @@ -3507,6 +4557,55 @@ "chksum_sha256": "80ebb3d62931e358c6d3bab71ecb14a8e9e6b614ebdd3df9feb5ea4465b3ca83", "format": 1 }, + { + "name": "tests/unit/fixtures/database_connection_read_response.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "24151ee2d877ce7ccc16b66b163eb1622c23db0b5f0002f9ddde733619b2ec27", + "format": 1 + }, + { + "name": "tests/unit/fixtures/database_connections_list_response.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7f6a94dc085560e91281059c1147f9851f1a75cbb514f63e668ddc31fc5cfb52", + "format": 1 + }, + { + "name": "tests/unit/fixtures/database_role_read_response.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "108ccdc116d131ecf87dc1aebe268693a1b3bd6b625e0769c7eb83b02e421d41", + "format": 1 + }, + { + "name": "tests/unit/fixtures/database_roles_list_response.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "08260f3a5167cec132d0162089498a7c64bec0f2f16d08d2f2fb368a4372e746", + "format": 1 + }, + { + "name": "tests/unit/fixtures/database_static_role_get_credentials_response.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f4c847fd41e6b6419aed4e205675dcc547b073e0015ec52ac2ccaebbf041e86d", + "format": 1 + }, + { + "name": "tests/unit/fixtures/database_static_role_read_response.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e815b6dc328429cf0d0e353098c100c7cc35da83fdc7e761c5373a982e7905c3", + "format": 1 + }, + { + "name": "tests/unit/fixtures/database_static_roles_list_response.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0fd331d4f627e6ac97986890a6445543d71b2c71fe23120203fe3428766b1fac", + "format": 1 + }, { "name": "tests/unit/fixtures/jwt_login_response.json", "ftype": "file", @@ -3686,14 +4785,14 @@ "name": "tests/unit/plugins/lookup/test_vault_token_create.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "da6e62da0beabc991cebc40e063f861b6b46f98ef501d4c28f17ee7e68e34b05", + "chksum_sha256": "2008e24f5096b3454cce19aed8b877c33f4a8bc1c2dc4a3908653395cd409d79", "format": 1 }, { "name": "tests/unit/plugins/lookup/test_vault_write.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "db7a4a050e4c80b9ef058ed9c28e06ff7f7c94d0d6fac535455d270e69cd06ed", + "chksum_sha256": "c2b5ee98baadba6e5a9520e95aacb899c01b4d989cc48453c340be0a1de2d9f3", "format": 1 }, { @@ -3728,14 +4827,14 @@ "name": "tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "47a0b6f5339479ccf7ba86344478bb936d468e7cac20fdabe8ea84248d4f086c", + "chksum_sha256": "5cd756c453da81d4dcb408139567b86a047175b88045ee112a4f958887c50b34", "format": 1 }, { "name": "tests/unit/plugins/module_utils/authentication/test_auth_azure.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e7874e069e88a75c257fb80cf612bf78316ace21e892289ad59981907906dd77", + "chksum_sha256": "651237f3b447adaabcb1dff9a7540a4125b07b012d04c54afc841e578c4c6743", "format": 1 }, { @@ -3770,7 +4869,7 @@ "name": "tests/unit/plugins/module_utils/authentication/test_auth_token.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "abac6adc2d23f2368700edac95f9734153379ce62837cacf277653024b7b63b4", + "chksum_sha256": "1576d74d9304af6c7dbc8494c34a605b2001484f3904830f1d08f789ff83edd7", "format": 1 }, { @@ -3784,7 +4883,7 @@ "name": "tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "0c0861f123a4cf0f291f857035d04754b6a547e79e47b1a406e48b4022f3b44b", + "chksum_sha256": "49d1a2b3df3afdda4957428e1ade75ecfd7ebeedc481139538a80749e2181ba3", "format": 1 }, { @@ -3812,21 +4911,21 @@ "name": "tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "df8f8ddc9ecf159214128c2987b6186805af8ea631cd855169a702db8617e767", + "chksum_sha256": "8025136869c598fdb79ca350e2f64d5448279240d33a047d69661074b5f7175d", "format": 1 }, { "name": "tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "d40bcd481379315d4362afb0cc0e3b735b024ec5c85fb54055b05374da52fcd6", + "chksum_sha256": "75521ab23dcd91023b82da4290ecf99a9eb7dc082ed35a1b053a4619fe64fdc6", "format": 1 }, { "name": "tests/unit/plugins/module_utils/test_hashi_vault_helper.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "02ca0e5fb0d77d7de7a86b1fe7ce9bce5f3d33a71bf64c1785376f50200aee89", + "chksum_sha256": "db9944713d7c7b70d1689b59b73f8ed7dfea644146ed89c0bf88df6722cdc8d4", "format": 1 }, { @@ -3850,6 +4949,111 @@ "chksum_sha256": "c43bad6fcdf0452b1fc5d3d1f42c030ead02c240139e2da976067488d5bddb46", "format": 1 }, + { + "name": "tests/unit/plugins/modules/test_vault_database_connection_configure.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0ac8a71b1858d9fb93c468a09fc34fdd745f397caee36a7cf83bbbccfe75cbdf", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_connection_delete.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3e09ebd72533c3ff547e707a3cac4b2b65605531fc207f65d548be227c54a231", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_connection_read.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "41f2b86409b0fe614883b206c72dbc9900833227bcb3a6dfc4220b77856ad10d", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_connection_reset.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2961c5f24715e8009b268a4027b05fb13953b98f4219afa2e5397d0cfe2d2794", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_connections_list.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fee63fc3547e48ac51e25c5beffd5899b079d0a151413673b86d8a84a0ec57fb", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_role_create.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4209c5095e09cde98a54b510f64438d7e40aa8a0fff0ef5ba0b978ee39a11fd3", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_role_delete.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "33ebdbf3d606fa48d7e89579ce2013dc563f7dd66ce5d05e4e5972ea018fb85e", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_role_read.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c4a9922cfed0444dacf22f8383eb077c17b164b10d51ee4b8e8e0723e5098b85", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_roles_list.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a52538e72f73d420862c2bc516a4675faf5a6f092fde520305b6c2f80f9619b5", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ae5b4d20fb6e2dba90a2a7c7a3d65f2ae3497cf46ee490abb6a5476940d9107", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_static_role_create.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "87b0a60aa3c09c6ec167741cc9724b69dc30a2a3f63c205b5425d36febdc631a", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6f5cb1b8f6fead7f89e9af378e8a63dd561c8958aed5a33f47b8bcf7ac840e8a", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_static_role_read.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "aa6a6e0b26dbcac35e01d04a53c1c338fcc366ef6127bef49264a35f8dcb2741", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0905fe00c51129d07a2cdfbb76ccee7774187626bdc504aee58da2785f373082", + "format": 1 + }, + { + "name": "tests/unit/plugins/modules/test_vault_database_static_roles_list.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "535af7025507c0fcc1b9ee82597a53b2f6e5c4c0f9ecaa69c10761403d6640c5", + "format": 1 + }, { "name": "tests/unit/plugins/modules/test_vault_kv1_get.py", "ftype": "file", @@ -3896,7 +5100,7 @@ "name": "tests/unit/plugins/modules/test_vault_pki_generate_certificate.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "2c7ffc3b60b172c704c2947bfd212c92ea2a2e4bef1b71a3967c3e022c9879e6", + "chksum_sha256": "bc53c528710a271501e8e3905ba94de223f958420754202f9d4ace391a019253", "format": 1 }, { @@ -3917,7 +5121,7 @@ "name": "tests/unit/plugins/modules/test_vault_write.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "b723e07376ec9c56bd5070e0be49c19d6e6542aa46b9b4e3491170bb1af6ce4c", + "chksum_sha256": "0a716b13c406579c7d26cb283658ea53299fbfe34920b7d12ab73e4e7d41cac6", "format": 1 }, { @@ -3927,27 +5131,6 @@ "chksum_sha256": null, "format": 1 }, - { - "name": "tests/unit/plugins/plugin_utils/authentication", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, - "format": 1 - }, - { - "name": "tests/unit/plugins/plugin_utils/authentication/conftest.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "7eaacca9465aa4ab541a88254fe6700ece427d3e9fd832c2733bfd71e30c6899", - "format": 1 - }, - { - "name": "tests/unit/plugins/plugin_utils/authentication/test_auth_token.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "b48581be86aa632e7580301a0d3d62d06219b3d24b44a94b6c4ca73e23e6f1fc", - "format": 1 - }, { "name": "tests/unit/plugins/plugin_utils/base", "ftype": "dir", @@ -3959,7 +5142,7 @@ "name": "tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "b38f37e9cb846e77a00e6b1dcf63db09ffde02460e02ec278317e091a950dd42", + "chksum_sha256": "ec0bccac48afd69d21644d3d2631f9617e7a604a72158473b26f011d48250c9e", "format": 1 }, { @@ -3980,77 +5163,63 @@ "name": "tests/unit/plugins/plugin_utils/option_adapter/conftest.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "692431478c133aedf9e66f939cb63ecc7fc66a58191ace5569759a3af40ed5c5", + "chksum_sha256": "2dd268286c9a921018df05152f8f6332f20279ab3ff25c731c8e34d22e676295", "format": 1 }, { "name": "tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "525504b9d635e74afe7e24efbb2431e9cd77ceb6b27b1ba1ebf2da92c8ac5901", - "format": 1 - }, - { - "name": "tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py", - "ftype": "file", - "chksum_type": "sha256", - "chksum_sha256": "30a555505f23377a8850ec84ad5df84a192dd24ba5774fb473fa67f97dac381b", + "chksum_sha256": "75c3eb27a1c78605461bba291dd5db145043c981845c4163f9b54b7259cced88", "format": 1 }, { - "name": "tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py", + "name": "tests/unit/conftest.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "14488b16acbb0cf0d991a84f4fe1805fb0ac5f0cfa4529cf1b57b7b448adc907", + "chksum_sha256": "da4017d6bcb97a9184ce968d216eaa62aac641ded86df8fd710fd6287357f7cd", "format": 1 }, { - "name": "tests/unit/conftest.py", + "name": "tests/unit/constraints.txt", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e29931074c13b6d08f944adba9ce6fbaf0e2b8585a9bceeac51cde6c99ab83e1", + "chksum_sha256": "9dec7a581a697549468372acb1cc3a37b2cbe897ea2902878f9565f3f8b7b3fb", "format": 1 }, { "name": "tests/unit/requirements.txt", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "1a7e15b893287335a87621a5738d46855524ee40b7e54c7af18fa567c85f30a5", - "format": 1 - }, - { - "name": "tests/utils", - "ftype": "dir", - "chksum_type": null, - "chksum_sha256": null, + "chksum_sha256": "18ae2786efc33af15a4f09d215cd4758daf61dd8c992154131afadf95ace170a", "format": 1 }, { - "name": "tests/utils/constraints.txt", + "name": "tests/config.yml", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "6587434a23557810c3378386918925a2bc372399682483bb1ee0c33001a30544", + "chksum_sha256": "f5174fec8c0d86b9970fd83767ffc181f4d6ef25aaad4a1f12f9d73ad38a23de", "format": 1 }, { - "name": "tests/config.yml", + "name": ".git-blame-ignore-revs", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "f5174fec8c0d86b9970fd83767ffc181f4d6ef25aaad4a1f12f9d73ad38a23de", + "chksum_sha256": "559c96731959d3d5e516775f2e4329064991505ffefb2f3c84d3b1f814270f90", "format": 1 }, { - "name": ".git-blame-ignore-revs", + "name": "CHANGELOG.md", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "559c96731959d3d5e516775f2e4329064991505ffefb2f3c84d3b1f814270f90", + "chksum_sha256": "7dbbb4c968b1d53ad5661e79a364f341e728da0d61ac1bdc868bf7136cd6e634", "format": 1 }, { "name": "CHANGELOG.rst", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "79bab511c63a4f5ffdffbf0deb76f4b6aed0db672e46dc34413030f308cbba4a", + "chksum_sha256": "9b52d95bfa031a3b374b7a519ea045b63a7ee696cf74af9d6bf70039a5ef4816", "format": 1 }, { @@ -4064,7 +5233,7 @@ "name": "README.md", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "44caa26d837f0ae09a1f6d7f97fca696d26261ea4d94d6d30ccf58bb37864ae3", + "chksum_sha256": "4561d2cec8f8ffd034351f3fba6d2788640b034df96805aeda0b67db9a408127", "format": 1 }, { diff --git a/ansible_collections/community/hashi_vault/MANIFEST.json b/ansible_collections/community/hashi_vault/MANIFEST.json index 3845b05b1..2524a07c4 100644 --- a/ansible_collections/community/hashi_vault/MANIFEST.json +++ b/ansible_collections/community/hashi_vault/MANIFEST.json @@ -2,7 +2,7 @@ "collection_info": { "namespace": "community", "name": "hashi_vault", - "version": "4.2.1", + "version": "6.2.0", "authors": [ "Julie Davila (@juliedavila) ", "Brian Scholer (@briantist)" @@ -32,7 +32,7 @@ "name": "FILES.json", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "a3546d2747fa04f54d5d67aee79aeb8d80598df269a6f484ba9ff2a0fc3895e1", + "chksum_sha256": "eafb51e763722dc3571899bd632595bc4c449ed0a39e9b8d707b5f6f03caf521", "format": 1 }, "format": 1 diff --git a/ansible_collections/community/hashi_vault/README.md b/ansible_collections/community/hashi_vault/README.md index c8cf2b82c..d80337060 100644 --- a/ansible_collections/community/hashi_vault/README.md +++ b/ansible_collections/community/hashi_vault/README.md @@ -12,17 +12,16 @@ Browsing the [**devel** collection documentation](https://docs.ansible.com/ansib We also separately publish [**latest commit** collection documentation](https://ansible-collections.github.io/community.hashi_vault/branch/main/) which shows docs for the _latest commit in the `main` branch_. If you use the Ansible package and don't update collections independently, use **latest**, if you install or update this collection directly from Galaxy, use **devel**. If you are looking to contribute, use **latest commit**. + ## Tested with Ansible -* 2.11 -* 2.12 -* 2.13 -* 2.14 -* 2.15 -* devel (latest development commit) +Please refer to the [`ansible-core` support matrix](https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix) to see which versions of `ansible-core` are still supported or end-of-life. + +Generally, we release a new major version of this collection a little before the release of a new `ansible-core` version, which is around every 6 months. In that release, we will update the CI matrix to drop the core versions that are about to go EoL, and add in new core versions if they have not been added already. + +We also regularly test against the [`devel` branch](https://github.com/ansible/ansible/tree/devel) (latest development commit). See [the CI configuration](https://github.com/ansible-collections/community.hashi_vault/blob/main/.github/workflows/ansible-test.yml) for the most accurate testing information. - ## Tested with Vault @@ -47,6 +46,7 @@ Currently we support and test against Python versions: * 3.9 * 3.10 * 3.11 +* 3.12 Note that for controller-side plugins, only the Python versions supported by the Ansible controller are supported (for example, you cannot use Python 3.7 with Ansible core 2.12). diff --git a/ansible_collections/community/hashi_vault/changelogs/changelog.yaml b/ansible_collections/community/hashi_vault/changelogs/changelog.yaml index cd982ec0e..0018040ff 100644 --- a/ansible_collections/community/hashi_vault/changelogs/changelog.yaml +++ b/ansible_collections/community/hashi_vault/changelogs/changelog.yaml @@ -644,3 +644,124 @@ releases: fragments: - 4.2.1.yml release_date: '2023-04-27' + 5.0.0: + changes: + breaking_changes: + - Support for ``ansible-core`` 2.11 and 2.12 has been removed (https://github.com/ansible-collections/community.hashi_vault/issues/340). + - The minimum version of ``hvac`` for ``community.hashi_vault`` is now ``1.1.0`` + (https://github.com/ansible-collections/community.hashi_vault/issues/324). + - hashi_vault lookup - duplicate option entries in the term string now raises + an exception instead of a warning (https://github.com/ansible-collections/community.hashi_vault/issues/356). + release_summary: This version makes some relatively minor but technically breaking + changes. Support for ``ansible-core`` versions ``2.11`` and ``2.12`` have + been dropped, and there is now a minimum supported version of ``hvac`` which + will be updated over time. A warning in the ``hashi_vault`` lookup on duplicate + option specifications in the term string has been changed to a fatal error. + fragments: + - 324-minimum-hvac-version.yml + - 340-drop-core-211-212.yml + - 356-duplicate-term-options.yml + - 5.0.0.yml + release_date: '2023-05-11' + 5.0.1: + changes: + bugfixes: + - vault_write - the ``vault_write`` lookup and module were not able to write + data containing keys named ``path`` or ``wrap_ttl`` due to a bug in the ``hvac`` + library. These plugins have now been updated to take advantage of fixes in + ``hvac>=1.2`` to address this (https://github.com/ansible-collections/community.hashi_vault/issues/389). + release_summary: This release fixes a bug in ``vault_write`` ahead of the collection's + next major release. + fragments: + - 381-localenv_docker.yml + - 404-vault_write-spicy-keys.yml + - 5.0.1.yml + release_date: '2023-11-05' + 6.0.0: + changes: + breaking_changes: + - The minimum required version of ``hvac`` is now ``1.2.1`` (https://docs.ansible.com/ansible/devel/collections/community/hashi_vault/docsite/user_guide.html#hvac-version-specifics). + release_summary: This major version of the collection has no functional changes + from the previous version, however the minimum versions of ``hvac`` and ``ansible-core`` + have been raised. While the collection may still work with those earlier versions, + future changes will not test against them. + removed_features: + - The minimum supported version of ``ansible-core`` is now ``2.14``, support + for ``2.13`` has been dropped (https://github.com/ansible-collections/community.hashi_vault/pull/403). + fragments: + - 403-core-vault-python.yml + - 6.0.0.yml + release_date: '2023-11-05' + 6.1.0: + changes: + major_changes: + - requirements - the ``requests`` package which is required by ``hvac`` now + has a more restrictive range for this collection in certain use cases due + to breaking security changes in ``ansible-core`` that were backported (https://github.com/ansible-collections/community.hashi_vault/pull/416). + release_summary: This release addresses some breaking changes in core that were + backported. + fragments: + - 416-core-changes.yml + - 6.1.0.yml + release_date: '2024-01-02' + 6.2.0: + changes: + minor_changes: + - cert auth - add option to set the ``cert_auth_public_key`` and ``cert_auth_private_key`` + parameters using the variables ``ansible_hashi_vault_cert_auth_public_key`` + and ``ansible_hashi_vault_cert_auth_private_key`` (https://github.com/ansible-collections/community.hashi_vault/issues/428). + release_summary: This release contains a dozen+ new modules for working with + Vault's database secrets engine and some new ``vars`` entries for specifying + public and private keys in ``cert`` auth. + fragments: + - 429-add-cert-auth-variables.yml + - 6.2.0.yml + modules: + - description: Configures the database engine + name: vault_database_connection_configure + namespace: '' + - description: Delete a Database Connection + name: vault_database_connection_delete + namespace: '' + - description: Returns the configuration settings for a O(connection_name) + name: vault_database_connection_read + namespace: '' + - description: Closes a O(connection_name) and its underlying plugin and restarts + it with the configuration stored + name: vault_database_connection_reset + namespace: '' + - description: Returns a list of available connections + name: vault_database_connections_list + namespace: '' + - description: Creates or updates a (dynamic) role definition + name: vault_database_role_create + namespace: '' + - description: Delete a role definition + name: vault_database_role_delete + namespace: '' + - description: Queries a dynamic role definition + name: vault_database_role_read + namespace: '' + - description: Returns a list of available (dynamic) roles + name: vault_database_roles_list + namespace: '' + - description: Rotates the root credentials stored for the database connection. + This user must have permissions to update its own password. + name: vault_database_rotate_root_credentials + namespace: '' + - description: Create or update a static role + name: vault_database_static_role_create + namespace: '' + - description: Returns the current credentials based on the named static role + name: vault_database_static_role_get_credentials + namespace: '' + - description: Queries a static role definition + name: vault_database_static_role_read + namespace: '' + - description: Trigger the credential rotation for a static role + name: vault_database_static_role_rotate_credentials + namespace: '' + - description: Returns a list of available static roles + name: vault_database_static_roles_list + namespace: '' + release_date: '2024-03-19' diff --git a/ansible_collections/community/hashi_vault/changelogs/config.yaml b/ansible_collections/community/hashi_vault/changelogs/config.yaml index f7f950db0..2eaf842ca 100644 --- a/ansible_collections/community/hashi_vault/changelogs/config.yaml +++ b/ansible_collections/community/hashi_vault/changelogs/config.yaml @@ -27,3 +27,4 @@ sections: - Known Issues title: community.hashi_vault trivial_section_name: trivial +output_formats: [rst, md] diff --git a/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst b/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst index 5223d4a97..4362dc7f0 100644 --- a/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst +++ b/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst @@ -1,9 +1,99 @@ -=================================== -community.hashi_vault Release Notes -=================================== +==================================== +community.hashi\_vault Release Notes +==================================== .. contents:: Topics +v6.2.0 +====== + +Release Summary +--------------- + +This release contains a dozen+ new modules for working with Vault's database secrets engine and some new ``vars`` entries for specifying public and private keys in ``cert`` auth. + +Minor Changes +------------- + +- cert auth - add option to set the ``cert_auth_public_key`` and ``cert_auth_private_key`` parameters using the variables ``ansible_hashi_vault_cert_auth_public_key`` and ``ansible_hashi_vault_cert_auth_private_key`` (https://github.com/ansible-collections/community.hashi_vault/issues/428). + +New Modules +----------- + +- vault_database_connection_configure - Configures the database engine +- vault_database_connection_delete - Delete a Database Connection +- vault_database_connection_read - Returns the configuration settings for a O(connection_name) +- vault_database_connection_reset - Closes a O(connection_name) and its underlying plugin and restarts it with the configuration stored +- vault_database_connections_list - Returns a list of available connections +- vault_database_role_create - Creates or updates a (dynamic) role definition +- vault_database_role_delete - Delete a role definition +- vault_database_role_read - Queries a dynamic role definition +- vault_database_roles_list - Returns a list of available (dynamic) roles +- vault_database_rotate_root_credentials - Rotates the root credentials stored for the database connection. This user must have permissions to update its own password. +- vault_database_static_role_create - Create or update a static role +- vault_database_static_role_get_credentials - Returns the current credentials based on the named static role +- vault_database_static_role_read - Queries a static role definition +- vault_database_static_role_rotate_credentials - Trigger the credential rotation for a static role +- vault_database_static_roles_list - Returns a list of available static roles + +v6.1.0 +====== + +Release Summary +--------------- + +This release addresses some breaking changes in core that were backported. + +Major Changes +------------- + +- requirements - the ``requests`` package which is required by ``hvac`` now has a more restrictive range for this collection in certain use cases due to breaking security changes in ``ansible-core`` that were backported (https://github.com/ansible-collections/community.hashi_vault/pull/416). + +v6.0.0 +====== + +Release Summary +--------------- + +This major version of the collection has no functional changes from the previous version, however the minimum versions of ``hvac`` and ``ansible-core`` have been raised. While the collection may still work with those earlier versions, future changes will not test against them. + +Breaking Changes / Porting Guide +-------------------------------- + +- The minimum required version of ``hvac`` is now ``1.2.1`` (https://docs.ansible.com/ansible/devel/collections/community/hashi_vault/docsite/user_guide.html#hvac-version-specifics). + +Removed Features (previously deprecated) +---------------------------------------- + +- The minimum supported version of ``ansible-core`` is now ``2.14``, support for ``2.13`` has been dropped (https://github.com/ansible-collections/community.hashi_vault/pull/403). + +v5.0.1 +====== + +Release Summary +--------------- + +This release fixes a bug in ``vault_write`` ahead of the collection's next major release. + +Bugfixes +-------- + +- vault_write - the ``vault_write`` lookup and module were not able to write data containing keys named ``path`` or ``wrap_ttl`` due to a bug in the ``hvac`` library. These plugins have now been updated to take advantage of fixes in ``hvac>=1.2`` to address this (https://github.com/ansible-collections/community.hashi_vault/issues/389). + +v5.0.0 +====== + +Release Summary +--------------- + +This version makes some relatively minor but technically breaking changes. Support for ``ansible-core`` versions ``2.11`` and ``2.12`` have been dropped, and there is now a minimum supported version of ``hvac`` which will be updated over time. A warning in the ``hashi_vault`` lookup on duplicate option specifications in the term string has been changed to a fatal error. + +Breaking Changes / Porting Guide +-------------------------------- + +- Support for ``ansible-core`` 2.11 and 2.12 has been removed (https://github.com/ansible-collections/community.hashi_vault/issues/340). +- The minimum version of ``hvac`` for ``community.hashi_vault`` is now ``1.1.0`` (https://github.com/ansible-collections/community.hashi_vault/issues/324). +- hashi_vault lookup - duplicate option entries in the term string now raises an exception instead of a warning (https://github.com/ansible-collections/community.hashi_vault/issues/356). v4.2.1 ====== @@ -601,4 +691,3 @@ Release Summary --------------- Our first release matches the ``hashi_vault`` lookup functionality provided by ``community.general`` version ``1.3.0``. - diff --git a/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst b/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst index a3f417800..badf7f8da 100644 --- a/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst +++ b/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst @@ -29,19 +29,18 @@ The content in ``community.hashi_vault`` requires the `hvac =2.28,<2.29``, setting certain options (``token``, ``namespace``) to values that come from lookups will raise an exception, do to Ansible's marking of the values as "unsafe" for templating. We recommend using ``requests>=2.29``, which won't work with Python 3.6. Retrying failed requests ======================== diff --git a/ansible_collections/community/hashi_vault/meta/ee-requirements.txt b/ansible_collections/community/hashi_vault/meta/ee-requirements.txt index 53393fd3e..457af229b 100644 --- a/ansible_collections/community/hashi_vault/meta/ee-requirements.txt +++ b/ansible_collections/community/hashi_vault/meta/ee-requirements.txt @@ -1,6 +1,6 @@ # ansible-builder doesn't seem to properly handle "; python_version" type of constraints # requirements here are assuming python 3.6 or higher -hvac >=0.10.6 +hvac >= 1.2.1 urllib3 >= 1.15 boto3 # these are only needed if inferring AWS credentials or diff --git a/ansible_collections/community/hashi_vault/meta/runtime.yml b/ansible_collections/community/hashi_vault/meta/runtime.yml index 02b09ecd2..9ed765c82 100644 --- a/ansible_collections/community/hashi_vault/meta/runtime.yml +++ b/ansible_collections/community/hashi_vault/meta/runtime.yml @@ -1,8 +1,22 @@ --- -requires_ansible: '>=2.11.0' +requires_ansible: '>=2.14.0' action_groups: # let's keep this in alphabetical order vault: + - vault_database_connection_configure + - vault_database_connection_delete + - vault_database_connection_read + - vault_database_connection_reset + - vault_database_connections_list + - vault_database_role_create + - vault_database_role_delete + - vault_database_roles_list + - vault_database_rotate_root_credentials + - vault_database_static_role_create + - vault_database_static_role_get_credentials + - vault_database_static_role_read + - vault_database_static_role_rotate_credentials + - vault_database_static_roles_list - vault_kv1_get - vault_kv2_delete - vault_kv2_get diff --git a/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py b/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py index 8c6bd8760..623029037 100644 --- a/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py +++ b/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py @@ -296,12 +296,18 @@ class ModuleDocFragment(object): cert_auth_public_key: env: - name: ANSIBLE_HASHI_VAULT_CERT_AUTH_PUBLIC_KEY + vars: + - name: ansible_hashi_vault_cert_auth_public_key + version_added: 6.2.0 ini: - section: hashi_vault_collection key: cert_auth_public_key cert_auth_private_key: env: - name: ANSIBLE_HASHI_VAULT_CERT_AUTH_PRIVATE_KEY + vars: + - name: ansible_hashi_vault_cert_auth_private_key + version_added: 6.2.0 ini: - section: hashi_vault_collection key: cert_auth_private_key diff --git a/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py b/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py index 1ea9b2c90..9fab815ba 100644 --- a/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py +++ b/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py @@ -305,13 +305,14 @@ class LookupModule(HashiVaultLookupBase): field = s_f[1] else: field = None - self.set_option('secret_field', field) + + self._secret_field = field def get(self): '''gets a secret. should always return a list''' + field = self._secret_field secret = self.get_option('secret') - field = self.get_option('secret_field') return_as = self.get_option('return_format') try: diff --git a/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py b/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py index 520288897..284f681d9 100644 --- a/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py +++ b/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py @@ -29,7 +29,7 @@ DOCUMENTATION = """ it may be more useful to set I(changed_when=false) if you are doing idempotency checks against the target system. - In check mode, this module will not create a token, and will instead return a basic structure with an empty token. However, this may not be useful if the token is required for follow on tasks. - It may be better to use this module with I(check_mode=no) in order to have a valid token that can be used. + It may be better to use this module with I(check_mode=false) in order to have a valid token that can be used. extends_documentation_fragment: - community.hashi_vault.connection - community.hashi_vault.connection.plugins diff --git a/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py b/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py index 6864c76fb..a8c056a73 100644 --- a/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py +++ b/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py @@ -43,7 +43,9 @@ DOCUMENTATION = """ type: str required: true data: - description: A dictionary to be serialized to JSON and then sent as the request body. + description: + - A dictionary to be serialized to JSON and then sent as the request body. + - If the dictionary contains keys named C(path) or C(wrap_ttl), the call will fail with C(hvac<1.2). type: dict required: false default: {} @@ -122,8 +124,8 @@ from ansible.utils.display import Display from ansible.module_utils.six import raise_from -from ansible_collections.community.hashi_vault.plugins.plugin_utils._hashi_vault_lookup_base import HashiVaultLookupBase -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultValueError +from ..plugin_utils._hashi_vault_lookup_base import HashiVaultLookupBase +from ..module_utils._hashi_vault_common import HashiVaultValueError display = Display() @@ -164,7 +166,16 @@ class LookupModule(HashiVaultLookupBase): for term in terms: try: - response = client.write(path=term, wrap_ttl=wrap_ttl, **data) + try: + # TODO: write_data will eventually turn back into write + # see: https://github.com/hvac/hvac/issues/1034 + response = client.write_data(path=term, wrap_ttl=wrap_ttl, data=data) + except AttributeError as e: + # https://github.com/ansible-collections/community.hashi_vault/issues/389 + if "path" in data or "wrap_ttl" in data: + raise_from(AnsibleError("To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1.2"), e) + else: + response = client.write(path=term, wrap_ttl=wrap_ttl, **data) except hvac.exceptions.Forbidden as e: raise_from(AnsibleError("Forbidden: Permission Denied to path '%s'." % term), e) except hvac.exceptions.InvalidPath as e: diff --git a/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py b/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py index 3b66b1937..2d95b67c3 100644 --- a/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py +++ b/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py @@ -81,7 +81,7 @@ class HashiVaultAuthMethodToken(HashiVaultAuthMethodBase): raise HashiVaultValueError("No Vault Token specified or discovered.") def authenticate(self, client, use_token=True, lookup_self=False): - token = self._stringify(self._options.get_option('token')) + token = self._options.get_option('token') validate = self._options.get_option_default('token_validate') response = None diff --git a/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py b/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py index f570479d0..726a9a4f8 100644 --- a/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py +++ b/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py @@ -100,11 +100,11 @@ class HashiVaultConnectionOptions(HashiVaultOptionGroupBase): # validate_certs is only used to optionally change the value of ca_cert def _filter(k, v): - return v is not None and k != 'validate_certs' + return v is not None and k not in ('validate_certs', 'ca_cert') # our transformed ca_cert value will become the verify parameter for the hvac client hvopts = self._options.get_filtered_options(_filter, *self.OPTIONS) - hvopts['verify'] = hvopts.pop('ca_cert') + hvopts['verify'] = self._conopt_verify retry_action = hvopts.pop('retry_action') if 'retries' in hvopts: @@ -255,6 +255,6 @@ class HashiVaultConnectionOptions(HashiVaultOptionGroupBase): validate_certs = True if not (validate_certs and ca_cert): - self._options.set_option('ca_cert', validate_certs) + self._conopt_verify = validate_certs else: - self._options.set_option('ca_cert', to_text(ca_cert, errors='surrogate_or_strict')) + self._conopt_verify = to_text(ca_cert, errors='surrogate_or_strict') diff --git a/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py b/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py index b39431c05..471022e1f 100644 --- a/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py +++ b/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py @@ -25,54 +25,18 @@ except ImportError: HAS_HVAC = False -def _stringify(input): - ''' - This method is primarily used to Un-Unsafe values that come from Ansible. - We want to remove the Unsafe context so that libraries don't get confused - by the values. - ''' - - # Since this is a module_util, and will be used by both plugins and modules, - # we cannot import the AnsibleUnsafe* types, because they are controller-only. - # However, they subclass the native types, so we can check for that. - - # bytes is the only consistent type to check against in both py2 and py3 - if isinstance(input, bytes): - # seems redundant, but this will give us a regular bytes object even - # when the input is AnsibleUnsafeBytes - return bytes(input) - else: - # instead of checking for py2 vs. py3 to cast to str or unicode, - # let's get the type from the literal. - return type(u'')(input) - - class HashiVaultValueError(ValueError): '''Use in common code to raise an Exception that can be turned into AnsibleError or used to fail_json()''' class HashiVaultHelper(): - - STRINGIFY_CANDIDATES = set([ - 'token', # Token will end up in a header, requests requires headers to be str or bytes, - # and newer versions of requests stopped converting automatically. Because our - # token could have been passed in from a previous lookup call, it could be one - # of the AnsibleUnsafe types instead, causing a failure. Tokens should always - # be strings, so we will convert them. - 'namespace', # namespace is also set in a header - ]) - def __init__(self): # TODO move hvac checking here? pass - @staticmethod - def _stringify(input): - return _stringify(input) - def get_vault_client( self, - hashi_vault_logout_inferred_token=True, hashi_vault_revoke_on_logout=False, hashi_vault_stringify_args=True, + hashi_vault_logout_inferred_token=True, hashi_vault_revoke_on_logout=False, **kwargs ): ''' @@ -84,16 +48,8 @@ class HashiVaultHelper(): :param hashi_vault_revoke_on_logout: if True revokes any current token on logout. Only used if a logout is performed. Not recommended. :type hashi_vault_revoke_on_logout: bool - - :param hashi_vault_stringify_args: if True converts a specific set of defined kwargs to a string type. - :type hashi_vault_stringify_args: bool ''' - if hashi_vault_stringify_args: - for key in kwargs.keys(): - if key in self.STRINGIFY_CANDIDATES: - kwargs[key] = self._stringify(kwargs[key]) - client = hvac.Client(**kwargs) # logout to prevent accidental use of inferred tokens @@ -296,7 +252,3 @@ class HashiVaultAuthMethodBase(HashiVaultOptionGroupBase): def deprecate(self, message, version=None, date=None, collection_name=None): self._deprecator(message, version=version, date=date, collection_name=collection_name) - - @staticmethod - def _stringify(input): - return _stringify(input) diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py new file mode 100644 index 000000000..035f2c4f5 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py @@ -0,0 +1,193 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_connection_configure +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Configures the database engine +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - Creates a L(new database connection for a database secrets engine,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#configuration), + identified by its O(engine_mount_point) in HashiCorp Vault. +notes: + - The database needs to be created and available to connect before you can configure the database secrets engine using the above configure method. + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the create / update will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + connection_name: + description: Name of the database connection. + type: str + required: True + plugin_name: + description: Plugin name used to connect to the database + type: str + required: True + allowed_roles: + description: Allowed roles + type: list + elements: str + required: True + connection_url: + description: Connection URL to the database + type: str + required: True + connection_username: + description: Username to connect to the database + type: str + required: True + connection_password: + description: Password to connect to the database + type: str + required: True +""" + +EXAMPLES = r""" +- name: Create a new Database Connection with the default mount point + community.hashi_vault.vault_database_connection_configure: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + connection_name: MyName + plugin_name: postgresql-database-plugin + connection_url: postgresql://{{'{{username}}'}}:{{'{{password}}'}}@postgres:5432/postgres?sslmode=disable + connection_username: SomeUser + connection_password: SomePass + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + + +- name: Create a new Database Connection with a custom mount point + community.hashi_vault.vault_database_connection_configure: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + connection_name: MyName + plugin_name: postgresql-database-plugin + connection_url: postgresql://{{'{{username}}'}}:{{'{{password}}'}}@postgres:5432/postgres?sslmode=disable + connection_username: SomeUser + connection_password: SomePass + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + plugin_name=dict(type="str", required=True), + allowed_roles=dict(type="list", required=True, elements="str"), + connection_name=dict(type="str", required=True), + connection_url=dict(type="str", required=True), + connection_username=dict(type="str", required=True), + connection_password=dict(type="str", required=True, no_log=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["plugin_name"] = module.params.get("plugin_name") + parameters["allowed_roles"] = module.params.get("allowed_roles") + parameters["connection_url"] = module.params.get("connection_url") + parameters["name"] = module.params.get("connection_name") + parameters["username"] = module.params.get("connection_username") + parameters["password"] = module.params.get("connection_password") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + client.secrets.database.configure(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/config/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidRequest as e: + module.fail_json( + msg="Error creating database connection ['%s/config/%s']. Please analyze the traceback for further details." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py new file mode 100644 index 000000000..4579d15f8 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py @@ -0,0 +1,146 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_connection_delete +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Delete a Database Connection +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - Deletes a L(Database Connection,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#delete-connection), + identified by its O(connection_name) from HashiCorp Vault. +notes: + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the deletion will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + connection_name: + description: The connection name to be deleted. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Delete a Database Connection with the default mount point + community.hashi_vault.vault_database_connection_delete: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + connection_name: SomeName + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Delete a Database Connection with a custom mount point + community.hashi_vault.vault_database_connection_delete: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + connection_name: SomeName + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + connection_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("connection_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + client.secrets.database.delete_connection(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/config/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py new file mode 100644 index 000000000..4d4fdb0f5 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py @@ -0,0 +1,162 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_connection_read +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Returns the configuration settings for a O(connection_name) +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Reads a Database Connection,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#read-configuration), + identified by its O(connection_name) from Hashcorp Vault. +notes: + - This module always reports C(changed) as False as it is a read operation that doesn't modify data. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.attributes.check_mode_read_only + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + connection_name: + description: The connection name to be read. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Read a Database Connection with the default mount point + community.hashi_vault.vault_database_connection_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + connection_name: SomeName + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Read a Database Connection with a custom mount point + community.hashi_vault.vault_database_connection_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r""" +data: &data + description: The C(data) field of the RV(raw) result. This can also be accessed via RV(raw.data). + returned: success + type: dict + sample: &data_sample + allowed_roles: [] + connection_details: + connection_url: "postgresql://{{username}}:{{password}}@postgres:5432/postgres?sslmode=disable" + username: "UserName" + password_policy": "" + plugin_name": "postgresql-database-plugin" + plugin_version": "" + root_credentials_rotate_statements": [] +raw: + description: The raw result of the operation + returned: success + type: dict + contains: + data: *data + sample: + auth: null, + data: *data_sample +""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + connection_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("connection_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.read_connection(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/config/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + + data = raw["data"] + module.exit_json(raw=raw, data=data, changed=False) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py new file mode 100644 index 000000000..858fdfc7f --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py @@ -0,0 +1,145 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_connection_reset +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Closes a O(connection_name) and its underlying plugin and restarts it with the configuration stored +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Resets a Database Connection,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#reset-connection). +notes: + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the reset will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + connection_name: + description: The connection name to be resetted. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Reset a Database Connection with the default mount point + community.hashi_vault.vault_database_connection_reset: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + connection_name: SomeName + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Reset a Database Connection with a custom mount point + community.hashi_vault.vault_database_connection_reset: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + connection_name: SomeName + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + connection_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("connection_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + client.secrets.database.reset_connection(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/reset/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py new file mode 100644 index 000000000..f570947d5 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py @@ -0,0 +1,176 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_connections_list +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Returns a list of available connections +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(List Database Connections,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#list-connections). +notes: + - This module always reports C(changed) as False as it is a read operation that doesn't modify data. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.attributes.check_mode_read_only + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +""" + +EXAMPLES = r""" +- name: List Database Connections with the default mount point + community.hashi_vault.vault_database_connections_list: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: List Database Connections with a custom mount point + community.hashi_vault.vault_database_connections_list: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r""" +data: + description: The C(data) field of raw result. This can also be accessed via RV(raw.data). + returned: success + type: dict + contains: &data_contains + keys: + description: The list of database connections. + returned: success + type: list + elements: str + sample: &sample_connections ["role1", "role2", "role3"] + sample: + keys: *sample_connections +connections: + description: The list of database connections or en empty list. This can also be accessed via RV(data.keys) or RV(raw.data.keys). + returned: success + type: list + elements: str + sample: *sample_connections +raw: + description: The raw result of the operation. + returned: success + type: dict + contains: + data: + description: The data field of the API response. + returned: success + type: dict + contains: *data_contains + sample: + auth: null + data: + keys: *sample_connections + lease_duration": 0 + lease_id: "" + renewable: false + request_id: "123456" + warnings: null + wrap_info: null +""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.list_connections(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/config']." + % (engine_mount_point or "database"), + exception=traceback.format_exc(), + ) + + data = raw.get("data", {"keys": []}) + connections = data["keys"] + module.exit_json( + raw=raw, + connections=connections, + data=data, + changed=False, + ) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py new file mode 100644 index 000000000..c005e27e7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py @@ -0,0 +1,207 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_role_create +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Creates or updates a (dynamic) role definition +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Creates or updates a dynamic role definition,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#create-static-role). +notes: + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the role creation will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + connection_name: + description: The connection name under which the role should be created. + type: str + required: True + role_name: + description: The name of the role that should be created. + type: str + required: True + creation_statements: + description: Specifies the database statements executed to create and configure a user. + type: list + required: True + elements: str + revocation_statements: + description: Specifies the database statements to be executed to revoke a user. + type: list + required: False + elements: str + rollback_statements: + description: Specifies the database statements to be executed to rollback a create operation in the event of an error. + type: list + required: False + elements: str + renew_statements: + description: Specifies the database statements to be executed to renew a user + type: list + required: False + elements: str + default_ttl: + description: Default TTL for the role. + type: int + required: False + default: 3600 + max_ttl: + description: Max TTL for the role. + type: int + required: False + default: 86400 +""" + +EXAMPLES = r""" +- name: Generate creation statement + ansible.builtin.set_fact: + creation_statements = [ + "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", + "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" + ] + +- name: Create / update Role with the default mount point + community.hashi_vault.vault_database_role_create: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + connection_name: SomeConnection + role_name: SomeRole + db_username: '{{ db_username}}' + creation_statements: '{{ creation_statements }}' + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Create / update Role with a custom mount point + community.hashi_vault.vault_database_role_create: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + connection_name: SomeConnection + role_name: SomeRole + db_username: '{{ db_username}}' + creation_statements: '{{ creation_statements }}' + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + connection_name=dict(type="str", required=True), + role_name=dict(type="str", required=True), + creation_statements=dict(type="list", required=True, elements="str"), + revocation_statements=dict(type="list", required=False, elements="str"), + rollback_statements=dict(type="list", required=False, elements="str"), + renew_statements=dict(type="list", required=False, elements="str"), + default_ttl=dict(type="int", required=False, default=3600), + max_ttl=dict(type="int", required=False, default=86400), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = { + "name": module.params.get("role_name"), + "db_name": module.params.get("connection_name"), + "creation_statements": module.params.get("creation_statements"), + "revocation_statements": module.params.get("revocation_statements"), + "rollback_statements": module.params.get("rollback_statements"), + "renew_statements": module.params.get("renew_statements"), + "default_ttl": module.params.get("default_ttl"), + "max_ttl": module.params.get("max_ttl"), + } + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + client.secrets.database.create_role(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/roles/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py new file mode 100644 index 000000000..7f20e3bba --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py @@ -0,0 +1,146 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_role_delete +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Delete a role definition +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Delete a role definition,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#delete-a-role). +notes: + - Applies to both static and dynamic roles. + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the deletion will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + role_name: + description: The name of the role to rotate credentials for. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Delete a Role with the default mount point + community.hashi_vault.vault_database_role_delete: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Delete a Role with a custom mount point + community.hashi_vault.vault_database_role_delete: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_path: db1 + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + role_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("role_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + client.secrets.database.delete_role(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/roles/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py new file mode 100644 index 000000000..68157dce1 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py @@ -0,0 +1,175 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_role_read +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Queries a dynamic role definition +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Queries a role definition,L(reads a static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#read-a-role), + identified by its O(role_name). +notes: + - This module always reports C(changed) as False as it is a read operation that doesn't modify data. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.attributes.check_mode_read_only + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + role_name: + description: The role name to be read from Hashicorp Vault. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Read Role with a default mount point + community.hashi_vault.vault_database_role_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Read Static Role with a custom moint point + community.hashi_vault.vault_database_role_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +""" + +RETURN = r""" +data: &data + description: The C(data) field of raw result. This can also be accessed via RV(raw.data). + returned: success + type: dict + sample: &data_sample + creation_statements: [ + "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", + "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" + ] + credential_type: "password" + db_name: "database" + default_ttl: 3600 + max_ttl: 86400 + renew_statements: [] + revocation_statements: [] + rollback_statements: [] +raw: + description: The raw result of the operation. + returned: success + type: dict + contains: + data: *data + sample: + auth: null + data: *data_sample + username: "SomeUser" + lease_duration": 0 + lease_id: "" + renewable: false + request_id: "123456" + warnings: null + wrap_info: null +""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + role_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("role_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.read_role(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/roles/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + + data = raw["data"] + + module.exit_json(data=data, raw=raw, changed=False) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py new file mode 100644 index 000000000..a0dc7e472 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py @@ -0,0 +1,173 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_roles_list +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Returns a list of available (dynamic) roles +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - Returns a list of available (dynamic) roles. +notes: + - This API returns a member named C(keys). + - In Ansible, accessing RV(data.keys) or RV(raw.data.keys) will not work because the dict object contains a method named C(keys). + - Instead, use RV(roles) to access the list of roles, or use the syntax C(data["keys"]) or C(raw.data["keys"]) to access the list via dict member. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.attributes.check_mode_read_only + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +""" + +EXAMPLES = r""" +- name: List all roles with the default mount point + community.hashi_vault.vault_database_roles_list: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: List all roles with a custom mount point + community.hashi_vault.vault_database_roles_list: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r""" +data: + description: The C(data) field of raw result. This can also be accessed via RV(raw.data). + returned: success + type: dict + contains: &data_contains + keys: + description: The list of dynamic role names. + returned: success + type: list + elements: str + sample: &sample_roles ["dyn_role1", "dyn_role2", "dyn_role3"] + sample: + keys: *sample_roles +roles: + description: The list of dynamic roles or en empty list. This can also be accessed via RV(data.keys) or RV(raw.data.keys). + returned: success + type: list + elements: str + sample: *sample_roles +raw: + description: The raw result of the operation. + returned: success + type: dict + contains: + data: + description: The data field of the API response. + returned: success + type: dict + contains: *data_contains + sample: + auth: null + data: + keys: *sample_roles + username: "SomeUser" + lease_duration": 0 + lease_id: "" + renewable: false + request_id: "123456" + warnings: null + wrap_info: null +""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.list_roles(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/roles']." + % (engine_mount_point or "database"), + exception=traceback.format_exc(), + ) + + data = raw.get("data", {"keys": []}) + roles = data["keys"] + + module.exit_json(data=data, roles=roles, raw=raw, changed=False) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py new file mode 100644 index 000000000..f5b58de1e --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py @@ -0,0 +1,150 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_rotate_root_credentials +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Rotates the root credentials stored for the database connection. This user must have permissions to update its own password. +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) >= 2.0.0 + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - Trigger L(root credential rotation,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#rotate-root-credentials) + of a Database Connection identified by its O(connection_name). +notes: + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the credential rotation will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + connection_name: + description: The connection name where the root credential rotation should be triggered. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Trigger root credentiaL rotation with the default mount point + community.hashi_vault.vault_database_rotate_root_credentials: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + connection_name: SomeName + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Trigger root credential rotation with the default mount point + community.hashi_vault.vault_database_rotate_root_credentials: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + connection_name: SomeName + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + connection_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("connection_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + client.secrets.database.rotate_root_credentials(**parameters) + except AttributeError as e: + module.fail_json( + msg="hvac>=2.0.0 is required", exception=traceback.format_exc() + ) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/rotate-root/%s']" + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py new file mode 100644 index 000000000..5dd57ccae --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py @@ -0,0 +1,188 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_static_role_create +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Create or update a static role +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Creates a new or updates an existing static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#create-static-role). +notes: + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the role creation will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + connection_name: + description: The connection name under which the role should be created. + type: str + required: True + role_name: + description: The name of the role that should be created. + type: str + required: True + db_username: + description: The database username - Note that the user must exist in the target database! + type: str + required: True + rotation_statements: + description: SQL statements to rotate the password for the given O(db_username) + type: list + required: True + elements: str + rotation_period: + description: Password rotation period in seconds (defaults to 24hs) + type: int + required: False + default: 86400 +""" + +EXAMPLES = r""" +- name: Generate rotation statement + ansible.builtin.set_fact: + rotation_statements = ["ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';"] + +- name: Create / update Static Role with the default mount point + community.hashi_vault.vault_database_static_role_create: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + connection_name: SomeConnection + role_name: SomeRole + db_username: '{{ db_username}}' + rotation_statements: '{{ rotation_statements }}' + register: response + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Create / update Static Role with a custom mount point + community.hashi_vault.vault_database_static_role_create: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + connection_name: SomeConnection + role_name: SomeRole + db_username: '{{ db_username}}' + rotation_statements: '{{ rotation_statements }}' + register: response + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + connection_name=dict(type="str", required=True), + role_name=dict(type="str", required=True), + db_username=dict(type="str", required=True), + rotation_statements=dict(type="list", required=True, elements="str"), + rotation_period=dict(type="int", required=False, default=86400), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["db_name"] = module.params.get("connection_name") + parameters["name"] = module.params.get("role_name") + parameters["username"] = module.params.get("db_username") + parameters["rotation_statements"] = module.params.get("rotation_statements") + rotation_period = module.params.get("rotation_period", None) + parameters["rotation_period"] = rotation_period + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + client.secrets.database.create_static_role(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/static-roles/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidRequest as e: + module.fail_json( + msg="Cannot update static role ['%s/static-roles/%s']. Please verify that the user exists on the database." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py new file mode 100644 index 000000000..a8a5cc9cc --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py @@ -0,0 +1,167 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_static_role_get_credentials +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Returns the current credentials based on the named static role +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - Returns the + L(current credentials based of the named static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#get-static-credentials), + identified by its O(role_name). +notes: + - This module always reports C(changed) as False as it is a read operation that doesn't modify data. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.attributes.check_mode_read_only + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + role_name: + description: The role name from which the credentials should be retrieved. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Returns the current credentials based on the named static role with the default mount point + community.hashi_vault.vault_database_static_role_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Returns the current credentials based on the named static role with a custom mount point + community.hashi_vault.vault_database_static_role_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r""" +data: &data + description: The C(data) field of raw result. This can also be accessed via RV(raw.data). + returned: success + type: dict + sample: &data_sample + last_vault_rotation": "2024-01-01T09:00:00+01:00" + password": "Th3_$3cr3t_P@ss!" + rotation_period": 86400 + ttl": 123456 + username: "SomeUser" +raw: + description: The raw result of the operation. + returned: success + type: dict + contains: + data: *data + sample: + auth: null, + data: *data_sample + lease_duration: 0 + lease_id: "" + renewable: false + request_id: "123456" + warnings: null, + wrap_info: null +""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + role_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("role_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.get_static_credentials(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point, + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/static-creds/%s']" + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + + data = raw["data"] + + module.exit_json(data=data, raw=raw, changed=False) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py new file mode 100644 index 000000000..f2ad972b6 --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py @@ -0,0 +1,171 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_static_role_read +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Queries a static role definition +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Queries a static role definition,L(reads a static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#read-static-role), + - identified by its O(role_name) +notes: + - This module always reports C(changed) as False as it is a read operation that doesn't modify data. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.attributes.check_mode_read_only + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + role_name: + description: The role name to be read from Hashicorp Vault. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Read Static Role with a default mount point + community.hashi_vault.vault_database_static_role_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Read Static Role with a custom moint point + community.hashi_vault.vault_database_static_role_read: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +""" + +RETURN = r""" +data: &data + description: The C(data) field of raw result. This can also be accessed via RV(raw.data). + returned: success + type: dict + sample: &data_sample + credential_type: "password" + db_name: "SomeConnection" + last_vault_rotation": "2024-01-01T09:00:00 +01:00" + rotation_period": 86400 + rotation_statements": [ + "ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';" + ] +raw: + description: The raw result of the operation. + returned: success + type: dict + contains: + data: *data + sample: + auth: null + data: *data_sample + username: "SomeUser" + lease_duration": 0 + lease_id: "" + renewable: false + request_id: "123456" + warnings: null + wrap_info: null +""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + role_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("role_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.read_static_role(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/static-roles/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + + data = raw["data"] + + module.exit_json(data=data, raw=raw, changed=False) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py new file mode 100644 index 000000000..660725b0b --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py @@ -0,0 +1,152 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_static_role_rotate_credentials +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Trigger the credential rotation for a static role +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) >= 2.0.0 + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - This endpoint is used to + - L(rotate the Static Role credentials,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#rotate-static-role-credentials) + - stored for a given role name. While Static Roles are rotated automatically by Vault at configured rotation periods, + - users can use this endpoint to manually trigger a rotation to change the stored password and reset the TTL of the Static Role's password. +notes: + - This module always reports C(changed) status because it cannot guarantee idempotence. + - Use C(changed_when) to control that in cases where the operation is known to not change state. +attributes: + check_mode: + support: partial + details: + - In check mode, a sample response will be returned, but the credential rotation will not be performed in Hashicorp Vault. +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +options: + role_name: + description: The name of the role to rotate credentials for. + type: str + required: True +""" + +EXAMPLES = r""" +- name: Rotate credentials of a static role with the default mount point + community.hashi_vault.vault_database_static_role_rotate_credentials: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" + +- name: Rotate credentials of a static role with a custom mount point + community.hashi_vault.vault_database_static_role_rotate_credentials: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + role_name: SomeRole + register: result + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ result }}" +""" + +RETURN = r"""""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + role_name=dict(type="str", required=True), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + if module.check_mode is True: + module.exit_json(changed=True) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + parameters["name"] = module.params.get("role_name") + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.rotate_static_role_credentials(**parameters) + except AttributeError as e: + module.fail_json( + msg="hvac>=2.0.0 is required", exception=traceback.format_exc() + ) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/rotate-role/%s']." + % (engine_mount_point or "database", parameters["name"]), + exception=traceback.format_exc(), + ) + else: + module.exit_json(changed=True) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py new file mode 100644 index 000000000..36a35337e --- /dev/null +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py @@ -0,0 +1,174 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2024, Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +module: vault_database_static_roles_list +version_added: 6.2.0 +author: + - Martin Chmielewski (@M4rt1nCh) +short_description: Returns a list of available static roles +requirements: + - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) + - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements). +description: + - L(Returns a list of available static roles,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#list-static-roles). +extends_documentation_fragment: + - community.hashi_vault.attributes + - community.hashi_vault.attributes.action_group + - community.hashi_vault.attributes.check_mode_read_only + - community.hashi_vault.connection + - community.hashi_vault.auth + - community.hashi_vault.engine_mount +notes: + - This API returns a member named C(keys). + - In Ansible, accessing RV(data.keys) or RV(raw.data.keys) will not work because the dict object contains a method named C(keys). + - Instead, use RV(roles) to access the list of roles, or use the syntax C(data["keys"]) or C(raw.data["keys"]) to access the list via dict member. +""" + +EXAMPLES = r""" +- name: List static roles with the default mount point + community.hashi_vault.vault_database_static_roles_list: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + register: response + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ response }}" + +- name: List static roles with a custom mount point + community.hashi_vault.vault_database_static_roles_list: + url: https://vault:8201 + auth_method: userpass + username: '{{ user }}' + password: '{{ passwd }}' + engine_mount_point: db1 + register: response + +- name: Display the result of the operation + ansible.builtin.debug: + msg: "{{ response }}" +""" + +RETURN = r""" +data: + description: The C(data) field of raw result. This can also be accessed via RV(raw.data). + returned: success + type: dict + contains: &data_contains + keys: + description: The list of role names. + returned: success + type: list + elements: str + sample: &sample_roles ["role1", "role2", "role3"] + sample: + keys: *sample_roles +roles: + description: The list of roles or en empty list. This can also be accessed via RV(data.keys) or RV(raw.data.keys). + returned: success + type: list + elements: str + sample: *sample_roles +raw: + description: The raw result of the operation. + returned: success + type: dict + contains: + data: + description: The data field of the API response. + returned: success + type: dict + contains: *data_contains + sample: + auth: null + data: + keys: *sample_roles + username: "SomeUser" + lease_duration": 0 + lease_id: "" + renewable: false + request_id: "123456" + warnings: null + wrap_info: null +""" + +import traceback + +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib + +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError + +try: + import hvac +except ImportError: + HAS_HVAC = False + HVAC_IMPORT_ERROR = traceback.format_exc() +else: + HVAC_IMPORT_ERROR = None + HAS_HVAC = True + + +def run_module(): + argspec = HashiVaultModule.generate_argspec( + engine_mount_point=dict(type="str", required=False), + ) + + module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True) + + if not HAS_HVAC: + module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR) + + parameters = {} + engine_mount_point = module.params.get("engine_mount_point", None) + if engine_mount_point is not None: + parameters["mount_point"] = engine_mount_point + + module.connection_options.process_connection_options() + client_args = module.connection_options.get_hvac_connection_options() + client = module.helper.get_vault_client(**client_args) + + try: + module.authenticator.validate() + module.authenticator.authenticate(client) + except (NotImplementedError, HashiVaultValueError) as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + try: + raw = client.secrets.database.list_static_roles(**parameters) + except hvac.exceptions.Forbidden as e: + module.fail_json( + msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point + or "database", + exception=traceback.format_exc(), + ) + except hvac.exceptions.InvalidPath as e: + module.fail_json( + msg="Invalid or missing path ['%s/static-roles']." + % (engine_mount_point or "database"), + exception=traceback.format_exc(), + ) + + data = raw.get("data", {"keys": []}) + roles = data["keys"] + + module.exit_json(data=data, roles=roles, raw=raw, changed=False) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py index 35c7fcb60..76cf4f8e9 100644 --- a/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py +++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py @@ -46,7 +46,9 @@ DOCUMENTATION = """ type: str required: True data: - description: A dictionary to be serialized to JSON and then sent as the request body. + description: + - A dictionary to be serialized to JSON and then sent as the request body. + - If the dictionary contains keys named C(path) or C(wrap_ttl), the call will fail with C(hvac<1.2). type: dict required: false default: {} @@ -108,8 +110,8 @@ import traceback from ansible.module_utils._text import to_native from ansible.module_utils.basic import missing_required_lib -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_module import HashiVaultModule -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultValueError +from ..module_utils._hashi_vault_module import HashiVaultModule +from ..module_utils._hashi_vault_common import HashiVaultValueError try: import hvac @@ -157,7 +159,16 @@ def run_module(): if module.check_mode: response = {} else: - response = client.write(path=path, wrap_ttl=wrap_ttl, **data) + try: + # TODO: write_data will eventually turn back into write + # see: https://github.com/hvac/hvac/issues/1034 + response = client.write_data(path=path, wrap_ttl=wrap_ttl, data=data) + except AttributeError: + # https://github.com/ansible-collections/community.hashi_vault/issues/389 + if "path" in data or "wrap_ttl" in data: + module.fail_json("To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1.2") + else: + response = client.write(path=path, wrap_ttl=wrap_ttl, **data) except hvac.exceptions.Forbidden: module.fail_json(msg="Forbidden: Permission Denied to path '%s'." % path, exception=traceback.format_exc()) except hvac.exceptions.InvalidPath: diff --git a/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py b/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py index 7a878cbb4..acc7a1b08 100644 --- a/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py +++ b/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py @@ -12,7 +12,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -from ansible.errors import AnsibleError +from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.plugins.lookup import LookupBase from ansible.utils.display import Display @@ -43,11 +43,8 @@ class HashiVaultLookupBase(HashiVaultPlugin, LookupBase): raise AnsibleError("%s lookup plugin needs key=value pairs, but received %s" % (plugin_name, term)) if key in param_dict: - removed_in = '5.0.0' msg = "Duplicate key '%s' in the term string '%s'." % (key, term) - display.deprecated(msg + "\nIn version %s of the collection, this will raise an exception." % (removed_in, ), removed_in) - # TODO: v5.0.0: remove deprecation message, uncomment: https://github.com/ansible-collections/community.hashi_vault/pull/350 - # raise AnsibleOptionsError(msg) + raise AnsibleOptionsError(msg) param_dict[key] = value diff --git a/ansible_collections/community/hashi_vault/tests/integration/constraints.txt b/ansible_collections/community/hashi_vault/tests/integration/constraints.txt new file mode 100644 index 000000000..f347921c3 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/constraints.txt @@ -0,0 +1,64 @@ +coverage >= 4.2, < 5.0.0, != 4.3.2 ; python_version <= '3.7' # features in 4.2+ required, avoid known bug in 4.3.2 on python 2.6, coverage 5.0+ incompatible +coverage >= 4.5.4, < 5.0.0 ; python_version > '3.7' # coverage had a bug in < 4.5.4 that would cause unit tests to hang in Python 3.8, coverage 5.0+ incompatible +cryptography < 2.2 ; python_version < '2.7' # cryptography 2.2 drops support for python 2.6 +deepdiff < 4.0.0 ; python_version < '3' # deepdiff 4.0.0 and later require python 3 +jinja2 < 2.11 ; python_version < '2.7' # jinja2 2.11 and later require python 2.7 or later +urllib3 < 1.24 ; python_version < '2.7' # urllib3 1.24 and later require python 2.7 or later +pywinrm >= 0.3.0 # message encryption support +sphinx < 1.6 ; python_version < '2.7' # sphinx 1.6 and later require python 2.7 or later +sphinx < 1.8 ; python_version >= '2.7' # sphinx 1.8 and later are currently incompatible with rstcheck 3.3 +pygments >= 2.4.0 # Pygments 2.4.0 includes bugfixes for YAML and YAML+Jinja lexers +wheel < 0.30.0 ; python_version < '2.7' # wheel 0.30.0 and later require python 2.7 or later +yamllint != 1.8.0, < 1.14.0 ; python_version < '2.7' # yamllint 1.8.0 and 1.14.0+ require python 2.7+ +pycrypto >= 2.6 # Need features found in 2.6 and greater +ncclient >= 0.5.2 # Need features added in 0.5.2 and greater +idna < 2.6, >= 2.5 # linode requires idna < 2.9, >= 2.5, requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead +paramiko < 2.4.0 ; python_version < '2.7' # paramiko 2.4.0 drops support for python 2.6 +pytest < 3.3.0 ; python_version < '2.7' # pytest 3.3.0 drops support for python 2.6 +pytest < 5.0.0 ; python_version == '2.7' # pytest 5.0.0 and later will no longer support python 2.7 +pytest-forked < 1.0.2 ; python_version < '2.7' # pytest-forked 1.0.2 and later require python 2.7 or later +pytest-forked >= 1.0.2 ; python_version >= '2.7' # pytest-forked before 1.0.2 does not work with pytest 4.2.0+ (which requires python 2.7+) +ntlm-auth >= 1.3.0 # message encryption support using cryptography +requests < 2.20.0 ; python_version < '2.7' # requests 2.20.0 drops support for python 2.6 +requests-ntlm >= 1.1.0 # message encryption support +requests-credssp >= 0.1.0 # message encryption support +voluptuous >= 0.11.0 # Schema recursion via Self +openshift >= 0.6.2, < 0.9.0 # merge_type support +virtualenv < 16.0.0 ; python_version < '2.7' # virtualenv 16.0.0 and later require python 2.7 or later +pathspec < 0.6.0 ; python_version < '2.7' # pathspec 0.6.0 and later require python 2.7 or later +pyopenssl < 18.0.0 ; python_version < '2.7' # pyOpenSSL 18.0.0 and later require python 2.7 or later +pyfmg == 0.6.1 # newer versions do not pass current unit tests +pyyaml < 5.1 ; python_version < '2.7' # pyyaml 5.1 and later require python 2.7 or later +pycparser < 2.19 ; python_version < '2.7' # pycparser 2.19 and later require python 2.7 or later +mock >= 2.0.0 # needed for features backported from Python 3.6 unittest.mock (assert_called, assert_called_once...) +pytest-mock >= 1.4.0 # needed for mock_use_standalone_module pytest option +xmltodict < 0.12.0 ; python_version < '2.7' # xmltodict 0.12.0 and later require python 2.7 or later +lxml < 4.3.0 ; python_version < '2.7' # lxml 4.3.0 and later require python 2.7 or later +pyvmomi < 6.0.0 ; python_version < '2.7' # pyvmomi 6.0.0 and later require python 2.7 or later +pyone == 1.1.9 # newer versions do not pass current integration tests +boto3 < 1.11 ; python_version < '2.7' # boto3 1.11 drops Python 2.6 support +botocore >= 1.10.0, < 1.14 ; python_version < '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca; botocore 1.14 drops Python 2.6 support +botocore >= 1.10.0 ; python_version >= '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca +setuptools < 45 ; python_version <= '2.7' # setuptools 45 and later require python 3.5 or later +cffi >= 1.14.2, != 1.14.3 # Yanked version which older versions of pip will still install: + +# freeze pylint and its requirements for consistent test results +astroid == 2.2.5 +isort == 4.3.15 +lazy-object-proxy == 1.3.1 +mccabe == 0.6.1 +pylint == 2.3.1 +typed-ast == 1.4.0 # 1.4.0 is required to compile on Python 3.8 +wrapt == 1.11.1 + +# hvac +hvac >= 1.2.1 ; python_version >= '3.6' + +# urllib3 +# these should be satisfied naturally by the requests versions required by hvac anyway +urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06 + +# requests +# https://github.com/psf/requests/pull/6356 +requests >= 2.29 ; python_version >= '3.7' +requests < 2.28 ; python_version < '3.7' diff --git a/ansible_collections/community/hashi_vault/tests/integration/requirements.txt b/ansible_collections/community/hashi_vault/tests/integration/requirements.txt index 033733f7c..c3a5354f0 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/requirements.txt +++ b/ansible_collections/community/hashi_vault/tests/integration/requirements.txt @@ -1,16 +1,4 @@ -# the collection supports python 3.6 and higher, however the constraints for -# earlier python versions are still needed for Ansible < 2.12 which doesn't -# support tests/config.yml, so that unit tests (which will be skipped) won't -# choke on installing requirements. - -hvac >= 0.10.6, != 0.10.12, != 0.10.13, < 1.0.0 ; python_version == '2.7' # bugs in 0.10.12 and 0.10.13 prevent it from working in Python 2 -hvac >= 0.10.6, < 1.0.0 ; python_version == '3.5' # py3.5 support will be dropped in 1.0.0 -hvac >= 0.10.6 ; python_version >= '3.6' - -# these should be satisfied naturally by the requests versions required by hvac anyway -urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06 -urllib3 >= 1.15, <2.0.0 ; python_version < '3.6' # https://urllib3.readthedocs.io/en/latest/v2-roadmap.html#optimized-for-python-3-6 - -# azure-identity 1.7.0 depends on cryptography 2.5 which drops python 2.6 support -azure-identity < 1.7.0; python_version < '2.7' -azure-identity; python_version >= '2.7' +hvac +urllib3 +azure-identity +psycopg[binary,pool] diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml index 8cf331b1d..48b5117f7 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml @@ -52,4 +52,4 @@ fail_msg: "An invalid secret ID somehow did not cause a failure." that: - (response is failed) == use_secret_id - - not use_secret_id or response.msg is search('invalid secret id') + - not use_secret_id or response.msg is search('(?i)invalid (?:role or )?secret id') diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml index 1f5796957..387195af9 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml @@ -40,10 +40,10 @@ register: response vault_test_auth: secret_id: fake - want_exception: yes + want_exception: true - assert: fail_msg: "An invalid secret ID somehow did not cause a failure." that: - (response.inner is failed) == use_secret_id - - not use_secret_id or response.msg is search('invalid secret id') + - not use_secret_id or response.msg is search('(?i)invalid (?:role or )?secret id') diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml index 79dfd38d7..5d31a32c3 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml @@ -49,4 +49,4 @@ use_secret_id: '{{ item[0][1] == secret_id_role }}' module_defaults: assert: - quiet: yes + quiet: true diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml index 0f4267f13..1e905afc9 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml @@ -29,7 +29,7 @@ register: response vault_test_auth: role_id: fail-me-role - want_exception: yes + want_exception: true - assert: fail_msg: "An invalid request somehow did not cause a failure." diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml index 50c57e5c6..b7598105c 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml @@ -20,4 +20,4 @@ this_path: '{{ item[0] }}' module_defaults: assert: - quiet: yes + quiet: true diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml index 0c637c706..3c2ff255a 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml @@ -32,7 +32,7 @@ register: response vault_test_auth: role_id: fail-me-role - want_exception: yes + want_exception: true - assert: fail_msg: "An invalid request somehow did not cause a failure." @@ -43,7 +43,7 @@ - name: Failure expected when role_id is not given register: response vault_test_auth: - want_exception: yes + want_exception: true - assert: fail_msg: | diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml index 95bde76e5..860f9bb18 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml @@ -23,4 +23,4 @@ this_path: '{{ item[0] }}' module_defaults: assert: - quiet: yes + quiet: true diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml index 897a2e1d3..e92b6c73a 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml @@ -30,7 +30,7 @@ vault_test_auth: cert_auth_public_key: "{{ invalid_auth_cert_cert }}" cert_auth_private_key: "{{ invalid_auth_cert_key }}" - want_exception: yes + want_exception: true register: response - assert: diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml index 7ac78b17f..fff6cf07d 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml @@ -48,7 +48,7 @@ this_path: '{{ item }}' module_defaults: assert: - quiet: yes + quiet: true - name: Run cert tests (target) loop: '{{ auth_paths }}' diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml index 25110f8fe..456cd2adc 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml @@ -30,7 +30,7 @@ register: response vault_test_auth: jwt: '{{ jwt_invalid }}' - want_exception: yes + want_exception: true - assert: fail_msg: "An invalid JWT somehow did not cause a failure." diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml index 1bef30955..1eb0d1ed2 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml @@ -47,7 +47,7 @@ this_path: '{{ item }}' module_defaults: assert: - quiet: yes + quiet: true - name: Run JWT tests (target) loop: '{{ auth_paths }}' diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml index 663f9065e..372dd7ea6 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml @@ -28,7 +28,7 @@ register: response vault_test_auth: username: fail-me-username - want_exception: yes + want_exception: true - assert: fail_msg: "An invalid request somehow did not cause a failure." diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml index 1e561648e..01dbb225c 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml @@ -20,4 +20,4 @@ this_path: '{{ item[0] }}' module_defaults: assert: - quiet: yes + quiet: true diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml index 768b8ac8c..b2949bb06 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml @@ -26,9 +26,9 @@ - import_tasks: token_test_target.yml module_defaults: assert: - quiet: yes + quiet: true - import_tasks: token_test_controller.yml module_defaults: assert: - quiet: yes + quiet: true diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml index 137c747ce..258d8d798 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml @@ -56,7 +56,7 @@ token: '{{ response.login.auth.client_token }}' path: '{{ secret }}' register: secret_data - ignore_errors: yes + ignore_errors: true - assert: that: diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml index cbfa30f70..235d2a7b3 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml @@ -54,7 +54,7 @@ token: '{{ response.login.auth.client_token }}' path: '{{ secret }}' register: secret_data - ignore_errors: yes + ignore_errors: true - assert: that: diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml index 39d6373f4..055c55e1d 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml @@ -47,4 +47,4 @@ this_path: '{{ item[0] }}' module_defaults: assert: - quiet: yes + quiet: true diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml index a502ba573..1d23e79a2 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml @@ -28,7 +28,7 @@ register: response vault_test_auth: password: fake - want_exception: yes + want_exception: true - assert: fail_msg: "An invalid password somehow did not cause a failure." diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml index f9c44fefe..cbd0150b5 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml @@ -2,7 +2,7 @@ - name: Connection Tests module_defaults: assert: - quiet: yes + quiet: true vars: # we don't set kwargs: {} here because of https://github.com/ansible/ansible/issues/75286 test_cmd: &test @@ -37,14 +37,14 @@ - name: test HTTP with wrong proxy <<: *test vars: - vault_test_connection_want_exception: yes + vault_test_connection_want_exception: true ansible_hashi_vault_proxies: http://127.0.0.1:4567 ansible_hashi_vault_retries: 2 - assert: that: - result is failed - - result.msg is search('Cannot connect to proxy') + - result.msg is search('(?:Cannot|Unable to) connect to proxy') - result.retries == 2 - name: HTTPS connection @@ -67,8 +67,8 @@ - name: test HTTPS with cert validation <<: *test vars: - vault_test_connection_want_args: yes - vault_test_connection_want_exception: yes + vault_test_connection_want_args: true + vault_test_connection_want_exception: true - <<: *assert @@ -85,13 +85,13 @@ - name: test HTTPS with wrong proxy & cert validation <<: *test vars: - vault_test_connection_want_exception: yes - ansible_hashi_vault_validate_certs: yes + vault_test_connection_want_exception: true + ansible_hashi_vault_validate_certs: true ansible_hashi_vault_proxies: http://127.0.0.1:4567 ansible_hashi_vault_retries: 2 - assert: that: - result is failed - - result.msg is search('Cannot connect to proxy') + - result.msg is search('(?:Cannot|Unable to) connect to proxy') - result.retries == 2 diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml index 7fb854b8d..45f9403da 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml @@ -2,7 +2,7 @@ - name: Connection Tests module_defaults: assert: - quiet: yes + quiet: true vars: assert_cmd: &assert assert: @@ -30,14 +30,14 @@ - name: test HTTP with wrong proxy register: result vault_test_connection: - want_exception: yes + want_exception: true proxies: http://127.0.0.1:4567 retries: 2 - assert: that: - result.inner is failed - - result.msg is search('Cannot connect to proxy') + - result.msg is search('(?:Cannot|Unable to) connect to proxy') - result.retries == 2 - name: HTTPS connection @@ -57,7 +57,7 @@ - name: test HTTPS with cert validation register: result vault_test_connection: - want_args: yes + want_args: true - <<: *assert @@ -72,13 +72,13 @@ - name: test HTTPS with wrong proxy & cert validation register: result vault_test_connection: - want_exception: yes - validate_certs: yes + want_exception: true + validate_certs: true proxies: http://127.0.0.1:4567 retries: 2 - assert: that: - result.inner is failed - - result.msg is search('Cannot connect to proxy') + - result.msg is search('(?:Cannot|Unable to) connect to proxy') - result.retries == 2 diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml index 21306ee9f..f9cf9674c 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml @@ -92,21 +92,20 @@ - test_inexistent.msg is search("doesn't seem to exist") fail_msg: "Expected failure but got success or wrong failure message." - # TODO: v5.0.0 - uncomment below: https://github.com/ansible-collections/community.hashi_vault/pull/350 - # - name: Failure expected when duplicate terms are used in the term string - # vars: - # duplicate_terms: >- - # {{ - # lookup('community.hashi_vault.hashi_vault', - # vault_kv2_api_path ~ '/secrets secret=' ~ vault_kv2_api_path ~ '/secret2', - # **kwargs) - # }} - # ansible.builtin.debug: - # msg: 'Failure is expected ({{ duplicate_terms }})' - # register: test_duplicate - # ignore_errors: true + - name: Failure expected when duplicate terms are used in the term string + vars: + duplicate_terms: >- + {{ + lookup('community.hashi_vault.hashi_vault', + vault_kv2_api_path ~ '/secrets secret=' ~ vault_kv2_api_path ~ '/secret2', + **kwargs) + }} + ansible.builtin.debug: + msg: 'Failure is expected ({{ duplicate_terms }})' + register: test_duplicate + ignore_errors: true - # - assert: - # that: - # - test_duplicate is failed - # - test_duplicate.msg is search("^Duplicate key 'secret' in term string") + - assert: + that: + - test_duplicate is failed + - test_duplicate.msg is search("Duplicate key 'secret' in the term string") diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml index 33dc245f9..e43c04708 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml @@ -11,6 +11,9 @@ test_data: a: 1 b: two + # https://github.com/ansible-collections/community.hashi_vault/issues/389 + path: path_value + wrap_ttl: wrap_ttl_value block: - name: Write data to the cubbyhole vars: diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml new file mode 100644 index 000000000..2c929267f --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_connection_configure_setup.yml +- import_tasks: module_vault_database_connection_configure_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml new file mode 100644 index 000000000..f43f5d09e --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml new file mode 100644 index 000000000..903425cdb --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml @@ -0,0 +1,192 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_connection_configure: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + block: + - name: Test database connection configure [check mode] + register: db_connection_configure + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + engine_mount_point: DOES NOT MATTER + connection_name: DOES NOT MATTER + plugin_name: DOES NOT MATTER + allowed_roles: DOES NOT MATTER + connection_url: DOES NOT MATTER + connection_username: DOES NOT MATTER + connection_password: DOES NOT MATTER + + - name: Check [check mode] + ansible.builtin.assert: &success + that: + - db_connection_configure is changed + + - name: Test database connection configure (explicit mount - invalid, plugin_name, connection_url, connection_user, connection_password) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + engine_mount_point: NOT REAL + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable" + connection_username: con1 + connection_password: con1 + + - name: Check (explicit mount - invalid, plugin_name, connection_url, connection_user, connection_password) + ansible.builtin.assert: &failure_invalid_mount + that: + - db_connection_configure is failed + - db_connection_configure.msg is search('Permission Denied') + + - name: Test database connection configure (explicit mount, plugin_name - invalid, connection_url, connection_user, connection_password) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + engine_mount_point: database + connection_name: con1-postgres + plugin_name: NOT REAL + allowed_roles: "*" + connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable" + connection_username: con1 + connection_password: con1 + + - name: Check (explicit mount, plugin_name - invalid, connection_url, connection_user, connection_password) + ansible.builtin.assert: &failure_invalid_request + that: + - db_connection_configure is failed + - db_connection_configure.msg is search('Error creating database connection') + + - name: Test database connection configure (explicit mount, plugin_name, connection_url - invalid, connection_user, connection_password) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + engine_mount_point: database + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@NOT_REAL:5432/hcvault?sslmode=disable + connection_username: con1 + connection_password: con1 + + - name: Check (explicit mount, plugin_name, connection_url - invalid, connection_user, connection_password) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database connection configure (explicit mount, plugin_name, connection_url, connection_user - invalid, connection_password) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + engine_mount_point: database + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable + connection_username: NOT REAL + connection_password: con1 + + - name: Check (explicit mount, plugin_name, connection_url, connection_user - invalid, connection_password) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database connection configure (explicit mount, plugin_name, connection_url, connection_user, connection_password - invalid) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + engine_mount_point: database + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable + connection_username: con1 + connection_password: NOT REAL + + - name: Check (explicit mount, plugin_name, connection_url, connection_user, connection_password) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database connection configure (explicit mount, plugin_name, connection_url, connection_user, connection_password - invalid) + register: db_connection_configure + community.hashi_vault.vault_database_connection_configure: + engine_mount_point: database + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable + connection_username: con1 + connection_password: con1 + + - name: Check (explicit mount, plugin_name, connection_url, connection_user, connection_password) + ansible.builtin.assert: *success + + - name: Test database connection configure (default mount, plugin_name - invalid, connection_url, connection_user, connection_password) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + connection_name: con1-postgres + plugin_name: NOT REAL + allowed_roles: "*" + connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable" + connection_username: con1 + connection_password: con1 + + - name: Check (default mount, plugin_name - invalid, connection_url, connection_user, connection_password) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database connection configure (default mount, plugin_name, connection_url - invalid, connection_user, connection_password) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@NOT_REAL:5432/hcvault?sslmode=disable + connection_username: con1 + connection_password: con1 + + - name: Check (default mount, plugin_name, connection_url - invalid, connection_user, connection_password) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database connection configure (default mount, plugin_name, connection_url, connection_user - invalid, connection_password) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable + connection_username: NOT REAL + connection_password: con1 + + - name: Check (default mount, plugin_name, connection_url, connection_user - invalid, connection_password) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database connection configure (default mount, plugin_name, connection_url, connection_user, connection_password - invalid) + register: db_connection_configure + ignore_errors: true + community.hashi_vault.vault_database_connection_configure: + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable + connection_username: con1 + connection_password: NOT REAL + + - name: Check (default mount, plugin_name, connection_url, connection_user, connection_password - invalid) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database connection configure (default mount, plugin_name, connection_url, connection_user, connection_password - invalid) + register: db_connection_configure + community.hashi_vault.vault_database_connection_configure: + connection_name: con1-postgres + plugin_name: postgresql-database-plugin + allowed_roles: "*" + connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable + connection_username: con1 + connection_password: con1 + + - name: Check (default mount, plugin_name, connection_url, connection_user, connection_password) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml new file mode 100644 index 000000000..210fb0ba9 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_connection_delete_setup.yml +- import_tasks: module_vault_database_connection_delete_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml new file mode 100644 index 000000000..ca5219b07 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml @@ -0,0 +1,36 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}" + vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}" + vault_ci_read: "{{ vault_plugins_module_defaults_common }}" + vault_ci_write: "{{ vault_plugins_module_defaults_common }}" + vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}" + vars: + connection_names: ["test-connection-delete-1", "test-connection-delete-2"] + usernames: ["con2", "con2"] + passwords: ["con2", "con2"] + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd + + - name: Define database connection data + ansible.builtin.set_fact: + db_sample_data: "{{ db_sample_data | default([]) + [ {'connection_name': item.0, 'username': item.1, 'password': item.2 } ] }}" + with_together: + - "{{ connection_names }}" + - "{{ usernames }}" + - "{{ passwords }}" + + - name: Create database connections that can be deleted in the following test + vault_ci_write: + path: "database/config/{{ item.connection_name }}" + data: + plugin_name: "{{ vault_database_plugin_name }}" + connection_url: "{{ vault_database_connection_url }}" + allowed_roles: "*" + username: "{{ item.username }}" + password: "{{ item.password }}" + loop: "{{ db_sample_data }}" diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml new file mode 100644 index 000000000..7d51d6e8f --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml @@ -0,0 +1,84 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_connection_delete: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test database connection delete (explicit mount, connection_name) [check mode] + register: db_connection_delete + check_mode: true + community.hashi_vault.vault_database_connection_delete: + engine_mount_point: database + connection_name: test-delete-connection-1 + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: &success + that: + - db_connection_delete is changed + + - name: Test database connection delete (explicit mount - invalid, connection_name) + register: db_connection_delete + ignore_errors: true + community.hashi_vault.vault_database_connection_delete: + engine_mount_point: NOT REAL + connection_name: test-connection-delete-1 + + - name: Check (explicit mount - invalid) + ansible.builtin.assert: &failure_bad_mount + that: + - db_connection_delete is failed + - db_connection_delete.msg is search('Permission Denied') + + - name: Test database connection delete (explicit mount, connection_name - invalid) + register: db_connection_delete + ignore_errors: true + community.hashi_vault.vault_database_connection_delete: + engine_mount_point: database + connection_name: NOT REAL + + - name: Check (explicit mount, connection_name - invalid) + ansible.builtin.assert: &failure_invalid_path + that: + - db_connection_delete is failed + - db_connection_delete.msg is search('Invalid or missing path') + + - name: Test database connection delete (explicit mount) + register: db_connection_delete + community.hashi_vault.vault_database_connection_delete: + engine_mount_point: database + connection_name: test-connection-delete-1 + + - name: Check (explicit mount) + ansible.builtin.assert: *success + + - name: Test database connection delete (default mount, connection_name) [check mode] + register: db_connection_delete + check_mode: true + community.hashi_vault.vault_database_connection_delete: + connection_name: test-connection-delete-2 + + - name: Check (explicit mount, connection_name) [check mode] + ansible.builtin.assert: *success + + - name: Test database connection delete (default mount, connection_name - invalid) + register: db_connection_delete + ignore_errors: true + community.hashi_vault.vault_database_connection_delete: + connection_name: NOT REAL + + - name: Check (default mount, connection_name - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test database connection delete (default mount) + register: db_connection_delete + community.hashi_vault.vault_database_connection_delete: + connection_name: test-connection-delete-2 + + - name: Check (default mount) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml new file mode 100644 index 000000000..dd4afd076 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_connection_read_setup.yml +- import_tasks: module_vault_database_connection_read_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml new file mode 100644 index 000000000..cd1b09dc7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [base-policy-database] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml new file mode 100644 index 000000000..329f6b94d --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml @@ -0,0 +1,134 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_connection_read: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test read database connection (explicit mount - invalid, connection_name) [check mode] + register: db_connection + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_connection_read: + engine_mount_point: NOT REAL + connection_name: my-postgresql-database + + - name: Check (explicit mount - invalid, connection_name) [check mode] + ansible.builtin.assert: &failure_bad_mount + that: + - db_connection is failed + - db_connection.msg is search('Permission Denied') + + - name: Test read database connection (explicit mount, connection_name - invalid) [check mode] + register: db_connection + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_connection_read: + engine_mount_point: database + connection_name: NOT_REAL + + - name: Check (explicit mount, connection_name - invalid) [check mode] + ansible.builtin.assert: &failure_invalid_path + that: + - db_connection is failed + - db_connection.msg is search('Invalid or missing path') + + - name: Test read database connection (explicit mount, connection_name) [check mode] + register: db_connection + check_mode: true + community.hashi_vault.vault_database_connection_read: + engine_mount_point: database + connection_name: my-postgresql-database + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: &success + that: + - db_connection is defined + - "'data' in db_connection" + - "'raw' in db_connection" + - db_connection["data"]["plugin_name"] == 'postgresql-database-plugin' + - db_connection["data"]["connection_details"]["username"] == 'postgres' + - "'allowed_roles' in db_connection['data']" + - "'password_policy' in db_connection['data']" + - "'root_credentials_rotate_statements' in db_connection['data']" + + - name: Test read database connection (explicit mount, connection_name invalid) [check mode] + register: db_connection + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_connection_read: + engine_mount_point: database + connection_name: NOT REAL + + - name: Check (explicit mount, connection_name invalid) [check mode] + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database connection (explicit mount, connection_name) + register: db_connection + community.hashi_vault.vault_database_connection_read: + engine_mount_point: database + connection_name: my-postgresql-database + + - name: Check (explicit mount, connection_name) + ansible.builtin.assert: *success + + - name: Test read database connection (explicit mount - invalid, connection_name) + register: db_connection + ignore_errors: true + community.hashi_vault.vault_database_connection_read: + engine_mount_point: NOT REAL + connection_name: my-postgresql-database + + - name: Check (explicit mount - invalid, connection_name) + ansible.builtin.assert: *failure_bad_mount + + - name: Test read database connection (explicit mount, connection_name - invalid) + register: db_connection + ignore_errors: true + community.hashi_vault.vault_database_connection_read: + engine_mount_point: database + connection_name: NOT REAL + + - name: Check (explicit mount, connection_name - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database connection (default mount) [check mode] + register: db_connection + check_mode: true + community.hashi_vault.vault_database_connection_read: + connection_name: my-postgresql-database + + - name: Check (default mount) [check mode] + ansible.builtin.assert: *success + + - name: Test read database connection (default mount, connection_name - invalid) [check mode] + register: db_connection + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_connection_read: + connection_name: NOT REAL + + - name: Check (default mount, connection_name - invalid) [check mode] + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database connection (default mount, connection_name) + register: db_connection + community.hashi_vault.vault_database_connection_read: + connection_name: my-postgresql-database + + - name: Check (76default mount, connection_name) + ansible.builtin.assert: *success + + - name: Test read database connection (default mount, connection_name - invalid) + register: db_connection + ignore_errors: true + community.hashi_vault.vault_database_connection_read: + connection_name: NOT REAL + + - name: Check (default mount, connection_name - invalid) + ansible.builtin.assert: *failure_invalid_path diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml new file mode 100644 index 000000000..4e52e7602 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_connection_reset_setup.yml +- import_tasks: module_vault_database_connection_reset_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml new file mode 100644 index 000000000..f43f5d09e --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml new file mode 100644 index 000000000..ce05750bc --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml @@ -0,0 +1,84 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_connection_reset: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test database connection reset (explicit mount) [check mode] + register: db_connection_reset + check_mode: true + community.hashi_vault.vault_database_connection_reset: + engine_mount_point: database + connection_name: "{{ vault_database_connection_name }}" + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: &success + that: + - db_connection_reset is changed + + - name: Test database connection reset (explicit mount - invalid, connection_name) + register: db_connection_reset + ignore_errors: true + community.hashi_vault.vault_database_connection_reset: + engine_mount_point: NOT REAL + connection_name: "{{ vault_database_connection_name }}" + + - name: Check (explicit mount - invalid) + ansible.builtin.assert: &failure_bad_mount + that: + - db_connection_reset is failed + - db_connection_reset.msg is search('Permission Denied') + + - name: Test database connection reset (explicit mount, connection_name - invalid) + register: db_connection_reset + ignore_errors: true + community.hashi_vault.vault_database_connection_reset: + engine_mount_point: database + connection_name: NOT REAL + + - name: Check (explicit mount, connection_name - invalid) + ansible.builtin.assert: &failure_invalid_path + that: + - db_connection_reset is failed + - db_connection_reset.msg is search('Invalid or missing path') + + - name: Test database connection reset (explicit mount, connection_name) + register: db_connection_reset + community.hashi_vault.vault_database_connection_reset: + engine_mount_point: database + connection_name: "{{ vault_database_connection_name }}" + + - name: Check (explicit mount) + ansible.builtin.assert: *success + + - name: Test database connection reset (default mount) [check mode] + register: db_connection_reset + check_mode: true + community.hashi_vault.vault_database_connection_reset: + connection_name: "{{ vault_database_connection_name }}" + + - name: Check (explicit mount, connection_name) [check mode] + ansible.builtin.assert: *success + + - name: Test database connection reset (default mount, connection_name - invalid) + register: db_connection_reset + ignore_errors: true + community.hashi_vault.vault_database_connection_reset: + connection_name: NOT REAL + + - name: Check (default mount, connection_name - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test database connection reset (default mount) + register: db_connection_reset + community.hashi_vault.vault_database_connection_reset: + connection_name: "{{ vault_database_connection_name }}" + + - name: Check (default mount) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml new file mode 100644 index 000000000..4d51ae24a --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_connection_list_setup.yml +- import_tasks: module_vault_database_connection_list_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml new file mode 100644 index 000000000..cd1b09dc7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [base-policy-database] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml new file mode 100644 index 000000000..c57890457 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml @@ -0,0 +1,72 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_connections_list: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test list database connections (explicit mount - invalid) [check mode] + register: db_connections + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_connections_list: + engine_mount_point: NOT REAL + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: &failure_bad_mount + that: + - db_connections is failed + - db_connections.msg is search('Permission Denied') + + - name: Test list database connections (explicit mount - invalid) + register: db_connections + ignore_errors: true + community.hashi_vault.vault_database_connections_list: + engine_mount_point: NOT REAL + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: *failure_bad_mount + + - name: Test list database connections (explicit mount) [check mode] + register: db_connections + check_mode: true + community.hashi_vault.vault_database_connections_list: + engine_mount_point: database + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: &success + that: + - db_connections is defined + - "'data' in db_connections" + - "'raw' in db_connections" + - "'connections' in db_connections" + - "'keys' in db_connections['data']" + - "'my-postgresql-database' in db_connections['data']['keys']" + + - name: Test list database connections (explicit mount) + register: db_connections + community.hashi_vault.vault_database_connections_list: + engine_mount_point: database + + - name: Check (explicit mount) + ansible.builtin.assert: *success + + - name: Test list database connections (default mount) [check mode] + check_mode: true + register: db_connections + community.hashi_vault.vault_database_connections_list: + + - name: Check (default mount) [check mode] + ansible.builtin.assert: *success + + - name: Test list database connections (default mount) + register: db_connections + community.hashi_vault.vault_database_connections_list: + + - name: Check (default mount) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml new file mode 100644 index 000000000..88f896f5a --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_role_create_setup.yml +- import_tasks: module_vault_database_role_create_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml new file mode 100644 index 000000000..7abb3ceb2 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml @@ -0,0 +1,13 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}' + vault_ci_read: '{{ vault_plugins_module_defaults_common }}' + vault_ci_write: '{{ vault_plugins_module_defaults_common }}' + vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml new file mode 100644 index 000000000..f82109ec1 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml @@ -0,0 +1,92 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_role_create: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test database create role [check mode] + register: db_create_role + check_mode: true + community.hashi_vault.vault_database_role_create: + engine_mount_point: Does Not Matter + connection_name: Does Not Matter + creation_statements: + - Does Not Matter + role_name: Does Not Matter + + - name: Check [check mode] + ansible.builtin.assert: &success + that: + - db_create_role is changed + + - name: Test database create role (explicit mount point - invalid, connection_name) + register: db_create_role + ignore_errors: true + community.hashi_vault.vault_database_role_create: + engine_mount_point: NOT REAL + connection_name: "{{ vault_database_connection_name }}" + creation_statements: + - "{{ vault_database_dynamic_user_sql }}" + role_name: dynamic_role_read + + - name: Check (explicit mount point - invalid, connection_name) + ansible.builtin.assert: &failure_bad_mount + that: + - db_create_role is failed + - db_create_role.msg is search('Permission Denied') + + - name: Test database create role (explicit mount point, connection_name - invalid) + register: db_create_role + ignore_errors: true + community.hashi_vault.vault_database_role_create: + engine_mount_point: database + connection_name: nonono + creation_statements: + - "{{ vault_database_dynamic_user_sql }}" + role_name: dynamic_role_read_invalid_1 + + # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing + - name: Check (explicit mount point, connection_name - invalid) + ansible.builtin.assert: *success + + - name: Test database create role (explicit mount point, connection_name) + register: db_create_role + community.hashi_vault.vault_database_role_create: + engine_mount_point: database + connection_name: "{{ vault_database_connection_name }}" + creation_statements: + - "{{ vault_database_dynamic_user_sql }}" + role_name: dynamic_role_read_1 + + - name: Check (explicit mount point) + ansible.builtin.assert: *success + + - name: Test database create role (default mount point, connection_name - invalid) + register: db_create_role + ignore_errors: true + community.hashi_vault.vault_database_role_create: + connection_name: NOT REAL + creation_statements: + - "{{ vault_database_dynamic_user_sql }}" + role_name: dynamic_role_read_invalid_2 + + # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing + - name: Check (default mount point, connection_name - invalid) + ansible.builtin.assert: *success + + - name: Test database create role (default mount point, connection_name) + register: db_create_role + community.hashi_vault.vault_database_role_create: + connection_name: "{{ vault_database_connection_name }}" + creation_statements: + - "{{ vault_database_dynamic_user_sql }}" + role_name: dynamic_role_read_2 + + - name: Check (explicit mount point) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml new file mode 100644 index 000000000..5d0a50d2a --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_role_delete_setup.yml +- import_tasks: module_vault_database_role_delete_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml new file mode 100644 index 000000000..c6d0e2e90 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml @@ -0,0 +1,34 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}" + vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}" + vault_ci_read: "{{ vault_plugins_module_defaults_common }}" + vault_ci_write: "{{ vault_plugins_module_defaults_common }}" + vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}" + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd + + - name: Set roles to be deleted + ansible.builtin.set_fact: + static_role_name: role5 + dynamic_role_name: dynamic_role + + - name: Create a static role + vault_ci_write: + path: "database/static-roles/{{ static_role_name }}" + data: + db_name: "{{ vault_database_connection_name }}" + username: "{{ static_role_name }}" + + - name: Create a readonly dynamic role + vault_ci_write: + path: "database/roles/{{ dynamic_role_name }}" + data: + db_name: "{{ vault_database_connection_name }}" + creation_statements: "{{ vault_database_dynamic_user_sql }}" + default_ttl: 1h + max_ttl: 24h diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml new file mode 100644 index 000000000..e7e869158 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml @@ -0,0 +1,75 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_role_delete: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test database static role delete [check mode] + register: db_role_delete + check_mode: true + community.hashi_vault.vault_database_role_delete: + engine_mount_point: DOES NOT MATTER + role_name: DOES NOT MATTER + + - name: Check [check mode] + ansible.builtin.assert: &success + that: + - db_role_delete is changed + + - name: Test database role delete (explicit mount - invalid, role_name) + register: db_role_delete + ignore_errors: true + community.hashi_vault.vault_database_role_delete: + engine_mount_point: NOT REAL + role_name: "{{ static_role_name }}" + + - name: Check (explicit mount - invalid, role_name) + ansible.builtin.assert: &failure_bad_mount + that: + - db_role_delete is failed + - db_role_delete.msg is search('Permission Denied') + + - name: Test database role delete (explicit mount, role_name - invalid) + register: db_role_delete + ignore_errors: true + community.hashi_vault.vault_database_role_delete: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount - invalid, role_name) + ansible.builtin.assert: &failure_invalid_path + that: + - db_role_delete is failed + - db_role_delete.msg is search('Invalid or missing path') + + - name: Test database role delete (explicit mount, role_name) + register: db_role_delete + community.hashi_vault.vault_database_role_delete: + engine_mount_point: database + role_name: "{{ static_role_name }}" + + - name: Check (explicit mount, role_name) + ansible.builtin.assert: *success + + - name: Test database role delete (default mount, role_name - invalid) + register: db_role_delete + ignore_errors: true + community.hashi_vault.vault_database_role_delete: + role_name: NOT REAL + + - name: Check (explicit mount - invalid, role_name) + ansible.builtin.assert: *failure_invalid_path + + - name: Test database role delete (default mount, role_name) + register: db_role_delete + community.hashi_vault.vault_database_role_delete: + role_name: "{{ dynamic_role_name }}" + + - name: Check (default mount, role_name) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml new file mode 100644 index 000000000..a601b07a3 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_role_read_setup.yml +- import_tasks: module_vault_database_role_read_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml new file mode 100644 index 000000000..cd1b09dc7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [base-policy-database] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml new file mode 100644 index 000000000..1e2d687ad --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml @@ -0,0 +1,126 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_role_read: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test read database role (explicit mount - invalid, role_name) [check mode] + register: db_role_read + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_role_read: + engine_mount_point: NOT REAL + role_name: readonly + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: &failure_bad_mount + that: + - db_role_read is failed + - db_role_read.msg is search('Permission Denied') + + - name: Test read database role (explicit mount, role_name - invalid) [check mode] + register: db_role_read + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_role_read: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: &failure_invalid_path + that: + - db_role_read is failed + - db_role_read.msg is search('Invalid or missing path') + + - name: Test read database role (explicit mount, role_name) [check mode] + register: db_role_read + check_mode: true + community.hashi_vault.vault_database_role_read: + engine_mount_point: database + role_name: readonly + + - name: Check (explicit mount, role_name) [check mode] + ansible.builtin.assert: &success + that: + - db_role_read is defined + - "'data' in db_role_read" + - "'raw' in db_role_read" + - "'creation_statements' in db_role_read['data']" + - "'credential_type' in db_role_read['data']" + - "'db_name' in db_role_read['data']" + - "'default_ttl' in db_role_read['data']" + - "'max_ttl' in db_role_read['data']" + - "'renew_statements' in db_role_read['data']" + - "'revocation_statements' in db_role_read['data']" + - "'rollback_statements' in db_role_read['data']" + + - name: Test read database role (explicit mount - invalid, role_name) + register: db_role_read + ignore_errors: true + community.hashi_vault.vault_database_role_read: + engine_mount_point: NOT REAL + role_name: readonly + + - name: Check (explicit mount - invalid) + ansible.builtin.assert: *failure_bad_mount + + - name: Test read database role (explicit mount, role_name - invalid) + register: db_role_read + ignore_errors: true + community.hashi_vault.vault_database_role_read: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database role (explicit mount, role_name) + register: db_role_read + community.hashi_vault.vault_database_role_read: + engine_mount_point: database + role_name: readonly + + - name: Check (explicit mount, role_name) + ansible.builtin.assert: *success + + - name: Test read database role (default mount, role_name - invalid) [check mode] + register: db_role_read + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_role_read: + role_name: NOT REAL + + - name: Check (default mount - invalid) [check mode] + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database role (default mount, role_name) [check mode] + register: db_role_read + check_mode: true + community.hashi_vault.vault_database_role_read: + role_name: readonly + + - name: Check (default mount, role_name) [check mode] + ansible.builtin.assert: *success + + - name: Test read database role (default mount, role_name - invalid) + register: db_role_read + ignore_errors: true + community.hashi_vault.vault_database_role_read: + role_name: NOT REAL + + - name: Check (default mount - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database role (default mount, role_name) + register: db_role_read + community.hashi_vault.vault_database_role_read: + role_name: readonly + + - name: Check (default mount, role_name) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml new file mode 100644 index 000000000..420aa1b76 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_roles_list_setup.yml +- import_tasks: module_vault_database_roles_list_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml new file mode 100644 index 000000000..cd1b09dc7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [base-policy-database] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml new file mode 100644 index 000000000..b49c06ade --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml @@ -0,0 +1,65 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + expected_role: readonly + module_defaults: + community.hashi_vault.vault_database_roles_list: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test list database dynamic roles (explicit mount - invalid) [check mode] + register: db_roles_list + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_roles_list: + engine_mount_point: NOT REAL + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: &failure_bad_mount + that: + - db_roles_list is failed + - db_roles_list.msg is search('Permission Denied') + + - name: Test list database dynamic roles (explicit mount) [check mode] + register: db_roles_list + check_mode: true + community.hashi_vault.vault_database_roles_list: + engine_mount_point: database + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: &success + that: + - db_roles_list is defined + - "'data' in db_roles_list" + - "'raw' in db_roles_list" + - "'keys' in db_roles_list['data']" + - "'roles' in db_roles_list" + - db_roles_list.roles == db_roles_list.data['keys'] + - expected_role in db_roles_list.roles + + - name: Test list database dynamic roles (explicit mount) + register: db_roles_list + community.hashi_vault.vault_database_roles_list: + engine_mount_point: database + + - name: Check (explicit mount) + ansible.builtin.assert: *success + + - name: Test list database dynamic roles (default mount) [check mode] + register: db_roles_list + check_mode: true + community.hashi_vault.vault_database_roles_list: + + - name: Check (default mount) [check mode] + ansible.builtin.assert: *success + + - name: Test list database dynamic roles (default mount) + register: db_roles_list + community.hashi_vault.vault_database_roles_list: + + - name: Check (default mount) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml new file mode 100644 index 000000000..7b05ed1af --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- name: Get python minor version + ansible.builtin.set_fact: + python_interpreter_minor: "{{ ansible_python_version | split('.') }}" + +- when: python_interpreter_minor[1] | int > 6 + block: + - import_tasks: module_vault_db_rotate_root_creds_setup.yml + - import_tasks: module_vault_db_rotate_root_creds_test.yml + - import_tasks: module_vault_db_rotate_root_creds_cleanup.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml new file mode 100644 index 000000000..e360aee6a --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml @@ -0,0 +1,12 @@ +--- +- name: Drop users in PostgreSQL + community.postgresql.postgresql_user: + db: "{{ vault_postgres_db }}" + name: "{{ item.username }}" + password: "{{ item.password }}" + login_user: "{{ vault_postgres_user }}" + login_password: "{{ vault_postgres_password }}" + port: "{{ vault_postgres_port }}" + login_host: "{{ vault_postgres_host }}" + state: absent + loop: "{{ users_to_create }}" diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml new file mode 100644 index 000000000..7f1eaee87 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml @@ -0,0 +1,46 @@ +--- +- name: Configuration tasks + vars: + users_to_create: + - { "username": "usr_to_rotate1", "password": "SuperSecret" } + - { "username": "usr_to_rotate2", "password": "SuperSecret" } + module_defaults: + vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}" + vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}" + vault_ci_read: "{{ vault_plugins_module_defaults_common }}" + vault_ci_write: "{{ vault_plugins_module_defaults_common }}" + vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}" + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd + + - name: Set facts + ansible.builtin.set_fact: + users_to_create: + - { "username": "usr_to_rotate1", "password": "SuperSecret" } + - { "username": "usr_to_rotate2", "password": "SuperSecret" } + + - name: Create a new user in PostgreSQL + community.postgresql.postgresql_user: + db: "{{ vault_postgres_db }}" + name: "{{ item.username }}" + password: "{{ item.password }}" + login_user: "{{ vault_postgres_user }}" + login_password: "{{ vault_postgres_password }}" + port: "{{ vault_postgres_port }}" + login_host: "{{ vault_postgres_host }}" + role_attr_flags: SUPERUSER + loop: "{{ users_to_create }}" + + - name: Create the Database Connection + vault_ci_write: + path: "database/config/{{ item.username }}" + data: + plugin_name: "{{ vault_database_plugin_name }}" + connection_url: "{{ vault_database_connection_url }}" + allowed_roles: "*" + username: "{{ item.username }}" + password: "{{ item.password }}" + loop: "{{ users_to_create }}" diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml new file mode 100644 index 000000000..50498e824 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml @@ -0,0 +1,132 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + vault_ci_read: "{{ vault_plugins_module_defaults_common }}" + community.hashi_vault.vault_database_rotate_root_credentials: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test rotate root credentials [check mode] + register: rotate_credentials + check_mode: true + community.hashi_vault.vault_database_rotate_root_credentials: + engine_mount_point: DOES NOT MATTER + connection_name: DOES NOT MATTER + + - name: Check [check mode] + ansible.builtin.assert: &success + that: + - rotate_credentials is changed + + - name: Test rotate root credentials (explicit mount - invalid, connection_name) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_rotate_root_credentials: + engine_mount_point: NOT REAL + connection_name: "{{ users_to_create[0].username }}" + + - name: Check (explicit mount - invalid, connection_name) + ansible.builtin.assert: &failure_bad_mount + that: + - rotate_credentials is failed + - rotate_credentials.msg is search('Permission Denied') + + - name: Test rotate root credentials (explicit mount, connection_name - invalid) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_rotate_root_credentials: + engine_mount_point: database + connection_name: NOT REAL + + - name: Check (explicit mount, connection_name - invalid) + ansible.builtin.assert: &failure_invalid_path + that: + - rotate_credentials is failed + - rotate_credentials.msg is search('Invalid or missing path') + + - name: Login before root credential rotation with user {{ users_to_create[0].username }} + community.postgresql.postgresql_ping: + db: "{{ vault_postgres_db }}" + login_user: "{{ users_to_create[0].username }}" + login_password: "{{ users_to_create[0].password }}" + port: "{{ vault_postgres_port }}" + login_host: "{{ vault_postgres_host }}" + register: login_result_before + + - name: Check db login before root credential rotation + ansible.builtin.assert: &login_before + that: + - login_result_before is defined + - login_result_before.is_available + - login_result_before.conn_err_msg | length == 0 + + - name: Test rotate root credentials (explicit_mount, connection_name) + register: rotate_credentials + community.hashi_vault.vault_database_rotate_root_credentials: + engine_mount_point: database + connection_name: "{{ users_to_create[0].username }}" + + - name: Check (explicit_mount, connection_name) + ansible.builtin.assert: *success + + - name: Try to login with the old password for user {{ users_to_create[0].username }} + community.postgresql.postgresql_ping: + db: "{{ vault_postgres_db }}" + login_user: "{{ users_to_create[0].username }}" + login_password: "{{ users_to_create[0].password }}" + port: "{{ vault_postgres_port }}" + login_host: "{{ vault_postgres_host }}" + register: login_result_after + + - name: Ensure that password was rotated + ansible.builtin.assert: &login_failed + that: + - login_result_after is defined + - not login_result_after.is_available + - login_result_after.conn_err_msg | length > 0 + + - name: Test rotate root credentials (default mount, connection_name - invalid) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_rotate_root_credentials: + connection_name: NOT REAL + + - name: Check (explicit mount, connection_name - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Login before root credential rotation with user {{ users_to_create[1].username }} + community.postgresql.postgresql_ping: + db: "{{ vault_postgres_db }}" + login_user: "{{ users_to_create[1].username }}" + login_password: "{{ users_to_create[1].password }}" + port: "{{ vault_postgres_port }}" + login_host: "{{ vault_postgres_host }}" + register: login_result_before + + - name: Check db login before root credential rotation + ansible.builtin.assert: *login_before + + - name: Test rotate root credentials (default, connection_name) + register: rotate_credentials + community.hashi_vault.vault_database_rotate_root_credentials: + connection_name: "{{ users_to_create[1].username }}" + + - name: Check (explicit_mount, connection_name) + ansible.builtin.assert: *success + + - name: Try to login with the old password for user {{ users_to_create[1].username }} + community.postgresql.postgresql_ping: + db: "{{ vault_postgres_db }}" + login_user: "{{ users_to_create[1].username }}" + login_password: "{{ users_to_create[1].password }}" + port: "{{ vault_postgres_port }}" + login_host: "{{ vault_postgres_host }}" + register: login_result_after + + - name: Ensure that password was rotated + ansible.builtin.assert: *login_failed diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml new file mode 100644 index 000000000..7a49731f3 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_static_role_create_setup.yml +- import_tasks: module_vault_database_static_role_create_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml new file mode 100644 index 000000000..7abb3ceb2 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml @@ -0,0 +1,13 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}' + vault_ci_read: '{{ vault_plugins_module_defaults_common }}' + vault_ci_write: '{{ vault_plugins_module_defaults_common }}' + vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml new file mode 100644 index 000000000..07bc1ac08 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml @@ -0,0 +1,130 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + rotation_statements: + - 'ALTER USER {{ "{{name}}" }} WITH PASSWORD {{ ''{{password}}'' }};' + module_defaults: + community.hashi_vault.vault_database_static_role_create: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test database create static role [check mode] + register: db_create_static_role + check_mode: true + community.hashi_vault.vault_database_static_role_create: + engine_mount_point: Does Not Matter + connection_name: Does Not Matter + rotation_statements: + - Does Not Matter + role_name: Does Not Matter + db_username: Does Not Matter + + - name: Check [check mode] + ansible.builtin.assert: &success + that: + - db_create_static_role is changed + + - name: Test database create static role (explicit mount point - invalid, connection_name, db_username) + register: db_create_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_create: + engine_mount_point: NOT REAL + connection_name: "{{ vault_database_connection_name }}" + rotation_statements: + - "{{ rotation_statements }}" + db_username: role3 + role_name: role3 + + - name: Check (explicit mount point - invalid, connection_name) + ansible.builtin.assert: &failure_bad_mount + that: + - db_create_static_role is failed + - db_create_static_role.msg is search('Permission Denied') + + - name: Test database create static role (explicit mount point, connection_name - invalid, db_username) + register: db_create_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_create: + engine_mount_point: database + connection_name: NOT REAL + rotation_statements: + - "{{ rotation_statements }}" + db_username: role3 + role_name: role3 + + # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing + - name: Check (explicit mount point, connection_name - invalid) + ansible.builtin.assert: *success + + - name: Test database create static role (explicit mount point, connection_name, db_username - invalid) + register: db_create_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_create: + engine_mount_point: database + connection_name: "{{ vault_database_connection_name }}" + rotation_statements: + - "{{ rotation_statements }}" + db_username: NOT REAL + role_name: role3 + + - name: Check (explicit mount point, connection_name, db_username - invalid) + ansible.builtin.assert: &failure_invalid_request + that: + - db_create_static_role is failed + - db_create_static_role.msg is search('Cannot update static role') + + - name: Test database create static role (explicit mount point, connection_name, db_username) + register: db_create_static_role + community.hashi_vault.vault_database_static_role_create: + engine_mount_point: database + connection_name: "{{ vault_database_connection_name }}" + rotation_statements: + - "{{ rotation_statements }}" + db_username: role3 + role_name: role3 + + - name: Check (explicit mount point, connection_name, db_username) + ansible.builtin.assert: *success + + - name: Test database create static role (default mount point, connection_name - invalid, db_username) + register: db_create_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_create: + connection_name: NOT REAL + rotation_statements: + - "{{ rotation_statements }}" + db_username: role3 + role_name: role3 + + # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing + - name: Check (default mount point, connection_name - invalid, db_username) + ansible.builtin.assert: *success + + - name: Test database create static role (default mount point, connection_name, db_username - invalid) + register: db_create_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_create: + connection_name: NOT REAL + rotation_statements: + - "{{ rotation_statements }}" + db_username: NOT REAL + role_name: role3 + + - name: Check (default mount point, connection_name, db_username - invalid) + ansible.builtin.assert: *failure_invalid_request + + - name: Test database create static role (default mount point, connection_name, db_username) + register: db_create_static_role + community.hashi_vault.vault_database_static_role_create: + connection_name: "{{ vault_database_connection_name }}" + rotation_statements: + - "{{ rotation_statements }}" + role_name: role3 + db_username: role3 + + - name: Check (default mount point, connection_name, db_username) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml new file mode 100644 index 000000000..3116a06a3 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_static_role_get_credentials_setup.yml +- import_tasks: module_vault_database_static_role_get_credentials_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml new file mode 100644 index 000000000..c843258fa --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml @@ -0,0 +1,13 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}' + vault_ci_read: '{{ vault_plugins_module_defaults_common }}' + vault_ci_write: '{{ vault_plugins_module_defaults_common }}' + vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [base-policy-database] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml new file mode 100644 index 000000000..7ee1bd7bc --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml @@ -0,0 +1,114 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_static_role_get_credentials: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test database get credentials of static role (explicit mount - invalid, role_name) [check mode] + register: db_static_role + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_static_role_get_credentials: + engine_mount_point: NOT REAL + role_name: role1 + + - name: Check (explicit mount - invalid, role_name) [check_mode] + ansible.builtin.assert: &failure_bad_mount + that: + - db_static_role is failed + - db_static_role.msg is search('Permission Denied') + + - name: Test database get credentials of static role (explicit mount, role_name - invalid) [check mode] + register: db_static_role + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_static_role_get_credentials: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount, role_name - invalid) [check_mode] + ansible.builtin.assert: &failure_invalid_path + that: + - db_static_role is failed + - db_static_role.msg is search('Invalid or missing path') + + - name: Test database get credentials of static role (explicit mount, role_name) [check mode] + register: db_static_role + check_mode: true + community.hashi_vault.vault_database_static_role_get_credentials: + engine_mount_point: database + role_name: role1 + + - name: Check (explicit mount, role_name) [check_mode] + ansible.builtin.assert: &success + that: + - db_static_role is defined + - "'data' in db_static_role" + - "'password' in db_static_role['data']" + - "'rotation_period' in db_static_role['data']" + - "'ttl' in db_static_role['data']" + - "'last_vault_rotation' in db_static_role['data']" + - "'raw' in db_static_role" + + - name: Test database get credentials of static role (explicit mount - invalid, role_name) + register: db_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_get_credentials: + engine_mount_point: NOT REAL + role_name: role1 + + - name: Check (explicit mount - invalid, role_name) + ansible.builtin.assert: *failure_bad_mount + + - name: Test database get credentials of static role (explicit mount, role_name - invalid) + register: db_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_get_credentials: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount, role_name - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test database get credentials of static role (explicit mount, role_name) + register: db_static_role + community.hashi_vault.vault_database_static_role_get_credentials: + engine_mount_point: database + role_name: role1 + + - name: Check (explicit mount, role_name) + ansible.builtin.assert: *success + + - name: Test database get credentials of static role (default mount, role_name - invalid) [check mode] + register: db_static_role + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_static_role_get_credentials: + role_name: NOT REAL + + - name: Check (default mount, role_name - invalid) [check mode] + ansible.builtin.assert: *failure_invalid_path + + - name: Test database get credentials of static role (default mount, role_name - invalid) + register: db_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_get_credentials: + role_name: NOT REAL + + - name: Check (default mount, role_name - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test database get credentials of static role (default mount, role_name) + register: db_static_role + ignore_errors: true + community.hashi_vault.vault_database_static_role_get_credentials: + role_name: role1 + + - name: Check (default mount, role_name) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml new file mode 100644 index 000000000..44e2405ee --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_static_role_read_setup.yml +- import_tasks: module_vault_database_static_role_read_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml new file mode 100644 index 000000000..cd1b09dc7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [base-policy-database] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml new file mode 100644 index 000000000..c8cc77423 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml @@ -0,0 +1,123 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + community.hashi_vault.vault_database_static_role_read: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test read database role (explicit mount - invalid, role_name) [check mode] + register: db_static_role_read + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_static_role_read: + engine_mount_point: NOT REAL + role_name: role2 + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: &failure_bad_mount + that: + - db_static_role_read is failed + - db_static_role_read.msg is search('Permission Denied') + + - name: Test read database role (explicit mount, role_name - invalid) [check mode] + register: db_static_role_read + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_static_role_read: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: &failure_invalid_path + that: + - db_static_role_read is failed + - db_static_role_read.msg is search('Invalid or missing path') + + - name: Test read database role (explicit mount, role_name) [check mode] + register: db_static_role_read + check_mode: true + community.hashi_vault.vault_database_static_role_read: + engine_mount_point: database + role_name: role2 + + - name: Check (explicit mount, role_name) [check mode] + ansible.builtin.assert: &success + that: + - db_static_role_read is defined + - "'data' in db_static_role_read" + - "'raw' in db_static_role_read" + - "'credential_type' in db_static_role_read['data']" + - "'db_name' in db_static_role_read['data']" + - "'last_vault_rotation' in db_static_role_read['data']" + - "'rotation_period' in db_static_role_read['data']" + - "'rotation_statements' in db_static_role_read['data']" + + - name: Test read database role (explicit mount - invalid, role_name) + register: db_static_role_read + ignore_errors: true + community.hashi_vault.vault_database_static_role_read: + engine_mount_point: NOT REAL + role_name: role2 + + - name: Check (explicit mount - invalid) + ansible.builtin.assert: *failure_bad_mount + + - name: Test read database role (explicit mount, role_name - invalid) + register: db_static_role_read + ignore_errors: true + community.hashi_vault.vault_database_static_role_read: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database role (explicit mount, role_name) + register: db_static_role_read + community.hashi_vault.vault_database_static_role_read: + engine_mount_point: database + role_name: role2 + + - name: Check (explicit mount, role_name) + ansible.builtin.assert: *success + + - name: Test read database role (default mount, role_name - invalid) [check mode] + register: db_static_role_read + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_static_role_read: + role_name: NOT REAL + + - name: Check (default mount - invalid) [check mode] + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database role (default mount, role_name) [check mode] + register: db_static_role_read + check_mode: true + community.hashi_vault.vault_database_static_role_read: + role_name: role2 + + - name: Check (default mount, role_name) [check mode] + ansible.builtin.assert: *success + + - name: Test read database role (default mount, role_name - invalid) + register: db_static_role_read + ignore_errors: true + community.hashi_vault.vault_database_static_role_read: + role_name: NOT REAL + + - name: Check (default mount - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test read database role (default mount, role_name) + register: db_static_role_read + community.hashi_vault.vault_database_static_role_read: + role_name: role2 + + - name: Check (default mount, role_name) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml new file mode 100644 index 000000000..b1c2e1029 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml @@ -0,0 +1,8 @@ +--- +- ansible.builtin.set_fact: + python_interpreter_minor: "{{ ansible_python_version | split('.') }}" + +- when: python_interpreter_minor[1] | int > 6 + block: + - import_tasks: module_vault_db_static_role_rotate_creds_setup.yml + - import_tasks: module_vault_db_static_role_rotate_creds_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml new file mode 100644 index 000000000..3e650be6b --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml @@ -0,0 +1,23 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}" + vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}" + vault_ci_read: "{{ vault_plugins_module_defaults_common }}" + vault_ci_write: "{{ vault_plugins_module_defaults_common }}" + vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}" + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [policy-database-all] + register: user_token_cmd + + - name: Set roles data + ansible.builtin.set_fact: + roles_to_rotate: ["role4", "role5"] + + - name: Read users + vault_ci_read: + path: "database/static-creds/{{ item }}" + register: roles_data_before + loop: "{{ roles_to_rotate }}" diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml new file mode 100644 index 000000000..caee65e9c --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml @@ -0,0 +1,120 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + module_defaults: + vault_ci_read: "{{ vault_plugins_module_defaults_common }}" + community.hashi_vault.vault_database_static_role_rotate_credentials: + &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test for python >= 3.8 + when: python_interpreter_minor[1] | int > 7 + block: + - name: Test rotate credential for a static role (explicit mount) [check mode] + register: rotate_credentials + check_mode: true + community.hashi_vault.vault_database_static_role_rotate_credentials: + engine_mount_point: database + role_name: "{{ roles_to_rotate[0] }}" + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: &success + that: + - rotate_credentials is changed + + - name: Test rotate credential for a static role (explicit mount - invalid, role_name) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_static_role_rotate_credentials: + engine_mount_point: NOT REAL + role_name: "{{ roles_to_rotate[0] }}" + + - name: Check (explicit mount - invalid, role_name) + ansible.builtin.assert: &failure_bad_mount + that: + - rotate_credentials is failed + - rotate_credentials.msg is search('Permission Denied') + + - name: Test rotate credential for a static role (explicit mount, role_name - invalid) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_static_role_rotate_credentials: + engine_mount_point: database + role_name: NOT REAL + + - name: Check (explicit mount, role_name - invalid) + ansible.builtin.assert: &failure_invalid_path + that: + - rotate_credentials is failed + - rotate_credentials.msg is search('Invalid or missing path') + + - name: Test rotate credential for a static role (explicit mount, role_name) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_static_role_rotate_credentials: + engine_mount_point: database + role_name: "{{ roles_to_rotate[0] }}" + + - name: Check (explicit mount, role_name) + ansible.builtin.assert: *success + + - name: Read user + vault_ci_read: + path: "database/static-creds/{{ roles_to_rotate[0] }}" + register: role_data_after + + - name: Check that passwords were rotated for "{{ roles_data_before[0] }}" + ansible.builtin.assert: + that: + - roles_data_before.results[0].result.data.password != role_data_after.result.data.password + - roles_data_before.results[0].result.data.ttl < role_data_after.result.data.ttl + + - name: Test rotate credential for a static role (default mount, role_name - invalid) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_static_role_rotate_credentials: + role_name: NOT REAL + + - name: Check (default mount, role_name - invalid) + ansible.builtin.assert: *failure_invalid_path + + - name: Test rotate credential for a static role (default mount, role_name) + register: rotate_credentials + ignore_errors: true + community.hashi_vault.vault_database_static_role_rotate_credentials: + engine_mount_point: database + role_name: "{{ roles_to_rotate[1] }}" + + - name: Check (explicit mount, role_name) + ansible.builtin.assert: *success + + - name: Read user + vault_ci_read: + path: "database/static-creds/{{ roles_to_rotate[1] }}" + register: role_data_after + + - name: Check + ansible.builtin.assert: + that: + - roles_data_before.results[1].result.data.password != role_data_after.result.data.password + - roles_data_before.results[1].result.data.ttl < role_data_after.result.data.ttl + + - name: Test for python < 3.8 + when: python_interpreter_minor[1] | int <= 7 + block: + - name: Test rotate credential for a static role [python < 3.8] + register: rotate_credentials + community.hashi_vault.vault_database_static_role_rotate_credentials: + engine_mount_point: database + role_name: "{{ role_name_to_rotate }}" + ignore_errors: true + + - name: Check python < 3.8 + ansible.builtin.assert: + that: + - rotate_credentials is failed diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases new file mode 100644 index 000000000..7636a9a65 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases @@ -0,0 +1 @@ +context/target diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml new file mode 100644 index 000000000..e867490b0 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - setup_vault_test_plugins + - setup_vault_configure_database diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml new file mode 100644 index 000000000..ab6b5c5bc --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: module_vault_database_static_roles_list_setup.yml +- import_tasks: module_vault_database_static_roles_list_test.yml diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml new file mode 100644 index 000000000..cd1b09dc7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml @@ -0,0 +1,9 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Create a test non-root token + vault_ci_token_create: + policies: [base-policy-database] + register: user_token_cmd diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml new file mode 100644 index 000000000..31aa86814 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml @@ -0,0 +1,91 @@ +--- +- name: Var block + vars: + user_token: "{{ user_token_cmd.result.auth.client_token }}" + expected_roles: + - role1 + - role2 + - role3 + - role4 + - role5 + + module_defaults: + community.hashi_vault.vault_database_static_roles_list: &defaults + url: "{{ vault_test_server_http }}" + auth_method: token + token: "{{ user_token }}" + token_validate: true + timeout: 5 + block: + - name: Test list database static roles (explicit mount - invalid) [check mode] + register: db_static_roles + check_mode: true + ignore_errors: true + community.hashi_vault.vault_database_static_roles_list: + engine_mount_point: NOT REAL + + - name: Check (explicit mount - invalid) [check mode] + ansible.builtin.assert: &failure_bad_mount + that: + - db_static_roles is failed + - db_static_roles.msg is search('Permission Denied') + + - name: Test list database static roles (explicit mount) [check mode] + register: db_static_roles + check_mode: true + community.hashi_vault.vault_database_static_roles_list: + engine_mount_point: database + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: &success + that: + - db_static_roles is defined + - db_static_roles is not changed + - "'raw' in db_static_roles" + - "'data' in db_static_roles" + - db_static_roles.data == db_static_roles.raw.data + - "'keys' in db_static_roles['data']" + - "'roles' in db_static_roles" + - db_static_roles.roles == db_static_roles.data['keys'] + - db_static_roles.roles == expected_roles + + - name: Test list database static roles (explicit mount - invalid) + register: db_static_roles + ignore_errors: true + community.hashi_vault.vault_database_static_roles_list: + engine_mount_point: NOT REAL + + - name: Check + ansible.builtin.assert: *failure_bad_mount + + - name: Test list database static roles (explicit mount) [check mode] + register: db_static_roles + check_mode: true + community.hashi_vault.vault_database_static_roles_list: + engine_mount_point: database + + - name: Check (explicit mount) [check mode] + ansible.builtin.assert: *success + + - name: Test list database static roles (explicit mount) + register: db_static_roles + community.hashi_vault.vault_database_static_roles_list: + engine_mount_point: database + + - name: Check (explicit mount) + ansible.builtin.assert: *success + + - name: Test list database static roles (default mount) [check mode] + register: db_static_roles + check_mode: true + community.hashi_vault.vault_database_static_roles_list: + + - name: Check (default mount) [check mode] + ansible.builtin.assert: *success + + - name: Test list database static roles (default mount) + register: db_static_roles + community.hashi_vault.vault_database_static_roles_list: + + - name: Check (default mount) + ansible.builtin.assert: *success diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml index be8e3acff..124099566 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml @@ -39,7 +39,7 @@ - name: Try a login in check mode register: result community.hashi_vault.vault_login: - check_mode: yes + check_mode: true - assert: that: diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml index 244b8e29a..b9824b91f 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml @@ -20,6 +20,9 @@ data: a: 1 b: two + # https://github.com/ansible-collections/community.hashi_vault/issues/389 + path: path_value + wrap_ttl: wrap_ttl_value - assert: that: @@ -42,6 +45,9 @@ data: a: 1 b: two + # https://github.com/ansible-collections/community.hashi_vault/issues/389 + path: path_value + wrap_ttl: wrap_ttl_value - assert: that: @@ -57,7 +63,13 @@ that: - "'result' in result" - "'data' in result.result" - - "result.result.data == {'a': 1, 'b': 'two'}" + - > + result.result.data == { + 'a': 1, + 'b': 'two', + 'path': 'path_value', + 'wrap_ttl': 'wrap_ttl_value', + } - name: Write data to an endpoint that returns data and test wrapping register: result diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml index d17c895f9..8f6095be1 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml @@ -13,18 +13,30 @@ docker_compose_project_name: hashi_vault vault_port_http: 8200 vault_port_https: 8300 vault_container_name: vault +vault_container_image: hashicorp/vault vault_target_name: '{{ vault_container_name }}' proxy_port: 8888 proxy_container_name: tinyproxy +proxy_container_image: monokal/tinyproxy proxy_target_name: '{{ proxy_container_name }}' mmock_server_port: 8900 mmock_console_port: 8901 mmock_container_name: mmock +mmock_container_image: jordimartin/mmock mmock_target_name: '{{ mmock_container_name }}' mmock_config_path: '{{ output_dir }}/mmock_config' +postgres_container_name: postgres +postgres_container_image: postgres +postgres_target_name: '{{ postgres_container_name }}' +postgres_config_path: '{{ output_dir }}/postgres' +postgres_sql_port: 5432 +postgres_db_name: hcvault +postgres_db_user: postgres +postgres_db_password: postgres + output_dir: '{{ role_path }}/files/.output' docker_compose_output: '{{ output_dir }}/{{ docker_compose_project_name }}' diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml index 6f6ae5ab9..18ff09ddc 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml @@ -1,5 +1,5 @@ --- - hosts: localhost - gather_facts: no + gather_facts: false roles: - setup_localenv_docker diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt index 16f5a6645..66daa618e 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt @@ -1,2 +1,3 @@ -docker >= 5.0.0 ; python_version >= '3.6' -docker < 5.0.0 ; python_version == '2.7' +# https://github.com/docker/docker-py/issues/3194#issuecomment-1849016391 +# Must use docker SDK for Python < 7 +docker >= 5.0.0,<7 ; python_version >= '3.6' diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt index de536a9e5..52fdd0170 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt @@ -1,3 +1,2 @@ docker docker-compose -six # https://github.com/ansible-collections/community.docker/issues/171 diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql new file mode 100644 index 000000000..2e9e73054 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql @@ -0,0 +1,16 @@ +-- Create users to manage database connections +CREATE USER con1 WITH PASSWORD 'con1'; +CREATE USER con2 WITH PASSWORD 'con2'; +CREATE USER con3 WITH PASSWORD 'con3'; +CREATE USER con4 WITH PASSWORD 'con4'; +CREATE USER con5 WITH PASSWORD 'con5'; + +-- Create another user to manage credential rotation +-- CREATE USER usr_to_rotate with PASSWORD 'SuperSecret' SUPERUSER; + +-- Create users to manage static roles +CREATE USER role1; +CREATE USER role2; +CREATE USER role3; +CREATE USER role4; +CREATE USER role5; diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml index 90223f1e4..967497a26 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml @@ -7,6 +7,7 @@ - '{{ docker_compose_output }}' - '{{ vault_config_output }}' - '{{ mmock_config_path }}' + - '{{ postgres_config_path }}' - name: "Create the docker-compose definition" template: @@ -21,19 +22,19 @@ - name: "Check if cert already exists" stat: path: '{{ vault_cert_file }}' - follow: yes - get_attributes: no - get_checksum: no - get_mime: no + follow: true + get_attributes: false + get_checksum: false + get_mime: false register: cert_status - name: "Check if key already exists" stat: path: '{{ vault_key_file }}' - follow: yes - get_attributes: no - get_checksum: no - get_mime: no + follow: true + get_attributes: false + get_checksum: false + get_mime: false register: key_status - name: "Generate certs" @@ -60,11 +61,17 @@ src: '{{ item }}' dest: '{{ mmock_config_path }}/{{ dest_name }}' -- include_tasks: docker.yml - when: docker_compose != 'none' - - name: "Template integration_config" template: src: integration_config.yml.j2 dest: '{{ output_dir }}/integration_config.yml' - force: yes + force: true + +- name: "Copy postgres init.sql script" + copy: + src: files/sql/init.sql + dest: "{{ postgres_config_path }}/init.sql" + force: true + +- include_tasks: docker.yml + when: docker_compose != 'none' diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2 b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2 index 365532c4c..6696a6dd0 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2 +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2 @@ -3,7 +3,7 @@ version: '3' services: vault: - image: 'vault:{{ vault_version }}' + image: '{{ vault_container_image }}:{{ vault_version }}' container_name: '{{ vault_container_name }}' ports: - '{{ vault_port_http }}:{{ vault_port_http }}' @@ -14,13 +14,13 @@ services: VAULT_DEV_ROOT_TOKEN_ID: '{{ vault_dev_root_token_id }}' SKIP_CHOWN: 1 tinyproxy: - image: 'monokal/tinyproxy' + image: '{{ proxy_container_image }}' container_name: '{{ proxy_container_name }}' ports: - '{{ proxy_port }}:{{ proxy_port }}' command: ANY mmock: - image: jordimartin/mmock + image: '{{ mmock_container_image }}' container_name: '{{ mmock_container_name }}' ports: - '{{ mmock_server_port }}:{{ mmock_server_port }}' @@ -30,3 +30,14 @@ services: command: >- -console-port {{ mmock_console_port }} -server-port {{ mmock_server_port }} + postgres: + image: '{{ postgres_container_image }}' + container_name: '{{ postgres_container_name }}' + environment: + POSTGRES_DB: '{{ postgres_db_name }}' + POSTGRES_PASSWORD: '{{ postgres_db_password }}' + POSTGRES_USER: '{{ postgres_db_user }}' + ports: + - '{{ postgres_sql_port }}:{{ postgres_sql_port }}' + volumes: + - '{{ postgres_config_path}}/init.sql:/docker-entrypoint-initdb.d/init.sql' diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml index fd0a0c36b..dc36fdae5 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml @@ -7,3 +7,8 @@ integration_config: vault_proxy_server: 'http://{{ proxy_target_name }}:{{ proxy_port }}' vault_cert_content: "{{ lookup('file', vault_cert_file) }}" vault_mmock_server_http: 'http://{{ mmock_target_name }}:{{ mmock_server_port }}' + vault_postgres_host: '{{ postgres_container_name }}' + vault_postgres_port: '{{ postgres_sql_port }}' + vault_postgres_db: '{{ postgres_db_name }}' + vault_postgres_user: '{{ postgres_db_user }}' + vault_postgres_password: '{{ postgres_db_password }}' diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml index aea370d3f..57b27677b 100644 --- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml @@ -1,5 +1,5 @@ --- - hosts: localhost - gather_facts: no + gather_facts: false roles: - setup_localenv_gha diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md new file mode 100644 index 000000000..2d948a957 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md @@ -0,0 +1,2 @@ +# `setup_vault_configure_database` +Performs configuration of the database engine in Vault. diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases new file mode 100644 index 000000000..4b3a017fd --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases @@ -0,0 +1,2 @@ +hidden +needs/target/setup_vault_test_plugins diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml new file mode 100644 index 000000000..290705e5e --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_vault_test_plugins diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml new file mode 100644 index 000000000..5640870ce --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml @@ -0,0 +1,48 @@ +--- +- name: Create database secrets engine + vault_ci_enable_engine: + backend_type: database + +- name: Create a database connection + vault_ci_write: + path: "/{{ vault_database_engine_mount_point }}/config/{{ vault_database_connection_name }}" + data: + plugin_name: "{{ vault_database_plugin_name }}" + connection_url: "{{ vault_database_connection_url }}" + allowed_roles: "*" + username: "{{ vault_database_connection_user }}" + password: "{{ vault_database_connection_password }}" + +- name: Create some static roles + vault_ci_write: + path: "{{ vault_database_engine_mount_point }}/static-roles/role{{ item }}" + data: + db_name: "{{ vault_database_connection_name }}" + username: "role{{ item }}" + rotation_period: 24h + loop: [1, 2, 3, 4, 5] + +- name: Create a readonly dynamic role + vault_ci_write: + path: "{{ vault_database_engine_mount_point }}/roles/readonly" + data: + db_name: "{{ vault_database_connection_name }}" + creation_statements: "{{ vault_database_dynamic_user_sql }}" + default_ttl: 1h + max_ttl: 24h + +- name: Create a database base policy + vault_ci_policy_put: + name: base-policy-database + policy: "{{ vault_base_policy_db }}" + +- name: Create a database all policy + vault_ci_policy_put: + name: policy-database-all + policy: "{{ vault_policy_db_all }}" + +- name: Write Canary + vault_ci_write: + path: "{{ vault_configure_engine_database_canary.path }}" + data: + value: "{{ vault_configure_engine_database_canary.value }}" diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml new file mode 100644 index 000000000..f6a343251 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: Configuration tasks + module_defaults: + vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}' + vault_ci_read: '{{ vault_plugins_module_defaults_common }}' + vault_ci_write: '{{ vault_plugins_module_defaults_common }}' + vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}' + vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}' + block: + - name: Canary for Vault Database engine setup + vault_ci_read: + path: '{{ vault_configure_engine_database_canary.path }}' + register: canary + + - name: Configure Vault Database engine basic setup + include_tasks: configure.yml + when: canary.result is none diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml new file mode 100644 index 000000000..4086901e7 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml @@ -0,0 +1,27 @@ +--- +vault_configure_engine_database_canary: + path: cubbyhole/configure_engine_database + value: complete # value does not matter + +vault_database_engine_mount_point: database +vault_database_connection_name: my-postgresql-database +vault_database_db_name: hcvault +vault_database_connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/{{ vault_database_db_name }}?sslmode=disable" +vault_database_plugin_name: postgresql-database-plugin +vault_database_connection_user: postgres +vault_database_connection_password: postgres + +vault_database_dynamic_user_sql: | + CREATE ROLE {{ "{{name}}" }} WITH LOGIN PASSWORD {{ '{{password}}' }} VALID UNTIL {{ '{{expiration}}' }} INHERIT; + GRANT ro TO {{ "{{name}}" }}; + +vault_base_policy_db: | + path "{{ vault_database_engine_mount_point }}/*" { + capabilities = ["read", "list"] + } + +vault_policy_db_all: | + {{ vault_base_policy_db }} + path "{{ vault_database_engine_mount_point }}/*" { + capabilities = ["create", "update", "patch", "delete"] + } diff --git a/ansible_collections/community/hashi_vault/tests/unit/conftest.py b/ansible_collections/community/hashi_vault/tests/unit/conftest.py index 862e93cf6..7b07c1b1e 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/conftest.py +++ b/ansible_collections/community/hashi_vault/tests/unit/conftest.py @@ -78,5 +78,15 @@ def patch_get_vault_client(vault_client): def requests_unparseable_response(): r = mock.MagicMock() r.json.side_effect = json.JSONDecodeError + return r + +# https://github.com/hvac/hvac/issues/797 +@pytest.fixture +def empty_response(requests_unparseable_response): + r = requests_unparseable_response + r.status_code = 204 + r._content = b"" + r.content = b"" + r.text = "" return r diff --git a/ansible_collections/community/hashi_vault/tests/unit/constraints.txt b/ansible_collections/community/hashi_vault/tests/unit/constraints.txt new file mode 100644 index 000000000..f347921c3 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/constraints.txt @@ -0,0 +1,64 @@ +coverage >= 4.2, < 5.0.0, != 4.3.2 ; python_version <= '3.7' # features in 4.2+ required, avoid known bug in 4.3.2 on python 2.6, coverage 5.0+ incompatible +coverage >= 4.5.4, < 5.0.0 ; python_version > '3.7' # coverage had a bug in < 4.5.4 that would cause unit tests to hang in Python 3.8, coverage 5.0+ incompatible +cryptography < 2.2 ; python_version < '2.7' # cryptography 2.2 drops support for python 2.6 +deepdiff < 4.0.0 ; python_version < '3' # deepdiff 4.0.0 and later require python 3 +jinja2 < 2.11 ; python_version < '2.7' # jinja2 2.11 and later require python 2.7 or later +urllib3 < 1.24 ; python_version < '2.7' # urllib3 1.24 and later require python 2.7 or later +pywinrm >= 0.3.0 # message encryption support +sphinx < 1.6 ; python_version < '2.7' # sphinx 1.6 and later require python 2.7 or later +sphinx < 1.8 ; python_version >= '2.7' # sphinx 1.8 and later are currently incompatible with rstcheck 3.3 +pygments >= 2.4.0 # Pygments 2.4.0 includes bugfixes for YAML and YAML+Jinja lexers +wheel < 0.30.0 ; python_version < '2.7' # wheel 0.30.0 and later require python 2.7 or later +yamllint != 1.8.0, < 1.14.0 ; python_version < '2.7' # yamllint 1.8.0 and 1.14.0+ require python 2.7+ +pycrypto >= 2.6 # Need features found in 2.6 and greater +ncclient >= 0.5.2 # Need features added in 0.5.2 and greater +idna < 2.6, >= 2.5 # linode requires idna < 2.9, >= 2.5, requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead +paramiko < 2.4.0 ; python_version < '2.7' # paramiko 2.4.0 drops support for python 2.6 +pytest < 3.3.0 ; python_version < '2.7' # pytest 3.3.0 drops support for python 2.6 +pytest < 5.0.0 ; python_version == '2.7' # pytest 5.0.0 and later will no longer support python 2.7 +pytest-forked < 1.0.2 ; python_version < '2.7' # pytest-forked 1.0.2 and later require python 2.7 or later +pytest-forked >= 1.0.2 ; python_version >= '2.7' # pytest-forked before 1.0.2 does not work with pytest 4.2.0+ (which requires python 2.7+) +ntlm-auth >= 1.3.0 # message encryption support using cryptography +requests < 2.20.0 ; python_version < '2.7' # requests 2.20.0 drops support for python 2.6 +requests-ntlm >= 1.1.0 # message encryption support +requests-credssp >= 0.1.0 # message encryption support +voluptuous >= 0.11.0 # Schema recursion via Self +openshift >= 0.6.2, < 0.9.0 # merge_type support +virtualenv < 16.0.0 ; python_version < '2.7' # virtualenv 16.0.0 and later require python 2.7 or later +pathspec < 0.6.0 ; python_version < '2.7' # pathspec 0.6.0 and later require python 2.7 or later +pyopenssl < 18.0.0 ; python_version < '2.7' # pyOpenSSL 18.0.0 and later require python 2.7 or later +pyfmg == 0.6.1 # newer versions do not pass current unit tests +pyyaml < 5.1 ; python_version < '2.7' # pyyaml 5.1 and later require python 2.7 or later +pycparser < 2.19 ; python_version < '2.7' # pycparser 2.19 and later require python 2.7 or later +mock >= 2.0.0 # needed for features backported from Python 3.6 unittest.mock (assert_called, assert_called_once...) +pytest-mock >= 1.4.0 # needed for mock_use_standalone_module pytest option +xmltodict < 0.12.0 ; python_version < '2.7' # xmltodict 0.12.0 and later require python 2.7 or later +lxml < 4.3.0 ; python_version < '2.7' # lxml 4.3.0 and later require python 2.7 or later +pyvmomi < 6.0.0 ; python_version < '2.7' # pyvmomi 6.0.0 and later require python 2.7 or later +pyone == 1.1.9 # newer versions do not pass current integration tests +boto3 < 1.11 ; python_version < '2.7' # boto3 1.11 drops Python 2.6 support +botocore >= 1.10.0, < 1.14 ; python_version < '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca; botocore 1.14 drops Python 2.6 support +botocore >= 1.10.0 ; python_version >= '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca +setuptools < 45 ; python_version <= '2.7' # setuptools 45 and later require python 3.5 or later +cffi >= 1.14.2, != 1.14.3 # Yanked version which older versions of pip will still install: + +# freeze pylint and its requirements for consistent test results +astroid == 2.2.5 +isort == 4.3.15 +lazy-object-proxy == 1.3.1 +mccabe == 0.6.1 +pylint == 2.3.1 +typed-ast == 1.4.0 # 1.4.0 is required to compile on Python 3.8 +wrapt == 1.11.1 + +# hvac +hvac >= 1.2.1 ; python_version >= '3.6' + +# urllib3 +# these should be satisfied naturally by the requests versions required by hvac anyway +urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06 + +# requests +# https://github.com/psf/requests/pull/6356 +requests >= 2.29 ; python_version >= '3.7' +requests < 2.28 ; python_version < '3.7' diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json new file mode 100644 index 000000000..36c4429a8 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json @@ -0,0 +1,20 @@ +{ + "auth": null, + "data": { + "allowed_roles": [], + "connection_details": { + "connection_url": "postgresql://{{username}}:{{password}}@postgres:5432/postgres?sslmode=disable", + "username": "UserName" + }, + "password_policy": "", + "plugin_name": "postgresql-database-plugin", + "plugin_version": "", + "root_credentials_rotate_statements": [] + }, + "lease_duration": 0, + "lease_id": "", + "renewable": false, + "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d", + "warnings": null, + "wrap_info": null +} diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json new file mode 100644 index 000000000..c5abad4ce --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json @@ -0,0 +1,21 @@ +{ + "auth": null, + "data": { + "keys": [ + "con1", + "con2", + "con3" + ] + }, + "connections": [ + "con1", + "con2", + "con3" + ], + "lease_duration": 0, + "lease_id": "", + "renewable": false, + "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d", + "warnings": null, + "wrap_info": null +} diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json new file mode 100644 index 000000000..c840ad1cb --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json @@ -0,0 +1,22 @@ +{ + "auth": null, + "data": { + "creation_statements": [ + "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", + "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" + ], + "credential_type": "password", + "db_name": "SomeConnection", + "default_ttl": 3600, + "max_ttl": 86400, + "renew_statements": [], + "revocation_statements": [], + "rollback_statements": [] + }, + "lease_duration": 0, + "lease_id": "", + "renewable": false, + "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d", + "warnings": null, + "wrap_info": null +} diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json new file mode 100644 index 000000000..00062fa20 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json @@ -0,0 +1,21 @@ +{ + "auth": null, + "data": { + "keys": [ + "dyn_role1", + "dyn_role2", + "dyn_role3" + ] + }, + "roles": [ + "dyn_role1", + "dyn_role2", + "dyn_role3" + ], + "lease_duration": 0, + "lease_id": "", + "renewable": false, + "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d", + "warnings": null, + "wrap_info": null +} diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json new file mode 100644 index 000000000..34e901a12 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json @@ -0,0 +1,25 @@ +{ + "data": { + "last_vault_rotation": "2024-01-01T09:00:00+01:00", + "password": "Th3_$3cr3t_P@ss!", + "rotation_period": 86400, + "ttl": 123456, + "username": "SomeUser" + }, + "raw": { + "auth": null, + "data": { + "last_vault_rotation": "2024-01-01T09:00:00+01:00", + "password": "Th3_$3cr3t_P@ss!", + "rotation_period": 86400, + "ttl": 123456, + "username": "SomeUser" + }, + "lease_duration": 0, + "lease_id": "", + "renewable": false, + "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d", + "warnings": null, + "wrap_info": null + } +} diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json new file mode 100644 index 000000000..cd4cbdc63 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json @@ -0,0 +1,18 @@ +{ + "auth": null, + "data": { + "credential_type": "password", + "db_name": "SomeConnection", + "last_vault_rotation": "2024-01-01T09:00:00 +01:00", + "rotation_period": 86400, + "rotation_statements": [ + "ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';" + ] + }, + "lease_duration": 0, + "lease_id": "", + "renewable": false, + "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d", + "warnings": null, + "wrap_info": null +} diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json new file mode 100644 index 000000000..be8700112 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json @@ -0,0 +1,21 @@ +{ + "auth": null, + "data": { + "keys": [ + "role1", + "role2", + "role3" + ] + }, + "roles": [ + "role1", + "role2", + "role3" + ], + "lease_duration": 0, + "lease_id": "", + "renewable": false, + "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d", + "warnings": null, + "wrap_info": null +} diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py index 05a74f8b4..37404d9a2 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py @@ -6,7 +6,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -import sys import pytest from ansible.plugins.loader import lookup_loader @@ -150,11 +149,7 @@ class TestVaultTokenCreateLookup(object): "lookup result did not match expected result:\nlookup: %r\nexpected: %r" % (result, token_create_response) ) - if sys.version_info < (3, 8): - # TODO: remove when python < 3.8 is dropped - assert pass_thru_options.items() <= client.auth.token.create.call_args[1].items() - else: - assert pass_thru_options.items() <= client.auth.token.create.call_args.kwargs.items() + assert pass_thru_options.items() <= client.auth.token.create.call_args.kwargs.items() def test_vault_token_create_orphan_options( self, vault_token_create_lookup, authenticator, minimal_vars, pass_thru_options, orphan_option_translation, token_create_response @@ -175,11 +170,7 @@ class TestVaultTokenCreateLookup(object): "lookup result did not match expected result:\nlookup: %r\nexpected: %r" % (result, token_create_response) ) - if sys.version_info < (3, 8): - # TODO: remove when python < 3.8 is dropped - call_kwargs = client.auth.token.create_orphan.call_args[1] - else: - call_kwargs = client.auth.token.create_orphan.call_args.kwargs + call_kwargs = client.auth.token.create_orphan.call_args.kwargs for name, orphan in orphan_option_translation.items(): assert name not in call_kwargs, ( diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py index c3c325228..eaac0ff08 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py @@ -68,18 +68,18 @@ class TestVaultWriteLookup(object): def test_vault_write_return_data(self, vault_write_lookup, minimal_vars, approle_secret_id_write_response, vault_client, paths, data, wrap_ttl): client = vault_client - expected_calls = [mock.call(path=p, wrap_ttl=wrap_ttl, **data) for p in paths] + expected_calls = [mock.call(path=p, wrap_ttl=wrap_ttl, data=data) for p in paths] - def _fake_write(path, wrap_ttl, **data): + def _fake_write(path, wrap_ttl, data=None): r = approle_secret_id_write_response.copy() r.update({'path': path}) return r - client.write = mock.Mock(wraps=_fake_write) + client.write_data = mock.Mock(wraps=_fake_write) response = vault_write_lookup.run(terms=paths, variables=minimal_vars, wrap_ttl=wrap_ttl, data=data) - client.write.assert_has_calls(expected_calls) + client.write_data.assert_has_calls(expected_calls) assert len(response) == len(paths), "%i paths processed but got %i responses" % (len(paths), len(response)) @@ -96,7 +96,7 @@ class TestVaultWriteLookup(object): requests_unparseable_response.status_code = 204 - client.write.return_value = requests_unparseable_response + client.write_data.return_value = requests_unparseable_response response = vault_write_lookup.run(terms=['fake'], variables=minimal_vars) @@ -108,7 +108,7 @@ class TestVaultWriteLookup(object): requests_unparseable_response.status_code = 200 requests_unparseable_response.content = '﷽' - client.write.return_value = requests_unparseable_response + client.write_data.return_value = requests_unparseable_response with mock.patch('ansible_collections.community.hashi_vault.plugins.lookup.vault_write.display.warning') as warning: response = vault_write_lookup.run(terms=['fake'], variables=minimal_vars) @@ -127,7 +127,40 @@ class TestVaultWriteLookup(object): def test_vault_write_exceptions(self, vault_write_lookup, minimal_vars, vault_client, exc): client = vault_client - client.write.side_effect = exc[0] + client.write_data.side_effect = exc[0] with pytest.raises(AnsibleError, match=exc[1]): vault_write_lookup.run(terms=['fake'], variables=minimal_vars) + + @pytest.mark.parametrize( + 'data', + [ + {"path": mock.sentinel.path_value}, + {"wrap_ttl": mock.sentinel.wrap_ttl_value}, + {"path": mock.sentinel.data_value, "wrap_ttl": mock.sentinel.write_ttl_value}, + ], + ) + def test_vault_write_data_fallback_bad_params(self, vault_write_lookup, minimal_vars, vault_client, data): + client = vault_client + client.mock_add_spec(['write']) + + with pytest.raises(AnsibleError, match=r"To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1\.2"): + vault_write_lookup.run(terms=['fake'], variables=minimal_vars, data=data) + + client.write.assert_not_called() + + @pytest.mark.parametrize( + 'data', + [ + {"item1": mock.sentinel.item1_value}, + {"item2": mock.sentinel.item2_value}, + {"item1": mock.sentinel.item1_value, "item2": mock.sentinel.item2_value}, + ], + ) + def test_vault_write_data_fallback_write(self, vault_write_lookup, minimal_vars, vault_client, data): + client = vault_client + client.mock_add_spec(['write']) + + vault_write_lookup.run(terms=['fake'], variables=minimal_vars, data=data) + + client.write.assert_called_once_with(path='fake', wrap_ttl=None, **data) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py index 678146b92..ac867dcd6 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py @@ -163,7 +163,7 @@ class TestAuthAwsIam(object): params = auth_aws_iam._auth_aws_iam_login_params - assert boto3.session.Session.called_once_with(profile_name=profile) + boto3.session.Session.assert_called_once_with(profile_name=profile) assert params['access_key'] == aws_access_key assert params['secret_key'] == aws_secret_key diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py index 747a432df..f0aabd78a 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py @@ -157,10 +157,10 @@ class TestAuthAzure(object): credential.get_token.return_value.token = jwt auth_azure.validate() - assert mocked_credential_class.called_once_with( + mocked_credential_class.assert_called_once_with( azure_tenant_id, azure_client_id, azure_client_secret ) - assert credential.get_token.called_once_with( + credential.get_token.assert_called_once_with( 'https://management.azure.com//.default' ) @@ -194,8 +194,8 @@ class TestAuthAzure(object): credential.get_token.return_value.token = jwt auth_azure.validate() - assert mocked_credential_class.called_once_with(azure_client_id) - assert credential.get_token.called_once_with( + mocked_credential_class.assert_called_once_with(client_id=azure_client_id) + credential.get_token.assert_called_once_with( 'https://management.azure.com//.default' ) @@ -215,8 +215,8 @@ class TestAuthAzure(object): credential.get_token.return_value.token = jwt auth_azure.validate() - assert mocked_credential_class.called_once_with() - assert credential.get_token.called_once_with( + mocked_credential_class.assert_called_once_with() + credential.get_token.assert_called_once_with( 'https://management.azure.com//.default' ) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py index d8a13435b..5003082a5 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py @@ -11,11 +11,7 @@ import pytest from ......tests.unit.compat import mock -try: - import hvac -except ImportError: - # python 2.6, which isn't supported anyway - hvac = mock.MagicMock() +import hvac from ......plugins.module_utils._auth_method_token import ( HashiVaultAuthMethodToken, diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py index 828cbdefc..36dfbcec0 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py @@ -8,13 +8,10 @@ __metaclass__ = type import pytest -from ansible_collections.community.hashi_vault.tests.unit.compat import mock - -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import ( +from ......plugins.module_utils._hashi_vault_common import ( HashiVaultAuthMethodBase, HashiVaultOptionGroupBase, HashiVaultValueError, - _stringify, ) @@ -75,12 +72,3 @@ class TestHashiVaultAuthMethodBase(object): auth_base.deprecate(msg, version, date, collection_name) deprecator.assert_called_once_with(msg, version=version, date=date, collection_name=collection_name) - - def test_has_stringify(self, auth_base): - v = 'X' - wrapper = mock.Mock(wraps=_stringify) - with mock.patch('ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common._stringify', wrapper): - r = auth_base._stringify(v) - - wrapper.assert_called_once_with(v) - assert r == v diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py index d3e205d68..9226de003 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py @@ -8,7 +8,7 @@ __metaclass__ = type import pytest -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter +from ......plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter SAMPLE_DICT = { @@ -103,18 +103,32 @@ class TestHashiVaultOptionAdapter(object): def test_has_option(self, adapter, option, expected): assert adapter.has_option(option) == expected - @pytest.mark.parametrize('value', ['__VALUE']) - @pytest.mark.parametrize('option', (SAMPLE_KEYS + MISSING_KEYS)) - def test_set_option(self, adapter, option, value, sample_dict): + @pytest.mark.parametrize('option', SAMPLE_KEYS) + def test_set_option_existing(self, adapter, option, sample_dict): + value = type(sample_dict.get(option, ""))() adapter.set_option(option, value) - # first check the underlying data, then ensure the adapter refelcts the change too assert sample_dict[option] == value assert adapter.get_option(option) == value + @pytest.mark.parametrize('option', MISSING_KEYS) + def test_set_option_missing(self, request, adapter, option, sample_dict): + value = MARKER + + for mark in request.node.own_markers: + if mark.name == 'option_adapter_raise_on_missing': + from ansible.errors import AnsibleError + with pytest.raises(AnsibleError, match=rf"^Requested entry.*?setting: {option}.*?was not defined in configuration"): + adapter.set_option(option, value) + break + else: + adapter.set_option(option, value) + assert sample_dict[option] == value + assert adapter.get_option(option) == value + @pytest.mark.parametrize('default', [MARKER]) - @pytest.mark.parametrize('option,expected', [(o, SAMPLE_DICT[o]) for o in SAMPLE_KEYS] + [(o, MARKER) for o in MISSING_KEYS]) - def test_set_option_default(self, adapter, option, default, expected, sample_dict): + @pytest.mark.parametrize('option,expected', [(o, SAMPLE_DICT[o]) for o in SAMPLE_KEYS]) + def test_set_option_default_existing(self, adapter, option, default, expected, sample_dict): value = adapter.set_option_default(option, default) # check return data, underlying data structure, and adapter retrieval @@ -122,25 +136,47 @@ class TestHashiVaultOptionAdapter(object): assert sample_dict[option] == expected assert adapter.get_option(option) == expected - @pytest.mark.parametrize('options', [[SAMPLE_KEYS[0], MISSING_KEYS[0]]]) - def test_set_options(self, adapter, options, sample_dict): - update = dict([(o, '__VALUE_%i' % i) for i, o in enumerate(options)]) + @pytest.mark.parametrize('default', [MARKER]) + @pytest.mark.parametrize('option,expected', [(o, MARKER) for o in MISSING_KEYS]) + def test_set_option_default_missing(self, request, adapter, option, default, expected, sample_dict): + for mark in request.node.own_markers: + if mark.name == 'option_adapter_raise_on_missing': + from ansible.errors import AnsibleError + with pytest.raises(AnsibleError, match=rf"^Requested entry.*?setting: {option}.*?was not defined in configuration"): + adapter.set_option_default(option, default) + break + else: + value = adapter.set_option_default(option, default) + # check return data, underlying data structure, and adapter retrieval + assert value == expected + assert sample_dict[option] == expected + assert adapter.get_option(option) == expected - adapter.set_options(**update) + @pytest.mark.parametrize('options', [[SAMPLE_KEYS[0], MISSING_KEYS[0]]]) + def test_set_options(self, request, adapter, options, sample_dict): + update = dict([(o, type(sample_dict.get(o, ""))(i)) for i, o in enumerate(options)]) + + for mark in request.node.own_markers: + if mark.name == 'option_adapter_raise_on_missing': + from ansible.errors import AnsibleError + with pytest.raises(AnsibleError, match=r"^Requested entry.*?setting:.*?was not defined in configuration"): + adapter.set_options(**update) + break + else: + adapter.set_options(**update) + for k in MISSING_KEYS: + if k in update: + assert sample_dict[k] == update[k] + assert adapter.get_option(k) == update[k] + else: + assert k not in sample_dict + assert not adapter.has_option(k) for k in SAMPLE_KEYS: expected = update[k] if k in update else SAMPLE_DICT[k] assert sample_dict[k] == expected assert adapter.get_option(k) == expected - for k in MISSING_KEYS: - if k in update: - assert sample_dict[k] == update[k] - assert adapter.get_option(k) == update[k] - else: - assert k not in sample_dict - assert not adapter.has_option(k) - @pytest.mark.parametrize('options', [[SAMPLE_KEYS[0], MISSING_KEYS[0]]]) def test_get_options_mixed(self, adapter, options): with pytest.raises(KeyError): diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py index 8766388e9..6a45b9859 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py @@ -101,7 +101,7 @@ class TestHashiVaultConnectionOptions(object): with mock.patch.dict(os.environ, envpatch): connection_options._boolean_or_cacert() - assert predefined_options['ca_cert'] == expected + assert connection_options._conopt_verify == expected # _process_option_proxies # proxies can be specified as a dictionary where key is protocol/scheme @@ -248,7 +248,7 @@ class TestHashiVaultConnectionOptions(object): # these should always be returned assert 'url' in opts and opts['url'] == predefined_options['url'] - assert 'verify' in opts and opts['verify'] == predefined_options['ca_cert'] + assert 'verify' in opts and opts['verify'] == connection_options._conopt_verify # these are optional assert 'proxies' not in opts or opts['proxies'] == predefined_options['proxies'] diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py index 6a5c6002b..14db5d1c8 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py @@ -12,7 +12,6 @@ import pytest from .....tests.unit.compat import mock from .....plugins.module_utils._hashi_vault_common import ( HashiVaultHelper, - _stringify, ) @@ -48,12 +47,3 @@ class TestHashiVaultHelper(object): client = hashi_vault_helper.get_vault_client(hashi_vault_logout_inferred_token=True) assert client.token is None - - def test_has_stringify(self, hashi_vault_helper): - v = 'X' - wrapper = mock.Mock(wraps=_stringify) - with mock.patch('ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common._stringify', wrapper): - r = hashi_vault_helper._stringify(v) - - wrapper.assert_called_once_with(v) - assert r == v, '%r != %r' % (r, v) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py new file mode 100644 index 000000000..17a4e063e --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_connection_configure +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_connection(): + return { + "connection_name": "foo", + "plugin_name": "bar", + "allowed_roles": [ + "baz", + ], + "connection_url": "postgresql://{{'{{username}}'}}:{{'{{password}}'}}@postgres:5432/postgres?sslmode=disable", + "connection_username": "SomeUser", + "connection_password": "SomePass", + } + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_connection()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseConnectionConfigure: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_configure_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_configure.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_configure_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_configure.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_configure_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_connection_configure, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_connection_configure.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/config/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_connection_configure_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.configure.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_connection_configure.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_configure_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.configure.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_connection_configure.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.configure.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["connection_name"], + plugin_name=patch_ansible_module["plugin_name"], + allowed_roles=patch_ansible_module["allowed_roles"], + connection_url=patch_ansible_module["connection_url"], + username=patch_ansible_module["connection_username"], + password=patch_ansible_module["connection_password"], + ) + + assert result["changed"] is True diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py new file mode 100644 index 000000000..5a24f85fa --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_connection_delete +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_connection(): + return {"connection_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_connection()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseConnectionDelete: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_delete_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_delete_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_delete_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.delete_connection.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_connection_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.delete_connection.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["connection_name"], + ) + + assert result["changed"] is True + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_delete_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_connection_delete, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_connection_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/config/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_connection_delete_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.delete_connection.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_connection_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py new file mode 100644 index 000000000..062ff7689 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_connection_read +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_connection(): + return {"connection_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_connection()) + opt.update(kwargs) + return opt + + +@pytest.fixture +def list_response(fixture_loader): + return fixture_loader("database_connection_read_response.json") + + +class TestModuleVaultDatabaseConnectionRead: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_read_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_read_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_read_return_data( + self, patch_ansible_module, list_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.read_connection.return_value = list_response.copy() + + with pytest.raises(SystemExit) as e: + vault_database_connection_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.read_connection.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["connection_name"], + ) + + raw = list_response.copy() + data = raw["data"] + + assert ( + result["raw"] == raw + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["data"] == data + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_read_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_connection_read, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_connection_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/config/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_connection_read_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.read_connection.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_connection_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py new file mode 100644 index 000000000..bddb858fd --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_connection_reset +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_connection(): + return {"connection_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_connection()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseConnectionReset: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_reset_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_reset.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connection_reset_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connection_reset.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_reset_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.reset_connection.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_connection_reset.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.reset_connection.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["connection_name"], + ) + + assert result["changed"] is True + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connection_reset_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_connection_reset, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_connection_reset.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/reset/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_connection_reset_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.reset_connection.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_connection_reset.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py new file mode 100644 index 000000000..057adc6f6 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_connections_list +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(kwargs) + return opt + + +@pytest.fixture +def list_response(fixture_loader): + return fixture_loader("database_connections_list_response.json") + + +class TestModuleVaultDatabaseConnectionsList: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connections_list_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connections_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_connections_list_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_connections_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connections_list_return_data( + self, patch_ansible_module, list_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.list_connections.return_value = list_response.copy() + + with pytest.raises(SystemExit) as e: + vault_database_connections_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.list_connections.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"] + ) + + raw = list_response.copy() + data = raw["data"] + roles = data["keys"] + + assert ( + result["raw"] == raw + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["data"] == data + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["connections"] == roles + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connections_list_no_data( + self, patch_ansible_module, vault_client, capfd + ): + client = vault_client + raw = {"errors": []} + client.secrets.database.list_connections.return_value = raw + + with pytest.raises(SystemExit) as e: + vault_database_connections_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.list_connections.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"] + ) + + empty_data = {"keys": []} + assert result["raw"] == raw + assert result["data"] == empty_data + assert result["connections"] == empty_data["keys"] + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_connections_list_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_connections_list, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_connections_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/config'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_connections_list_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.list_connections.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_connections_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py new file mode 100644 index 000000000..f8c752a00 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_role_create +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_role(): + return { + "role_name": "foo", + "connection_name": "bar", + "creation_statements": [ + "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", + 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";', + ], + "default_ttl": 3600, + "max_ttl": 86400, + } + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_role()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseRoleCreate: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_role_create_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_role_create_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_role_create_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.create_role.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.create_role.assert_called_once_with( + name=patch_ansible_module["role_name"], + db_name=patch_ansible_module["connection_name"], + creation_statements=patch_ansible_module["creation_statements"], + revocation_statements=patch_ansible_module.get("revocation_statements"), + rollback_statements=patch_ansible_module.get("rollback_statements"), + renew_statements=patch_ansible_module.get("renew_statements"), + default_ttl=patch_ansible_module["default_ttl"], + max_ttl=patch_ansible_module["max_ttl"], + mount_point=patch_ansible_module["engine_mount_point"], + ) + + assert result["changed"] is True + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_role_create_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_role_create, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/roles/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_role_create_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.create_role.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py new file mode 100644 index 000000000..e0b254bd1 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_role_delete +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_role(): + return {"role_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_role()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseRoleDelete: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_role_delete_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_role_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_role_delete_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_role_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_role_delete_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.delete_role.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_role_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.delete_role.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["role_name"], + ) + + assert result["changed"] is True + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_role_delete_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_role_delete, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_role_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/roles/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_role_delete_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.delete_role.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_role_delete.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py new file mode 100644 index 000000000..9dfcd4117 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_role_read +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_role(): + return {"role_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_role()) + opt.update(kwargs) + return opt + + +@pytest.fixture +def list_response(fixture_loader): + return fixture_loader("database_role_read_response.json") + + +class TestModuleVaultDatabaseRoleRead: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_role_read_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_role_read_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_role_read_return_data( + self, patch_ansible_module, list_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.read_role.return_value = list_response.copy() + + with pytest.raises(SystemExit) as e: + vault_database_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.read_role.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["role_name"], + ) + + raw = list_response.copy() + data = raw["data"] + + assert ( + result["raw"] == raw + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["data"] == data + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_role_read_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_role_read, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/roles/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_role_read_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.read_role.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py new file mode 100644 index 000000000..bcfadb062 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Martin Chmielewski (@M4rt1nCh) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_roles_list +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(kwargs) + return opt + + +@pytest.fixture +def list_response(fixture_loader): + return fixture_loader("database_roles_list_response.json") + + +class TestModuleVaultDatabaseRolesList: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_roles_list_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_roles_list_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_roles_list_return_data( + self, patch_ansible_module, list_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.list_roles.return_value = list_response.copy() + + with pytest.raises(SystemExit) as e: + vault_database_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.list_roles.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"] + ) + + raw = list_response.copy() + data = raw["data"] + roles = data["keys"] + + assert ( + result["raw"] == raw + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["data"] == data + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["roles"] == roles + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_roles_list_no_data( + self, patch_ansible_module, vault_client, capfd + ): + client = vault_client + raw = {"errors": []} + client.secrets.database.list_roles.return_value = raw + + with pytest.raises(SystemExit) as e: + vault_database_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.list_roles.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"] + ) + + empty_data = {"keys": []} + assert result["raw"] == raw + assert result["data"] == empty_data + assert result["roles"] == empty_data["keys"] + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_roles_list_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_roles_list, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/roles'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_roles_list_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.list_roles.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py new file mode 100644 index 000000000..1b22aaa0c --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_rotate_root_credentials +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_connection(): + return {"connection_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_connection()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseRotateRootCredentials: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_rotate_root_credentials_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_rotate_root_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_rotate_root_credentials_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_rotate_root_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_rotate_root_credentials_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.rotate_root_credentials.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_rotate_root_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.rotate_root_credentials.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["connection_name"], + ) + + assert result["changed"] is True + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_rotate_root_credentials_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_rotate_root_credentials, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_rotate_root_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_rotate_root_credentials_old_hvac(self, vault_client, capfd): + client = vault_client + client.secrets.database.rotate_root_credentials.side_effect = AttributeError + + with pytest.raises(SystemExit) as e: + vault_database_rotate_root_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "hvac>=2.0.0 is required" + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/rotate-root/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_rotate_root_credentials_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.rotate_root_credentials.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_rotate_root_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py new file mode 100644 index 000000000..eab22477b --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_static_role_create +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_role(): + return { + "role_name": "foo", + "connection_name": "bar", + "db_username": "baz", + "rotation_statements": [ + "ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';" + ], + "rotation_period": 86400, + } + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_role()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseStaticRoleCreate: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_create_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_create_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_create_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.create_static_role.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_static_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.create_static_role.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["role_name"], + db_name=patch_ansible_module["connection_name"], + username=patch_ansible_module["db_username"], + rotation_statements=patch_ansible_module["rotation_statements"], + rotation_period=patch_ansible_module["rotation_period"], + ) + + assert result["changed"] is True + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_create_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_static_role_create, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_static_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/static-roles/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_static_role_create_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.create_static_role.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_static_role_create.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py new file mode 100644 index 000000000..b15364ab6 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_static_role_get_credentials +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_role(): + return {"role_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_role()) + opt.update(kwargs) + return opt + + +@pytest.fixture +def list_response(fixture_loader): + return fixture_loader("database_static_role_get_credentials_response.json") + + +class TestModuleVaultDatabaseStaticRoleGetCredentials: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_get_credentials_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_get_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_get_credentials_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_get_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_get_credentials_return_data( + self, patch_ansible_module, list_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.get_static_credentials.return_value = ( + list_response.copy() + ) + + with pytest.raises(SystemExit) as e: + vault_database_static_role_get_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.get_static_credentials.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["role_name"], + ) + + raw = list_response.copy() + data = raw["data"] + + assert ( + result["raw"] == raw + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["data"] == data + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_get_credentials_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_static_role_get_credentials, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_static_role_get_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/static-creds/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_static_role_get_credentials_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.get_static_credentials.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_static_role_get_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py new file mode 100644 index 000000000..6a0b087b4 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_static_role_read +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_role(): + return {"role_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_role()) + opt.update(kwargs) + return opt + + +@pytest.fixture +def list_response(fixture_loader): + return fixture_loader("database_static_role_read_response.json") + + +class TestModuleVaultDatabaseStaticRoleRead: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_read_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_read_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_read_return_data( + self, patch_ansible_module, list_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.read_static_role.return_value = list_response.copy() + + with pytest.raises(SystemExit) as e: + vault_database_static_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.read_static_role.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["role_name"], + ) + + raw = list_response.copy() + data = raw["data"] + + assert ( + result["raw"] == raw + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["data"] == data + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_read_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_static_role_read, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_static_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/static-roles/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_static_role_read_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.read_static_role.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_static_role_read.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py new file mode 100644 index 000000000..b6e266755 --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py @@ -0,0 +1,199 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_static_role_rotate_credentials +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _sample_role(): + return {"role_name": "foo"} + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(_sample_role()) + opt.update(kwargs) + return opt + + +class TestModuleVaultDatabaseStaticRoleRotateCredentials: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_rotate_credentials_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_rotate_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_role_rotate_credentials_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_role_rotate_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_rotate_credentials_success( + self, patch_ansible_module, empty_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.rotate_static_role_credentials.return_value = empty_response + + with pytest.raises(SystemExit) as e: + vault_database_static_role_rotate_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.rotate_static_role_credentials.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"], + name=patch_ansible_module["role_name"], + ) + + assert result["changed"] is True + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_rotate_credentials_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_static_role_rotate_credentials, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_static_role_rotate_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_role_rotate_credentials_old_hvac(self, vault_client, capfd): + client = vault_client + client.secrets.database.rotate_static_role_credentials.side_effect = AttributeError + + with pytest.raises(SystemExit) as e: + vault_database_static_role_rotate_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "hvac>=2.0.0 is required" + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/rotate-role/([^']+)'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_static_role_rotate_credentials_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.rotate_static_role_credentials.side_effect = exc[0]( + exc[1] + ) + + with pytest.raises(SystemExit) as e: + vault_database_static_role_rotate_credentials.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py new file mode 100644 index 000000000..7a028e76d --- /dev/null +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2024 Brian Scholer (@briantist) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest +import re +import json + +from ansible.module_utils.basic import missing_required_lib + +from ...compat import mock +from .....plugins.modules import vault_database_static_roles_list +from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError + + +hvac = pytest.importorskip("hvac") + + +pytestmark = pytest.mark.usefixtures( + "patch_ansible_module", + "patch_authenticator", + "patch_get_vault_client", +) + + +def _connection_options(): + return { + "auth_method": "token", + "url": "http://myvault", + "token": "beep-boop", + } + + +def _sample_options(): + return { + "engine_mount_point": "dbmount", + } + + +def _combined_options(**kwargs): + opt = _connection_options() + opt.update(_sample_options()) + opt.update(kwargs) + return opt + + +@pytest.fixture +def list_response(fixture_loader): + return fixture_loader("database_static_roles_list_response.json") + + +class TestModuleVaultDatabaseStaticRolesList: + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_roles_list_authentication_error( + self, authenticator, exc, capfd + ): + authenticator.authenticate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg", "result: %r" % result + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + @pytest.mark.parametrize( + "exc", + [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")], + ) + def test_vault_database_static_roles_list_auth_validation_error( + self, authenticator, exc, capfd + ): + authenticator.validate.side_effect = exc + + with pytest.raises(SystemExit) as e: + vault_database_static_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == "throwaway msg" + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_roles_list_return_data( + self, patch_ansible_module, list_response, vault_client, capfd + ): + client = vault_client + client.secrets.database.list_static_roles.return_value = list_response.copy() + + with pytest.raises(SystemExit) as e: + vault_database_static_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.list_static_roles.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"] + ) + + raw = list_response.copy() + data = raw["data"] + roles = data["keys"] + + assert ( + result["raw"] == raw + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["data"] == data + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + assert ( + result["roles"] == roles + ), "module result did not match expected result:\nexpected: %r\ngot: %r" % ( + list_response, + result, + ) + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_roles_list_no_data( + self, patch_ansible_module, vault_client, capfd + ): + client = vault_client + raw = {"errors": []} + client.secrets.database.list_static_roles.return_value = raw + + with pytest.raises(SystemExit) as e: + vault_database_static_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.secrets.database.list_static_roles.assert_called_once_with( + mount_point=patch_ansible_module["engine_mount_point"] + ) + + empty_data = {"keys": []} + assert result["raw"] == raw + assert result["data"] == empty_data + assert result["roles"] == empty_data["keys"] + + @pytest.mark.parametrize( + "patch_ansible_module", [_combined_options()], indirect=True + ) + def test_vault_database_static_roles_list_no_hvac(self, capfd): + with mock.patch.multiple( + vault_database_static_roles_list, + HAS_HVAC=False, + HVAC_IMPORT_ERROR=None, + create=True, + ): + with pytest.raises(SystemExit) as e: + vault_database_static_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert result["msg"] == missing_required_lib("hvac") + + @pytest.mark.parametrize( + "exc", + [ + ( + hvac.exceptions.Forbidden, + "", + r"^Forbidden: Permission Denied to path \['([^']+)'\]", + ), + ( + hvac.exceptions.InvalidPath, + "", + r"^Invalid or missing path \['([^']+)/static-roles'\]", + ), + ], + ) + @pytest.mark.parametrize( + "patch_ansible_module", + [[_combined_options(), "engine_mount_point"]], + indirect=True, + ) + @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"]) + def test_vault_database_static_roles_list_vault_exception( + self, vault_client, exc, opt_engine_mount_point, capfd + ): + + client = vault_client + client.secrets.database.list_static_roles.side_effect = exc[0](exc[1]) + + with pytest.raises(SystemExit) as e: + vault_database_static_roles_list.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + match = re.search(exc[2], result["msg"]) + assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2]) + + assert opt_engine_mount_point == match.group(1) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py index 29bba2165..c5374b537 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py @@ -71,7 +71,7 @@ def translated_options(sample_options): if k in toplevel: opt[toplevel[k]] = v else: - if type(v) is list: + if isinstance(v, list): val = ','.join(v) else: val = v diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py index afe877e8d..59d2e38a1 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py @@ -88,7 +88,7 @@ class TestModuleVaultWrite(): @pytest.mark.parametrize('patch_ansible_module', [[_combined_options(), 'data', 'wrap_ttl']], indirect=True) def test_vault_write_return_data(self, patch_ansible_module, approle_secret_id_write_response, vault_client, opt_wrap_ttl, opt_data, capfd): client = vault_client - client.write.return_value = approle_secret_id_write_response + client.write_data.return_value = approle_secret_id_write_response with pytest.raises(SystemExit) as e: vault_write.main() @@ -98,7 +98,7 @@ class TestModuleVaultWrite(): assert e.value.code == 0, "result: %r" % (result,) - client.write.assert_called_once_with(path=patch_ansible_module['path'], wrap_ttl=opt_wrap_ttl, **opt_data) + client.write_data.assert_called_once_with(path=patch_ansible_module['path'], wrap_ttl=opt_wrap_ttl, data=opt_data) assert result['data'] == approle_secret_id_write_response, ( "module result did not match expected result:\nmodule: %r\nexpected: %r" % (result['data'], approle_secret_id_write_response) @@ -110,7 +110,7 @@ class TestModuleVaultWrite(): requests_unparseable_response.status_code = 204 - client.write.return_value = requests_unparseable_response + client.write_data.return_value = requests_unparseable_response with pytest.raises(SystemExit) as e: vault_write.main() @@ -129,7 +129,7 @@ class TestModuleVaultWrite(): requests_unparseable_response.status_code = 200 requests_unparseable_response.content = '﷽' - client.write.return_value = requests_unparseable_response + client.write_data.return_value = requests_unparseable_response with pytest.raises(SystemExit) as e: vault_write.main() @@ -166,7 +166,7 @@ class TestModuleVaultWrite(): def test_vault_write_vault_exception(self, vault_client, exc, capfd): client = vault_client - client.write.side_effect = exc[0] + client.write_data.side_effect = exc[0] with pytest.raises(SystemExit) as e: vault_write.main() @@ -176,3 +176,51 @@ class TestModuleVaultWrite(): assert e.value.code != 0, "result: %r" % (result,) assert re.search(exc[1], result['msg']) is not None + + @pytest.mark.parametrize( + 'opt_data', + [ + {"path": 'path_value'}, + {"wrap_ttl": 'wrap_ttl_value'}, + {"path": 'data_value', "wrap_ttl": 'write_ttl_value'}, + ], + ) + @pytest.mark.parametrize('patch_ansible_module', [[_combined_options(), 'data']], indirect=True) + def test_vault_write_data_fallback_bad_params(self, vault_client, opt_data, capfd): + client = vault_client + client.mock_add_spec(['write']) + + with pytest.raises(SystemExit) as e: + vault_write.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code != 0, "result: %r" % (result,) + assert re.search(r"To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1\.2", result['msg']) is not None + + client.write.assert_not_called() + + @pytest.mark.parametrize( + 'opt_data', + [ + {"item1": 'item1_value'}, + {"item2": 'item2_value'}, + {"item1": 'item1_value', "item2": 'item2_value'}, + ], + ) + @pytest.mark.parametrize('patch_ansible_module', [[_combined_options(), 'data']], indirect=True) + def test_vault_write_data_fallback_write(self, vault_client, opt_data, patch_ansible_module, approle_secret_id_write_response, capfd): + client = vault_client + client.mock_add_spec(['write']) + client.write.return_value = approle_secret_id_write_response + + with pytest.raises(SystemExit) as e: + vault_write.main() + + out, err = capfd.readouterr() + result = json.loads(out) + + assert e.value.code == 0, "result: %r" % (result,) + + client.write.assert_called_once_with(path=patch_ansible_module['path'], wrap_ttl=None, **opt_data) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/conftest.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/conftest.py deleted file mode 100644 index bf577a2d0..000000000 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/conftest.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2022 Brian Scholer (@briantist) -# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) -# SPDX-License-Identifier: GPL-3.0-or-later - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -# pylint: disable=wildcard-import,unused-wildcard-import -from ...module_utils.authentication.conftest import * diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py deleted file mode 100644 index 3dbc4c7fc..000000000 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2022 Brian Scholer (@briantist) -# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) -# SPDX-License-Identifier: GPL-3.0-or-later - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import pytest - -from ansible.utils.unsafe_proxy import AnsibleUnsafe, AnsibleUnsafeBytes, AnsibleUnsafeText - -from ansible_collections.community.hashi_vault.tests.unit.compat import mock - -from ansible_collections.community.hashi_vault.plugins.module_utils._auth_method_token import ( - HashiVaultAuthMethodToken, -) - - -@pytest.fixture -def option_dict(): - return { - 'auth_method': 'fake', - 'token': None, - 'token_path': None, - 'token_file': '.vault-token', - 'token_validate': True, - } - - -@pytest.fixture(params=[AnsibleUnsafeBytes(b'ub_opaque'), AnsibleUnsafeText(u'ut_opaque'), b'b_opaque', u't_opaque']) -def stringy(request): - return request.param - - -@pytest.fixture -def auth_token(adapter, warner, deprecator): - return HashiVaultAuthMethodToken(adapter, warner, deprecator) - - -class TestAuthToken(object): - def test_auth_token_unsafes(self, auth_token, client, adapter, stringy): - adapter.set_option('token', stringy) - adapter.set_option('token_validate', False) - - wrapper = mock.Mock(wraps=auth_token._stringify) - - with mock.patch.object(auth_token, '_stringify', wrapper): - response = auth_token.authenticate(client, use_token=True, lookup_self=False) - - assert isinstance(response['auth']['client_token'], (bytes, type(u''))), repr(response['auth']['client_token']) - assert isinstance(client.token, (bytes, type(u''))), repr(client.token) - assert not isinstance(response['auth']['client_token'], AnsibleUnsafe), repr(response['auth']['client_token']) - assert not isinstance(client.token, AnsibleUnsafe), repr(client.token) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py index 620583b41..aa71687b4 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py @@ -8,10 +8,11 @@ __metaclass__ = type import pytest -from ansible.errors import AnsibleError +from re import escape as re_escape + +from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.plugins.lookup import LookupBase -from ....compat import mock from ......plugins.plugin_utils._hashi_vault_plugin import HashiVaultPlugin from ......plugins.plugin_utils._hashi_vault_lookup_base import HashiVaultLookupBase @@ -72,7 +73,6 @@ class TestHashiVaultLookupBase(object): with pytest.raises(TypeError): parsed = hashi_vault_lookup_module.parse_kev_term('key1=value1', first_unqualified='fake') - # TODO: v5.0.0 - should raise not warn: https://github.com/ansible-collections/community.hashi_vault/pull/350 @pytest.mark.parametrize('term', [ 'one secret=two a=1 b=2', 'a=1 secret=one b=2 secret=two', @@ -80,10 +80,10 @@ class TestHashiVaultLookupBase(object): ]) def test_parse_kev_term_duplicate_option(self, term, hashi_vault_lookup_module): dup_key = 'secret' - removed_in = '5.0.0' - expected_template = "Duplicate key '%s' in the term string '%s'.\nIn version %s of the collection, this will raise an exception." - expected_msg = expected_template % (dup_key, term, removed_in) + expected_template = "Duplicate key '%s' in the term string '%s'." + expected_msg = expected_template % (dup_key, term) + expected_re = re_escape(expected_msg) + expected_match = "^%s$" % (expected_re,) - with mock.patch('ansible_collections.community.hashi_vault.plugins.plugin_utils._hashi_vault_lookup_base.display') as display: + with pytest.raises(AnsibleOptionsError, match=expected_match): hashi_vault_lookup_module.parse_kev_term(term, plugin_name='fake', first_unqualified=dup_key) - display.deprecated.assert_called_once_with(expected_msg, removed_in) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py index 5c1aa7ed6..dd292cf10 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py @@ -15,18 +15,33 @@ __metaclass__ = type import pytest +from packaging import version +from ansible.release import __version__ as ansible_version from ansible.plugins import AnsiblePlugin -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter +from ......plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter -class FakePlugin(AnsiblePlugin): - _load_name = 'community.hashi_vault.fake' +ver = version.parse(ansible_version) +cutoff = version.parse('2.17') +option_adapter_from_plugin_marks = pytest.mark.option_adapter_raise_on_missing if ver.release >= cutoff.release else [] +# https://github.com/ansible-collections/community.hashi_vault/issues/417 + + +def _generate_options(opts: dict) -> dict: + return {k: {"type": type(v).__name__} if v is not None else {} for k, v in opts.items()} @pytest.fixture def ansible_plugin(sample_dict): - plugin = FakePlugin() + optdef = _generate_options(opts=sample_dict) + + class LookupModule(AnsiblePlugin): + _load_name = 'community.hashi_vault.fake' + + import ansible.constants as C + C.config.initialize_plugin_configuration_definitions("lookup", LookupModule._load_name, optdef) + plugin = LookupModule() plugin._options = sample_dict return plugin @@ -39,7 +54,11 @@ def adapter_from_ansible_plugin(ansible_plugin): return _create_adapter_from_ansible_plugin -@pytest.fixture(params=['dict', 'dict_defaults', 'ansible_plugin']) +@pytest.fixture(params=[ + 'dict', + 'dict_defaults', + pytest.param('ansible_plugin', marks=option_adapter_from_plugin_marks), +]) def adapter(request, adapter_from_dict, adapter_from_dict_defaults, adapter_from_ansible_plugin): return { 'dict': adapter_from_dict, diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py index e78feec17..2d6d16ae7 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py +++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py @@ -12,4 +12,4 @@ __metaclass__ = type # So we really do want to import * and so we disable lint failure on wildcard imports. # # pylint: disable=wildcard-import,unused-wildcard-import -from ansible_collections.community.hashi_vault.tests.unit.plugins.module_utils.option_adapter.test_hashi_vault_option_adapter import * +from ...module_utils.option_adapter.test_hashi_vault_option_adapter import * diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py deleted file mode 100644 index 1fcd3fd5e..000000000 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2022 Brian Scholer (@briantist) -# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) -# SPDX-License-Identifier: GPL-3.0-or-later - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import pytest - -from ansible.utils.unsafe_proxy import AnsibleUnsafe, AnsibleUnsafeBytes, AnsibleUnsafeText - -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import _stringify - - -@pytest.fixture -def uvalue(): - return u'fake123' - - -@pytest.fixture -def bvalue(): - return b'fake456' - - -class TestHashiVaultCommonStringify(object): - @pytest.mark.parametrize('unsafe', [True, False]) - def test_stringify_bytes(self, unsafe, bvalue): - token = bvalue - if unsafe: - token = AnsibleUnsafeBytes(token) - - r = _stringify(token) - - assert isinstance(r, bytes) - assert not isinstance(r, AnsibleUnsafe) - - @pytest.mark.parametrize('unsafe', [True, False]) - def test_stringify_unicode(self, unsafe, uvalue): - token = uvalue - utype = type(token) - if unsafe: - token = AnsibleUnsafeText(token) - - r = _stringify(token) - - assert isinstance(r, utype) - assert not isinstance(r, AnsibleUnsafe) diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py deleted file mode 100644 index e71e625c0..000000000 --- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2022 Brian Scholer (@briantist) -# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) -# SPDX-License-Identifier: GPL-3.0-or-later - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import pytest - -from ansible.utils.unsafe_proxy import AnsibleUnsafeBytes, AnsibleUnsafeText - -from ansible_collections.community.hashi_vault.tests.unit.compat import mock -from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultHelper - - -@pytest.fixture -def hashi_vault_helper(): - return HashiVaultHelper() - - -@pytest.fixture -def expected_stringify_candidates(): - return set([ - 'token', - 'namespace', - ]) - - -class TestHashiVaultHelper(object): - def test_expected_stringify_candidates(self, hashi_vault_helper, expected_stringify_candidates): - # If we add more candidates to the set without updating the tests, - # this will help us catch that. The purpose is not to simply update - # the set in the fixture, but to also add specific tests where appropriate. - assert hashi_vault_helper.STRINGIFY_CANDIDATES == expected_stringify_candidates, '%r' % ( - hashi_vault_helper.STRINGIFY_CANDIDATES ^ expected_stringify_candidates - ) - - @pytest.mark.parametrize('input', [b'one', u'two', AnsibleUnsafeBytes(b'three'), AnsibleUnsafeText(u'four')]) - @pytest.mark.parametrize('stringify', [True, False]) - def test_get_vault_client_stringify(self, hashi_vault_helper, expected_stringify_candidates, input, stringify): - kwargs = { - '__no_candidate': AnsibleUnsafeText(u'value'), - } - expected_calls = [] - for k in expected_stringify_candidates: - v = '%s_%s' % (k, input) - kwargs[k] = v - if stringify: - expected_calls.append(mock.call(v)) - - wrapper = mock.Mock(wraps=hashi_vault_helper._stringify) - with mock.patch('hvac.Client'): - with mock.patch.object(hashi_vault_helper, '_stringify', wrapper): - hashi_vault_helper.get_vault_client(hashi_vault_stringify_args=stringify, **kwargs) - - assert wrapper.call_count == len(expected_calls) - wrapper.assert_has_calls(expected_calls) diff --git a/ansible_collections/community/hashi_vault/tests/unit/requirements.txt b/ansible_collections/community/hashi_vault/tests/unit/requirements.txt index d8844e35b..af9366e75 100644 --- a/ansible_collections/community/hashi_vault/tests/unit/requirements.txt +++ b/ansible_collections/community/hashi_vault/tests/unit/requirements.txt @@ -1,15 +1,3 @@ -# the collection supports python 3.6 and higher, however the constraints for -# earlier python versions are still needed for Ansible < 2.12 which doesn't -# support tests/config.yml, so that unit tests (which will be skipped) won't -# choke on installing requirements. -hvac >= 0.10.6, != 0.10.12, != 0.10.13, < 1.0.0 ; python_version == '2.7' # bugs in 0.10.12 and 0.10.13 prevent it from working in Python 2 -hvac >= 0.10.6, < 1.0.0 ; python_version == '3.5' # py3.5 support will be dropped in 1.0.0 -hvac >= 0.10.6 ; python_version >= '3.6' - -# these should be satisfied naturally by the requests versions required by hvac anyway -urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06 -urllib3 >= 1.15, <2.0.0 ; python_version < '3.6' # https://urllib3.readthedocs.io/en/latest/v2-roadmap.html#optimized-for-python-3-6 - -# azure-identity 1.7.0 depends on cryptography 2.5 which drops python 2.6 support -azure-identity < 1.7.0; python_version < '2.7' -azure-identity; python_version >= '2.7' +hvac +urllib3 +azure-identity diff --git a/ansible_collections/community/hashi_vault/tests/utils/constraints.txt b/ansible_collections/community/hashi_vault/tests/utils/constraints.txt deleted file mode 100644 index f0efeb2e8..000000000 --- a/ansible_collections/community/hashi_vault/tests/utils/constraints.txt +++ /dev/null @@ -1,62 +0,0 @@ -coverage >= 4.2, < 5.0.0, != 4.3.2 ; python_version <= '3.7' # features in 4.2+ required, avoid known bug in 4.3.2 on python 2.6, coverage 5.0+ incompatible -coverage >= 4.5.4, < 5.0.0 ; python_version > '3.7' # coverage had a bug in < 4.5.4 that would cause unit tests to hang in Python 3.8, coverage 5.0+ incompatible -cryptography < 2.2 ; python_version < '2.7' # cryptography 2.2 drops support for python 2.6 -deepdiff < 4.0.0 ; python_version < '3' # deepdiff 4.0.0 and later require python 3 -jinja2 < 2.11 ; python_version < '2.7' # jinja2 2.11 and later require python 2.7 or later -urllib3 < 1.24 ; python_version < '2.7' # urllib3 1.24 and later require python 2.7 or later -pywinrm >= 0.3.0 # message encryption support -sphinx < 1.6 ; python_version < '2.7' # sphinx 1.6 and later require python 2.7 or later -sphinx < 1.8 ; python_version >= '2.7' # sphinx 1.8 and later are currently incompatible with rstcheck 3.3 -pygments >= 2.4.0 # Pygments 2.4.0 includes bugfixes for YAML and YAML+Jinja lexers -wheel < 0.30.0 ; python_version < '2.7' # wheel 0.30.0 and later require python 2.7 or later -yamllint != 1.8.0, < 1.14.0 ; python_version < '2.7' # yamllint 1.8.0 and 1.14.0+ require python 2.7+ -pycrypto >= 2.6 # Need features found in 2.6 and greater -ncclient >= 0.5.2 # Need features added in 0.5.2 and greater -idna < 2.6, >= 2.5 # linode requires idna < 2.9, >= 2.5, requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead -paramiko < 2.4.0 ; python_version < '2.7' # paramiko 2.4.0 drops support for python 2.6 -pytest < 3.3.0 ; python_version < '2.7' # pytest 3.3.0 drops support for python 2.6 -pytest < 5.0.0 ; python_version == '2.7' # pytest 5.0.0 and later will no longer support python 2.7 -pytest-forked < 1.0.2 ; python_version < '2.7' # pytest-forked 1.0.2 and later require python 2.7 or later -pytest-forked >= 1.0.2 ; python_version >= '2.7' # pytest-forked before 1.0.2 does not work with pytest 4.2.0+ (which requires python 2.7+) -ntlm-auth >= 1.3.0 # message encryption support using cryptography -requests < 2.20.0 ; python_version < '2.7' # requests 2.20.0 drops support for python 2.6 -requests-ntlm >= 1.1.0 # message encryption support -requests-credssp >= 0.1.0 # message encryption support -voluptuous >= 0.11.0 # Schema recursion via Self -openshift >= 0.6.2, < 0.9.0 # merge_type support -virtualenv < 16.0.0 ; python_version < '2.7' # virtualenv 16.0.0 and later require python 2.7 or later -pathspec < 0.6.0 ; python_version < '2.7' # pathspec 0.6.0 and later require python 2.7 or later -pyopenssl < 18.0.0 ; python_version < '2.7' # pyOpenSSL 18.0.0 and later require python 2.7 or later -pyfmg == 0.6.1 # newer versions do not pass current unit tests -pyyaml < 5.1 ; python_version < '2.7' # pyyaml 5.1 and later require python 2.7 or later -pycparser < 2.19 ; python_version < '2.7' # pycparser 2.19 and later require python 2.7 or later -mock >= 2.0.0 # needed for features backported from Python 3.6 unittest.mock (assert_called, assert_called_once...) -pytest-mock >= 1.4.0 # needed for mock_use_standalone_module pytest option -xmltodict < 0.12.0 ; python_version < '2.7' # xmltodict 0.12.0 and later require python 2.7 or later -lxml < 4.3.0 ; python_version < '2.7' # lxml 4.3.0 and later require python 2.7 or later -pyvmomi < 6.0.0 ; python_version < '2.7' # pyvmomi 6.0.0 and later require python 2.7 or later -pyone == 1.1.9 # newer versions do not pass current integration tests -boto3 < 1.11 ; python_version < '2.7' # boto3 1.11 drops Python 2.6 support -botocore >= 1.10.0, < 1.14 ; python_version < '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca; botocore 1.14 drops Python 2.6 support -botocore >= 1.10.0 ; python_version >= '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca -setuptools < 45 ; python_version <= '2.7' # setuptools 45 and later require python 3.5 or later -cffi >= 1.14.2, != 1.14.3 # Yanked version which older versions of pip will still install: - -# freeze pylint and its requirements for consistent test results -astroid == 2.2.5 -isort == 4.3.15 -lazy-object-proxy == 1.3.1 -mccabe == 0.6.1 -pylint == 2.3.1 -typed-ast == 1.4.0 # 1.4.0 is required to compile on Python 3.8 -wrapt == 1.11.1 - -# hvac -hvac >= 0.10.6, != 0.10.12, != 0.10.13, < 1.0.0 ; python_version == '2.7' # bugs in 0.10.12 and 0.10.13 prevent it from working in Python 2 -hvac >= 0.10.6, < 1.0.0 ; python_version == '3.5' # py3.5 support will be dropped in 1.0.0 -hvac >= 0.10.6 ; python_version >= '3.6' - -# urllib3 -# these should be satisfied naturally by the requests versions required by hvac anyway -urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06 -urllib3 >= 1.15, <2.0.0 ; python_version < '3.6' # https://urllib3.readthedocs.io/en/latest/v2-roadmap.html#optimized-for-python-3-6 -- cgit v1.2.3