From 973ce30def7e1be5887c4c1643ef1693305f40fd Mon Sep 17 00:00:00 2001 From: Anastasiya Date: Wed, 25 Jan 2017 17:27:59 +0400 Subject: [PATCH] Add action delete command this command deletes jobs, pods and appropriate config maps Change-Id: I362322f4d8dd243f3730bdc802512b1a68bd5804 --- fuel_ccp/action.py | 72 +++++++++++++++++++++++++++++++++++++++++- fuel_ccp/cli.py | 14 ++++++++ fuel_ccp/kubernetes.py | 22 ++++++++++--- setup.cfg | 1 + 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/fuel_ccp/action.py b/fuel_ccp/action.py index 5d9ebd53..552a336c 100644 --- a/fuel_ccp/action.py +++ b/fuel_ccp/action.py @@ -4,6 +4,7 @@ import logging import os import uuid +from pykube import exceptions as pykube_exc import yaml from fuel_ccp.common import utils @@ -217,6 +218,8 @@ class ActionStatus(object): self.name = k8s_spec.name self.component = k8s_spec.labels["ccp-component"] self.date = k8s_spec.obj["metadata"]["creationTimestamp"] + self.terminating = k8s_spec.obj["metadata"].get("deletionTimestamp", + False) if k8s_spec.kind == "Job": self.restarts = k8s_spec.obj["status"].get("failed", 0) self.active = k8s_spec.obj["status"].get("active", 0) @@ -229,6 +232,8 @@ class ActionStatus(object): @property def status(self): + if self.terminating: + return "terminating" if self.failed: return "fail" if self.active: @@ -244,7 +249,47 @@ class ActionStatus(object): for pod in pods: if pod.obj['status']['phase'] == "Failed": continue - return pod.logs() + return pod.logs()\ + + + @classmethod + def delete(cls, action_name): + delete_configmap_status = False + delete_action_status = cls.delete_action(action_name) + if delete_action_status: + delete_configmap_status = cls.delete_configmap(action_name) + return {'action_status': delete_action_status, + 'configmap_status': delete_configmap_status} + + @staticmethod + def delete_action(action_name): + try: + action = kubernetes.list_cluster_jobs(name=action_name) + except pykube_exc.ObjectDoesNotExist: + try: + action = kubernetes.list_cluster_pods(name=action_name) + except pykube_exc.ObjectDoesNotExist: + LOG.error('Action with name %s not found', action_name) + return False + try: + action.delete() + except pykube_exc.HTTPError as ex: + LOG.error(ex.message) + return False + LOG.info('Action %s is terminating', action_name) + return True + + @staticmethod + def delete_configmap(action_name): + try: + configmap = kubernetes.get_configmap(action_name) + configmap.delete() + except pykube_exc.ObjectDoesNotExist: + pass + except pykube_exc.HTTPError as ex: + LOG.error(ex.message) + return False + return True def list_actions(): @@ -317,3 +362,28 @@ def get_action_statuses_by_names(action_names): "Action(s) with name(s) %s not found" % ( ", ".join(action_names))) return actions + + +def delete_action(action_names): + """Delete action. + + :raises: fuel_ccp.exceptions.NotFoundException + """ + not_removed = [] + configmap_not_removed = [] + for action_name in action_names: + action_status = ActionStatus.delete(action_name) + if not action_status.get('action_status'): + not_removed.append(action_name) + if not action_status.get('configmap_status'): + configmap_not_removed.append(action_name) + if not_removed: + raise exceptions.NotFoundException( + 'The following actions were not removed: %s' + % ','.join(not_removed) + ) + if configmap_not_removed: + raise exceptions.NotFoundException( + 'Configmaps for the following actions were not removed: %s' + % ','.join(configmap_not_removed) + ) diff --git a/fuel_ccp/cli.py b/fuel_ccp/cli.py index cf7b2abe..9d13ccf7 100644 --- a/fuel_ccp/cli.py +++ b/fuel_ccp/cli.py @@ -366,6 +366,20 @@ def get_statuses_for_actions(action_objects): ) +class ActionDelete(BaseCommand): + """Delete action""" + + def get_parser(self, *args, **kwargs): + parser = super(ActionDelete, self).get_parser(*args, **kwargs) + parser.add_argument("actions", + nargs='+', + help="Delete actions") + return parser + + def take_action(self, parsed_args): + action.delete_action(parsed_args.actions) + + def signal_handler(signo, frame): sys.exit(-signo) diff --git a/fuel_ccp/kubernetes.py b/fuel_ccp/kubernetes.py index 213290f7..c8deb339 100644 --- a/fuel_ccp/kubernetes.py +++ b/fuel_ccp/kubernetes.py @@ -162,7 +162,8 @@ def list_cluster_deployments(selector=None): selector=ccp_selector) -def list_cluster_pods(service=None, selector=None, raw_selector=None): +def list_cluster_pods(service=None, selector=None, raw_selector=None, + name=None): if raw_selector is not None: ccp_selector = raw_selector else: @@ -172,19 +173,25 @@ def list_cluster_pods(service=None, selector=None, raw_selector=None): if selector: ccp_selector += "," + selector client = get_client() - return pykube.Pod.objects(client).filter( + pods = pykube.Pod.objects(client).filter( namespace=CONF.kubernetes.namespace, selector=str(ccp_selector)) + if name: + return pods.get_by_name(name) + return pods -def list_cluster_jobs(selector=None): +def list_cluster_jobs(selector=None, name=None): ccp_selector = "ccp=true" if selector: ccp_selector += "," + selector client = get_client() - return pykube.Job.objects(client).filter( + jobs = pykube.Job.objects(client).filter( namespace=CONF.kubernetes.namespace, selector=ccp_selector) + if name: + return jobs.get_by_name(name) + return jobs def list_cluster_services(): @@ -212,3 +219,10 @@ def get_object_names(items): for item in items: names.append(item.name) return names + + +def get_configmap(name): + client = get_client() + return pykube.ConfigMap.objects(client).filter( + namespace=CONF.kubernetes.namespace, + selector="ccp=true").get_by_name(name) diff --git a/setup.cfg b/setup.cfg index ed0c72ba..0eaa6e62 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,7 @@ ccp.cli = action_run = fuel_ccp.cli:ActionRun action_show = fuel_ccp.cli:ActionShow action_status = fuel_ccp.cli:ActionStatus + action_delete = fuel_ccp.cli:ActionDelete build = fuel_ccp.cli:Build cleanup = fuel_ccp.cli:Cleanup deploy = fuel_ccp.cli:Deploy