mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-03-27 05:43:02 +00:00
* Rename from community.kubernetes to kubernetes.core This goes through and renames community.kubernetes to kubernetes.core. Most of this was generated from the downstream build script that was used on the community repository, plus whatever hand edits I could find that were needed. The downstream build and test process has also been removed as this repository is now the downstream repository. * Fix CONTRIBUTING.md
220 lines
6.6 KiB
Python
220 lines
6.6 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright: (c) 2020, Julien Huon <@julienhuon> Institut National de l'Audiovisuel
|
|
# 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
|
|
|
|
|
|
DOCUMENTATION = r'''
|
|
module: k8s_rollback
|
|
short_description: Rollback Kubernetes (K8S) Deployments and DaemonSets
|
|
version_added: "1.0.0"
|
|
author:
|
|
- "Julien Huon (@julienhuon)"
|
|
description:
|
|
- Use the OpenShift Python client to perform the Rollback.
|
|
- Authenticate using either a config file, certificates, password or token.
|
|
- Similar to the C(kubectl rollout undo) command.
|
|
options:
|
|
label_selectors:
|
|
description: List of label selectors to use to filter results.
|
|
type: list
|
|
elements: str
|
|
field_selectors:
|
|
description: List of field selectors to use to filter results.
|
|
type: list
|
|
elements: str
|
|
extends_documentation_fragment:
|
|
- kubernetes.core.k8s_auth_options
|
|
- kubernetes.core.k8s_name_options
|
|
requirements:
|
|
- "python >= 2.7"
|
|
- "openshift >= 0.6"
|
|
- "PyYAML >= 3.11"
|
|
'''
|
|
|
|
EXAMPLES = r'''
|
|
- name: Rollback a failed deployment
|
|
kubernetes.core.k8s_rollback:
|
|
api_version: apps/v1
|
|
kind: Deployment
|
|
name: web
|
|
namespace: testing
|
|
'''
|
|
|
|
RETURN = r'''
|
|
rollback_info:
|
|
description:
|
|
- The object that was rolled back.
|
|
returned: success
|
|
type: complex
|
|
contains:
|
|
api_version:
|
|
description: The versioned schema of this representation of an object.
|
|
returned: success
|
|
type: str
|
|
code:
|
|
description: The HTTP Code of the response
|
|
returned: success
|
|
type: str
|
|
kind:
|
|
description: Status
|
|
returned: success
|
|
type: str
|
|
metadata:
|
|
description:
|
|
- Standard object metadata.
|
|
- Includes name, namespace, annotations, labels, etc.
|
|
returned: success
|
|
type: dict
|
|
status:
|
|
description: Current status details for the object.
|
|
returned: success
|
|
type: dict
|
|
'''
|
|
|
|
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, NAME_ARG_SPEC)
|
|
|
|
|
|
def get_managed_resource(module):
|
|
managed_resource = {}
|
|
|
|
kind = module.params['kind']
|
|
if kind == "DaemonSet":
|
|
managed_resource['kind'] = "ControllerRevision"
|
|
managed_resource['api_version'] = "apps/v1"
|
|
elif kind == "Deployment":
|
|
managed_resource['kind'] = "ReplicaSet"
|
|
managed_resource['api_version'] = "apps/v1"
|
|
else:
|
|
module.fail(msg="Cannot perform rollback on resource of kind {0}".format(kind))
|
|
return managed_resource
|
|
|
|
|
|
def execute_module(module, k8s_ansible_mixin):
|
|
results = []
|
|
|
|
resources = k8s_ansible_mixin.kubernetes_facts(
|
|
module.params['kind'],
|
|
module.params['api_version'],
|
|
module.params['name'],
|
|
module.params['namespace'],
|
|
module.params['label_selectors'],
|
|
module.params['field_selectors'])
|
|
|
|
for resource in resources['resources']:
|
|
result = perform_action(module, k8s_ansible_mixin, resource)
|
|
results.append(result)
|
|
|
|
module.exit_json(**{
|
|
'changed': True,
|
|
'rollback_info': results
|
|
})
|
|
|
|
|
|
def perform_action(module, k8s_ansible_mixin, resource):
|
|
if module.params['kind'] == "DaemonSet":
|
|
current_revision = resource['metadata']['generation']
|
|
elif module.params['kind'] == "Deployment":
|
|
current_revision = resource['metadata']['annotations']['deployment.kubernetes.io/revision']
|
|
|
|
managed_resource = get_managed_resource(module)
|
|
managed_resources = k8s_ansible_mixin.kubernetes_facts(
|
|
managed_resource['kind'],
|
|
managed_resource['api_version'],
|
|
'',
|
|
module.params['namespace'],
|
|
resource['spec']
|
|
['selector']
|
|
['matchLabels'],
|
|
'')
|
|
|
|
prev_managed_resource = get_previous_revision(managed_resources['resources'],
|
|
current_revision)
|
|
|
|
if module.params['kind'] == "Deployment":
|
|
del prev_managed_resource['spec']['template']['metadata']['labels']['pod-template-hash']
|
|
|
|
resource_patch = [{
|
|
"op": "replace",
|
|
"path": "/spec/template",
|
|
"value": prev_managed_resource['spec']['template']
|
|
}, {
|
|
"op": "replace",
|
|
"path": "/metadata/annotations",
|
|
"value": {
|
|
"deployment.kubernetes.io/revision": prev_managed_resource['metadata']['annotations']['deployment.kubernetes.io/revision']
|
|
}
|
|
}]
|
|
|
|
api_target = 'deployments'
|
|
content_type = 'application/json-patch+json'
|
|
elif module.params['kind'] == "DaemonSet":
|
|
resource_patch = prev_managed_resource["data"]
|
|
|
|
api_target = 'daemonsets'
|
|
content_type = 'application/strategic-merge-patch+json'
|
|
|
|
rollback = k8s_ansible_mixin.client.request(
|
|
"PATCH",
|
|
"/apis/{0}/namespaces/{1}/{2}/{3}"
|
|
.format(module.params['api_version'],
|
|
module.params['namespace'],
|
|
api_target,
|
|
module.params['name']),
|
|
body=resource_patch,
|
|
content_type=content_type)
|
|
|
|
result = {'changed': True}
|
|
result['method'] = 'patch'
|
|
result['body'] = resource_patch
|
|
result['resources'] = rollback.to_dict()
|
|
return result
|
|
|
|
|
|
def argspec():
|
|
args = copy.deepcopy(AUTH_ARG_SPEC)
|
|
args.update(NAME_ARG_SPEC)
|
|
args.update(
|
|
dict(
|
|
label_selectors=dict(type='list', elements='str', default=[]),
|
|
field_selectors=dict(type='list', elements='str', default=[]),
|
|
)
|
|
)
|
|
return args
|
|
|
|
|
|
def get_previous_revision(all_resources, current_revision):
|
|
for resource in all_resources:
|
|
if resource['kind'] == 'ReplicaSet':
|
|
if int(resource['metadata']
|
|
['annotations']
|
|
['deployment.kubernetes.io/revision']) == int(current_revision) - 1:
|
|
return resource
|
|
elif resource['kind'] == 'ControllerRevision':
|
|
if int(resource['metadata']
|
|
['annotations']
|
|
['deprecated.daemonset.template.generation']) == int(current_revision) - 1:
|
|
return resource
|
|
return None
|
|
|
|
|
|
def main():
|
|
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True)
|
|
from ansible_collections.kubernetes.core.plugins.module_utils.common import (K8sAnsibleMixin, get_api_client)
|
|
|
|
k8s_ansible_mixin = K8sAnsibleMixin(module)
|
|
k8s_ansible_mixin.client = get_api_client(module=module)
|
|
execute_module(module, k8s_ansible_mixin)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|