Skip to content

Commit

Permalink
Refactor and extend argument spec helper, use for ACME modules (ansib…
Browse files Browse the repository at this point in the history
…le-collections#749)

* Refactor argument spec helper.

* Remove superfluous comments.
  • Loading branch information
felixfontein authored May 5, 2024
1 parent f82b335 commit f3c9cb7
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 122 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/749-argspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
deprecated_features:
- "crypto.module_backends.common module utils - the ``crypto.module_backends.common`` module utils is deprecated and will be removed from community.crypto 3.0.0. Use the improved ``argspec`` module util instead (https:/ansible-collections/community.crypto/pull/749)."
24 changes: 24 additions & 0 deletions plugins/module_utils/acme/acme.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.six import PY3

from ansible_collections.community.crypto.plugins.module_utils.argspec import ArgumentSpec

from ansible_collections.community.crypto.plugins.module_utils.acme.backend_openssl_cli import (
OpenSSLCLIBackend,
)
Expand Down Expand Up @@ -439,6 +441,28 @@ def get_default_argspec(with_account=True):
return argspec


def create_default_argspec(with_account=True, require_account_key=True):
'''
Provides default argument spec for the options documented in the acme doc fragment.
'''
result = ArgumentSpec(
get_default_argspec(with_account=with_account),
)
if with_account:
if require_account_key:
result.update(
required_one_of=[
['account_key_src', 'account_key_content'],
],
)
result.update(
mutually_exclusive=[
['account_key_src', 'account_key_content'],
],
)
return result


def create_backend(module, needs_acme_v2):
if not HAS_IPADDRESS:
module.fail_json(msg=missing_required_lib('ipaddress'), exception=IPADDRESS_IMPORT_ERROR)
Expand Down
75 changes: 75 additions & 0 deletions plugins/module_utils/argspec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2020, Felix Fontein <[email protected]>
# 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.module_utils.basic import AnsibleModule


def _ensure_list(value):
if value is None:
return []
return list(value)


class ArgumentSpec:
def __init__(self, argument_spec=None, mutually_exclusive=None, required_together=None, required_one_of=None, required_if=None, required_by=None):
self.argument_spec = argument_spec or {}
self.mutually_exclusive = _ensure_list(mutually_exclusive)
self.required_together = _ensure_list(required_together)
self.required_one_of = _ensure_list(required_one_of)
self.required_if = _ensure_list(required_if)
self.required_by = required_by or {}

def update_argspec(self, **kwargs):
self.argument_spec.update(kwargs)
return self

def update(self, mutually_exclusive=None, required_together=None, required_one_of=None, required_if=None, required_by=None):
if mutually_exclusive:
self.mutually_exclusive.extend(mutually_exclusive)
if required_together:
self.required_together.extend(required_together)
if required_one_of:
self.required_one_of.extend(required_one_of)
if required_if:
self.required_if.extend(required_if)
if required_by:
for k, v in required_by.items():
if k in self.required_by:
v = list(self.required_by[k]) + list(v)
self.required_by[k] = v
return self

def merge(self, other):
self.update_argspec(other.argument_spec)
self.update(
mutually_exclusive=other.mutually_exclusive,
required_together=other.required_together,
required_one_of=other.required_one_of,
required_if=other.required_if,
required_by=other.required_by,
)
return self

def create_ansible_module_helper(self, clazz, args, **kwargs):
return clazz(
*args,
argument_spec=self.argument_spec,
mutually_exclusive=self.mutually_exclusive,
required_together=self.required_together,
required_one_of=self.required_one_of,
required_if=self.required_if,
required_by=self.required_by,
**kwargs)

def create_ansible_module(self, **kwargs):
return self.create_ansible_module_helper(AnsibleModule, (), **kwargs)


__all__ = ('ArgumentSpec', )
4 changes: 2 additions & 2 deletions plugins/module_utils/crypto/module_backends/certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib

from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.argspec import ArgumentSpec

from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion

from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
OpenSSLObjectError,
Expand Down
33 changes: 13 additions & 20 deletions plugins/module_utils/crypto/module_backends/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,19 @@

from ansible.module_utils.basic import AnsibleModule

from ansible_collections.community.crypto.plugins.module_utils.argspec import ArgumentSpec as _ArgumentSpec

class ArgumentSpec:
def __init__(self, argument_spec, mutually_exclusive=None, required_together=None, required_one_of=None, required_if=None, required_by=None):
self.argument_spec = argument_spec
self.mutually_exclusive = mutually_exclusive or []
self.required_together = required_together or []
self.required_one_of = required_one_of or []
self.required_if = required_if or []
self.required_by = required_by or {}

class ArgumentSpec(_ArgumentSpec):
def create_ansible_module_helper(self, clazz, args, **kwargs):
return clazz(
*args,
argument_spec=self.argument_spec,
mutually_exclusive=self.mutually_exclusive,
required_together=self.required_together,
required_one_of=self.required_one_of,
required_if=self.required_if,
required_by=self.required_by,
**kwargs)

def create_ansible_module(self, **kwargs):
return self.create_ansible_module_helper(AnsibleModule, (), **kwargs)
result = super(ArgumentSpec, self).create_ansible_module_helper(clazz, args, **kwargs)
result.deprecate(
"The crypto.module_backends.common module utils is deprecated and will be removed from community.crypto 3.0.0."
" Use the argspec module utils from community.crypto instead.",
version='3.0.0',
collection_name='community.crypto',
)
return result


__all__ = ('AnsibleModule', 'ArgumentSpec')
4 changes: 2 additions & 2 deletions plugins/module_utils/crypto/module_backends/csr.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text

from ansible_collections.community.crypto.plugins.module_utils.argspec import ArgumentSpec

from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion

from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
Expand Down Expand Up @@ -49,8 +51,6 @@
get_csr_info,
)

from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec


MINIMAL_CRYPTOGRAPHY_VERSION = '1.3'

Expand Down
4 changes: 2 additions & 2 deletions plugins/module_utils/crypto/module_backends/privatekey.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes

from ansible_collections.community.crypto.plugins.module_utils.argspec import ArgumentSpec

from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion

from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
Expand All @@ -42,8 +44,6 @@
get_privatekey_info,
)

from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec


MINIMAL_CRYPTOGRAPHY_VERSION = '1.2.3'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_bytes

from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.argspec import ArgumentSpec

from ansible_collections.community.crypto.plugins.module_utils.io import (
load_file,
)

from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion

from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
CRYPTOGRAPHY_HAS_X25519,
CRYPTOGRAPHY_HAS_X448,
Expand All @@ -37,8 +39,6 @@
identify_private_key_format,
)

from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.common import ArgumentSpec


MINIMAL_CRYPTOGRAPHY_VERSION = '1.2.3'

Expand Down
19 changes: 6 additions & 13 deletions plugins/modules/acme_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,9 @@

import base64

from ansible.module_utils.basic import AnsibleModule

from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
create_backend,
get_default_argspec,
create_default_argspec,
ACMEClient,
)

Expand All @@ -189,8 +187,8 @@


def main():
argument_spec = get_default_argspec()
argument_spec.update(dict(
argument_spec = create_default_argspec()
argument_spec.update_argspec(
terms_agreed=dict(type='bool', default=False),
state=dict(type='str', required=True, choices=['absent', 'present', 'changed_key']),
allow_creation=dict(type='bool', default=True),
Expand All @@ -203,23 +201,18 @@ def main():
alg=dict(type='str', required=True, choices=['HS256', 'HS384', 'HS512']),
key=dict(type='str', required=True, no_log=True),
))
))
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=(
['account_key_src', 'account_key_content'],
),
)
argument_spec.update(
mutually_exclusive=(
['account_key_src', 'account_key_content'],
['new_account_key_src', 'new_account_key_content'],
),
required_if=(
# Make sure that for state == changed_key, one of
# new_account_key_src and new_account_key_content are specified
['state', 'changed_key', ['new_account_key_src', 'new_account_key_content'], True],
),
supports_check_mode=True,
)
module = argument_spec.create_ansible_module(supports_check_mode=True)
backend = create_backend(module, True)

if module.params['external_account_binding']:
Expand Down
19 changes: 4 additions & 15 deletions plugins/modules/acme_account_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,9 @@
version_added: 1.5.0
'''

from ansible.module_utils.basic import AnsibleModule

from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
create_backend,
get_default_argspec,
create_default_argspec,
ACMEClient,
)

Expand Down Expand Up @@ -271,20 +269,11 @@ def get_order(client, order_url):


def main():
argument_spec = get_default_argspec()
argument_spec.update(dict(
argument_spec = create_default_argspec()
argument_spec.update_argspec(
retrieve_orders=dict(type='str', default='ignore', choices=['ignore', 'url_list', 'object_list']),
))
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=(
['account_key_src', 'account_key_content'],
),
mutually_exclusive=(
['account_key_src', 'account_key_content'],
),
supports_check_mode=True,
)
module = argument_spec.create_ansible_module(supports_check_mode=True)
backend = create_backend(module, True)

try:
Expand Down
15 changes: 6 additions & 9 deletions plugins/modules/acme_ari_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,33 +98,30 @@
sample: '2024-04-29T01:17:10.236921+00:00'
'''

from ansible.module_utils.basic import AnsibleModule

from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
create_backend,
get_default_argspec,
create_default_argspec,
ACMEClient,
)

from ansible_collections.community.crypto.plugins.module_utils.acme.errors import ModuleFailException


def main():
argument_spec = get_default_argspec(with_account=False)
argument_spec.update(dict(
argument_spec = create_default_argspec(with_account=False)
argument_spec.update_argspec(
certificate_path=dict(type='path'),
certificate_content=dict(type='str'),
))
module = AnsibleModule(
argument_spec=argument_spec,
)
argument_spec.update(
required_one_of=(
['certificate_path', 'certificate_content'],
),
mutually_exclusive=(
['certificate_path', 'certificate_content'],
),
supports_check_mode=True,
)
module = argument_spec.create_ansible_module(supports_check_mode=True)
backend = create_backend(module, True)

try:
Expand Down
Loading

0 comments on commit f3c9cb7

Please sign in to comment.