mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-23 19:01:26 -07:00
This reverts commit 4373b155a5
.
This commit is contained in:
parent
950ff6bce6
commit
78023e79d7
18 changed files with 1881 additions and 538 deletions
|
@ -18,12 +18,13 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import copy
|
||||
|
||||
from ansible.module_utils.k8s.common import KubernetesAnsibleModule
|
||||
|
||||
from ansible.module_utils.k8s.helper import COMMON_ARG_SPEC, AUTH_ARG_SPEC, OPENSHIFT_ARG_SPEC
|
||||
from ansible.module_utils.k8s.common import KubernetesAnsibleModule, OpenShiftAnsibleModuleMixin, to_snake
|
||||
|
||||
try:
|
||||
from openshift.dynamic.exceptions import DynamicApiError, NotFoundError, ConflictError
|
||||
from openshift.helper.exceptions import KubernetesException
|
||||
except ImportError:
|
||||
# Exception handled in common
|
||||
pass
|
||||
|
@ -32,8 +33,6 @@ except ImportError:
|
|||
class KubernetesRawModule(KubernetesAnsibleModule):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.client = None
|
||||
|
||||
mutually_exclusive = [
|
||||
('resource_definition', 'src'),
|
||||
]
|
||||
|
@ -43,140 +42,170 @@ class KubernetesRawModule(KubernetesAnsibleModule):
|
|||
supports_check_mode=True,
|
||||
**kwargs)
|
||||
|
||||
kind = self.params.pop('kind')
|
||||
api_version = self.params.pop('api_version')
|
||||
name = self.params.pop('name')
|
||||
namespace = self.params.pop('namespace')
|
||||
resource_definition = self.params.pop('resource_definition')
|
||||
if resource_definition:
|
||||
self.resource_definitions = [resource_definition]
|
||||
src = self.params.pop('src')
|
||||
if src:
|
||||
self.resource_definitions = self.load_resource_definitions(src)
|
||||
self.kind = self.params.pop('kind')
|
||||
self.api_version = self.params.pop('api_version')
|
||||
self.resource_definition = self.params.pop('resource_definition')
|
||||
self.src = self.params.pop('src')
|
||||
if self.src:
|
||||
self.resource_definition = self.load_resource_definition(self.src)
|
||||
|
||||
if not resource_definition and not src:
|
||||
self.resource_definitions = [{
|
||||
'kind': kind,
|
||||
'apiVersion': api_version,
|
||||
'metadata': {
|
||||
'name': name,
|
||||
'namespace': namespace
|
||||
}
|
||||
}]
|
||||
if self.resource_definition:
|
||||
self.api_version = self.resource_definition.get('apiVersion')
|
||||
self.kind = self.resource_definition.get('kind')
|
||||
|
||||
self.api_version = self.api_version.lower()
|
||||
self.kind = to_snake(self.kind)
|
||||
|
||||
if not self.api_version:
|
||||
self.fail_json(
|
||||
msg=("Error: no api_version specified. Use the api_version parameter, or provide it as part of a ",
|
||||
"resource_definition.")
|
||||
)
|
||||
if not self.kind:
|
||||
self.fail_json(
|
||||
msg="Error: no kind specified. Use the kind parameter, or provide it as part of a resource_definition"
|
||||
)
|
||||
|
||||
self.helper = self.get_helper(self.api_version, self.kind)
|
||||
|
||||
@property
|
||||
def argspec(self):
|
||||
argspec = copy.deepcopy(COMMON_ARG_SPEC)
|
||||
argspec.update(copy.deepcopy(AUTH_ARG_SPEC))
|
||||
return argspec
|
||||
|
||||
def execute_module(self):
|
||||
changed = False
|
||||
results = []
|
||||
self.client = self.get_api_client()
|
||||
for definition in self.resource_definitions:
|
||||
kind = definition.get('kind')
|
||||
search_kind = kind
|
||||
if kind.lower().endswith('list'):
|
||||
search_kind = kind[:-4]
|
||||
api_version = definition.get('apiVersion')
|
||||
try:
|
||||
resource = self.client.resources.get(kind=search_kind, api_version=api_version)
|
||||
except Exception as e:
|
||||
self.fail_json(msg='Failed to find resource {0}.{1}: {2}'.format(
|
||||
api_version, search_kind, e
|
||||
))
|
||||
result = self.perform_action(resource, definition)
|
||||
changed = changed or result['changed']
|
||||
results.append(result)
|
||||
if self.resource_definition:
|
||||
resource_params = self.resource_to_parameters(self.resource_definition)
|
||||
self.params.update(resource_params)
|
||||
|
||||
if len(results) == 1:
|
||||
self.exit_json(**results[0])
|
||||
self.authenticate()
|
||||
|
||||
self.exit_json(**{
|
||||
'changed': changed,
|
||||
'result': {
|
||||
'results': results
|
||||
}
|
||||
})
|
||||
|
||||
def perform_action(self, resource, definition):
|
||||
result = {'changed': False, 'result': {}}
|
||||
state = self.params.pop('state', None)
|
||||
force = self.params.pop('force', False)
|
||||
name = definition.get('metadata', {}).get('name')
|
||||
namespace = definition.get('metadata', {}).get('namespace')
|
||||
name = self.params.get('name')
|
||||
namespace = self.params.get('namespace')
|
||||
existing = None
|
||||
|
||||
self.remove_aliases()
|
||||
|
||||
if definition['kind'].endswith('list'):
|
||||
result['result'] = resource.get(namespace=namespace).to_dict()
|
||||
result['changed'] = False
|
||||
result['method'] = 'get'
|
||||
return result
|
||||
return_attributes = dict(changed=False, result=dict())
|
||||
|
||||
if self.helper.base_model_name_snake.endswith('list'):
|
||||
k8s_obj = self._read(name, namespace)
|
||||
return_attributes['result'] = k8s_obj.to_dict()
|
||||
self.exit_json(**return_attributes)
|
||||
|
||||
try:
|
||||
existing = resource.get(name=name, namespace=namespace)
|
||||
except NotFoundError:
|
||||
pass
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc.body),
|
||||
error=exc.status, status=exc.status, reason=exc.reason)
|
||||
existing = self.helper.get_object(name, namespace)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc.message),
|
||||
error=exc.value.get('status'))
|
||||
|
||||
if state == 'absent':
|
||||
result['method'] = "delete"
|
||||
if not existing:
|
||||
# The object already does not exist
|
||||
return result
|
||||
self.exit_json(**return_attributes)
|
||||
else:
|
||||
# Delete the object
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = resource.delete(name, namespace=namespace)
|
||||
result['result'] = k8s_obj.to_dict()
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg="Failed to delete object: {0}".format(exc.body),
|
||||
error=exc.status, status=exc.status, reason=exc.reason)
|
||||
result['changed'] = True
|
||||
return result
|
||||
self.helper.delete_object(name, namespace)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg="Failed to delete object: {0}".format(exc.message),
|
||||
error=exc.value.get('status'))
|
||||
return_attributes['changed'] = True
|
||||
self.exit_json(**return_attributes)
|
||||
else:
|
||||
if not existing:
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = resource.create(definition, namespace=namespace)
|
||||
except ConflictError:
|
||||
# Some resources, like ProjectRequests, can't be created multiple times,
|
||||
# because the resources that they create don't match their kind
|
||||
# In this case we'll mark it as unchanged and warn the user
|
||||
self.warn("{0} was not found, but creating it returned a 409 Conflict error. This can happen \
|
||||
if the resource you are creating does not directly create a resource of the same kind.".format(name))
|
||||
return result
|
||||
result['result'] = k8s_obj.to_dict()
|
||||
result['changed'] = True
|
||||
result['method'] = 'create'
|
||||
return result
|
||||
k8s_obj = self._create(namespace)
|
||||
return_attributes['result'] = k8s_obj.to_dict()
|
||||
return_attributes['changed'] = True
|
||||
self.exit_json(**return_attributes)
|
||||
|
||||
if existing and force:
|
||||
k8s_obj = None
|
||||
request_body = self.helper.request_body_from_params(self.params)
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = resource.replace(definition, name=name, namespace=namespace)
|
||||
result['result'] = k8s_obj.to_dict()
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg="Failed to replace object: {0}".format(exc.body),
|
||||
error=exc.status, status=exc.status, reason=exc.reason)
|
||||
result['changed'] = True
|
||||
result['method'] = 'replace'
|
||||
return result
|
||||
|
||||
match, diffs = self.diff_objects(existing.to_dict(), definition)
|
||||
k8s_obj = self.helper.replace_object(name, namespace, body=request_body)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg="Failed to replace object: {0}".format(exc.message),
|
||||
error=exc.value.get('status'))
|
||||
return_attributes['result'] = k8s_obj.to_dict()
|
||||
return_attributes['changed'] = True
|
||||
self.exit_json(**return_attributes)
|
||||
|
||||
# Check if existing object should be patched
|
||||
k8s_obj = copy.deepcopy(existing)
|
||||
try:
|
||||
self.helper.object_from_params(self.params, obj=k8s_obj)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg="Failed to patch object: {0}".format(exc.message))
|
||||
match, diff = self.helper.objects_match(self.helper.fix_serialization(existing), k8s_obj)
|
||||
if match:
|
||||
result['result'] = existing.to_dict()
|
||||
return result
|
||||
return_attributes['result'] = existing.to_dict()
|
||||
self.exit_json(**return_attributes)
|
||||
# Differences exist between the existing obj and requested params
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = resource.patch(definition, name=name, namespace=namespace)
|
||||
result['result'] = k8s_obj.to_dict()
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg="Failed to patch object: {0}".format(exc.body),
|
||||
error=exc.status, status=exc.status, reason=exc.reason)
|
||||
result['changed'] = True
|
||||
result['method'] = 'patch'
|
||||
result['diff'] = diffs
|
||||
return result
|
||||
k8s_obj = self.helper.patch_object(name, namespace, k8s_obj)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg="Failed to patch object: {0}".format(exc.message))
|
||||
return_attributes['result'] = k8s_obj.to_dict()
|
||||
return_attributes['changed'] = True
|
||||
self.exit_json(**return_attributes)
|
||||
|
||||
def _create(self, namespace):
|
||||
request_body = None
|
||||
k8s_obj = None
|
||||
try:
|
||||
request_body = self.helper.request_body_from_params(self.params)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg="Failed to create object: {0}".format(exc.message))
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = self.helper.create_object(namespace, body=request_body)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg="Failed to create object: {0}".format(exc.message),
|
||||
error=exc.value.get('status'))
|
||||
return k8s_obj
|
||||
|
||||
def _read(self, name, namespace):
|
||||
k8s_obj = None
|
||||
try:
|
||||
k8s_obj = self.helper.get_object(name, namespace)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg='Failed to retrieve requested object',
|
||||
error=exc.value.get('status'))
|
||||
return k8s_obj
|
||||
|
||||
|
||||
class OpenShiftRawModule(OpenShiftAnsibleModuleMixin, KubernetesRawModule):
|
||||
|
||||
@property
|
||||
def argspec(self):
|
||||
args = super(OpenShiftRawModule, self).argspec
|
||||
args.update(copy.deepcopy(OPENSHIFT_ARG_SPEC))
|
||||
return args
|
||||
|
||||
def _create(self, namespace):
|
||||
if self.kind.lower() == 'project':
|
||||
return self._create_project()
|
||||
return KubernetesRawModule._create(self, namespace)
|
||||
|
||||
def _create_project(self):
|
||||
new_obj = None
|
||||
k8s_obj = None
|
||||
try:
|
||||
new_obj = self.helper.object_from_params(self.params)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg="Failed to create object: {0}".format(exc.message))
|
||||
try:
|
||||
k8s_obj = self.helper.create_project(metadata=new_obj.metadata,
|
||||
display_name=self.params.get('display_name'),
|
||||
description=self.params.get('description'))
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg='Failed to retrieve requested object',
|
||||
error=exc.value.get('status'))
|
||||
return k8s_obj
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue