refactoring for ansible_module.turbo integration (#313)

* refactoring for ansible_module.turbo integration

This refactoring prepares the integration of `ansible_module.turbo`

- Delay the loading of `common.py`, move the shared structure in
  `args_common`.
- Avoid the use of one single object per module, this to increase the
  amount of Python structure that we can cache.
- Cache the Kubernetes client.

See: https://github.com/ansible-collections/community.kubernetes/pull/270

Co-authored-by: Jill Rouleau <jill.rouleau@bespokess.com>
This commit is contained in:
Gonéri Le Bouder
2021-03-16 17:16:18 -04:00
committed by GitHub
parent 2f6fae322c
commit 39660dd40e
14 changed files with 798 additions and 892 deletions

View File

@@ -117,7 +117,7 @@ connections:
import json
from ansible.errors import AnsibleError
from ansible_collections.community.kubernetes.plugins.module_utils.common import K8sAnsibleMixin, HAS_K8S_MODULE_HELPER, k8s_import_exception
from ansible_collections.community.kubernetes.plugins.module_utils.common import K8sAnsibleMixin, HAS_K8S_MODULE_HELPER, k8s_import_exception, get_api_client
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
try:
@@ -180,7 +180,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sAnsibleM
for connection in connections:
if not isinstance(connection, dict):
raise K8sInventoryException("Expecting connection to be a dictionary.")
client = self.get_api_client(**connection)
client = get_api_client(**connection)
name = connection.get('name', self.get_default_host_name(client.configuration.host))
if connection.get('namespaces'):
namespaces = connection['namespaces']
@@ -190,7 +190,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sAnsibleM
self.get_pods_for_namespace(client, name, namespace)
self.get_services_for_namespace(client, name, namespace)
else:
client = self.get_api_client()
client = get_api_client()
name = self.get_default_host_name(client.configuration.host)
namespaces = self.get_available_namespaces(client)
for namespace in namespaces:

View File

@@ -198,7 +198,7 @@ from ansible.errors import AnsibleError
from ansible.module_utils.common._collections_compat import KeysView
from ansible.plugins.lookup import LookupBase
from ansible_collections.community.kubernetes.plugins.module_utils.common import K8sAnsibleMixin
from ansible_collections.community.kubernetes.plugins.module_utils.common import K8sAnsibleMixin, get_api_client
try:
@@ -235,7 +235,7 @@ class KubernetesLookup(K8sAnsibleMixin):
def run(self, terms, variables=None, **kwargs):
self.params = kwargs
self.client = self.get_api_client()
self.client = get_api_client()
cluster_info = kwargs.get('cluster_info')
if cluster_info == 'version':

View File

@@ -0,0 +1,6 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule # noqa: F401

View File

@@ -0,0 +1,133 @@
from __future__ import (absolute_import, division, print_function)
from ansible.module_utils.six import string_types
__metaclass__ = type
def list_dict_str(value):
if isinstance(value, (list, dict, string_types)):
return value
raise TypeError
AUTH_ARG_SPEC = {
'kubeconfig': {
'type': 'path',
},
'context': {},
'host': {},
'api_key': {
'no_log': True,
},
'username': {},
'password': {
'no_log': True,
},
'validate_certs': {
'type': 'bool',
'aliases': ['verify_ssl'],
},
'ca_cert': {
'type': 'path',
'aliases': ['ssl_ca_cert'],
},
'client_cert': {
'type': 'path',
'aliases': ['cert_file'],
},
'client_key': {
'type': 'path',
'aliases': ['key_file'],
},
'proxy': {
'type': 'str',
},
'persist_config': {
'type': 'bool',
},
}
WAIT_ARG_SPEC = dict(
wait=dict(type='bool', default=False),
wait_sleep=dict(type='int', default=5),
wait_timeout=dict(type='int', default=120),
wait_condition=dict(
type='dict',
default=None,
options=dict(
type=dict(),
status=dict(default=True, choices=[True, False, "Unknown"]),
reason=dict()
)
)
)
# Map kubernetes-client parameters to ansible parameters
AUTH_ARG_MAP = {
'kubeconfig': 'kubeconfig',
'context': 'context',
'host': 'host',
'api_key': 'api_key',
'username': 'username',
'password': 'password',
'verify_ssl': 'validate_certs',
'ssl_ca_cert': 'ca_cert',
'cert_file': 'client_cert',
'key_file': 'client_key',
'proxy': 'proxy',
'persist_config': 'persist_config',
}
NAME_ARG_SPEC = {
'kind': {},
'name': {},
'namespace': {},
'api_version': {
'default': 'v1',
'aliases': ['api', 'version'],
},
}
COMMON_ARG_SPEC = {
'state': {
'default': 'present',
'choices': ['present', 'absent'],
},
'force': {
'type': 'bool',
'default': False,
},
}
RESOURCE_ARG_SPEC = {
'resource_definition': {
'type': list_dict_str,
'aliases': ['definition', 'inline']
},
'src': {
'type': 'path',
},
}
ARG_ATTRIBUTES_BLACKLIST = ('property_path',)
DELETE_OPTS_ARG_SPEC = {
'propagationPolicy': {
'choices': ['Foreground', 'Background', 'Orphan'],
},
'gracePeriodSeconds': {
'type': 'int',
},
'preconditions': {
'type': 'dict',
'options': {
'resourceVersion': {
'type': 'str',
},
'uid': {
'type': 'str',
}
}
}
}

View File

@@ -26,6 +26,7 @@ import sys
from datetime import datetime
from distutils.version import LooseVersion
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (AUTH_ARG_MAP, AUTH_ARG_SPEC)
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.six import iteritems, string_types
@@ -99,160 +100,43 @@ except ImportError as e:
K8S_IMP_ERR = traceback.format_exc()
def list_dict_str(value):
if isinstance(value, (list, dict, string_types)):
return value
raise TypeError
def configuration_digest(configuration):
import hashlib
m = hashlib.sha256()
for k in AUTH_ARG_MAP:
if not hasattr(configuration, k):
v = None
else:
v = getattr(configuration, k)
if v and k in ["ssl_ca_cert", "cert_file", "key_file"]:
with open(str(v), "r") as fd:
content = fd.read()
m.update(content.encode())
else:
m.update(str(v).encode())
digest = m.hexdigest()
return digest
ARG_ATTRIBUTES_BLACKLIST = ('property_path',)
COMMON_ARG_SPEC = {
'state': {
'default': 'present',
'choices': ['present', 'absent'],
},
'force': {
'type': 'bool',
'default': False,
},
}
RESOURCE_ARG_SPEC = {
'resource_definition': {
'type': list_dict_str,
'aliases': ['definition', 'inline']
},
'src': {
'type': 'path',
},
}
NAME_ARG_SPEC = {
'kind': {},
'name': {},
'namespace': {},
'api_version': {
'default': 'v1',
'aliases': ['api', 'version'],
},
}
AUTH_ARG_SPEC = {
'kubeconfig': {
'type': 'path',
},
'context': {},
'host': {},
'api_key': {
'no_log': True,
},
'username': {},
'password': {
'no_log': True,
},
'validate_certs': {
'type': 'bool',
'aliases': ['verify_ssl'],
},
'ca_cert': {
'type': 'path',
'aliases': ['ssl_ca_cert'],
},
'client_cert': {
'type': 'path',
'aliases': ['cert_file'],
},
'client_key': {
'type': 'path',
'aliases': ['key_file'],
},
'proxy': {
'type': 'str',
},
'persist_config': {
'type': 'bool',
},
}
WAIT_ARG_SPEC = dict(
wait=dict(type='bool', default=False),
wait_sleep=dict(type='int', default=5),
wait_timeout=dict(type='int', default=120),
wait_condition=dict(
type='dict',
default=None,
options=dict(
type=dict(),
status=dict(type='str', default="True", choices=["True", "False", "Unknown"]),
reason=dict()
)
)
)
DELETE_OPTS_ARG_SPEC = {
'propagationPolicy': {
'choices': ['Foreground', 'Background', 'Orphan'],
},
'gracePeriodSeconds': {
'type': 'int',
},
'preconditions': {
'type': 'dict',
'options': {
'resourceVersion': {
'type': 'str',
},
'uid': {
'type': 'str',
}
}
}
}
# Map kubernetes-client parameters to ansible parameters
AUTH_ARG_MAP = {
'kubeconfig': 'kubeconfig',
'context': 'context',
'host': 'host',
'api_key': 'api_key',
'username': 'username',
'password': 'password',
'verify_ssl': 'validate_certs',
'ssl_ca_cert': 'ca_cert',
'cert_file': 'client_cert',
'key_file': 'client_key',
'proxy': 'proxy',
'persist_config': 'persist_config',
}
class K8sAnsibleMixin(object):
def __init__(self, *args, **kwargs):
if not HAS_K8S_MODULE_HELPER:
self.fail_json(msg=missing_required_lib('openshift'), exception=K8S_IMP_ERR,
error=to_native(k8s_import_exception))
self.openshift_version = openshift.__version__
if not HAS_YAML:
self.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR)
def get_api_client(self, **auth_params):
auth_params = auth_params or getattr(self, 'params', {})
def get_api_client(module=None):
auth = {}
def _raise_or_fail(exc, msg):
if module:
module.fail_json(msg % to_native(exc))
else:
raise exc
# If authorization variables aren't defined, look for them in environment variables
for true_name, arg_name in AUTH_ARG_MAP.items():
if auth_params.get(arg_name) is None:
if module and module.params.get(arg_name):
auth[true_name] = module.params.get(arg_name)
else:
env_value = os.getenv('K8S_AUTH_{0}'.format(arg_name.upper()), None) or os.getenv('K8S_AUTH_{0}'.format(true_name.upper()), None)
if env_value is not None:
if AUTH_ARG_SPEC[arg_name].get('type') == 'bool':
env_value = env_value.lower() not in ['0', 'false', 'no']
auth[true_name] = env_value
else:
auth[true_name] = auth_params[arg_name]
def auth_set(*names):
return all([auth.get(name) for name in names])
@@ -264,7 +148,8 @@ class K8sAnsibleMixin(object):
try:
kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config'))
except Exception as err:
self.fail(msg='Failed to load kubeconfig due to %s' % to_native(err))
_raise_or_fail(err, 'Failed to load kubeconfig due to %s')
else:
# First try to do incluster config, then kubeconfig
try:
@@ -273,7 +158,7 @@ class K8sAnsibleMixin(object):
try:
kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config'))
except Exception as err:
self.fail(msg='Failed to load kubeconfig due to %s' % to_native(err))
_raise_or_fail(err, 'Failed to load kubeconfig due to %s')
# Override any values in the default configuration with Ansible parameters
# As of kubernetes-client v12.0.0, get_default_copy() is required here
@@ -289,11 +174,33 @@ class K8sAnsibleMixin(object):
else:
setattr(configuration, key, value)
kubernetes.client.Configuration.set_default(configuration)
digest = configuration_digest(configuration)
if digest in get_api_client._pool:
client = get_api_client._pool[digest]
return client
try:
return DynamicClient(kubernetes.client.ApiClient(configuration))
client = DynamicClient(kubernetes.client.ApiClient(configuration))
except Exception as err:
self.fail(msg='Failed to get client due to %s' % to_native(err))
_raise_or_fail(err, 'Failed to get client due to %s')
get_api_client._pool[digest] = client
return client
get_api_client._pool = {}
class K8sAnsibleMixin(object):
def __init__(self, module, *args, **kwargs):
if not HAS_K8S_MODULE_HELPER:
module.fail_json(msg=missing_required_lib('openshift'), exception=K8S_IMP_ERR,
error=to_native(k8s_import_exception))
self.openshift_version = openshift.__version__
if not HAS_YAML:
module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR)
def find_resource(self, kind, api_version, fail=False):
for attribute in ['kind', 'name', 'singular_name']:
@@ -513,8 +420,8 @@ class K8sAnsibleMixin(object):
predicate = _resource_absent
return self._wait_for(resource, definition['metadata']['name'], definition['metadata'].get('namespace'), predicate, sleep, timeout, state)
def set_resource_definitions(self):
resource_definition = self.params.get('resource_definition')
def set_resource_definitions(self, module):
resource_definition = module.params.get('resource_definition')
self.resource_definitions = []
@@ -529,7 +436,7 @@ class K8sAnsibleMixin(object):
else:
self.resource_definitions = [resource_definition]
src = self.params.get('src')
src = module.params.get('src')
if src:
self.resource_definitions = self.load_resource_definitions(src)
try:
@@ -539,12 +446,12 @@ class K8sAnsibleMixin(object):
if not resource_definition and not src:
implicit_definition = dict(
kind=self.kind,
apiVersion=self.api_version,
metadata=dict(name=self.name)
kind=module.params['kind'],
apiVersion=module.params['api_version'],
metadata=dict(name=module.params['name'])
)
if self.namespace:
implicit_definition['metadata']['namespace'] = self.namespace
if module.params.get('namespace'):
implicit_definition['metadata']['namespace'] = module.params.get('namespace')
self.resource_definitions = [implicit_definition]
def check_library_version(self):
@@ -577,7 +484,7 @@ class K8sAnsibleMixin(object):
changed = False
results = []
try:
self.client = self.get_api_client()
self.client = get_api_client()
# Hopefully the kubernetes client will provide its own exception class one day
except (urllib3.exceptions.RequestError) as e:
self.fail_json(msg="Couldn't connect to Kubernetes: %s" % str(e))

View File

@@ -1,166 +0,0 @@
#
# Copyright 2018 Red Hat | Ansible
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC, K8sAnsibleMixin)
try:
from openshift.dynamic.exceptions import NotFoundError
except ImportError:
pass
SCALE_ARG_SPEC = {
'replicas': {'type': 'int', 'required': True},
'current_replicas': {'type': 'int'},
'resource_version': {},
'wait': {'type': 'bool', 'default': True},
'wait_timeout': {'type': 'int', 'default': 20},
}
class KubernetesAnsibleScaleModule(K8sAnsibleMixin):
def __init__(self, k8s_kind=None, *args, **kwargs):
self.client = None
self.warnings = []
mutually_exclusive = [
('resource_definition', 'src'),
]
module = AnsibleModule(
argument_spec=self.argspec,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)
self.module = module
self.params = self.module.params
self.check_mode = self.module.check_mode
self.fail_json = self.module.fail_json
self.fail = self.module.fail_json
self.exit_json = self.module.exit_json
super(KubernetesAnsibleScaleModule, self).__init__()
self.kind = k8s_kind or self.params.get('kind')
self.api_version = self.params.get('api_version')
self.name = self.params.get('name')
self.namespace = self.params.get('namespace')
self.set_resource_definitions()
def execute_module(self):
definition = self.resource_definitions[0]
self.client = self.get_api_client()
name = definition['metadata']['name']
namespace = definition['metadata'].get('namespace')
api_version = definition['apiVersion']
kind = definition['kind']
current_replicas = self.params.get('current_replicas')
replicas = self.params.get('replicas')
resource_version = self.params.get('resource_version')
wait = self.params.get('wait')
wait_time = self.params.get('wait_timeout')
existing = None
existing_count = None
return_attributes = dict(changed=False, result=dict(), diff=dict())
if wait:
return_attributes['duration'] = 0
resource = self.find_resource(kind, api_version, fail=True)
try:
existing = resource.get(name=name, namespace=namespace)
return_attributes['result'] = existing.to_dict()
except NotFoundError as exc:
self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc),
error=exc.value.get('status'))
if self.kind == 'job':
existing_count = existing.spec.parallelism
elif hasattr(existing.spec, 'replicas'):
existing_count = existing.spec.replicas
if existing_count is None:
self.fail_json(msg='Failed to retrieve the available count for the requested object.')
if resource_version and resource_version != existing.metadata.resourceVersion:
self.exit_json(**return_attributes)
if current_replicas is not None and existing_count != current_replicas:
self.exit_json(**return_attributes)
if existing_count != replicas:
return_attributes['changed'] = True
if not self.check_mode:
if self.kind == 'job':
existing.spec.parallelism = replicas
return_attributes['result'] = resource.patch(existing.to_dict()).to_dict()
else:
return_attributes = self.scale(resource, existing, replicas, wait, wait_time)
self.exit_json(**return_attributes)
@property
def argspec(self):
args = copy.deepcopy(SCALE_ARG_SPEC)
args.update(RESOURCE_ARG_SPEC)
args.update(NAME_ARG_SPEC)
args.update(AUTH_ARG_SPEC)
return args
def scale(self, resource, existing_object, replicas, wait, wait_time):
name = existing_object.metadata.name
namespace = existing_object.metadata.namespace
kind = existing_object.kind
if not hasattr(resource, 'scale'):
self.fail_json(
msg="Cannot perform scale on resource of kind {0}".format(resource.kind)
)
scale_obj = {'kind': kind, 'metadata': {'name': name, 'namespace': namespace}, 'spec': {'replicas': replicas}}
existing = resource.get(name=name, namespace=namespace)
try:
resource.scale.patch(body=scale_obj)
except Exception as exc:
self.fail_json(msg="Scale request failed: {0}".format(exc))
k8s_obj = resource.get(name=name, namespace=namespace).to_dict()
match, diffs = self.diff_objects(existing.to_dict(), k8s_obj)
result = dict()
result['result'] = k8s_obj
result['changed'] = not match
result['diff'] = diffs
if wait:
success, result['result'], result['duration'] = self.wait(resource, scale_obj, 5, wait_time)
if not success:
self.fail_json(msg="Resource scaling timed out", **result)
return result

View File

@@ -263,74 +263,68 @@ result:
import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, COMMON_ARG_SPEC, NAME_ARG_SPEC, RESOURCE_ARG_SPEC, AUTH_ARG_SPEC,
WAIT_ARG_SPEC, DELETE_OPTS_ARG_SPEC)
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (
AUTH_ARG_SPEC, WAIT_ARG_SPEC, NAME_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC, DELETE_OPTS_ARG_SPEC)
class KubernetesModule(K8sAnsibleMixin):
@property
def validate_spec(self):
def validate_spec():
return dict(
fail_on_error=dict(type='bool'),
version=dict(),
strict=dict(type='bool', default=True)
)
@property
def argspec(self):
def argspec():
argument_spec = copy.deepcopy(COMMON_ARG_SPEC)
argument_spec.update(copy.deepcopy(NAME_ARG_SPEC))
argument_spec.update(copy.deepcopy(RESOURCE_ARG_SPEC))
argument_spec.update(copy.deepcopy(AUTH_ARG_SPEC))
argument_spec.update(copy.deepcopy(WAIT_ARG_SPEC))
argument_spec['merge_type'] = dict(type='list', elements='str', choices=['json', 'merge', 'strategic-merge'])
argument_spec['validate'] = dict(type='dict', default=None, options=self.validate_spec)
argument_spec['validate'] = dict(type='dict', default=None, options=validate_spec())
argument_spec['append_hash'] = dict(type='bool', default=False)
argument_spec['apply'] = dict(type='bool', default=False)
argument_spec['template'] = dict(type='raw', default=None)
argument_spec['delete_options'] = dict(type='dict', default=None, options=copy.deepcopy(DELETE_OPTS_ARG_SPEC))
return argument_spec
def __init__(self, k8s_kind=None, *args, **kwargs):
def execute_module(module, k8s_ansible_mixin):
k8s_ansible_mixin.module = module
k8s_ansible_mixin.argspec = module.argument_spec
k8s_ansible_mixin.check_mode = k8s_ansible_mixin.module.check_mode
k8s_ansible_mixin.params = k8s_ansible_mixin.module.params
k8s_ansible_mixin.fail_json = k8s_ansible_mixin.module.fail_json
k8s_ansible_mixin.fail = k8s_ansible_mixin.module.fail_json
k8s_ansible_mixin.exit_json = k8s_ansible_mixin.module.exit_json
k8s_ansible_mixin.warnings = []
k8s_ansible_mixin.kind = k8s_ansible_mixin.params.get('kind')
k8s_ansible_mixin.api_version = k8s_ansible_mixin.params.get('api_version')
k8s_ansible_mixin.name = k8s_ansible_mixin.params.get('name')
k8s_ansible_mixin.namespace = k8s_ansible_mixin.params.get('namespace')
k8s_ansible_mixin.check_library_version()
k8s_ansible_mixin.set_resource_definitions(module)
k8s_ansible_mixin.execute_module()
def main():
mutually_exclusive = [
('resource_definition', 'src'),
('merge_type', 'apply'),
('template', 'resource_definition'),
('template', 'src'),
]
module = AnsibleModule(argument_spec=argspec(), mutually_exclusive=mutually_exclusive, supports_check_mode=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, get_api_client)
module = AnsibleModule(
argument_spec=self.argspec,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)
self.module = module
self.check_mode = self.module.check_mode
self.params = self.module.params
self.fail_json = self.module.fail_json
self.fail = self.module.fail_json
self.exit_json = self.module.exit_json
super(KubernetesModule, self).__init__(*args, **kwargs)
self.client = None
self.warnings = []
self.kind = k8s_kind or self.params.get('kind')
self.api_version = self.params.get('api_version')
self.name = self.params.get('name')
self.namespace = self.params.get('namespace')
self.check_library_version()
self.set_resource_definitions()
def main():
KubernetesModule().execute_module()
k8s_ansible_mixin = K8sAnsibleMixin(module)
k8s_ansible_mixin.client = get_api_client(module=module)
execute_module(module, k8s_ansible_mixin)
if __name__ == '__main__':

View File

@@ -159,50 +159,19 @@ apis:
import copy
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible.module_utils.parsing.convert_bool import boolean
from ansible_collections.community.kubernetes.plugins.module_utils.common import K8sAnsibleMixin, AUTH_ARG_SPEC
try:
try:
from openshift import __version__ as version
# >=0.10
from openshift.dynamic.resource import ResourceList
except ImportError:
# <0.10
from openshift.dynamic.client import ResourceList
HAS_K8S_INSTANCE_HELPER = True
k8s_import_exception = None
except ImportError:
HAS_K8S_INSTANCE_HELPER = False
k8s_import_exception = traceback.format_exc()
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (AUTH_ARG_SPEC)
class KubernetesInfoModule(K8sAnsibleMixin):
def __init__(self):
module = AnsibleModule(
argument_spec=self.argspec,
supports_check_mode=True,
)
self.module = module
self.params = self.module.params
if not HAS_K8S_INSTANCE_HELPER:
self.module.fail_json(msg=missing_required_lib("openshift >= 0.6.2", reason="for merge_type"),
exception=k8s_import_exception)
super(KubernetesInfoModule, self).__init__()
def execute_module(self):
self.client = self.get_api_client()
invalidate_cache = boolean(self.module.params.get('invalidate_cache', True), strict=False)
def execute_module(module, client):
invalidate_cache = boolean(module.params.get('invalidate_cache', True), strict=False)
if invalidate_cache:
self.client.resources.invalidate_cache()
client.resources.invalidate_cache()
results = {}
for resource in list(self.client.resources):
from openshift.dynamic.resource import ResourceList
for resource in list(client.resources):
resource = resource[0]
if isinstance(resource, ResourceList):
continue
@@ -216,7 +185,7 @@ class KubernetesInfoModule(K8sAnsibleMixin):
'short_names': resource.short_names if resource.short_names else [],
'singular_name': resource.singular_name,
}
configuration = self.client.configuration
configuration = client.configuration
connection = {
'cert_file': configuration.cert_file,
'host': configuration.host,
@@ -226,21 +195,24 @@ class KubernetesInfoModule(K8sAnsibleMixin):
'username': configuration.username,
'verify_ssl': configuration.verify_ssl,
}
from openshift import __version__ as version
version_info = {
'client': version,
'server': self.client.version,
'server': client.version,
}
self.module.exit_json(changed=False, apis=results, connection=connection, version=version_info)
module.exit_json(changed=False, apis=results, connection=connection, version=version_info)
@property
def argspec(self):
def argspec():
spec = copy.deepcopy(AUTH_ARG_SPEC)
spec['invalidate_cache'] = dict(type='bool', default=True)
return spec
def main():
KubernetesInfoModule().execute_module()
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import get_api_client
execute_module(module, client=get_api_client(module=module))
if __name__ == '__main__':

View File

@@ -118,10 +118,10 @@ except ImportError:
# ImportError are managed by the common module already.
pass
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible.module_utils._text import to_native
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, AUTH_ARG_SPEC
AUTH_ARG_SPEC
)
try:
@@ -132,20 +132,7 @@ except ImportError:
pass
class KubernetesExecCommand(K8sAnsibleMixin):
def __init__(self):
module = AnsibleModule(
argument_spec=self.argspec,
supports_check_mode=True,
)
self.module = module
self.params = self.module.params
self.fail_json = self.module.fail_json
super(KubernetesExecCommand, self).__init__()
@property
def argspec(self):
def argspec():
spec = copy.deepcopy(AUTH_ARG_SPEC)
spec['namespace'] = dict(type='str', required=True)
spec['pod'] = dict(type='str', required=True)
@@ -153,29 +140,30 @@ class KubernetesExecCommand(K8sAnsibleMixin):
spec['command'] = dict(type='str', required=True)
return spec
def execute_module(self):
def execute_module(module, k8s_ansible_mixin):
# Load kubernetes.client.Configuration
self.get_api_client()
api = core_v1_api.CoreV1Api()
# hack because passing the container as None breaks things
optional_kwargs = {}
if self.params.get('container'):
optional_kwargs['container'] = self.params['container']
if module.params.get('container'):
optional_kwargs['container'] = module.params['container']
try:
resp = stream(
api.connect_get_namespaced_pod_exec,
self.params["pod"],
self.params["namespace"],
command=shlex.split(self.params["command"]),
module.params["pod"],
module.params["namespace"],
command=shlex.split(module.params["command"]),
stdout=True,
stderr=True,
stdin=False,
tty=False,
_preload_content=False, **optional_kwargs)
except Exception as e:
self.module.fail_json(msg="Failed to execute on pod %s"
" due to : %s" % (self.params.get('pod'), to_native(e)))
module.fail_json(msg="Failed to execute on pod %s"
" due to : %s" % (module.params.get('pod'), to_native(e)))
stdout, stderr, rc = [], [], 0
while resp.is_open():
resp.update(timeout=1)
@@ -190,7 +178,7 @@ class KubernetesExecCommand(K8sAnsibleMixin):
else:
rc = int(err['details']['causes'][0]['message'])
self.module.exit_json(
module.exit_json(
# Some command might change environment, but ultimately failing at end
changed=True,
stdout="".join(stdout),
@@ -200,7 +188,16 @@ class KubernetesExecCommand(K8sAnsibleMixin):
def main():
KubernetesExecCommand().execute_module()
module = AnsibleModule(
argument_spec=argspec(),
supports_check_mode=True,
)
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, get_api_client)
k8s_ansible_mixin = K8sAnsibleMixin(module)
k8s_ansible_mixin.client = get_api_client(module=module)
execute_module(module, k8s_ansible_mixin)
if __name__ == '__main__':

View File

@@ -148,41 +148,27 @@ resources:
import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, AUTH_ARG_SPEC, WAIT_ARG_SPEC)
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (AUTH_ARG_SPEC, WAIT_ARG_SPEC)
class KubernetesInfoModule(K8sAnsibleMixin):
def __init__(self, *args, **kwargs):
module = AnsibleModule(
argument_spec=self.argspec,
supports_check_mode=True,
def execute_module(module, k8s_ansible_mixin):
facts = k8s_ansible_mixin.kubernetes_facts(
module.params["kind"],
module.params["api_version"],
name=module.params["name"],
namespace=module.params["namespace"],
label_selectors=module.params["label_selectors"],
field_selectors=module.params["field_selectors"],
wait=module.params["wait"],
wait_sleep=module.params["wait_sleep"],
wait_timeout=module.params["wait_timeout"],
condition=module.params["wait_condition"],
)
self.module = module
self.params = self.module.params
self.fail_json = self.module.fail_json
self.exit_json = self.module.exit_json
super(KubernetesInfoModule, self).__init__()
module.exit_json(changed=False, **facts)
def execute_module(self):
self.client = self.get_api_client()
self.exit_json(changed=False,
**self.kubernetes_facts(self.params['kind'],
self.params['api_version'],
name=self.params['name'],
namespace=self.params['namespace'],
label_selectors=self.params['label_selectors'],
field_selectors=self.params['field_selectors'],
wait=self.params['wait'],
wait_sleep=self.params['wait_sleep'],
wait_timeout=self.params['wait_timeout'],
condition=self.params['wait_condition']))
@property
def argspec(self):
def argspec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(WAIT_ARG_SPEC)
args.update(
@@ -199,7 +185,13 @@ class KubernetesInfoModule(K8sAnsibleMixin):
def main():
KubernetesInfoModule().execute_module()
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, get_api_client)
k8s_ansible_mixin = K8sAnsibleMixin(module)
k8s_ansible_mixin.client = get_api_client(module=module)
execute_module(module, k8s_ansible_mixin)
if __name__ == '__main__':

View File

@@ -111,29 +111,13 @@ log_lines:
import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible.module_utils.six import PY2
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, AUTH_ARG_SPEC, NAME_ARG_SPEC)
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (AUTH_ARG_SPEC, NAME_ARG_SPEC)
class KubernetesLogModule(K8sAnsibleMixin):
def __init__(self):
module = AnsibleModule(
argument_spec=self.argspec,
supports_check_mode=True,
)
self.module = module
self.params = self.module.params
self.fail_json = self.module.fail_json
self.fail = self.module.fail_json
self.exit_json = self.module.exit_json
super(KubernetesLogModule, self).__init__()
@property
def argspec(self):
def argspec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(NAME_ARG_SPEC)
args.update(
@@ -145,35 +129,35 @@ class KubernetesLogModule(K8sAnsibleMixin):
)
return args
def execute_module(self):
name = self.params.get('name')
namespace = self.params.get('namespace')
label_selector = ','.join(self.params.get('label_selectors', {}))
if name and label_selector:
self.fail(msg='Only one of name or label_selectors can be provided')
self.client = self.get_api_client()
resource = self.find_resource(self.params['kind'], self.params['api_version'], fail=True)
v1_pods = self.find_resource('Pod', 'v1', fail=True)
def execute_module(module, k8s_ansible_mixin):
name = module.params.get('name')
namespace = module.params.get('namespace')
label_selector = ','.join(module.params.get('label_selectors', {}))
if name and label_selector:
module.fail(msg='Only one of name or label_selectors can be provided')
resource = k8s_ansible_mixin.find_resource(module.params['kind'], module.params['api_version'], fail=True)
v1_pods = k8s_ansible_mixin.find_resource('Pod', 'v1', fail=True)
if 'log' not in resource.subresources:
if not name:
self.fail(msg='name must be provided for resources that do not support the log subresource')
module.fail(msg='name must be provided for resources that do not support the log subresource')
instance = resource.get(name=name, namespace=namespace)
label_selector = ','.join(self.extract_selectors(instance))
label_selector = ','.join(extract_selectors(module, instance))
resource = v1_pods
if label_selector:
instances = v1_pods.get(namespace=namespace, label_selector=label_selector)
if not instances.items:
self.fail(msg='No pods in namespace {0} matched selector {1}'.format(namespace, label_selector))
module.fail(msg='No pods in namespace {0} matched selector {1}'.format(namespace, label_selector))
# This matches the behavior of kubectl when logging pods via a selector
name = instances.items[0].metadata.name
resource = v1_pods
kwargs = {}
if self.params.get('container'):
kwargs['query_params'] = dict(container=self.params['container'])
if module.params.get('container'):
kwargs['query_params'] = dict(container=module.params['container'])
log = serialize_log(resource.log.get(
name=name,
@@ -182,14 +166,15 @@ class KubernetesLogModule(K8sAnsibleMixin):
**kwargs
))
self.exit_json(changed=False, log=log, log_lines=log.split('\n'))
module.exit_json(changed=False, log=log, log_lines=log.split('\n'))
def extract_selectors(self, instance):
def extract_selectors(module, instance):
# Parses selectors on an object based on the specifications documented here:
# https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
selectors = []
if not instance.spec.selector:
self.fail(msg='{0} {1} does not support the log subresource directly, and no Pod selector was found on the object'.format(
module.fail(msg='{0} {1} does not support the log subresource directly, and no Pod selector was found on the object'.format(
'/'.join(instance.group, instance.apiVersion), instance.kind))
if not (instance.spec.selector.matchLabels or instance.spec.selector.matchExpressions):
@@ -217,7 +202,7 @@ class KubernetesLogModule(K8sAnsibleMixin):
values='({0})'.format(', '.join(expression.values))
))
else:
self.fail(msg='The k8s_log module does not support the {0} matchExpression operator'.format(operator.lower()))
module.fail(msg='The k8s_log module does not support the {0} matchExpression operator'.format(operator.lower()))
return selectors
@@ -229,7 +214,13 @@ def serialize_log(response):
def main():
KubernetesLogModule().execute_module()
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, get_api_client)
k8s_ansible_mixin = K8sAnsibleMixin(module)
k8s_ansible_mixin.client = get_api_client(module=module)
execute_module(module, k8s_ansible_mixin)
if __name__ == '__main__':

View File

@@ -78,70 +78,59 @@ rollback_info:
import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, AUTH_ARG_SPEC, NAME_ARG_SPEC)
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (
AUTH_ARG_SPEC, NAME_ARG_SPEC)
class KubernetesRollbackModule(K8sAnsibleMixin):
def get_managed_resource(module):
managed_resource = {}
def __init__(self):
module = AnsibleModule(
argument_spec=self.argspec,
supports_check_mode=True,
)
self.module = module
self.params = self.module.params
self.fail_json = self.module.fail_json
self.fail = self.module.fail_json
self.exit_json = self.module.exit_json
super(KubernetesRollbackModule, self).__init__()
self.kind = self.params['kind']
self.api_version = self.params['api_version']
self.name = self.params['name']
self.namespace = self.params['namespace']
self.managed_resource = {}
if self.kind == "DaemonSet":
self.managed_resource['kind'] = "ControllerRevision"
self.managed_resource['api_version'] = "apps/v1"
elif self.kind == "Deployment":
self.managed_resource['kind'] = "ReplicaSet"
self.managed_resource['api_version'] = "apps/v1"
kind = module.params['kind']
if kind == "DaemonSet":
managed_resource['kind'] = "ControllerRevision"
managed_resource['api_version'] = "apps/v1"
elif kind == "Deployment":
managed_resource['kind'] = "ReplicaSet"
managed_resource['api_version'] = "apps/v1"
else:
self.fail(msg="Cannot perform rollback on resource of kind {0}".format(self.kind))
module.fail(msg="Cannot perform rollback on resource of kind {0}".format(kind))
return managed_resource
def execute_module(self):
def execute_module(module, k8s_ansible_mixin):
results = []
self.client = self.get_api_client()
resources = self.kubernetes_facts(self.kind,
self.api_version,
self.name,
self.namespace,
self.params['label_selectors'],
self.params['field_selectors'])
resources = k8s_ansible_mixin.kubernetes_facts(
module.params['kind'],
module.params['api_version'],
module.params['name'],
module.params['namespace'],
module.params['label_selectors'],
module.params['field_selectors'])
for resource in resources['resources']:
result = self.perform_action(resource)
result = perform_action(module, k8s_ansible_mixin, resource)
results.append(result)
self.exit_json(**{
module.exit_json(**{
'changed': True,
'rollback_info': results
})
def perform_action(self, resource):
if self.kind == "DaemonSet":
def perform_action(module, k8s_ansible_mixin, resource):
if module.params['kind'] == "DaemonSet":
current_revision = resource['metadata']['generation']
elif self.kind == "Deployment":
elif module.params['kind'] == "Deployment":
current_revision = resource['metadata']['annotations']['deployment.kubernetes.io/revision']
managed_resources = self.kubernetes_facts(self.managed_resource['kind'],
self.managed_resource['api_version'],
managed_resource = get_managed_resource(module)
managed_resources = k8s_ansible_mixin.kubernetes_facts(
managed_resource['kind'],
managed_resource['api_version'],
'',
self.namespace,
module.params['namespace'],
resource['spec']
['selector']
['matchLabels'],
@@ -150,7 +139,7 @@ class KubernetesRollbackModule(K8sAnsibleMixin):
prev_managed_resource = get_previous_revision(managed_resources['resources'],
current_revision)
if self.kind == "Deployment":
if module.params['kind'] == "Deployment":
del prev_managed_resource['spec']['template']['metadata']['labels']['pod-template-hash']
resource_patch = [{
@@ -167,18 +156,19 @@ class KubernetesRollbackModule(K8sAnsibleMixin):
api_target = 'deployments'
content_type = 'application/json-patch+json'
elif self.kind == "DaemonSet":
elif module.params['kind'] == "DaemonSet":
resource_patch = prev_managed_resource["data"]
api_target = 'daemonsets'
content_type = 'application/strategic-merge-patch+json'
rollback = self.client.request("PATCH",
rollback = k8s_ansible_mixin.client.request(
"PATCH",
"/apis/{0}/namespaces/{1}/{2}/{3}"
.format(self.api_version,
self.namespace,
.format(module.params['api_version'],
module.params['namespace'],
api_target,
self.name),
module.params['name']),
body=resource_patch,
content_type=content_type)
@@ -188,8 +178,8 @@ class KubernetesRollbackModule(K8sAnsibleMixin):
result['resources'] = rollback.to_dict()
return result
@property
def argspec(self):
def argspec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(NAME_ARG_SPEC)
args.update(
@@ -217,7 +207,12 @@ def get_previous_revision(all_resources, current_revision):
def main():
KubernetesRollbackModule().execute_module()
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import (K8sAnsibleMixin, get_api_client)
k8s_ansible_mixin = K8sAnsibleMixin(module)
k8s_ansible_mixin.client = get_api_client(module=module)
execute_module(module, k8s_ansible_mixin)
if __name__ == '__main__':

View File

@@ -118,11 +118,129 @@ result:
sample: 48
'''
from ansible_collections.community.kubernetes.plugins.module_utils.scale import KubernetesAnsibleScaleModule
import copy
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (
AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC)
SCALE_ARG_SPEC = {
'replicas': {'type': 'int', 'required': True},
'current_replicas': {'type': 'int'},
'resource_version': {},
'wait': {'type': 'bool', 'default': True},
'wait_timeout': {'type': 'int', 'default': 20},
}
def execute_module(module, k8s_ansible_mixin,):
k8s_ansible_mixin.set_resource_definitions(module)
definition = k8s_ansible_mixin.resource_definitions[0]
name = definition['metadata']['name']
namespace = definition['metadata'].get('namespace')
api_version = definition['apiVersion']
kind = definition['kind']
current_replicas = module.params.get('current_replicas')
replicas = module.params.get('replicas')
resource_version = module.params.get('resource_version')
wait = module.params.get('wait')
wait_time = module.params.get('wait_timeout')
existing = None
existing_count = None
return_attributes = dict(changed=False, result=dict(), diff=dict())
if wait:
return_attributes['duration'] = 0
resource = k8s_ansible_mixin.find_resource(kind, api_version, fail=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import NotFoundError
try:
existing = resource.get(name=name, namespace=namespace)
return_attributes['result'] = existing.to_dict()
except NotFoundError as exc:
module.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc),
error=exc.value.get('status'))
if module.params['kind'] == 'job':
existing_count = existing.spec.parallelism
elif hasattr(existing.spec, 'replicas'):
existing_count = existing.spec.replicas
if existing_count is None:
module.fail_json(msg='Failed to retrieve the available count for the requested object.')
if resource_version and resource_version != existing.metadata.resourceVersion:
module.exit_json(**return_attributes)
if current_replicas is not None and existing_count != current_replicas:
module.exit_json(**return_attributes)
if existing_count != replicas:
return_attributes['changed'] = True
if not module.check_mode:
if module.params['kind'] == 'job':
existing.spec.parallelism = replicas
return_attributes['result'] = resource.patch(existing.to_dict()).to_dict()
else:
return_attributes = scale(module, k8s_ansible_mixin, resource, existing, replicas, wait, wait_time)
module.exit_json(**return_attributes)
def argspec():
args = copy.deepcopy(SCALE_ARG_SPEC)
args.update(RESOURCE_ARG_SPEC)
args.update(NAME_ARG_SPEC)
args.update(AUTH_ARG_SPEC)
return args
def scale(module, k8s_ansible_mixin, resource, existing_object, replicas, wait, wait_time):
name = existing_object.metadata.name
namespace = existing_object.metadata.namespace
kind = existing_object.kind
if not hasattr(resource, 'scale'):
module.fail_json(
msg="Cannot perform scale on resource of kind {0}".format(resource.kind)
)
scale_obj = {'kind': kind, 'metadata': {'name': name, 'namespace': namespace}, 'spec': {'replicas': replicas}}
existing = resource.get(name=name, namespace=namespace)
try:
resource.scale.patch(body=scale_obj)
except Exception as exc:
module.fail_json(msg="Scale request failed: {0}".format(exc))
k8s_obj = resource.get(name=name, namespace=namespace).to_dict()
match, diffs = k8s_ansible_mixin.diff_objects(existing.to_dict(), k8s_obj)
result = dict()
result['result'] = k8s_obj
result['changed'] = not match
result['diff'] = diffs
if wait:
success, result['result'], result['duration'] = k8s_ansible_mixin.wait(resource, scale_obj, 5, wait_time)
if not success:
module.fail_json(msg="Resource scaling timed out", **result)
return result
def main():
KubernetesAnsibleScaleModule().execute_module()
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, get_api_client)
k8s_ansible_mixin = K8sAnsibleMixin(module)
k8s_ansible_mixin.client = get_api_client(module=module)
execute_module(module, k8s_ansible_mixin)
if __name__ == '__main__':

View File

@@ -145,14 +145,12 @@ result:
'''
import copy
import traceback
from collections import defaultdict
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, AUTH_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC)
from ansible_collections.community.kubernetes.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible_collections.community.kubernetes.plugins.module_utils.args_common import (
AUTH_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC)
SERVICE_ARG_SPEC = {
'apply': {
@@ -173,45 +171,11 @@ SERVICE_ARG_SPEC = {
}
class KubernetesService(K8sAnsibleMixin):
def __init__(self, *args, **kwargs):
mutually_exclusive = [
('resource_definition', 'src'),
('merge_type', 'apply'),
]
module = AnsibleModule(
argument_spec=self.argspec,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)
self.module = module
self.check_mode = self.module.check_mode
self.params = self.module.params
self.fail_json = self.module.fail_json
self.fail = self.module.fail_json
self.exit_json = self.module.exit_json
super(KubernetesService, self).__init__(*args, **kwargs)
self.client = None
self.warnings = []
self.kind = self.params.get('kind')
self.api_version = self.params.get('api_version')
self.name = self.params.get('name')
self.namespace = self.params.get('namespace')
self.check_library_version()
self.set_resource_definitions()
@staticmethod
def merge_dicts(x, y):
for k in set(x.keys()).union(y.keys()):
if k in x and k in y:
if isinstance(x[k], dict) and isinstance(y[k], dict):
yield (k, dict(KubernetesService.merge_dicts(x[k], y[k])))
yield (k, dict(merge_dicts(x[k], y[k])))
else:
yield (k, y[k])
elif k in x:
@@ -219,8 +183,8 @@ class KubernetesService(K8sAnsibleMixin):
else:
yield (k, y[k])
@property
def argspec(self):
def argspec():
""" argspec property builder """
argument_spec = copy.deepcopy(AUTH_ARG_SPEC)
argument_spec.update(COMMON_ARG_SPEC)
@@ -228,14 +192,15 @@ class KubernetesService(K8sAnsibleMixin):
argument_spec.update(SERVICE_ARG_SPEC)
return argument_spec
def execute_module(self):
def execute_module(module, k8s_ansible_mixin):
""" Module execution """
self.client = self.get_api_client()
k8s_ansible_mixin.set_resource_definitions(module)
api_version = 'v1'
selector = self.params.get('selector')
service_type = self.params.get('type')
ports = self.params.get('ports')
selector = module.params.get('selector')
service_type = module.params.get('type')
ports = module.params.get('ports')
definition = defaultdict(defaultdict)
@@ -248,25 +213,27 @@ class KubernetesService(K8sAnsibleMixin):
def_spec['selector'] = selector
def_meta = definition['metadata']
def_meta['name'] = self.params.get('name')
def_meta['namespace'] = self.params.get('namespace')
def_meta['name'] = module.params.get('name')
def_meta['namespace'] = module.params.get('namespace')
# 'resource_definition:' has lower priority than module parameters
definition = dict(self.merge_dicts(self.resource_definitions[0], definition))
definition = dict(merge_dicts(k8s_ansible_mixin.resource_definitions[0], definition))
resource = self.find_resource('Service', api_version, fail=True)
definition = self.set_defaults(resource, definition)
result = self.perform_action(resource, definition)
resource = k8s_ansible_mixin.find_resource('Service', api_version, fail=True)
definition = k8s_ansible_mixin.set_defaults(resource, definition)
result = k8s_ansible_mixin.perform_action(resource, definition)
self.exit_json(**result)
module.exit_json(**result)
def main():
module = KubernetesService()
try:
module.execute_module()
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True)
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
K8sAnsibleMixin, get_api_client)
k8s_ansible_mixin = K8sAnsibleMixin(module)
k8s_ansible_mixin.client = get_api_client(module=module)
execute_module(module, k8s_ansible_mixin)
if __name__ == '__main__':