mirror of
https://github.com/openshift/community.okd.git
synced 2026-05-06 13:12:37 +00:00
update collection with latest feature from kubernetes.core (#181)
* Rebase code with kubernetes.core stable-2.4
This commit is contained in:
@@ -6,79 +6,113 @@ __metaclass__ = type
|
||||
import re
|
||||
import operator
|
||||
from functools import reduce
|
||||
import traceback
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.resource import create_definitions
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import CoreException
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError, NotFoundError, ForbiddenError
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
pass
|
||||
|
||||
|
||||
TRIGGER_ANNOTATION = 'image.openshift.io/triggers'
|
||||
TRIGGER_CONTAINER = re.compile(r"(?P<path>.*)\[((?P<index>[0-9]+)|\?\(@\.name==[\"'\\]*(?P<name>[a-z0-9]([-a-z0-9]*[a-z0-9])?))")
|
||||
|
||||
|
||||
class OKDRawModule(K8sAnsibleMixin):
|
||||
class OKDRawModule(AnsibleOpenshiftModule):
|
||||
|
||||
def __init__(self, module, k8s_kind=None, *args, **kwargs):
|
||||
self.module = module
|
||||
self.client = get_api_client(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
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super(OKDRawModule, self).__init__(module, *args, **kwargs)
|
||||
super(OKDRawModule, self).__init__(**kwargs)
|
||||
|
||||
self.warnings = []
|
||||
@property
|
||||
def module(self):
|
||||
return self._module
|
||||
|
||||
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')
|
||||
def execute_module(self):
|
||||
results = []
|
||||
changed = False
|
||||
|
||||
self.check_library_version()
|
||||
self.set_resource_definitions(module)
|
||||
try:
|
||||
definitions = create_definitions(self.params)
|
||||
except Exception as e:
|
||||
msg = "Failed to load resource definition: {0}".format(e)
|
||||
raise CoreException(msg) from e
|
||||
|
||||
def perform_action(self, resource, definition):
|
||||
state = self.params.get('state', None)
|
||||
name = definition['metadata'].get('name')
|
||||
namespace = definition['metadata'].get('namespace')
|
||||
for definition in definitions:
|
||||
result = {"changed": False, "result": {}}
|
||||
warnings = []
|
||||
|
||||
if state != 'absent':
|
||||
if self.params.get("state") != 'absent':
|
||||
existing = None
|
||||
name = definition.get("metadata", {}).get("name")
|
||||
namespace = definition.get("metadata", {}).get("namespace")
|
||||
if definition.get("kind") in ['Project', 'ProjectRequest']:
|
||||
try:
|
||||
resource = self.svc.find_resource(kind=definition.get("kind"), api_version=definition.get("apiVersion", "v1"))
|
||||
existing = resource.get(name=name, namespace=namespace).to_dict()
|
||||
except (NotFoundError, ForbiddenError):
|
||||
result = self.create_project_request(definition)
|
||||
changed |= result["changed"]
|
||||
results.append(result)
|
||||
continue
|
||||
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)
|
||||
|
||||
if resource.kind in ['Project', 'ProjectRequest']:
|
||||
try:
|
||||
resource.get(name, namespace)
|
||||
except (NotFoundError, ForbiddenError):
|
||||
return self.create_project_request(definition)
|
||||
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)
|
||||
if definition.get("kind") not in ['Project', 'ProjectRequest']:
|
||||
try:
|
||||
resource = self.svc.find_resource(kind=definition.get("kind"), api_version=definition.get("apiVersion", "v1"))
|
||||
existing = resource.get(name=name, namespace=namespace).to_dict()
|
||||
except Exception:
|
||||
existing = None
|
||||
|
||||
if existing:
|
||||
if resource.kind == 'DeploymentConfig':
|
||||
if definition.get('spec', {}).get('triggers'):
|
||||
definition = self.resolve_imagestream_triggers(existing, definition)
|
||||
elif existing['metadata'].get('annotations', {}).get(TRIGGER_ANNOTATION):
|
||||
definition = self.resolve_imagestream_trigger_annotation(existing, definition)
|
||||
|
||||
if self.params.get("validate") is not None:
|
||||
warnings = self.validate(definition)
|
||||
|
||||
try:
|
||||
existing = resource.get(name=name, namespace=namespace).to_dict()
|
||||
except Exception:
|
||||
existing = None
|
||||
result = self.perform_action(definition, self.params)
|
||||
except Exception as e:
|
||||
try:
|
||||
error = e.result
|
||||
except AttributeError:
|
||||
error = {}
|
||||
try:
|
||||
error["reason"] = e.__cause__.reason
|
||||
except AttributeError:
|
||||
pass
|
||||
error["msg"] = to_native(e)
|
||||
if warnings:
|
||||
error.setdefault("warnings", []).extend(warnings)
|
||||
|
||||
if existing:
|
||||
if resource.kind == 'DeploymentConfig':
|
||||
if definition.get('spec', {}).get('triggers'):
|
||||
definition = self.resolve_imagestream_triggers(existing, definition)
|
||||
elif existing['metadata'].get('annotations', {}).get(TRIGGER_ANNOTATION):
|
||||
definition = self.resolve_imagestream_trigger_annotation(existing, definition)
|
||||
if self.params.get("continue_on_error"):
|
||||
result["error"] = error
|
||||
else:
|
||||
self.fail_json(**error)
|
||||
|
||||
return super(OKDRawModule, self).perform_action(resource, definition)
|
||||
if warnings:
|
||||
result.setdefault("warnings", []).extend(warnings)
|
||||
changed |= result["changed"]
|
||||
results.append(result)
|
||||
|
||||
if len(results) == 1:
|
||||
self.exit_json(**results[0])
|
||||
|
||||
self.exit_json(**{"changed": changed, "result": {"results": results}})
|
||||
|
||||
@staticmethod
|
||||
def get_index(desired, objects, keys):
|
||||
@@ -173,7 +207,7 @@ class OKDRawModule(K8sAnsibleMixin):
|
||||
def create_project_request(self, definition):
|
||||
definition['kind'] = 'ProjectRequest'
|
||||
result = {'changed': False, 'result': {}}
|
||||
resource = self.find_resource('ProjectRequest', definition['apiVersion'], fail=True)
|
||||
resource = self.svc.find_resource(kind='ProjectRequest', api_version=definition['apiVersion'], fail=True)
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = resource.create(definition)
|
||||
|
||||
@@ -3,22 +3,9 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
try:
|
||||
from kubernetes import client
|
||||
@@ -27,24 +14,9 @@ except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class OpenShiftAdmPruneAuth(K8sAnsibleMixin):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.fail_json = self.module.fail_json
|
||||
self.exit_json = self.module.exit_json
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.module.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
super(OpenShiftAdmPruneAuth, self).__init__(self.module)
|
||||
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
self.client = get_api_client(self.module)
|
||||
class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftAdmPruneAuth, self).__init__(**kwargs)
|
||||
|
||||
def prune_resource_binding(self, kind, api_version, ref_kind, ref_namespace_names, propagation_policy=None):
|
||||
|
||||
|
||||
@@ -8,18 +8,7 @@ import traceback
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
try:
|
||||
from kubernetes import client
|
||||
@@ -42,24 +31,10 @@ def get_deploymentconfig_for_replicationcontroller(replica_controller):
|
||||
return None
|
||||
|
||||
|
||||
class OpenShiftAdmPruneDeployment(K8sAnsibleMixin):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.fail_json = self.module.fail_json
|
||||
self.exit_json = self.module.exit_json
|
||||
class OpenShiftAdmPruneDeployment(AnsibleOpenshiftModule):
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.module.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
super(OpenShiftAdmPruneDeployment, self).__init__(self.module)
|
||||
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
self.client = get_api_client(self.module)
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftAdmPruneDeployment, self).__init__(**kwargs)
|
||||
|
||||
def filter_replication_controller(self, replicacontrollers):
|
||||
def _deployment(obj):
|
||||
@@ -109,7 +84,7 @@ class OpenShiftAdmPruneDeployment(K8sAnsibleMixin):
|
||||
results = filter(pred, results)
|
||||
return list(results)
|
||||
|
||||
def execute(self):
|
||||
def execute_module(self):
|
||||
# list replicationcontroller candidate for pruning
|
||||
kind = 'ReplicationController'
|
||||
api_version = 'v1'
|
||||
|
||||
@@ -11,18 +11,7 @@ from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.module_utils.six import iteritems
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_images_common import (
|
||||
OpenShiftAnalyzeImageStream,
|
||||
@@ -102,36 +91,9 @@ def determine_host_registry(module, images, image_streams):
|
||||
return result['hostname']
|
||||
|
||||
|
||||
class OpenShiftAdmPruneImages(K8sAnsibleMixin):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.fail_json = self.module.fail_json
|
||||
self.exit_json = self.module.exit_json
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
super(OpenShiftAdmPruneImages, self).__init__(self.module)
|
||||
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
try:
|
||||
self.client = get_api_client(self.module)
|
||||
except DynamicApiError as e:
|
||||
self.fail_json(
|
||||
msg="Failed to get kubernetes client.",
|
||||
reason=e.reason,
|
||||
status=e.status,
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail_json(
|
||||
msg="Failed to get kubernetes client.",
|
||||
error=to_native(e)
|
||||
)
|
||||
class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftAdmPruneImages, self).__init__(**kwargs)
|
||||
|
||||
self.max_creation_timestamp = self.get_max_creation_timestamp()
|
||||
self._rest_client = None
|
||||
@@ -239,7 +201,7 @@ class OpenShiftAdmPruneImages(K8sAnsibleMixin):
|
||||
result = definition
|
||||
if not self.check_mode:
|
||||
try:
|
||||
result = self.client.request(
|
||||
result = self.request(
|
||||
"PUT",
|
||||
"/apis/{api_version}/namespaces/{namespace}/imagestreams/{name}/status".format(
|
||||
api_version=api_version,
|
||||
|
||||
@@ -9,18 +9,7 @@ import time
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -28,24 +17,9 @@ except ImportError as e:
|
||||
pass
|
||||
|
||||
|
||||
class OpenShiftBuilds(K8sAnsibleMixin):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.fail_json = self.module.fail_json
|
||||
self.exit_json = self.module.exit_json
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.module.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
super(OpenShiftBuilds, self).__init__(self.module)
|
||||
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
self.client = get_api_client(self.module)
|
||||
class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftBuilds, self).__init__(**kwargs)
|
||||
|
||||
def get_build_config(self, name, namespace):
|
||||
params = dict(
|
||||
@@ -57,78 +31,9 @@ class OpenShiftBuilds(K8sAnsibleMixin):
|
||||
result = self.kubernetes_facts(**params)
|
||||
return result["resources"]
|
||||
|
||||
def prune(self):
|
||||
# list replicationcontroller candidate for pruning
|
||||
kind = 'Build'
|
||||
api_version = 'build.openshift.io/v1'
|
||||
resource = self.find_resource(kind=kind, api_version=api_version, fail=True)
|
||||
|
||||
self.max_creation_timestamp = None
|
||||
keep_younger_than = self.params.get("keep_younger_than")
|
||||
if keep_younger_than:
|
||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
self.max_creation_timestamp = now - timedelta(minutes=keep_younger_than)
|
||||
|
||||
def _prunable_build(build):
|
||||
return build["status"]["phase"] in ("Complete", "Failed", "Error", "Cancelled")
|
||||
|
||||
def _orphan_build(build):
|
||||
if not _prunable_build(build):
|
||||
return False
|
||||
|
||||
config = build["status"].get("config", None)
|
||||
if not config:
|
||||
return True
|
||||
build_config = self.get_build_config(config["name"], config["namespace"])
|
||||
return len(build_config) == 0
|
||||
|
||||
def _younger_build(build):
|
||||
if not self.max_creation_timestamp:
|
||||
return False
|
||||
creation_timestamp = datetime.strptime(build['metadata']['creationTimestamp'], '%Y-%m-%dT%H:%M:%SZ')
|
||||
return creation_timestamp < self.max_creation_timestamp
|
||||
|
||||
predicates = [
|
||||
_prunable_build,
|
||||
]
|
||||
if self.params.get("orphans"):
|
||||
predicates.append(_orphan_build)
|
||||
if self.max_creation_timestamp:
|
||||
predicates.append(_younger_build)
|
||||
|
||||
# Get ReplicationController
|
||||
params = dict(
|
||||
kind=kind,
|
||||
api_version=api_version,
|
||||
namespace=self.params.get("namespace"),
|
||||
)
|
||||
result = self.kubernetes_facts(**params)
|
||||
candidates = result["resources"]
|
||||
for pred in predicates:
|
||||
candidates = list(filter(pred, candidates))
|
||||
|
||||
if self.check_mode:
|
||||
changed = len(candidates) > 0
|
||||
self.exit_json(changed=changed, builds=candidates)
|
||||
|
||||
changed = False
|
||||
for build in candidates:
|
||||
changed = True
|
||||
try:
|
||||
name = build["metadata"]["name"]
|
||||
namespace = build["metadata"]["namespace"]
|
||||
resource.delete(name=name, namespace=namespace, body={})
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (namespace, name, exc.body)
|
||||
self.fail_json(msg=msg, status=exc.status, reason=exc.reason)
|
||||
except Exception as e:
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (namespace, name, to_native(e))
|
||||
self.fail_json(msg=msg, error=to_native(e), exception=e)
|
||||
self.exit_json(changed=changed, builds=candidates)
|
||||
|
||||
def clone_build(self, name, namespace, request):
|
||||
try:
|
||||
result = self.client.request(
|
||||
result = self.request(
|
||||
method="POST",
|
||||
path="/apis/build.openshift.io/v1/namespaces/{namespace}/builds/{name}/clone".format(
|
||||
namespace=namespace,
|
||||
@@ -147,7 +52,7 @@ class OpenShiftBuilds(K8sAnsibleMixin):
|
||||
|
||||
def instantiate_build_config(self, name, namespace, request):
|
||||
try:
|
||||
result = self.client.request(
|
||||
result = self.request(
|
||||
method="POST",
|
||||
path="/apis/build.openshift.io/v1/namespaces/{namespace}/buildconfigs/{name}/instantiate".format(
|
||||
namespace=namespace,
|
||||
@@ -300,8 +205,9 @@ class OpenShiftBuilds(K8sAnsibleMixin):
|
||||
|
||||
namespace = self.params.get("namespace")
|
||||
phases = ["new", "pending", "running"]
|
||||
if len(self.params.get("build_phases")):
|
||||
phases = [p.lower() for p in self.params.get("build_phases")]
|
||||
build_phases = self.params.get("build_phases", [])
|
||||
if build_phases:
|
||||
phases = [p.lower() for p in build_phases]
|
||||
|
||||
names = []
|
||||
if self.params.get("build_name"):
|
||||
@@ -318,7 +224,7 @@ class OpenShiftBuilds(K8sAnsibleMixin):
|
||||
|
||||
def _filter_builds(build):
|
||||
config = build["metadata"].get("labels", {}).get("openshift.io/build-config.name")
|
||||
return config in build_config
|
||||
return build_config is None or (build_config is not None and config in build_config)
|
||||
|
||||
for item in list(filter(_filter_builds, resources)):
|
||||
name = item["metadata"]["name"]
|
||||
@@ -361,7 +267,7 @@ class OpenShiftBuilds(K8sAnsibleMixin):
|
||||
changed = True
|
||||
try:
|
||||
content_type = "application/json"
|
||||
cancelled_build = self.client.request(
|
||||
cancelled_build = self.request(
|
||||
"PUT",
|
||||
"/apis/build.openshift.io/v1/namespaces/{0}/builds/{1}".format(
|
||||
namespace, name
|
||||
@@ -427,3 +333,77 @@ class OpenShiftBuilds(K8sAnsibleMixin):
|
||||
else:
|
||||
restart = bool(state == "restarted")
|
||||
self.cancel_build(restart=restart)
|
||||
|
||||
|
||||
class OpenShiftPruneBuilds(OpenShiftBuilds):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftPruneBuilds, self).__init__(**kwargs)
|
||||
|
||||
def execute_module(self):
|
||||
# list replicationcontroller candidate for pruning
|
||||
kind = 'Build'
|
||||
api_version = 'build.openshift.io/v1'
|
||||
resource = self.find_resource(kind=kind, api_version=api_version, fail=True)
|
||||
|
||||
self.max_creation_timestamp = None
|
||||
keep_younger_than = self.params.get("keep_younger_than")
|
||||
if keep_younger_than:
|
||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
self.max_creation_timestamp = now - timedelta(minutes=keep_younger_than)
|
||||
|
||||
def _prunable_build(build):
|
||||
return build["status"]["phase"] in ("Complete", "Failed", "Error", "Cancelled")
|
||||
|
||||
def _orphan_build(build):
|
||||
if not _prunable_build(build):
|
||||
return False
|
||||
|
||||
config = build["status"].get("config", None)
|
||||
if not config:
|
||||
return True
|
||||
build_config = self.get_build_config(config["name"], config["namespace"])
|
||||
return len(build_config) == 0
|
||||
|
||||
def _younger_build(build):
|
||||
if not self.max_creation_timestamp:
|
||||
return False
|
||||
creation_timestamp = datetime.strptime(build['metadata']['creationTimestamp'], '%Y-%m-%dT%H:%M:%SZ')
|
||||
return creation_timestamp < self.max_creation_timestamp
|
||||
|
||||
predicates = [
|
||||
_prunable_build,
|
||||
]
|
||||
if self.params.get("orphans"):
|
||||
predicates.append(_orphan_build)
|
||||
if self.max_creation_timestamp:
|
||||
predicates.append(_younger_build)
|
||||
|
||||
# Get ReplicationController
|
||||
params = dict(
|
||||
kind=kind,
|
||||
api_version=api_version,
|
||||
namespace=self.params.get("namespace"),
|
||||
)
|
||||
result = self.kubernetes_facts(**params)
|
||||
candidates = result["resources"]
|
||||
for pred in predicates:
|
||||
candidates = list(filter(pred, candidates))
|
||||
|
||||
if self.check_mode:
|
||||
changed = len(candidates) > 0
|
||||
self.exit_json(changed=changed, builds=candidates)
|
||||
|
||||
changed = False
|
||||
for build in candidates:
|
||||
changed = True
|
||||
try:
|
||||
name = build["metadata"]["name"]
|
||||
namespace = build["metadata"]["namespace"]
|
||||
resource.delete(name=name, namespace=namespace, body={})
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (namespace, name, exc.body)
|
||||
self.fail_json(msg=msg, status=exc.status, reason=exc.reason)
|
||||
except Exception as e:
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (namespace, name, to_native(e))
|
||||
self.fail_json(msg=msg, error=to_native(e), exception=e)
|
||||
self.exit_json(changed=changed, builds=candidates)
|
||||
|
||||
93
plugins/module_utils/openshift_common.py
Normal file
93
plugins/module_utils/openshift_common.py
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import traceback
|
||||
from abc import abstractmethod
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import get_api_client
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import AnsibleK8SModule
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.service import (
|
||||
K8sService,
|
||||
diff_objects,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.runner import (
|
||||
perform_action,
|
||||
validate,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.resource import (
|
||||
create_definitions,
|
||||
merge_params,
|
||||
flatten_list_kind,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import CoreException
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
|
||||
|
||||
class AnsibleOpenshiftModule(AnsibleK8SModule):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(AnsibleOpenshiftModule, self).__init__(**kwargs)
|
||||
|
||||
self.client = get_api_client(module=self)
|
||||
self.fail = self.fail_json
|
||||
|
||||
self.svc = K8sService(self.client, self._module)
|
||||
self.find_resource = self.svc.find_resource
|
||||
self.kubernetes_facts = self.svc.find
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
@property
|
||||
def module(self):
|
||||
return self._module
|
||||
|
||||
@abstractmethod
|
||||
def execute_module(self):
|
||||
pass
|
||||
|
||||
def request(self, *args, **kwargs):
|
||||
return self.client.client.request(*args, **kwargs)
|
||||
|
||||
def set_resource_definitions(self):
|
||||
self.resource_definitions = create_definitions(self.params)
|
||||
|
||||
def perform_action(self, definition, params):
|
||||
return perform_action(self.svc, definition, params)
|
||||
|
||||
def validate(self, definition):
|
||||
validate(self.client, self, definition)
|
||||
|
||||
@staticmethod
|
||||
def merge_params(definition, params):
|
||||
return merge_params(definition, params)
|
||||
|
||||
@staticmethod
|
||||
def flatten_list_kind(definition, params):
|
||||
return flatten_list_kind(definition, params)
|
||||
|
||||
@staticmethod
|
||||
def diff_objects(existing, new):
|
||||
return diff_objects(existing, new)
|
||||
|
||||
def run_module(self):
|
||||
|
||||
try:
|
||||
self.execute_module()
|
||||
except CoreException as e:
|
||||
self.fail_from_exception(e)
|
||||
@@ -10,7 +10,6 @@ __metaclass__ = type
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (K8sAnsibleMixin, get_api_client)
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.basic import missing_required_lib
|
||||
@@ -31,18 +30,7 @@ except ImportError as e:
|
||||
HAS_PYTHON_LDAP = False
|
||||
PYTHON_LDAP_ERROR = e
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -264,13 +252,11 @@ class OpenshiftLDAPGroups(object):
|
||||
return result
|
||||
|
||||
|
||||
class OpenshiftGroupsSync(K8sAnsibleMixin):
|
||||
class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
|
||||
def __init__(self, module):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
self.module = module
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
super(OpenshiftGroupsSync, self).__init__(**kwargs)
|
||||
self.__k8s_group_api = None
|
||||
self.__ldap_connection = None
|
||||
self.host = None
|
||||
@@ -279,22 +265,11 @@ class OpenshiftGroupsSync(K8sAnsibleMixin):
|
||||
self.scheme = None
|
||||
self.config = self.params.get("sync_config")
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.module.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
if not HAS_PYTHON_LDAP:
|
||||
self.fail_json(
|
||||
msg=missing_required_lib('python-ldap'), error=to_native(PYTHON_LDAP_ERROR)
|
||||
)
|
||||
|
||||
super(OpenshiftGroupsSync, self).__init__(self.module)
|
||||
|
||||
self.client = get_api_client(self.module)
|
||||
|
||||
@property
|
||||
def k8s_group_api(self):
|
||||
if not self.__k8s_group_api:
|
||||
|
||||
@@ -11,7 +11,7 @@ from ansible.module_utils.six import iteritems
|
||||
|
||||
|
||||
def get_image_blobs(image):
|
||||
blobs = [layer["image"] for layer in image["dockerImageLayers"]]
|
||||
blobs = [layer["image"] for layer in image["dockerImageLayers"] if "image" in layer]
|
||||
docker_image_metadata = image.get("dockerImageMetadata")
|
||||
if not docker_image_metadata:
|
||||
return blobs, "failed to read metadata for image %s" % image["metadata"]["name"]
|
||||
@@ -53,7 +53,7 @@ class OpenShiftAnalyzeImageStream(object):
|
||||
if error:
|
||||
return error
|
||||
|
||||
if len(result['hostname']) == 0 or len(result['namespace']) == 0:
|
||||
if not result['hostname'] or not result['namespace']:
|
||||
# image reference does not match hostname/namespace/name pattern - skipping
|
||||
return None
|
||||
|
||||
@@ -161,41 +161,35 @@ class OpenShiftAnalyzeImageStream(object):
|
||||
return name, tag, None
|
||||
|
||||
from_strategy = _determine_source_strategy()
|
||||
if not from_strategy:
|
||||
# Build strategy not found
|
||||
return
|
||||
|
||||
if from_strategy.get('kind') == "DockerImage":
|
||||
docker_image_ref = from_strategy.get('name').strip()
|
||||
if len(docker_image_ref) > 0:
|
||||
err = self.analyze_reference_image(docker_image_ref, referrer)
|
||||
|
||||
elif from_strategy.get('kind') == "ImageStreamImage":
|
||||
name, tag, error = _parse_image_stream_image_name(from_strategy.get('name'))
|
||||
if error:
|
||||
if not self.ignore_invalid_refs:
|
||||
return error
|
||||
else:
|
||||
namespace = from_strategy.get('namespace') or namespace
|
||||
self.used_images.append({
|
||||
'namespace': namespace,
|
||||
'name': name,
|
||||
'tag': tag
|
||||
})
|
||||
elif from_strategy.get('kind') == "ImageStreamTag":
|
||||
name, tag, error = _parse_image_stream_tag_name(from_strategy.get('name'))
|
||||
if error:
|
||||
if not self.ignore_invalid_refs:
|
||||
return error
|
||||
else:
|
||||
namespace = from_strategy.get('namespace') or namespace
|
||||
self.used_tags.append({
|
||||
'namespace': namespace,
|
||||
'name': name,
|
||||
'tag': tag
|
||||
})
|
||||
|
||||
return None
|
||||
if from_strategy:
|
||||
if from_strategy.get('kind') == "DockerImage":
|
||||
docker_image_ref = from_strategy.get('name').strip()
|
||||
if len(docker_image_ref) > 0:
|
||||
err = self.analyze_reference_image(docker_image_ref, referrer)
|
||||
elif from_strategy.get('kind') == "ImageStreamImage":
|
||||
name, tag, error = _parse_image_stream_image_name(from_strategy.get('name'))
|
||||
if error:
|
||||
if not self.ignore_invalid_refs:
|
||||
return error
|
||||
else:
|
||||
namespace = from_strategy.get('namespace') or namespace
|
||||
self.used_images.append({
|
||||
'namespace': namespace,
|
||||
'name': name,
|
||||
'tag': tag
|
||||
})
|
||||
elif from_strategy.get('kind') == "ImageStreamTag":
|
||||
name, tag, error = _parse_image_stream_tag_name(from_strategy.get('name'))
|
||||
if error:
|
||||
if not self.ignore_invalid_refs:
|
||||
return error
|
||||
else:
|
||||
namespace = from_strategy.get('namespace') or namespace
|
||||
self.used_tags.append({
|
||||
'namespace': namespace,
|
||||
'name': name,
|
||||
'tag': tag
|
||||
})
|
||||
|
||||
def analyze_refs_from_build_strategy(self, resources):
|
||||
# Json Path is always spec.strategy
|
||||
@@ -212,7 +206,7 @@ class OpenShiftAnalyzeImageStream(object):
|
||||
error = self.analyze_refs_from_strategy(obj['spec']['strategy'],
|
||||
obj['metadata']['namespace'],
|
||||
referrer)
|
||||
if not error:
|
||||
if error is not None:
|
||||
return "%s/%s/%s: %s" % (referrer["kind"], referrer["namespace"], referrer["name"], error)
|
||||
|
||||
def analyze_image_stream(self, resources):
|
||||
|
||||
@@ -10,18 +10,7 @@ from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.module_utils.six import string_types
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -86,24 +75,9 @@ def follow_imagestream_tag_reference(stream, tag):
|
||||
multiple = True
|
||||
|
||||
|
||||
class OpenShiftImportImage(K8sAnsibleMixin):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.fail_json = self.module.fail_json
|
||||
self.exit_json = self.module.exit_json
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
super(OpenShiftImportImage, self).__init__(self.module)
|
||||
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
self.client = get_api_client(self.module)
|
||||
class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftImportImage, self).__init__(**kwargs)
|
||||
|
||||
self._rest_client = None
|
||||
self.registryhost = self.params.get('registry_url')
|
||||
|
||||
@@ -6,47 +6,20 @@ __metaclass__ = type
|
||||
import os
|
||||
import traceback
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError, NotFoundError
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError, NotFoundError
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class OpenShiftProcess(K8sAnsibleMixin):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.fail_json = self.module.fail_json
|
||||
self.exit_json = self.module.exit_json
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.module.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
super(OpenShiftProcess, self).__init__(self.module)
|
||||
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
self.client = get_api_client(self.module)
|
||||
class OpenShiftProcess(AnsibleOpenshiftModule):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftProcess, self).__init__(**kwargs)
|
||||
|
||||
def execute_module(self):
|
||||
v1_templates = self.find_resource(
|
||||
@@ -76,7 +49,7 @@ class OpenShiftProcess(K8sAnsibleMixin):
|
||||
template = None
|
||||
|
||||
if src or definition:
|
||||
self.set_resource_definitions(self.module)
|
||||
self.set_resource_definitions()
|
||||
if len(self.resource_definitions) < 1:
|
||||
self.fail_json(
|
||||
"Unable to load a Template resource from src or resource_definition"
|
||||
@@ -101,7 +74,7 @@ class OpenShiftProcess(K8sAnsibleMixin):
|
||||
reason=exc.reason,
|
||||
)
|
||||
except Exception as exc:
|
||||
self.module.fail_json(
|
||||
self.fail_json(
|
||||
msg="Failed to retrieve Template with name '{0}' in namespace '{1}': {2}".format(
|
||||
name, namespace, to_native(exc)
|
||||
),
|
||||
@@ -134,7 +107,7 @@ class OpenShiftProcess(K8sAnsibleMixin):
|
||||
reason=exc.reason,
|
||||
)
|
||||
except Exception as exc:
|
||||
self.module.fail_json(
|
||||
self.fail_json(
|
||||
msg="Server failed to render the Template: {0}".format(to_native(exc)),
|
||||
error="",
|
||||
status="",
|
||||
@@ -146,16 +119,41 @@ class OpenShiftProcess(K8sAnsibleMixin):
|
||||
result["resources"] = response["objects"]
|
||||
|
||||
if state != "rendered":
|
||||
self.resource_definitions = response["objects"]
|
||||
self.kind = self.api_version = self.name = None
|
||||
self.namespace = self.params.get("namespace_target")
|
||||
self.append_hash = False
|
||||
self.apply = False
|
||||
self.params["validate"] = None
|
||||
self.params["merge_type"] = None
|
||||
super(OpenShiftProcess, self).execute_module()
|
||||
self.create_resources(response["objects"])
|
||||
|
||||
self.module.exit_json(**result)
|
||||
self.exit_json(**result)
|
||||
|
||||
def create_resources(self, definitions):
|
||||
|
||||
params = {"namespace": self.params.get("namespace_target")}
|
||||
|
||||
self.params["apply"] = False
|
||||
self.params["validate"] = None
|
||||
|
||||
changed = False
|
||||
results = []
|
||||
|
||||
flattened_definitions = []
|
||||
for definition in definitions:
|
||||
if definition is None:
|
||||
continue
|
||||
kind = definition.get("kind")
|
||||
if kind and kind.endswith("List"):
|
||||
flattened_definitions.extend(
|
||||
self.flatten_list_kind(definition, params)
|
||||
)
|
||||
else:
|
||||
flattened_definitions.append(self.merge_params(definition, params))
|
||||
|
||||
for definition in flattened_definitions:
|
||||
result = self.perform_action(definition, self.params)
|
||||
changed = changed or result["changed"]
|
||||
results.append(result)
|
||||
|
||||
if len(results) == 1:
|
||||
self.exit_json(**results[0])
|
||||
|
||||
self.exit_json(**{"changed": changed, "result": {"results": results}})
|
||||
|
||||
def update_template_param(self, template, k, v):
|
||||
for i, param in enumerate(template["parameters"]):
|
||||
|
||||
@@ -6,20 +6,7 @@ __metaclass__ = type
|
||||
import traceback
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
)
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
k8s_collection_import_exception = e
|
||||
K8S_COLLECTION_ERROR = traceback.format_exc()
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_docker_image import (
|
||||
parse_docker_image_ref,
|
||||
@@ -36,25 +23,9 @@ except ImportError as e:
|
||||
REQUESTS_MODULE_ERROR = traceback.format_exc()
|
||||
|
||||
|
||||
class OpenShiftRegistry(K8sAnsibleMixin):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.fail_json = self.module.fail_json
|
||||
self.exit_json = self.module.exit_json
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
self.fail_json(
|
||||
msg="The kubernetes.core collection must be installed",
|
||||
exception=K8S_COLLECTION_ERROR,
|
||||
error=to_native(k8s_collection_import_exception),
|
||||
)
|
||||
|
||||
super(OpenShiftRegistry, self).__init__(self.module)
|
||||
|
||||
self.params = self.module.params
|
||||
self.check_mode = self.module.check_mode
|
||||
self.client = get_api_client(self.module)
|
||||
|
||||
class OpenShiftRegistry(AnsibleOpenshiftModule):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftRegistry, self).__init__(**kwargs)
|
||||
self.check = self.params.get("check")
|
||||
|
||||
def list_image_streams(self, namespace=None):
|
||||
@@ -103,7 +74,7 @@ class OpenShiftRegistry(K8sAnsibleMixin):
|
||||
|
||||
self.fail_json(msg="No Image Streams could be located to retrieve registry info.")
|
||||
|
||||
def info(self):
|
||||
def execute_module(self):
|
||||
result = {}
|
||||
result["internal_hostname"], result["public_hostname"] = self.find_registry_info()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user