mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-03-26 21:33:02 +00:00
Add support for configuring garbage collection (#334)
* Add support for configuring garbage collection This surfaces deleteOptions functionality in a top-level delete_options parameter. * Add changelog fragment * Remove kind and apiVersion from delete_options * Add release version to docs
This commit is contained in:
2
changelogs/fragments/334-delete-options.yaml
Normal file
2
changelogs/fragments/334-delete-options.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
minor_changes:
|
||||
- k8s - add a ``delete_options`` parameter to control garbage collection behavior when deleting a resource (https://github.com/ansible-collections/community.kubernetes/issues/253).
|
||||
@@ -30,6 +30,7 @@
|
||||
- include_tasks: tasks/cluster_info.yml
|
||||
- include_tasks: tasks/access_review.yml
|
||||
- include_tasks: tasks/rollback.yml
|
||||
- include_tasks: tasks/gc.yml
|
||||
|
||||
roles:
|
||||
- helm
|
||||
|
||||
211
molecule/default/tasks/gc.yml
Normal file
211
molecule/default/tasks/gc.yml
Normal file
@@ -0,0 +1,211 @@
|
||||
---
|
||||
- vars:
|
||||
gc_namespace: garbage
|
||||
gc_name: garbage-job
|
||||
# This is a job definition that runs for 10 minutes and won't gracefully
|
||||
# shutdown. It allows us to test foreground vs background deletion.
|
||||
job_definition:
|
||||
apiVersion: v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: "{{ gc_name }}"
|
||||
namespace: "{{ gc_namespace }}"
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
job: gc
|
||||
spec:
|
||||
containers:
|
||||
- name: "{{ gc_name }}"
|
||||
image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "600"
|
||||
restartPolicy: Never
|
||||
|
||||
block:
|
||||
- name: Ensure namespace exists
|
||||
k8s:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: "{{ gc_namespace }}"
|
||||
|
||||
- name: Add a job
|
||||
k8s:
|
||||
definition: "{{ job_definition }}"
|
||||
|
||||
- name: Test that job's pod is running
|
||||
k8s_info:
|
||||
kind: Pod
|
||||
namespace: "{{ gc_namespace }}"
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
wait: yes
|
||||
wait_timeout: 100
|
||||
register: job
|
||||
|
||||
- name: Assert job's pod is running
|
||||
assert:
|
||||
that: job.resources[0].status.phase == "Running"
|
||||
|
||||
- name: Delete job in foreground
|
||||
k8s:
|
||||
kind: Job
|
||||
name: "{{ gc_name }}"
|
||||
namespace: "{{ gc_namespace }}"
|
||||
state: absent
|
||||
wait: yes
|
||||
wait_timeout: 100
|
||||
delete_options:
|
||||
propagationPolicy: Foreground
|
||||
|
||||
- name: Test job's pod does not exist
|
||||
k8s_info:
|
||||
kind: Pod
|
||||
namespace: "{{ gc_namespace }}"
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
register: job
|
||||
|
||||
- name: Assert job's pod does not exist
|
||||
assert:
|
||||
that: not job.resources
|
||||
|
||||
- name: Add a job
|
||||
k8s:
|
||||
definition: "{{ job_definition }}"
|
||||
|
||||
- name: Test that job's pod is running
|
||||
k8s_info:
|
||||
kind: Pod
|
||||
namespace: "{{ gc_namespace }}"
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
wait: yes
|
||||
wait_timeout: 100
|
||||
register: job
|
||||
|
||||
- name: Assert job's pod is running
|
||||
assert:
|
||||
that: job.resources[0].status.phase == "Running"
|
||||
|
||||
- name: Delete job in background
|
||||
k8s:
|
||||
kind: Job
|
||||
name: "{{ gc_name }}"
|
||||
namespace: "{{ gc_namespace }}"
|
||||
state: absent
|
||||
wait: yes
|
||||
wait_timeout: 100
|
||||
delete_options:
|
||||
propagationPolicy: "Background"
|
||||
|
||||
# The default grace period is 30s so this pod should still be running.
|
||||
- name: Test job's pod exists
|
||||
k8s_info:
|
||||
kind: Pod
|
||||
namespace: "{{ gc_namespace }}"
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
register: job
|
||||
|
||||
- name: Assert job's pod still running
|
||||
assert:
|
||||
that: job.resources[0].status.phase == "Running"
|
||||
|
||||
- name: Add a job
|
||||
k8s:
|
||||
definition: "{{ job_definition }}"
|
||||
|
||||
- name: Test that job's pod is running
|
||||
k8s_info:
|
||||
kind: Pod
|
||||
namespace: "{{ gc_namespace }}"
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
wait: yes
|
||||
wait_timeout: 100
|
||||
register: job
|
||||
|
||||
- name: Assert job's pod is running
|
||||
assert:
|
||||
that: job.resources[0].status.phase == "Running"
|
||||
|
||||
- name: Orphan the job's pod
|
||||
k8s:
|
||||
kind: Job
|
||||
name: "{{ gc_name }}"
|
||||
namespace: "{{ gc_namespace }}"
|
||||
state: absent
|
||||
wait: yes
|
||||
wait_timeout: 100
|
||||
delete_options:
|
||||
propagationPolicy: "Orphan"
|
||||
|
||||
- name: Ensure grace period has expired
|
||||
pause:
|
||||
seconds: 60
|
||||
|
||||
- name: Test that job's pod is still running
|
||||
k8s_info:
|
||||
kind: Pod
|
||||
namespace: "{{ gc_namespace }}"
|
||||
label_selectors:
|
||||
- "job=gc"
|
||||
register: job
|
||||
|
||||
- name: Assert job's pod is still running
|
||||
assert:
|
||||
that: job.resources[0].status.phase == "Running"
|
||||
|
||||
- name: Add a job
|
||||
k8s:
|
||||
definition: "{{ job_definition }}"
|
||||
register: job
|
||||
|
||||
- name: Delete a job with failing precondition
|
||||
k8s:
|
||||
kind: Job
|
||||
name: "{{ gc_name }}"
|
||||
namespace: "{{ gc_namespace }}"
|
||||
state: absent
|
||||
delete_options:
|
||||
preconditions:
|
||||
uid: not-a-valid-uid
|
||||
ignore_errors: yes
|
||||
register: result
|
||||
|
||||
- name: Assert that deletion failed
|
||||
assert:
|
||||
that: result is failed
|
||||
|
||||
- name: Delete a job using a valid precondition
|
||||
k8s:
|
||||
kind: Job
|
||||
name: "{{ gc_name }}"
|
||||
namespace: "{{ gc_namespace }}"
|
||||
state: absent
|
||||
delete_options:
|
||||
preconditions:
|
||||
uid: "{{ job.result.metadata.uid }}"
|
||||
|
||||
- name: Check that job is deleted
|
||||
k8s_info:
|
||||
kind: Job
|
||||
namespace: "{{ gc_namespace }}"
|
||||
name: "{{ gc_name }}"
|
||||
register: job
|
||||
|
||||
- name: Assert job is deleted
|
||||
assert:
|
||||
that: not job.resources
|
||||
|
||||
always:
|
||||
- name: Delete namespace
|
||||
k8s:
|
||||
kind: Namespace
|
||||
name: "{{ gc_namespace }}"
|
||||
state: absent
|
||||
51
plugins/doc_fragments/k8s_delete_options.py
Normal file
51
plugins/doc_fragments/k8s_delete_options.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2020, Red Hat | Ansible
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Options for specifying object wait
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
options:
|
||||
delete_options:
|
||||
type: dict
|
||||
version_added: '1.2.0'
|
||||
description:
|
||||
- Configure behavior when deleting an object.
|
||||
- Only used when I(state=absent).
|
||||
suboptions:
|
||||
propagationPolicy:
|
||||
type: str
|
||||
description:
|
||||
- Use to control how dependent objects are deleted.
|
||||
- If not specified, the default policy for the object type will be used. This may vary across object types.
|
||||
choices:
|
||||
- "Foreground"
|
||||
- "Background"
|
||||
- "Orphan"
|
||||
gracePeriodSeconds:
|
||||
type: int
|
||||
description:
|
||||
- Specify how many seconds to wait before forcefully terminating.
|
||||
- Only implemented for Pod resources.
|
||||
- If not specified, the default grace period for the object type will be used.
|
||||
preconditions:
|
||||
type: dict
|
||||
description:
|
||||
- Specify condition that must be met for delete to proceed.
|
||||
suboptions:
|
||||
resourceVersion:
|
||||
type: str
|
||||
description:
|
||||
- Specify the resource version of the target object.
|
||||
uid:
|
||||
type: str
|
||||
description:
|
||||
- Specify the UID of the target object.
|
||||
'''
|
||||
@@ -189,6 +189,27 @@ WAIT_ARG_SPEC = dict(
|
||||
)
|
||||
)
|
||||
|
||||
DELETE_OPTS_ARG_SPEC = {
|
||||
'propagationPolicy': {
|
||||
'choices': ['Foreground', 'Background', 'Orphan'],
|
||||
},
|
||||
'gracePeriodSeconds': {
|
||||
'type': 'int',
|
||||
},
|
||||
'preconditions': {
|
||||
'type': 'dict',
|
||||
'options': {
|
||||
'resourceVersion': {
|
||||
'type': 'str',
|
||||
},
|
||||
'uid': {
|
||||
'type': 'str',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Map kubernetes-client parameters to ansible parameters
|
||||
AUTH_ARG_MAP = {
|
||||
'kubeconfig': 'kubeconfig',
|
||||
@@ -594,6 +615,7 @@ class K8sAnsibleMixin(object):
|
||||
return definition
|
||||
|
||||
def perform_action(self, resource, definition):
|
||||
delete_options = self.params.get('delete_options')
|
||||
result = {'changed': False, 'result': {}}
|
||||
state = self.params.get('state', None)
|
||||
force = self.params.get('force', False)
|
||||
@@ -646,6 +668,13 @@ class K8sAnsibleMixin(object):
|
||||
# Delete the object
|
||||
result['changed'] = True
|
||||
if not self.check_mode:
|
||||
if delete_options:
|
||||
body = {
|
||||
'apiVersion': 'v1',
|
||||
'kind': 'DeleteOptions',
|
||||
}
|
||||
body.update(delete_options)
|
||||
params['body'] = body
|
||||
try:
|
||||
k8s_obj = resource.delete(**params)
|
||||
result['result'] = k8s_obj.to_dict()
|
||||
|
||||
@@ -34,6 +34,7 @@ extends_documentation_fragment:
|
||||
- community.kubernetes.k8s_resource_options
|
||||
- community.kubernetes.k8s_auth_options
|
||||
- community.kubernetes.k8s_wait_options
|
||||
- community.kubernetes.k8s_delete_options
|
||||
|
||||
notes:
|
||||
- If your OpenShift Python library is not 0.9.0 or newer and you are trying to
|
||||
@@ -252,7 +253,8 @@ import copy
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.kubernetes.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin, COMMON_ARG_SPEC, NAME_ARG_SPEC, RESOURCE_ARG_SPEC, AUTH_ARG_SPEC, WAIT_ARG_SPEC)
|
||||
K8sAnsibleMixin, COMMON_ARG_SPEC, NAME_ARG_SPEC, RESOURCE_ARG_SPEC, AUTH_ARG_SPEC,
|
||||
WAIT_ARG_SPEC, DELETE_OPTS_ARG_SPEC)
|
||||
|
||||
|
||||
class KubernetesModule(K8sAnsibleMixin):
|
||||
@@ -277,6 +279,7 @@ class KubernetesModule(K8sAnsibleMixin):
|
||||
argument_spec['append_hash'] = dict(type='bool', default=False)
|
||||
argument_spec['apply'] = dict(type='bool', default=False)
|
||||
argument_spec['template'] = dict(type='raw', default=None)
|
||||
argument_spec['delete_options'] = dict(type='dict', default=None, options=copy.deepcopy(DELETE_OPTS_ARG_SPEC))
|
||||
return argument_spec
|
||||
|
||||
def __init__(self, k8s_kind=None, *args, **kwargs):
|
||||
|
||||
Reference in New Issue
Block a user