mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-06 13:02:37 +00:00
merge with main branch
This commit is contained in:
@@ -23,14 +23,12 @@ import time
|
||||
import os
|
||||
import traceback
|
||||
import sys
|
||||
import tempfile
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (AUTH_ARG_MAP, AUTH_ARG_SPEC, AUTH_PROXY_HEADERS_SPEC)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.hashes import generate_hash
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.cache import get_default_cache_id
|
||||
|
||||
from ansible.module_utils.basic import missing_required_lib
|
||||
from ansible.module_utils.six import iteritems, string_types
|
||||
@@ -42,10 +40,10 @@ from ansible.errors import AnsibleError
|
||||
K8S_IMP_ERR = None
|
||||
try:
|
||||
import kubernetes
|
||||
import openshift
|
||||
from kubernetes.dynamic.exceptions import (
|
||||
NotFoundError, ResourceNotFoundError, ResourceNotUniqueError, DynamicApiError,
|
||||
ConflictError, ForbiddenError, MethodNotAllowedError, BadRequestError
|
||||
ConflictError, ForbiddenError, MethodNotAllowedError, BadRequestError,
|
||||
KubernetesValidateMissing
|
||||
)
|
||||
HAS_K8S_MODULE_HELPER = True
|
||||
k8s_import_exception = None
|
||||
@@ -57,6 +55,7 @@ except ImportError as e:
|
||||
IMP_K8S_CLIENT = None
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8sdynamicclient import K8SDynamicClient
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.client.discovery import LazyDiscoverer
|
||||
IMP_K8S_CLIENT = True
|
||||
except ImportError as e:
|
||||
IMP_K8S_CLIENT = False
|
||||
@@ -71,14 +70,6 @@ except ImportError:
|
||||
YAML_IMP_ERR = traceback.format_exc()
|
||||
HAS_YAML = False
|
||||
|
||||
K8S_CONFIG_HASH_IMP_ERR = None
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import KubernetesValidateMissing
|
||||
HAS_K8S_CONFIG_HASH = True
|
||||
except ImportError:
|
||||
K8S_CONFIG_HASH_IMP_ERR = traceback.format_exc()
|
||||
HAS_K8S_CONFIG_HASH = False
|
||||
|
||||
HAS_K8S_APPLY = None
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.apply import apply_object
|
||||
@@ -114,6 +105,17 @@ except ImportError as e:
|
||||
HAS_JSONPATH_RW = False
|
||||
jsonpath_import_exception = e
|
||||
|
||||
JSON_PATCH_IMP_ERR = None
|
||||
try:
|
||||
import jsonpatch
|
||||
HAS_JSON_PATCH = True
|
||||
jsonpatch_import_exception = None
|
||||
except ImportError as e:
|
||||
HAS_JSON_PATCH = False
|
||||
jsonpatch_import_exception = e
|
||||
JSON_PATCH_IMP_ERR = traceback.format_exc()
|
||||
|
||||
|
||||
def configuration_digest(configuration):
|
||||
m = hashlib.sha256()
|
||||
for k in AUTH_ARG_MAP:
|
||||
@@ -211,15 +213,8 @@ def get_api_client(module=None, **kwargs):
|
||||
client = get_api_client._pool[digest]
|
||||
return client
|
||||
|
||||
def generate_cache_file(kubeclient):
|
||||
cache_file_name = 'k8srcp-{0}.json'.format(hashlib.sha256(get_default_cache_id(kubeclient)).hexdigest())
|
||||
return os.path.join(tempfile.gettempdir(), cache_file_name)
|
||||
|
||||
kubeclient = kubernetes.client.ApiClient(configuration)
|
||||
cache_file = generate_cache_file(kubeclient)
|
||||
|
||||
try:
|
||||
client = K8SDynamicClient(kubeclient, cache_file)
|
||||
client = K8SDynamicClient(kubernetes.client.ApiClient(configuration), discoverer=LazyDiscoverer)
|
||||
except Exception as err:
|
||||
_raise_or_fail(err, 'Failed to get client due to %s')
|
||||
|
||||
@@ -234,9 +229,9 @@ 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,
|
||||
module.fail_json(msg=missing_required_lib('kubernetes'), exception=K8S_IMP_ERR,
|
||||
error=to_native(k8s_import_exception))
|
||||
self.openshift_version = openshift.__version__
|
||||
self.kubernetes_version = kubernetes.__version__
|
||||
|
||||
if not HAS_YAML:
|
||||
module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR)
|
||||
@@ -514,21 +509,8 @@ class K8sAnsibleMixin(object):
|
||||
self.resource_definitions = [implicit_definition]
|
||||
|
||||
def check_library_version(self):
|
||||
validate = self.params.get('validate')
|
||||
if validate and LooseVersion(self.openshift_version) < LooseVersion("0.8.0"):
|
||||
self.fail_json(msg="openshift >= 0.8.0 is required for validate")
|
||||
self.append_hash = self.params.get('append_hash')
|
||||
if self.append_hash and not HAS_K8S_CONFIG_HASH:
|
||||
self.fail_json(msg=missing_required_lib("openshift >= 0.7.2", reason="for append_hash"),
|
||||
exception=K8S_CONFIG_HASH_IMP_ERR)
|
||||
if self.params['merge_type'] and LooseVersion(self.openshift_version) < LooseVersion("0.6.2"):
|
||||
self.fail_json(msg=missing_required_lib("openshift >= 0.6.2", reason="for merge_type"))
|
||||
self.apply = self.params.get('apply', False)
|
||||
if self.apply and not HAS_K8S_APPLY:
|
||||
self.fail_json(msg=missing_required_lib("openshift >= 0.9.2", reason="for apply"))
|
||||
wait = self.params.get('wait', False)
|
||||
if wait and not HAS_K8S_INSTANCE_HELPER:
|
||||
self.fail_json(msg=missing_required_lib("openshift >= 0.4.0", reason="for wait"))
|
||||
if LooseVersion(self.kubernetes_version) < LooseVersion("12.0.0"):
|
||||
self.fail_json(msg="kubernetes >= 12.0.0 is required")
|
||||
|
||||
def flatten_list_kind(self, list_resource, definitions):
|
||||
flattened = []
|
||||
@@ -609,6 +591,8 @@ class K8sAnsibleMixin(object):
|
||||
return definition
|
||||
|
||||
def perform_action(self, resource, definition):
|
||||
append_hash = self.params.get('append_hash', False)
|
||||
apply = self.params.get('apply', False)
|
||||
delete_options = self.params.get('delete_options')
|
||||
result = {'changed': False, 'result': {}}
|
||||
state = self.params.get('state', None)
|
||||
@@ -633,7 +617,7 @@ class K8sAnsibleMixin(object):
|
||||
|
||||
try:
|
||||
# ignore append_hash for resources other than ConfigMap and Secret
|
||||
if self.append_hash and definition['kind'] in ['ConfigMap', 'Secret']:
|
||||
if append_hash and definition['kind'] in ['ConfigMap', 'Secret']:
|
||||
name = '%s-%s' % (name, generate_hash(definition))
|
||||
definition['metadata']['name'] = name
|
||||
params = dict(name=name)
|
||||
@@ -710,7 +694,7 @@ class K8sAnsibleMixin(object):
|
||||
self.fail_json(msg=build_error_msg(definition['kind'], origin_name, msg), **result)
|
||||
return result
|
||||
else:
|
||||
if self.apply:
|
||||
if apply:
|
||||
if self.check_mode:
|
||||
ignored, patch = apply_object(resource, _encode_stringdata(definition))
|
||||
if existing:
|
||||
@@ -806,7 +790,7 @@ class K8sAnsibleMixin(object):
|
||||
k8s_obj = _encode_stringdata(definition)
|
||||
else:
|
||||
try:
|
||||
k8s_obj = resource.replace(definition, name=name, namespace=namespace, append_hash=self.append_hash).to_dict()
|
||||
k8s_obj = resource.replace(definition, name=name, namespace=namespace, append_hash=append_hash).to_dict()
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to replace object: {0}".format(exc.body)
|
||||
if self.warnings:
|
||||
@@ -839,15 +823,11 @@ class K8sAnsibleMixin(object):
|
||||
if self.check_mode:
|
||||
k8s_obj = dict_merge(existing.to_dict(), _encode_stringdata(definition))
|
||||
else:
|
||||
if LooseVersion(self.openshift_version) < LooseVersion("0.6.2"):
|
||||
for merge_type in self.params['merge_type'] or ['strategic-merge', 'merge']:
|
||||
k8s_obj, error = self.patch_resource(resource, definition, existing, name,
|
||||
namespace)
|
||||
else:
|
||||
for merge_type in self.params['merge_type'] or ['strategic-merge', 'merge']:
|
||||
k8s_obj, error = self.patch_resource(resource, definition, existing, name,
|
||||
namespace, merge_type=merge_type)
|
||||
if not error:
|
||||
break
|
||||
namespace, merge_type=merge_type)
|
||||
if not error:
|
||||
break
|
||||
if error:
|
||||
if continue_on_error:
|
||||
result['error'] = error
|
||||
@@ -874,12 +854,42 @@ class K8sAnsibleMixin(object):
|
||||
self.fail_json(msg=msg, **result)
|
||||
return result
|
||||
|
||||
def json_patch(self, existing, definition, merge_type):
|
||||
if merge_type == "json":
|
||||
if not HAS_JSON_PATCH:
|
||||
error = {
|
||||
"msg": missing_required_lib('jsonpatch'),
|
||||
"exception": JSON_PATCH_IMP_ERR,
|
||||
"error": to_native(jsonpatch_import_exception)
|
||||
}
|
||||
return None, error
|
||||
try:
|
||||
patch = jsonpatch.JsonPatch([definition])
|
||||
result_patch = patch.apply(existing.to_dict())
|
||||
return result_patch, None
|
||||
except jsonpatch.InvalidJsonPatch as e:
|
||||
error = {
|
||||
"msg": "invalid json patch",
|
||||
"error": to_native(e)
|
||||
}
|
||||
return None, error
|
||||
except jsonpatch.JsonPatchConflict as e:
|
||||
error = {
|
||||
"msg": "patch could not be applied due to conflict situation",
|
||||
"error": to_native(e)
|
||||
}
|
||||
return None, error
|
||||
return definition, None
|
||||
|
||||
def patch_resource(self, resource, definition, existing, name, namespace, merge_type=None):
|
||||
try:
|
||||
params = dict(name=name, namespace=namespace)
|
||||
if merge_type:
|
||||
params['content_type'] = 'application/{0}-patch+json'.format(merge_type)
|
||||
k8s_obj = resource.patch(definition, **params).to_dict()
|
||||
patch_data, error = self.json_patch(existing, definition, merge_type)
|
||||
if error is not None:
|
||||
return None, error
|
||||
k8s_obj = resource.patch(patch_data, **params).to_dict()
|
||||
match, diffs = self.diff_objects(existing.to_dict(), k8s_obj)
|
||||
error = {}
|
||||
return k8s_obj, {}
|
||||
|
||||
Reference in New Issue
Block a user