diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index fcde2f0608..c117e290da 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -1399,6 +1399,8 @@ files: maintainers: $team_suse $tests/a_module.py: maintainers: felixfontein + $tests/fqdn_valid.py: + maintainers: vbotka ######################### tests/: labels: tests diff --git a/plugins/test/fqdn_valid.py b/plugins/test/fqdn_valid.py new file mode 100644 index 0000000000..1ec7742077 --- /dev/null +++ b/plugins/test/fqdn_valid.py @@ -0,0 +1,103 @@ +# Copyright (c) 2023, Vladimir Botka +# 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 + +from ansible.errors import AnsibleError +from ansible.module_utils.six import raise_from + +try: + from fqdn import FQDN +except ImportError as imp_exc: + ANOTHER_LIBRARY_IMPORT_ERROR = imp_exc +else: + ANOTHER_LIBRARY_IMPORT_ERROR = None + + +DOCUMENTATION = ''' + name: fqdn_valid + short_description: Validates fully-qualified domain names against RFC 1123 + version_added: 8.1.0 + author: Vladimir Botka (@vbotka) + requirements: + - fqdn>=1.5.1 (PyPI) + description: + - This test validates Fully Qualified Domain Names (FQDNs) + conforming to the Internet Engineering Task Force specification + RFC 1123 and RFC 952. + - The design intent is to validate that a string would be + traditionally acceptable as a public Internet hostname to + RFC-conforming software, which is a strict subset of the logic + in modern web browsers like Mozilla Firefox and Chromium that + determines whether make a DNS lookup. + - Certificate Authorities like Let's Encrypt run a narrower set of + string validation logic to determine validity for issuance. This + test is not intended to achieve functional parity with CA + issuance. + - Single label names are allowed by default (O(min_labels=1)). + options: + _input: + description: Name of the host. + type: str + required: true + min_labels: + description: Required minimum of labels, separated by period. + default: 1 + type: int + required: false + allow_underscores: + description: Allow underscore characters. + default: false + type: bool + required: false +''' + +EXAMPLES = ''' +- name: Make sure that hostname is valid + ansible.builtin.assert: + that: hostname is community.general.fqdn_valid + +- name: Make sure that hostname is at least 3 labels long (a.b.c) + ansible.builtin.assert: + that: hostname is community.general.fqdn_valid(min_labels=3) + +- name: Make sure that hostname is at least 2 labels long (a.b). Allow '_' + ansible.builtin.assert: + that: hostname is community.general.fqdn_valid(min_labels=2, allow_underscores=True) +''' + +RETURN = ''' + _value: + description: Whether the name is valid. + type: bool +''' + + +def fqdn_valid(name, min_labels=1, allow_underscores=False): + """ + Example: + - 'srv.example.com' is community.general.fqdn_valid + - 'foo_bar.example.com' is community.general.fqdn_valid(allow_underscores=True) + """ + + if ANOTHER_LIBRARY_IMPORT_ERROR: + raise_from( + AnsibleError('Python package fqdn must be installed to use this test.'), + ANOTHER_LIBRARY_IMPORT_ERROR + ) + + fobj = FQDN(name, min_labels=min_labels, allow_underscores=allow_underscores) + return (fobj.is_valid) + + +class TestModule(object): + ''' Ansible test hostname validity. + https://pypi.org/project/fqdn/ + ''' + + def tests(self): + return { + 'fqdn_valid': fqdn_valid, + } diff --git a/tests/integration/targets/test_fqdn_valid/aliases b/tests/integration/targets/test_fqdn_valid/aliases new file mode 100644 index 0000000000..12d1d6617e --- /dev/null +++ b/tests/integration/targets/test_fqdn_valid/aliases @@ -0,0 +1,5 @@ +# Copyright (c) Ansible Project +# 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 + +azp/posix/2 diff --git a/tests/integration/targets/test_fqdn_valid/runme.sh b/tests/integration/targets/test_fqdn_valid/runme.sh new file mode 100755 index 0000000000..cd97ac9493 --- /dev/null +++ b/tests/integration/targets/test_fqdn_valid/runme.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Copyright (c) Ansible Project +# 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 + +set -eux + +source virtualenv.sh + +# Requirements have to be installed prior to running ansible-playbook +# because plugins and requirements are loaded before the task runs + +pip install fqdn + +ANSIBLE_ROLES_PATH=../ ansible-playbook runme.yml "$@" diff --git a/tests/integration/targets/test_fqdn_valid/runme.yml b/tests/integration/targets/test_fqdn_valid/runme.yml new file mode 100644 index 0000000000..37f965b282 --- /dev/null +++ b/tests/integration/targets/test_fqdn_valid/runme.yml @@ -0,0 +1,8 @@ +--- +# Copyright (c) Ansible Project +# 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 + +- hosts: localhost + roles: + - {role: test_fqdn_valid} diff --git a/tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml b/tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml new file mode 100644 index 0000000000..36cfffad0c --- /dev/null +++ b/tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml @@ -0,0 +1,58 @@ +--- +# Copyright (c) Ansible Project +# 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 + +- name: Debug ansible_version + ansible.builtin.debug: + var: ansible_version + when: debug_test|d(false)|bool + tags: t0 + +- name: 1. Test valid hostnames. Default options. + block: + - name: "1. Default min_labels=1, allow_underscores=False" + ansible.builtin.debug: + msg: "hosts_invalid: {{ hosts_invalid }}" + when: debug_test|d(false)|bool + - name: Assert + ansible.builtin.assert: + that: hosts_invalid|difference(result)|length == 0 + vars: + hosts_valid: "{{ names1|select('community.general.fqdn_valid') }}" + hosts_invalid: "{{ names1|difference(hosts_valid) }}" + result: [-rv.example.com, -rv, s_v] + tags: t1 + +- name: 2. Test valid hostnames. allow_underscores=True + block: + - name: "2. allow_underscores=True, default min_labels=1" + ansible.builtin.debug: + msg: "hosts_invalid: {{ hosts_invalid }}" + when: debug_test|d(false)|bool + - name: Assert + ansible.builtin.assert: + that: hosts_invalid|difference(result)|length == 0 + vars: + hosts_valid: "{{ names2|select('community.general.fqdn_valid', + allow_underscores=True) }}" + hosts_invalid: "{{ names2|difference(hosts_valid) }}" + result: [-rv] + tags: t2 + +- name: 3. Test valid hostnames. min_labels=2, allow_underscores=True + block: + - name: "3. allow_underscores=True, min_labels=2" + ansible.builtin.debug: + msg: "hosts_invalid: {{ hosts_invalid }}" + when: debug_test|d(false)|bool + - name: Assert + ansible.builtin.assert: + that: hosts_invalid|difference(result)|length == 0 + vars: + hosts_valid: "{{ names3|select('community.general.fqdn_valid', + min_labels=2, + allow_underscores=True) }}" + hosts_invalid: "{{ names3|difference(hosts_valid) }}" + result: [9rv, s_v-.x.y] + tags: t3 diff --git a/tests/integration/targets/test_fqdn_valid/tasks/main.yml b/tests/integration/targets/test_fqdn_valid/tasks/main.yml new file mode 100644 index 0000000000..3bb62555ac --- /dev/null +++ b/tests/integration/targets/test_fqdn_valid/tasks/main.yml @@ -0,0 +1,7 @@ +--- +# Copyright (c) Ansible Project +# 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 + +- name: Test fqdn_valid + ansible.builtin.import_tasks: fqdn_valid_1.yml diff --git a/tests/integration/targets/test_fqdn_valid/vars/main.yml b/tests/integration/targets/test_fqdn_valid/vars/main.yml new file mode 100644 index 0000000000..ba0a0eb087 --- /dev/null +++ b/tests/integration/targets/test_fqdn_valid/vars/main.yml @@ -0,0 +1,15 @@ +--- +# Copyright (c) Ansible Project +# 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 + +names1: + - srv.example.com + - 9rv.example.com + - -rv.example.com + - srv + - 9rv + - -rv + - s_v +names2: [9rv, -rv, s_v] +names3: [9rv, srv.x, s_v.x.y, s_v-.x.y]