k8s - patch existing resource (#90)

* patch only

* add changelogs

* Rename 89-k8s-add-parameter-patch_only.yml to 90-k8s-add-parameter-patch_only.yml

* Update 90-k8s-add-parameter-patch_only.yml

* patch_only parameter changed to state=patched

* Update 90-k8s-add-parameter-patch_only.yml

* Update plugins/modules/k8s.py

Co-authored-by: Fabian von Feilitzsch <fabian@fabianism.us>

* Update molecule/default/tasks/patched.yml

Co-authored-by: John Mazzitelli <mazz@redhat.com>

* Update molecule/default/tasks/patched.yml

Co-authored-by: John Mazzitelli <mazz@redhat.com>

* sanity issue

Co-authored-by: Fabian von Feilitzsch <fabian@fabianism.us>
Co-authored-by: John Mazzitelli <mazz@redhat.com>
This commit is contained in:
abikouo
2021-05-19 11:03:11 +02:00
committed by GitHub
parent 5856948657
commit 192cae1507
5 changed files with 178 additions and 7 deletions

View File

@@ -0,0 +1,3 @@
---
minor_changes:
- k8s - support ``patched`` value for ``state`` option. patched state is an existing resource that has a given patch applied (https://github.com/ansible-collections/kubernetes.core/pull/90).

View File

@@ -141,6 +141,14 @@
tags:
- always
- name: Include patched.yml
include_tasks:
file: tasks/patched.yml
apply:
tags: [ patched, k8s ]
tags:
- always
roles:
- role: helm
tags:

View File

@@ -0,0 +1,123 @@
---
- block:
- set_fact:
patch_only_namespace:
first: patched-namespace-1
second: patched-namespace-2
- name: Ensure namespace {{ patch_only_namespace.first }} exist
kubernetes.core.k8s:
definition:
apiVersion: v1
kind: Namespace
metadata:
name: "{{ patch_only_namespace.first }}"
labels:
existingLabel: "labelValue"
annotations:
existingAnnotation: "annotationValue"
wait: yes
- name: Ensure namespace {{ patch_only_namespace.second }} does not exist
kubernetes.core.k8s_info:
kind: namespace
name: "{{ patch_only_namespace.second }}"
register: second_namespace
- name: assert that second namespace does not exist
assert:
that:
- second_namespace.resources | length == 0
- name: apply patch on existing resource
kubernetes.core.k8s:
state: patched
wait: yes
definition: |
---
apiVersion: v1
kind: Namespace
metadata:
name: "{{ patch_only_namespace.first }}"
labels:
ansible: patched
---
apiVersion: v1
kind: Namespace
metadata:
name: "{{ patch_only_namespace.second }}"
labels:
ansible: patched
register: patch_resource
- name: assert that patch succeed
assert:
that:
- patch_resource.changed
- patch_resource.result.results | selectattr('warning', 'defined') | list | length == 1
- name: Ensure namespace {{ patch_only_namespace.first }} was patched correctly
kubernetes.core.k8s_info:
kind: namespace
name: "{{ patch_only_namespace.first }}"
register: first_namespace
- name: assert labels are as expected
assert:
that:
- first_namespace.resources[0].metadata.labels.ansible == "patched"
- first_namespace.resources[0].metadata.labels.existingLabel == "labelValue"
- first_namespace.resources[0].metadata.annotations.existingAnnotation == "annotationValue"
- name: Ensure namespace {{ patch_only_namespace.second }} was not created
kubernetes.core.k8s_info:
kind: namespace
name: "{{ patch_only_namespace.second }}"
register: second_namespace
- name: assert that second namespace does not exist
assert:
that:
- second_namespace.resources | length == 0
- name: patch all resources (create if does not exist)
kubernetes.core.k8s:
state: present
definition: |
---
apiVersion: v1
kind: Namespace
metadata:
name: "{{ patch_only_namespace.first }}"
labels:
patch: ansible
---
apiVersion: v1
kind: Namespace
metadata:
name: "{{ patch_only_namespace.second }}"
labels:
patch: ansible
wait: yes
register: patch_resource
- name: Ensure namespace {{ patch_only_namespace.second }} was created
kubernetes.core.k8s_info:
kind: namespace
name: "{{ patch_only_namespace.second }}"
register: second_namespace
- name: assert that second namespace exist
assert:
that:
- second_namespace.resources | length == 1
always:
- name: Remove namespace
kubernetes.core.k8s:
kind: Namespace
name: "{{ item }}"
state: absent
with_items:
- "{{ patch_only_namespace.first }}"
- "{{ patch_only_namespace.second }}"
ignore_errors: true

View File

@@ -529,7 +529,8 @@ class K8sAnsibleMixin(object):
if self.params['validate'] is not None:
self.warnings = self.validate(definition)
result = self.perform_action(resource, definition)
result['warnings'] = self.warnings
if self.warnings:
result['warnings'] = self.warnings
changed = changed or result['changed']
results.append(result)
@@ -670,6 +671,7 @@ class K8sAnsibleMixin(object):
else:
self.fail_json(msg=build_error_msg(definition['kind'], origin_name, msg), **result)
return result
else:
if apply:
if self.check_mode:
@@ -713,7 +715,14 @@ class K8sAnsibleMixin(object):
return result
if not existing:
if self.check_mode:
if state == 'patched':
# Silently skip this resource (do not raise an error) as 'patch_only' is set to true
result['changed'] = False
result['warning'] = "resource 'kind={kind},name={name}' was not found but will not be created as 'state'\
parameter has been set to '{state}'".format(
kind=definition['kind'], name=origin_name, state=state)
return result
elif self.check_mode:
k8s_obj = _encode_stringdata(definition)
else:
try:
@@ -762,7 +771,7 @@ class K8sAnsibleMixin(object):
match = False
diffs = []
if existing and force:
if state == 'present' and existing and force:
if self.check_mode:
k8s_obj = _encode_stringdata(definition)
else:

View File

@@ -30,7 +30,6 @@ description:
- Supports check mode.
extends_documentation_fragment:
- kubernetes.core.k8s_state_options
- kubernetes.core.k8s_name_options
- kubernetes.core.k8s_resource_options
- kubernetes.core.k8s_auth_options
@@ -38,6 +37,21 @@ extends_documentation_fragment:
- kubernetes.core.k8s_delete_options
options:
state:
description:
- Determines if an object should be created, patched, or deleted. When set to C(present), an object will be
created, if it does not already exist. If set to C(absent), an existing object will be deleted. If set to
C(present), an existing object will be patched, if its attributes differ from those specified using
I(resource_definition) or I(src).
- C(patched) state is an existing resource that has a given patch applied. If the resource doesn't exist, silently skip it (do not raise an error).
type: str
default: present
choices: [ absent, present, patched ]
force:
description:
- If set to C(yes), and I(state) is C(present), an existing object will be replaced.
type: bool
default: no
merge_type:
description:
- Whether to override the default patch merge approach with a specific type. By default, the strategic
@@ -236,6 +250,17 @@ EXAMPLES = r'''
type: Progressing
status: Unknown
reason: DeploymentPaused
# Patch existing namespace : add label
- name: add label to existing namespace
kubernetes.core.k8s:
state: patched
kind: Namespace
name: patch_namespace
definition:
metadata:
labels:
support: patch
'''
RETURN = r'''
@@ -284,7 +309,7 @@ import copy
from ansible_collections.kubernetes.core.plugins.module_utils.ansiblemodule import AnsibleModule
from ansible_collections.kubernetes.core.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)
AUTH_ARG_SPEC, WAIT_ARG_SPEC, NAME_ARG_SPEC, RESOURCE_ARG_SPEC, DELETE_OPTS_ARG_SPEC)
def validate_spec():
@@ -296,8 +321,7 @@ def validate_spec():
def argspec():
argument_spec = copy.deepcopy(COMMON_ARG_SPEC)
argument_spec.update(copy.deepcopy(NAME_ARG_SPEC))
argument_spec = 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))
@@ -308,6 +332,9 @@ def argspec():
argument_spec['template'] = dict(type='raw', default=None)
argument_spec['delete_options'] = dict(type='dict', default=None, options=copy.deepcopy(DELETE_OPTS_ARG_SPEC))
argument_spec['continue_on_error'] = dict(type='bool', default=False)
argument_spec['state'] = dict(default='present', choices=['present', 'absent', 'patched'])
argument_spec['force'] = dict(type='bool', default=False)
return argument_spec
@@ -319,6 +346,7 @@ def execute_module(module, k8s_ansible_mixin):
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.warn = k8s_ansible_mixin.module.warn
k8s_ansible_mixin.warnings = []
k8s_ansible_mixin.kind = k8s_ansible_mixin.params.get('kind')