diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7583855..88475cb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,15 +10,20 @@ jobs: integration-test: environment: test runs-on: ubuntu-latest + defaults: + run: + working-directory: ansible/ansible_collections/devolutions/dvls steps: - name: Checkout code uses: actions/checkout@v4 + with: + path: ansible/ansible_collections/devolutions/dvls - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.x + python-version: 3.13 - name: Install Python dependencies run: | @@ -26,7 +31,10 @@ jobs: python3 -m pip install -r requirements.txt python3 -m pip list - - name: Build + - name: Test code sanity + run: ansible-test sanity + + - name: Build collection id: build run: | OUTPUT=$(ansible-galaxy collection build) @@ -37,11 +45,30 @@ jobs: - name: Install collection run: ansible-galaxy collection install ${{ steps.build.outputs.collection_path }} --force - working-directory: tests/integration + working-directory: ansible/ansible_collections/devolutions/dvls/tests/integration + + - name: Test collection documentation + run: | + # Generate the list of modules dynamically + ansible_modules=($(ansible-doc -l devolutions.dvls | awk '{print $1}')) + + # Check if any modules were found + if [ ${#ansible_modules[@]} -eq 0 ]; then + echo "Error: No modules found for devolutions.dvls." + exit 1 + fi + echo "Modules: ${ansible_modules[@]}" + + # Loop through each module and run ansible-doc + for ansible_module in "${ansible_modules[@]}"; do + echo "Running ansible-doc for module: $ansible_module" + ansible-doc -t module "$ansible_module" + echo "----------------------------------------------------" + done - name: Run get-vaults run: ansible-playbook test_manage_server.yml - working-directory: tests/integration + working-directory: ansible/ansible_collections/devolutions/dvls/tests/integration env: DVLS_APP_KEY: ${{ secrets.DVLS_APP_KEY }} DVLS_APP_SECRET: ${{ secrets.DVLS_APP_SECRET }} @@ -50,7 +77,7 @@ jobs: - name: Run get-secrets run: ansible-playbook test_manage_secrets.yml - working-directory: tests/integration + working-directory: ansible/ansible_collections/devolutions/dvls/tests/integration env: DVLS_APP_KEY: ${{ secrets.DVLS_APP_KEY }} DVLS_APP_SECRET: ${{ secrets.DVLS_APP_SECRET }} diff --git a/.gitignore b/.gitignore index b462cdc..9a90395 100644 --- a/.gitignore +++ b/.gitignore @@ -3,13 +3,17 @@ .lock .ansible +# asnible-test +output + # vscode.. .vscode # macosx... .DS_Store -# python envs +# python +*.pyc .env .venv env diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..ef486c5 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1 @@ +ignore = ["E402"] diff --git a/README.md b/README.md index 0f0c77d..063d043 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This Ansible module allows you to authenticate with DVLS and fetch server inform - Flexible support for static secrets or fetching all secrets in a vault. ## Requirements -- Ansible +- Ansible 2.18 - Python `requests` library - A DVLS application identity (create at `{your-dvls-url}/administration/applications`). - The application must have permissions to fetch the desired secrets. @@ -107,7 +107,6 @@ Example response "server": { "accessURI": "https://example.dvls-server.com/", "changed": false, - "expirationDate": "2030-12-31T23:59:59", "failed": false, "vaults": [ { @@ -129,16 +128,16 @@ Example response ## Secrets definition -To access a particular field within a secret, you can use the format ```{{ secrets['name-or-id'].value }}```. Here’s a breakdown of the available categories and their fields: +To access a particular field within a secret, you can use the format ```{{ secrets['name-or-id'].value }}```. Here's a breakdown of the available categories and their fields: -| **Category** | **Fields** | -|---------------------------|---------------------------------------------------------------------------| -| Username and password | `domain`, `password`, `username` | -| Connection string | `connectionString` | -| Secret | `password` | -| API key | `apiId`, `apiKey`, `tenantId` | +| **Category** | **Fields** | +|---------------------------|---------------------------------------------------------------------------------------------------------------------------| +| Username and password | `domain`, `password`, `username` | +| Connection string | `connectionString` | +| Secret | `password` | +| API key | `apiId`, `apiKey`, `tenantId` | | SSH key | `domain`, `password`, `privateKeyData`, `privateKeyOverridePassword`, `privateKeyPassPhrase`, `publicKeyData`, `username` | -| Azure service principal | `clientId`, `clientSecret`, `tenantId` | +| Azure service principal | `clientId`, `clientSecret`, `tenantId` | ### Example using secret value diff --git a/galaxy.yml b/galaxy.yml index 37ca3bc..9753b95 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,6 +1,6 @@ namespace: devolutions name: dvls -version: 1.2.1 +version: 1.2.2 readme: README.md authors: - Danny Bédard @@ -16,4 +16,4 @@ repository: https://github.com/Devolutions/ansible-dvls documentation: https://github.com/Devolutions/ansible-dvls homepage: https://github.com/Devolutions/ansible-dvls issues: https://github.com/Devolutions/ansible-dvls/issues -build_ignore: [.github, requirements.txt, tests] +build_ignore: [.github, .ruff.toml, requirements.txt, tests] diff --git a/meta/runtime.yml b/meta/runtime.yml index 2ee3c9f..893e618 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,2 +1,2 @@ --- -requires_ansible: '>=2.9.10' +requires_ansible: '~=2.18' diff --git a/plugins/module_utils/auth.py b/plugins/module_utils/auth.py index 3625044..ca9eb8f 100644 --- a/plugins/module_utils/auth.py +++ b/plugins/module_utils/auth.py @@ -1,36 +1,43 @@ -import requests import json +import traceback + +try: + import requests +except ImportError: + HAS_REQUESTS_LIBRARY = False + REQUESTS_LIBRARY_IMPORT_ERROR = traceback.format_exc() +else: + HAS_REQUESTS_LIBRARY_LIBRARY = True + REQUESTS_LIBRARY_IMPORT_ERROR = None + def login(server_base_url, app_key, app_secret): login_url = f"{server_base_url}/api/v1/login" - login_data = { - "appKey": app_key, - "appSecret": app_secret - } - login_headers = { - "Content-Type": "application/json" - } + login_data = {"appKey": app_key, "appSecret": app_secret} + login_headers = {"Content-Type": "application/json"} try: - response = requests.post(login_url, headers=login_headers, data=json.dumps(login_data)) + response = requests.post( + login_url, headers=login_headers, data=json.dumps(login_data) + ) response.raise_for_status() except Exception as e: - raise Exception(f"Failed to login: Unable to reach the server. Verify your network connection and server URL: {e}") + raise Exception( + f"Failed to login: Unable to reach the server. Verify your network connection and server URL: {e}" + ) auth_response = response.json() - token = auth_response.get('tokenId') + token = auth_response.get("tokenId") if not token or token == "null": raise Exception("Failed to login or obtain token.") return token + def logout(server_base_url, token): logout_url = f"{server_base_url}/api/v1/logout" - logout_headers = { - "Content-Type": "application/json", - "tokenId": token - } + logout_headers = {"Content-Type": "application/json", "tokenId": token} requests.post(logout_url, headers=logout_headers) return None diff --git a/plugins/module_utils/server.py b/plugins/module_utils/server.py index 2c030f9..a11089e 100644 --- a/plugins/module_utils/server.py +++ b/plugins/module_utils/server.py @@ -1,28 +1,37 @@ -import requests +import traceback + +try: + import requests +except ImportError: + HAS_REQUESTS_LIBRARY = False + REQUESTS_LIBRARY_IMPORT_ERROR = traceback.format_exc() +else: + HAS_REQUESTS_LIBRARY_LIBRARY = True + REQUESTS_LIBRARY_IMPORT_ERROR = None + def public_instance_information(server_base_url, token): url = f"{server_base_url}/api/public-instance-information" - headers = { - "Content-Type": "application/json", - "tokenId": token - } + headers = {"Content-Type": "application/json", "tokenId": token} try: response = requests.get(url, headers=headers) return response.json() except Exception as e: - raise Exception(f"An error occurred while fetching public instance information: {e}") + raise Exception( + f"An error occurred while fetching public instance information: {e}" + ) + def private_instance_information(server_base_url, token): url = f"{server_base_url}/api/private-instance-information" - headers = { - "Content-Type": "application/json", - "tokenId": token - } + headers = {"Content-Type": "application/json", "tokenId": token} try: response = requests.get(url, headers=headers) response.raise_for_status() return response.json() except Exception as e: - raise Exception(f"An error occurred while fetching private instance information: {e}") + raise Exception( + f"An error occurred while fetching private instance information: {e}" + ) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index f87f293..4fc63d4 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -1,10 +1,13 @@ -from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import get_vault_entry +from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import ( + get_vault_entry, +) + def get_sensible_value(server_base_url, token, vault_id, entries): fetched_secrets = {} - if isinstance(entries, dict) and 'data' in entries: - entries = entries.get('data', []) + if isinstance(entries, dict) and "data" in entries: + entries = entries.get("data", []) if not isinstance(entries, list): return {"error": f"Expected list of entries, got {type(entries).__name__}"} @@ -13,14 +16,14 @@ def get_sensible_value(server_base_url, token, vault_id, entries): if not isinstance(secret, dict): continue - entry_name = secret.get('name') - if not entry_name or 'id' not in secret: + entry_name = secret.get("name") + if not entry_name or "id" not in secret: continue try: - entry = get_vault_entry(server_base_url, token, vault_id, secret['id']) - if isinstance(entry, dict) and 'data' in entry: - fetched_secrets[entry_name] = entry['data'] + entry = get_vault_entry(server_base_url, token, vault_id, secret["id"]) + if isinstance(entry, dict) and "data" in entry: + fetched_secrets[entry_name] = entry["data"] except Exception as e: fetched_secrets[entry_name] = {"error": str(e)} diff --git a/plugins/module_utils/vaults.py b/plugins/module_utils/vaults.py index c1bb27f..a61935a 100644 --- a/plugins/module_utils/vaults.py +++ b/plugins/module_utils/vaults.py @@ -1,30 +1,35 @@ -import requests +import traceback + +try: + import requests +except ImportError: + HAS_REQUESTS_LIBRARY = False + REQUESTS_LIBRARY_IMPORT_ERROR = traceback.format_exc() +else: + HAS_REQUESTS_LIBRARY_LIBRARY = True + REQUESTS_LIBRARY_IMPORT_ERROR = None + def get_vaults(server_base_url, token): vaults_url = f"{server_base_url}/api/v1/vault" - vaults_headers = { - "Content-Type": "application/json", - "tokenId": token - } + vaults_headers = {"Content-Type": "application/json", "tokenId": token} try: response = requests.get(vaults_url, headers=vaults_headers) response.raise_for_status() json_data = response.json() - if 'data' not in json_data: + if "data" not in json_data: raise ValueError(f"'data' key missing in response: {json_data}") - return json_data.get('data', []) + return json_data.get("data", []) except Exception as e: raise Exception(f"An error occurred while getting vaults: {e}") + def get_vault_entry(server_base_url, token, vault_id, entry_id): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry/{entry_id}" - vault_headers = { - "Content-Type": "application/json", - "tokenId": token - } + vault_headers = {"Content-Type": "application/json", "tokenId": token} try: response = requests.get(vault_url, headers=vault_headers) @@ -34,60 +39,60 @@ def get_vault_entry(server_base_url, token, vault_id, entry_id): except Exception as e: raise Exception(f"An error occurred while getting a vault entry: {e}") + def get_vault_entry_from_name(server_base_url, token, vault_id, entry_name): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" - vault_headers = { - "Content-Type": "application/json", - "tokenId": token - } + vault_headers = {"Content-Type": "application/json", "tokenId": token} try: - response = requests.get(vault_url, headers=vault_headers, params={'name': entry_name}) + response = requests.get( + vault_url, headers=vault_headers, params={"name": entry_name} + ) response.raise_for_status() return response.json() except Exception as e: raise Exception(f"An error occurred while getting a vault entry: {e}") + def get_vault_entry_from_tag(server_base_url, token, vault_id, entry_tag): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" - vault_headers = { - "Content-Type": "application/json", - "tokenId": token - } + vault_headers = {"Content-Type": "application/json", "tokenId": token} try: - response = requests.get(vault_url, headers=vault_headers, params={'tag': entry_tag}) + response = requests.get( + vault_url, headers=vault_headers, params={"tag": entry_tag} + ) response.raise_for_status() return response.json() except Exception as e: raise Exception(f"An error occurred while getting a vault entry: {e}") + def get_vault_entry_from_path(server_base_url, token, vault_id, entry_path): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" - vault_headers = { - "Content-Type": "application/json", - "tokenId": token - } + vault_headers = {"Content-Type": "application/json", "tokenId": token} try: - response = requests.get(vault_url, headers=vault_headers, params={'path': entry_path}) + response = requests.get( + vault_url, headers=vault_headers, params={"path": entry_path} + ) response.raise_for_status() return response.json() except Exception as e: raise Exception(f"An error occurred while getting a vault entry: {e}") + def get_vault_entry_from_type(server_base_url, token, vault_id, entry_type): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" - vault_headers = { - "Content-Type": "application/json", - "tokenId": token - } + vault_headers = {"Content-Type": "application/json", "tokenId": token} try: - response = requests.get(vault_url, headers=vault_headers, params={'type': entry_type}) + response = requests.get( + vault_url, headers=vault_headers, params={"type": entry_type} + ) response.raise_for_status() return response.json() @@ -97,25 +102,23 @@ def get_vault_entry_from_type(server_base_url, token, vault_id, entry_type): def get_vault_entries(server_base_url, token, vault_id): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" - vault_headers = { - "Content-Type": "application/json", - "tokenId": token - } + vault_headers = {"Content-Type": "application/json", "tokenId": token} try: response = requests.get(vault_url, headers=vault_headers) response.raise_for_status() json_data = response.json() - if 'data' not in json_data: + if "data" not in json_data: raise ValueError(f"'data' key missing in response: {json_data}") - return json_data.get('data', []) + return json_data.get("data", []) except Exception as e: raise Exception(f"An error occurred while getting vault entries: {e}") + def find_entry_by_name(entries, name): for entry in entries: - if entry.get('name') == name: + if entry.get("name") == name: return entry return None diff --git a/plugins/modules/create_secret.py b/plugins/modules/create_secret.py index 684c60f..d5af2c6 100644 --- a/plugins/modules/create_secret.py +++ b/plugins/modules/create_secret.py @@ -1,17 +1,5 @@ #!/usr/bin/python -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout -from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import ( - get_vault_entries, - find_entry_by_name, -) -import requests - DOCUMENTATION = r""" --- module: create_secret @@ -19,8 +7,8 @@ short_description: create or update a credential to DVLS description: - - This module logs into the DVLS (Devolutions Server) service, checks if a entry inside a given path already exists and updates or creates a Credential by name. - - The module requires DVLS application credentials, a server base URL and the data needed to create a secret. + - Logs into the DVLS (Devolutions Server) service, checks if an entry exists at a given path, and updates or creates a Credential by name. + - Requires DVLS application credentials, a server base URL and the data needed to create a secret. options: server_base_url: @@ -42,8 +30,7 @@ secret: description: the credential object, containing username and password. required: true - type: list - elements: dict + type: dict suboptions: secret_name: description: the entry name/username. @@ -61,7 +48,7 @@ description: the type of secret that will get created. required: false type: str - default: Credentials + default: Credential secret_subtype: description: the secret subtype. required: false @@ -77,7 +64,7 @@ """ EXAMPLES = r""" -- name: Upload Credentials to DVLS +- name: Upload Credential to DVLS devolutions.dvls.create_secret: server_base_url: "https://example.yourcompany.com" app_key: "{{ lookup('env', 'DVLS_APP_KEY') }}" @@ -94,32 +81,62 @@ description: returns the ID of the created/updated entry. type: dict returned: changed + """ +import traceback + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout +from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import ( + get_vault_entries, + find_entry_by_name, +) + +try: + import requests +except ImportError: + HAS_REQUESTS_LIBRARY = False + REQUESTS_LIBRARY_IMPORT_ERROR = traceback.format_exc() +else: + HAS_REQUESTS_LIBRARY = True + REQUESTS_LIBRARY_IMPORT_ERROR = None + def run_module(): - module_args = dict( + argument_spec = dict( server_base_url=dict(type="str", required=True), - app_key=dict(type="str", required=True), - app_secret=dict(type="str", required=True), + app_key=dict(type="str", required=True, no_log=True), + app_secret=dict(type="str", required=True, no_log=True), vault_id=dict(type="str", required=True), secret=dict( type="dict", options=dict( - secret_name=dict(type="str", required=True), - value=dict(type="str", required=True), - secret_path=dict(type="str", required=False), - secret_type=dict(type="str", required=False, default="Credential"), - secret_subtype=dict(type="str", required=False, default="Default"), - secret_description=dict(type="str", required=False), + secret_name=dict(type="str", required=True, no_log=False), + value=dict(type="str", required=True, no_log=True), + secret_path=dict(type="str", required=False, no_log=False), + secret_type=dict( + type="str", required=False, default="Credential", no_log=False + ), + secret_subtype=dict( + type="str", required=False, default="Default", no_log=False + ), + secret_description=dict(type="str", required=False, no_log=False), ), required=True, + no_log=False, ), ) result = dict() - module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + + if not HAS_REQUESTS_LIBRARY: + module.fail_json( + msg=missing_required_lib("requests"), + exception=REQUESTS_LIBRARY_IMPORT_ERROR, + ) if module.check_mode: module.exit_json(**result) diff --git a/plugins/modules/fetch_secrets.py b/plugins/modules/fetch_secrets.py index 81de677..0f1ee33 100644 --- a/plugins/modules/fetch_secrets.py +++ b/plugins/modules/fetch_secrets.py @@ -1,24 +1,5 @@ #!/usr/bin/python -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout -from ansible_collections.devolutions.dvls.plugins.module_utils.utils import ( - get_sensible_value, -) -from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import ( - get_vault_entry, - get_vault_entry_from_name, - get_vault_entry_from_tag, - get_vault_entry_from_type, - get_vault_entry_from_path, - get_vault_entries, -) - - DOCUMENTATION = r""" --- module: fetch_secrets @@ -26,8 +7,8 @@ short_description: Fetch secrets from DVLS description: - - This module logs into the DVLS (Devolutions Server) service, retrieves specified secrets from a specified vault by name or ID. - - The module requires DVLS application credentials, a server base URL, and either a secret name or ID. + - Logs into the DVLS (Devolutions Server) service, retrieves specified secrets from a specified vault by name or ID. + - Requires DVLS application credentials, a server base URL, and either a secret name or ID. options: server_base_url: @@ -48,7 +29,6 @@ type: str secrets: description: A list of secrets to fetch. Each secret can be specified by name or ID. - required: true type: list elements: dict suboptions: @@ -60,6 +40,18 @@ description: The ID of the secret to fetch. required: false type: str + secret_path: + description: The path of the secret to fetch. + required: false + type: str + secret_type: + description: The type of the secret to fetch. + required: false + type: str + secret_tag: + description: The tag of the secret to fetch. + required: false + type: str author: - Danny Bédard (@DannyBedard) @@ -86,30 +78,45 @@ returned: always """ +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout +from ansible_collections.devolutions.dvls.plugins.module_utils.utils import ( + get_sensible_value, +) +from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import ( + get_vault_entry, + get_vault_entry_from_name, + get_vault_entry_from_tag, + get_vault_entry_from_type, + get_vault_entry_from_path, + get_vault_entries, +) + def run_module(): - module_args = dict( + argument_spec = dict( server_base_url=dict(type="str", required=True), - app_key=dict(type="str", required=True), - app_secret=dict(type="str", required=True), + app_key=dict(type="str", required=True, no_log=True), + app_secret=dict(type="str", required=True, no_log=True), vault_id=dict(type="str", required=True), secrets=dict( type="list", elements="dict", options=dict( - secret_name=dict(type="str", required=False), - secret_id=dict(type="str", required=False), - secret_path=dict(type="str", required=False), - secret_type=dict(type="str", required=False), - secret_tag=dict(type="str", required=False), + secret_name=dict(type="str", required=False, no_log=False), + secret_id=dict(type="str", required=False, no_log=False), + secret_path=dict(type="str", required=False, no_log=False), + secret_type=dict(type="str", required=False, no_log=False), + secret_tag=dict(type="str", required=False, no_log=False), ), required=False, + no_log=False, ), ) result = dict() - module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if module.check_mode: module.exit_json(**result) diff --git a/plugins/modules/fetch_server.py b/plugins/modules/fetch_server.py index 607e5dd..6c64995 100644 --- a/plugins/modules/fetch_server.py +++ b/plugins/modules/fetch_server.py @@ -1,18 +1,5 @@ #!/usr/bin/python -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout -from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import get_vaults -from ansible_collections.devolutions.dvls.plugins.module_utils.server import ( - public_instance_information, - private_instance_information, -) - - DOCUMENTATION = r""" --- module: fetch_server @@ -20,8 +7,8 @@ short_description: Fetch server from DVLS description: - - This module logs into the DVLS (Devolutions Server) service, retrieves server information and vaults list. - - The module requires DVLS application credentials and a server base URL. + - Logs into the DVLS (Devolutions Server) service, retrieves server information and vaults list. + - Requires DVLS application credentials and a server base URL. options: server_base_url: @@ -43,11 +30,11 @@ EXAMPLES = r""" - name: Fetch dvls server information - server: + devolutions.dvls.fetch_server: server_base_url: "https://example.yourcompany.com" app_key: "{{ lookup('env', 'DVLS_APP_KEY') }}" app_secret: "{{ lookup('env', 'DVLS_APP_SECRET') }}" - register: server + register: server """ RETURN = r""" @@ -57,17 +44,25 @@ returned: always """ +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout +from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import get_vaults +from ansible_collections.devolutions.dvls.plugins.module_utils.server import ( + public_instance_information, + private_instance_information, +) + def run_module(): - module_args = dict( + argument_spec = dict( server_base_url=dict(type="str", required=True), - app_key=dict(type="str", required=True), - app_secret=dict(type="str", required=True), + app_key=dict(type="str", required=True, no_log=True), + app_secret=dict(type="str", required=True, no_log=True), ) result = dict() - module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if module.check_mode: module.exit_json(**result) @@ -83,15 +78,12 @@ def run_module(): public_info = public_instance_information(server_base_url, token) private_info = private_instance_information(server_base_url, token) - if "expirationDate" not in public_info["data"]: - raise KeyError("expirationDate missing from fetched server") if "version" not in public_info["data"]: raise KeyError("version missing from fetched server']") if "accessURI" not in private_info["data"]: raise KeyError("accessURI missing from fetched server") result = { - "expirationDate": public_info["data"].get("expirationDate"), "version": public_info["data"].get("version"), "accessURI": private_info["data"].get("accessURI"), "vaults": vaults, diff --git a/requirements.txt b/requirements.txt index 8e8b23f..fbebe5a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ -ansible==11.3.0 +ansible~=11.3 +ansible-lint~=25.1 requests==2.32.3 diff --git a/tests/debug/vscode/debug_create_secrets.py b/tests/debug/vscode/debug_create_secrets.py new file mode 100644 index 0000000..38d7e47 --- /dev/null +++ b/tests/debug/vscode/debug_create_secrets.py @@ -0,0 +1,28 @@ +# Copy this in the .vscode folder of your project to debug your module + +import sys +import os +import io +import json + +# Wrap arguments under ANSIBLE_MODULE_ARGS +mock_args = { + "ANSIBLE_MODULE_ARGS": { + "server_base_url": os.getenv("DVLS_SERVER_BASE_URL"), + "app_key": os.getenv("DVLS_APP_KEY"), + "app_secret": os.getenv("DVLS_APP_SECRET"), + "vault_id": os.getenv("DVLS_VAULT_ID"), + "secret": { + "secret_name": "test", + "value": "test" + } + } +} + +# Convert to bytes, wrap for stdin +input_bytes = json.dumps(mock_args).encode("utf-8") +sys.stdin = io.TextIOWrapper(io.BytesIO(input_bytes), encoding="utf-8") + +# Import and run your module +from ansible_collections.devolutions.dvls.plugins.modules import create_secret +create_secret.main() diff --git a/tests/debug/vscode/debug_fetch_secrets.py b/tests/debug/vscode/debug_fetch_secrets.py new file mode 100644 index 0000000..ea0eac7 --- /dev/null +++ b/tests/debug/vscode/debug_fetch_secrets.py @@ -0,0 +1,24 @@ +# Copy this in the .vscode folder of your project to debug your module + +import sys +import os +import io +import json + +# Wrap arguments under ANSIBLE_MODULE_ARGS +mock_args = { + "ANSIBLE_MODULE_ARGS": { + "server_base_url": os.getenv("DVLS_SERVER_BASE_URL"), + "app_key": os.getenv("DVLS_APP_KEY"), + "app_secret": os.getenv("DVLS_APP_SECRET"), + "vault_id": os.getenv("DVLS_VAULT_ID"), + } +} + +# Convert to bytes, wrap for stdin +input_bytes = json.dumps(mock_args).encode("utf-8") +sys.stdin = io.TextIOWrapper(io.BytesIO(input_bytes), encoding="utf-8") + +# Import and run your module +from ansible_collections.devolutions.dvls.plugins.modules import fetch_secrets +fetch_secrets.main() diff --git a/tests/debug/vscode/debug_fetch_server.py b/tests/debug/vscode/debug_fetch_server.py new file mode 100644 index 0000000..cd2843c --- /dev/null +++ b/tests/debug/vscode/debug_fetch_server.py @@ -0,0 +1,23 @@ +# Copy this in the .vscode folder of your project to debug your module + +import sys +import os +import io +import json + +# Wrap arguments under ANSIBLE_MODULE_ARGS +mock_args = { + "ANSIBLE_MODULE_ARGS": { + "server_base_url": os.getenv("DVLS_SERVER_BASE_URL"), + "app_key": os.getenv("DVLS_APP_KEY"), + "app_secret": os.getenv("DVLS_APP_SECRET") + } +} + +# Convert to bytes, wrap for stdin +input_bytes = json.dumps(mock_args).encode("utf-8") +sys.stdin = io.TextIOWrapper(io.BytesIO(input_bytes), encoding="utf-8") + +# Import and run your module +from ansible_collections.devolutions.dvls.plugins.modules import fetch_server +fetch_server.main() diff --git a/tests/debug/vscode/launch.json b/tests/debug/vscode/launch.json new file mode 100644 index 0000000..ffd9196 --- /dev/null +++ b/tests/debug/vscode/launch.json @@ -0,0 +1,50 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug - fetch_server.py", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/.vscode/debug_fetch_server.py", + "console": "integratedTerminal", + "env": { + "DVLS_SERVER_BASE_URL": "", + "DVLS_APP_KEY": "", + "DVLS_APP_SECRET": "", + "DVLS_VAULT_ID": "", + "PYTHONPATH": "/Users//dev/git/ansible" + }, + "justMyCode": false + }, + { + "name": "Debug - fetch_secrets.py", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/.vscode/debug_fetch_secrets.py", + "console": "integratedTerminal", + "env": { + "DVLS_SERVER_BASE_URL": "", + "DVLS_APP_KEY": "", + "DVLS_APP_SECRET": "", + "DVLS_VAULT_ID": "", + "PYTHONPATH": "/Users//dev/git/ansible" + }, + "justMyCode": false + }, + { + "name": "Debug - create_secrets.py", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/.vscode/debug_create_secrets.py", + "console": "integratedTerminal", + "env": { + "DVLS_SERVER_BASE_URL": "", + "DVLS_APP_KEY": "", + "DVLS_APP_SECRET": "", + "DVLS_VAULT_ID": "", + "PYTHONPATH": "/Users//dev/git/ansible" + }, + "justMyCode": false + } + ] +} diff --git a/tests/sanity/ignore-2.18.txt b/tests/sanity/ignore-2.18.txt new file mode 100644 index 0000000..9d461ee --- /dev/null +++ b/tests/sanity/ignore-2.18.txt @@ -0,0 +1,3 @@ +plugins/modules/fetch_secrets.py validate-modules:missing-gplv3-license # ignore license check +plugins/modules/create_secret.py validate-modules:missing-gplv3-license # ignore license check +plugins/modules/fetch_server.py validate-modules:missing-gplv3-license # ignore license check