diff options
Diffstat (limited to 'lib/ansible/modules/deb822_repository.py')
-rw-r--r-- | lib/ansible/modules/deb822_repository.py | 555 |
1 files changed, 0 insertions, 555 deletions
diff --git a/lib/ansible/modules/deb822_repository.py b/lib/ansible/modules/deb822_repository.py deleted file mode 100644 index 6b73cfe2..00000000 --- a/lib/ansible/modules/deb822_repository.py +++ /dev/null @@ -1,555 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright: Contributors to the Ansible project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -DOCUMENTATION = ''' -author: 'Ansible Core Team (@ansible)' -short_description: 'Add and remove deb822 formatted repositories' -description: -- 'Add and remove deb822 formatted repositories in Debian based distributions' -module: deb822_repository -notes: -- This module will not automatically update caches, call the apt module based - on the changed state. -options: - allow_downgrade_to_insecure: - description: - - Allow downgrading a package that was previously authenticated but - is no longer authenticated - type: bool - allow_insecure: - description: - - Allow insecure repositories - type: bool - allow_weak: - description: - - Allow repositories signed with a key using a weak digest algorithm - type: bool - architectures: - description: - - 'Architectures to search within repository' - type: list - elements: str - by_hash: - description: - - Controls if APT should try to acquire indexes via a URI constructed - from a hashsum of the expected file instead of using the well-known - stable filename of the index. - type: bool - check_date: - description: - - Controls if APT should consider the machine's time correct and hence - perform time related checks, such as verifying that a Release file - is not from the future. - type: bool - check_valid_until: - description: - - Controls if APT should try to detect replay attacks. - type: bool - components: - description: - - Components specify different sections of one distribution version - present in a Suite. - type: list - elements: str - date_max_future: - description: - - Controls how far from the future a repository may be. - type: int - enabled: - description: - - Tells APT whether the source is enabled or not. - type: bool - inrelease_path: - description: - - Determines the path to the InRelease file, relative to the normal - position of an InRelease file. - type: str - languages: - description: - - Defines which languages information such as translated - package descriptions should be downloaded. - type: list - elements: str - name: - description: - - Name of the repo. Specifically used for C(X-Repolib-Name) and in - naming the repository and signing key files. - required: true - type: str - pdiffs: - description: - - Controls if APT should try to use PDiffs to update old indexes - instead of downloading the new indexes entirely - type: bool - signed_by: - description: - - Either a URL to a GPG key, absolute path to a keyring file, one or - more fingerprints of keys either in the C(trusted.gpg) keyring or in - the keyrings in the C(trusted.gpg.d/) directory, or an ASCII armored - GPG public key block. - type: str - suites: - description: - - >- - Suite can specify an exact path in relation to the URI(s) provided, - in which case the Components: must be omitted and suite must end - with a slash (C(/)). Alternatively, it may take the form of a - distribution version (e.g. a version codename like disco or artful). - If the suite does not specify a path, at least one component must - be present. - type: list - elements: str - targets: - description: - - Defines which download targets apt will try to acquire from this - source. - type: list - elements: str - trusted: - description: - - Decides if a source is considered trusted or if warnings should be - raised before e.g. packages are installed from this source. - type: bool - types: - choices: - - deb - - deb-src - default: - - deb - type: list - elements: str - description: - - Which types of packages to look for from a given source; either - binary V(deb) or source code V(deb-src) - uris: - description: - - The URIs must specify the base of the Debian distribution archive, - from which APT finds the information it needs. - type: list - elements: str - mode: - description: - - The octal mode for newly created files in sources.list.d. - type: raw - default: '0644' - state: - description: - - A source string state. - type: str - choices: - - absent - - present - default: present -requirements: - - python3-debian / python-debian -version_added: '2.15' -''' - -EXAMPLES = ''' -- name: Add debian repo - deb822_repository: - name: debian - types: deb - uris: http://deb.debian.org/debian - suites: stretch - components: - - main - - contrib - - non-free - -- name: Add debian repo with key - deb822_repository: - name: debian - types: deb - uris: https://deb.debian.org - suites: stable - components: - - main - - contrib - - non-free - signed_by: |- - -----BEGIN PGP PUBLIC KEY BLOCK----- - - mDMEYCQjIxYJKwYBBAHaRw8BAQdAD/P5Nvvnvk66SxBBHDbhRml9ORg1WV5CvzKY - CuMfoIS0BmFiY2RlZoiQBBMWCgA4FiEErCIG1VhKWMWo2yfAREZd5NfO31cFAmAk - IyMCGyMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQREZd5NfO31fbOwD6ArzS - dM0Dkd5h2Ujy1b6KcAaVW9FOa5UNfJ9FFBtjLQEBAJ7UyWD3dZzhvlaAwunsk7DG - 3bHcln8DMpIJVXht78sL - =IE0r - -----END PGP PUBLIC KEY BLOCK----- - -- name: Add repo using key from URL - deb822_repository: - name: example - types: deb - uris: https://download.example.com/linux/ubuntu - suites: '{{ ansible_distribution_release }}' - components: stable - architectures: amd64 - signed_by: https://download.example.com/linux/ubuntu/gpg -''' - -RETURN = ''' -repo: - description: A source string for the repository - returned: always - type: str - sample: | - X-Repolib-Name: debian - Types: deb - URIs: https://deb.debian.org - Suites: stable - Components: main contrib non-free - Signed-By: - -----BEGIN PGP PUBLIC KEY BLOCK----- - . - mDMEYCQjIxYJKwYBBAHaRw8BAQdAD/P5Nvvnvk66SxBBHDbhRml9ORg1WV5CvzKY - CuMfoIS0BmFiY2RlZoiQBBMWCgA4FiEErCIG1VhKWMWo2yfAREZd5NfO31cFAmAk - IyMCGyMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQREZd5NfO31fbOwD6ArzS - dM0Dkd5h2Ujy1b6KcAaVW9FOa5UNfJ9FFBtjLQEBAJ7UyWD3dZzhvlaAwunsk7DG - 3bHcln8DMpIJVXht78sL - =IE0r - -----END PGP PUBLIC KEY BLOCK----- - -dest: - description: Path to the repository file - returned: always - type: str - sample: /etc/apt/sources.list.d/focal-archive.sources - -key_filename: - description: Path to the signed_by key file - returned: always - type: str - sample: /etc/apt/keyrings/debian.gpg -''' - -import os -import re -import tempfile -import textwrap -import traceback - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.basic import missing_required_lib -from ansible.module_utils.common.collections import is_sequence -from ansible.module_utils.common.text.converters import to_bytes -from ansible.module_utils.common.text.converters import to_native -from ansible.module_utils.six import raise_from # type: ignore[attr-defined] -from ansible.module_utils.urls import generic_urlparse -from ansible.module_utils.urls import open_url -from ansible.module_utils.urls import get_user_agent -from ansible.module_utils.urls import urlparse - -HAS_DEBIAN = True -DEBIAN_IMP_ERR = None -try: - from debian.deb822 import Deb822 # type: ignore[import] -except ImportError: - HAS_DEBIAN = False - DEBIAN_IMP_ERR = traceback.format_exc() - -KEYRINGS_DIR = '/etc/apt/keyrings' - - -def ensure_keyrings_dir(module): - changed = False - if not os.path.isdir(KEYRINGS_DIR): - if not module.check_mode: - os.mkdir(KEYRINGS_DIR, 0o755) - changed |= True - - changed |= module.set_fs_attributes_if_different( - { - 'path': KEYRINGS_DIR, - 'secontext': [None, None, None], - 'owner': 'root', - 'group': 'root', - 'mode': '0755', - 'attributes': None, - }, - changed, - ) - - return changed - - -def make_signed_by_filename(slug, ext): - return os.path.join(KEYRINGS_DIR, '%s.%s' % (slug, ext)) - - -def make_sources_filename(slug): - return os.path.join( - '/etc/apt/sources.list.d', - '%s.sources' % slug - ) - - -def format_bool(v): - return 'yes' if v else 'no' - - -def format_list(v): - return ' '.join(v) - - -def format_multiline(v): - return '\n' + textwrap.indent( - '\n'.join(line.strip() or '.' for line in v.strip().splitlines()), - ' ' - ) - - -def format_field_name(v): - if v == 'name': - return 'X-Repolib-Name' - elif v == 'uris': - return 'URIs' - return v.replace('_', '-').title() - - -def is_armored(b_data): - return b'-----BEGIN PGP PUBLIC KEY BLOCK-----' in b_data - - -def write_signed_by_key(module, v, slug): - changed = False - if os.path.isfile(v): - return changed, v, None - - b_data = None - - parts = generic_urlparse(urlparse(v)) - if parts.scheme: - try: - r = open_url(v, http_agent=get_user_agent()) - except Exception as exc: - raise_from(RuntimeError(to_native(exc)), exc) - else: - b_data = r.read() - else: - # Not a file, nor a URL, just pass it through - return changed, None, v - - if not b_data: - return changed, v, None - - tmpfd, tmpfile = tempfile.mkstemp(dir=module.tmpdir) - with os.fdopen(tmpfd, 'wb') as f: - f.write(b_data) - - ext = 'asc' if is_armored(b_data) else 'gpg' - filename = make_signed_by_filename(slug, ext) - - src_chksum = module.sha256(tmpfile) - dest_chksum = module.sha256(filename) - - if src_chksum != dest_chksum: - changed |= ensure_keyrings_dir(module) - if not module.check_mode: - module.atomic_move(tmpfile, filename) - changed |= True - - changed |= module.set_mode_if_different(filename, 0o0644, False) - - return changed, filename, None - - -def main(): - module = AnsibleModule( - argument_spec={ - 'allow_downgrade_to_insecure': { - 'type': 'bool', - }, - 'allow_insecure': { - 'type': 'bool', - }, - 'allow_weak': { - 'type': 'bool', - }, - 'architectures': { - 'elements': 'str', - 'type': 'list', - }, - 'by_hash': { - 'type': 'bool', - }, - 'check_date': { - 'type': 'bool', - }, - 'check_valid_until': { - 'type': 'bool', - }, - 'components': { - 'elements': 'str', - 'type': 'list', - }, - 'date_max_future': { - 'type': 'int', - }, - 'enabled': { - 'type': 'bool', - }, - 'inrelease_path': { - 'type': 'str', - }, - 'languages': { - 'elements': 'str', - 'type': 'list', - }, - 'name': { - 'type': 'str', - 'required': True, - }, - 'pdiffs': { - 'type': 'bool', - }, - 'signed_by': { - 'type': 'str', - }, - 'suites': { - 'elements': 'str', - 'type': 'list', - }, - 'targets': { - 'elements': 'str', - 'type': 'list', - }, - 'trusted': { - 'type': 'bool', - }, - 'types': { - 'choices': [ - 'deb', - 'deb-src', - ], - 'elements': 'str', - 'type': 'list', - 'default': [ - 'deb', - ] - }, - 'uris': { - 'elements': 'str', - 'type': 'list', - }, - # non-deb822 args - 'mode': { - 'type': 'raw', - 'default': '0644', - }, - 'state': { - 'type': 'str', - 'choices': [ - 'present', - 'absent', - ], - 'default': 'present', - }, - }, - supports_check_mode=True, - ) - - if not HAS_DEBIAN: - module.fail_json(msg=missing_required_lib("python3-debian"), - exception=DEBIAN_IMP_ERR) - - check_mode = module.check_mode - - changed = False - - # Make a copy, so we don't mutate module.params to avoid future issues - params = module.params.copy() - - # popped non-deb822 args - mode = params.pop('mode') - state = params.pop('state') - - name = params['name'] - slug = re.sub( - r'[^a-z0-9-]+', - '', - re.sub( - r'[_\s]+', - '-', - name.lower(), - ), - ) - sources_filename = make_sources_filename(slug) - - if state == 'absent': - if os.path.exists(sources_filename): - if not check_mode: - os.unlink(sources_filename) - changed |= True - for ext in ('asc', 'gpg'): - signed_by_filename = make_signed_by_filename(slug, ext) - if os.path.exists(signed_by_filename): - if not check_mode: - os.unlink(signed_by_filename) - changed = True - module.exit_json( - repo=None, - changed=changed, - dest=sources_filename, - key_filename=signed_by_filename, - ) - - deb822 = Deb822() - signed_by_filename = None - for key, value in params.items(): - if value is None: - continue - - if isinstance(value, bool): - value = format_bool(value) - elif isinstance(value, int): - value = to_native(value) - elif is_sequence(value): - value = format_list(value) - elif key == 'signed_by': - try: - key_changed, signed_by_filename, signed_by_data = write_signed_by_key(module, value, slug) - value = signed_by_filename or signed_by_data - changed |= key_changed - except RuntimeError as exc: - module.fail_json( - msg='Could not fetch signed_by key: %s' % to_native(exc) - ) - - if value.count('\n') > 0: - value = format_multiline(value) - - deb822[format_field_name(key)] = value - - repo = deb822.dump() - tmpfd, tmpfile = tempfile.mkstemp(dir=module.tmpdir) - with os.fdopen(tmpfd, 'wb') as f: - f.write(to_bytes(repo)) - - sources_filename = make_sources_filename(slug) - - src_chksum = module.sha256(tmpfile) - dest_chksum = module.sha256(sources_filename) - - if src_chksum != dest_chksum: - if not check_mode: - module.atomic_move(tmpfile, sources_filename) - changed |= True - - changed |= module.set_mode_if_different(sources_filename, mode, False) - - module.exit_json( - repo=repo, - changed=changed, - dest=sources_filename, - key_filename=signed_by_filename, - ) - - -if __name__ == '__main__': - main() |