mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 12:50:22 -07:00
k8s append_hash (#48830)
* Add append_hash functionality to k8s module append_hash adds a hash based on the contents of a ConfigMap or Secret to the name - this enables immutable ConfigMaps and Secrets. * Provide k8s_config_resource_name plugin The k8s_config_resource_name filter plugin provides a means of determining the name of ConfigMaps and Secrets created with append_hash * Add changelog fragment * fix failing tests * Update openshift version needed for append_hash
This commit is contained in:
parent
c3770bf6f2
commit
960ebd981f
11 changed files with 174 additions and 24 deletions
|
@ -29,6 +29,8 @@ from ansible.module_utils.six import string_types
|
|||
from ansible.module_utils.k8s.common import KubernetesAnsibleModule
|
||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
|
||||
try:
|
||||
import yaml
|
||||
|
@ -43,6 +45,12 @@ try:
|
|||
except ImportError:
|
||||
HAS_KUBERNETES_VALIDATE = False
|
||||
|
||||
try:
|
||||
from openshift.helper.hashes import generate_hash
|
||||
HAS_K8S_CONFIG_HASH = True
|
||||
except ImportError:
|
||||
HAS_K8S_CONFIG_HASH = False
|
||||
|
||||
|
||||
class KubernetesRawModule(KubernetesAnsibleModule):
|
||||
|
||||
|
@ -62,6 +70,7 @@ class KubernetesRawModule(KubernetesAnsibleModule):
|
|||
argument_spec['wait'] = dict(type='bool', default=False)
|
||||
argument_spec['wait_timeout'] = dict(type='int', default=120)
|
||||
argument_spec['validate'] = dict(type='dict', default=None, options=self.validate_spec)
|
||||
argument_spec['append_hash'] = dict(type='bool', default=False)
|
||||
return argument_spec
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -83,6 +92,10 @@ class KubernetesRawModule(KubernetesAnsibleModule):
|
|||
if self.params['validate']:
|
||||
if 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:
|
||||
if not HAS_K8S_CONFIG_HASH:
|
||||
self.fail_json(msg="openshift >= 0.7.2 is required for append_hash")
|
||||
if self.params['merge_type']:
|
||||
if LooseVersion(self.openshift_version) < LooseVersion("0.6.2"):
|
||||
self.fail_json(msg="openshift >= 0.6.2 is required for merge_type")
|
||||
|
@ -96,7 +109,7 @@ class KubernetesRawModule(KubernetesAnsibleModule):
|
|||
self.resource_definitions = resource_definition
|
||||
else:
|
||||
self.resource_definitions = [resource_definition]
|
||||
src = self.params.pop('src')
|
||||
src = self.params.get('src')
|
||||
if src:
|
||||
self.resource_definitions = self.load_resource_definitions(src)
|
||||
|
||||
|
@ -181,7 +194,12 @@ class KubernetesRawModule(KubernetesAnsibleModule):
|
|||
return result
|
||||
|
||||
try:
|
||||
existing = resource.get(name=name, namespace=namespace)
|
||||
# ignore append_hash for resources other than ConfigMap and Secret
|
||||
if self.append_hash and definition['kind'] in ['ConfigMap', 'Secret']:
|
||||
name = '%s-%s' % (name, generate_hash(definition))
|
||||
definition['metadata']['name'] = name
|
||||
params = dict(name=name, namespace=namespace)
|
||||
existing = resource.get(**params)
|
||||
except NotFoundError:
|
||||
# Remove traceback so that it doesn't show up in later failures
|
||||
try:
|
||||
|
@ -207,7 +225,7 @@ class KubernetesRawModule(KubernetesAnsibleModule):
|
|||
# Delete the object
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = resource.delete(name, namespace=namespace)
|
||||
k8s_obj = resource.delete(**params)
|
||||
result['result'] = k8s_obj.to_dict()
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg="Failed to delete object: {0}".format(exc.body),
|
||||
|
@ -256,7 +274,7 @@ class KubernetesRawModule(KubernetesAnsibleModule):
|
|||
k8s_obj = definition
|
||||
else:
|
||||
try:
|
||||
k8s_obj = resource.replace(definition, name=name, namespace=namespace).to_dict()
|
||||
k8s_obj = resource.replace(definition, name=name, namespace=namespace, append_hash=self.append_hash).to_dict()
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to replace object: {0}".format(exc.body)
|
||||
if self.warnings:
|
||||
|
|
|
@ -89,6 +89,16 @@ options:
|
|||
default: no
|
||||
type: bool
|
||||
version_added: "2.8"
|
||||
append_hash:
|
||||
description:
|
||||
- Whether to append a hash to a resource name for immutability purposes
|
||||
- Applies only to ConfigMap and Secret resources
|
||||
- The parameter will be silently ignored for other resource kinds
|
||||
- The full definition of an object is needed to generate the hash - this means that deleting an object created with append_hash
|
||||
will only work if the same object is passed with state=absent (alternatively, just use state=absent with the name including
|
||||
the generated hash and append_hash=no)
|
||||
type: bool
|
||||
version_added: "2.8"
|
||||
|
||||
requirements:
|
||||
- "python >= 2.7"
|
||||
|
|
40
lib/ansible/plugins/filter/k8s.py
Normal file
40
lib/ansible/plugins/filter/k8s.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) 2017 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
|
||||
try:
|
||||
from openshift.helper.hashes import generate_hash
|
||||
HAS_GENERATE_HASH = True
|
||||
except ImportError:
|
||||
HAS_GENERATE_HASH = False
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
|
||||
|
||||
def k8s_config_resource_name(resource):
|
||||
if not HAS_GENERATE_HASH:
|
||||
raise AnsibleFilterError("k8s_config_resource_name requires openshift>=0.7.2")
|
||||
try:
|
||||
return resource['metadata']['name'] + '-' + generate_hash(resource)
|
||||
except KeyError:
|
||||
raise AnsibleFilterError("resource must have a metadata.name key to generate a resource name")
|
||||
|
||||
|
||||
# ---- Ansible filters ----
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'k8s_config_resource_name': k8s_config_resource_name
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue