1 # ============LICENSE_START=======================================================
3 # ================================================================================
4 # Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
5 # ================================================================================
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 # ============LICENSE_END=========================================================
19 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
21 # -*- coding: utf-8 -*-
23 Provides utilities for undeploying components
25 from functools import partial
26 from dcae_cli.util.exc import DcaeException
27 import dcae_cli.util.profiles as profiles
28 from dcae_cli.util.cdap_util import undeploy_component as undeploy_cdap_component
29 from dcae_cli.util.discovery import get_healthy_instances, get_defective_instances, \
31 from dcae_cli.util import docker_util as du
32 from dcae_cli.util.logger import get_logger
35 log = get_logger('Undeploy')
38 def _handler(undeploy_funcs, instances):
39 """Handles the undeployment
41 Executes all undeployment functions for all instances and gathers up the
42 results. No short circuiting.
46 undeploy_funcs: List of functions that have the following signature `fn: string->boolean`
47 the input is a fully qualified instance name and the return is True upon
48 success and False for failures
49 instances: List of fully qualified instance names
53 (failures, results) where each are a list of tuples. Each tuple has the
54 structure: `(<instance name>, result of func 1, result of func 2, ..)`.
59 # Invoke all undeploy funcs for all instances
60 def invoke_undeploys(instance):
61 return tuple([ undeploy_func(instance) for undeploy_func in undeploy_funcs ])
63 results = [ (instance, ) + invoke_undeploys(instance) for instance in instances ]
66 filter_failures_func = partial(filter, lambda result: not all(result[1:]))
67 failures = list(filter_failures_func(results))
69 return failures, results
72 def _handler_report(failures, results):
73 """Reports the result of handling"""
75 failed_names = [ result[0] for result in failures ]
76 log.warn("Could not completely undeploy: {0}".format(", ".join(failed_names)))
78 # This message captures a case where you are seeing a false negative. If
79 # you attempted to undeploy a component instance and it partially failed
80 # the first time but "succeeded" the second time, the second undeploy
81 # would get reported as a failure. The second undeploy would probably
82 # also be partial undeploy because the undeploy operation that succeeded
83 # the first time will fail the second time.
84 log.warn("NOTE: This could be expected since we are attempting to undeploy a component in a bad partial state")
85 elif len(results) == 0:
86 log.warn("No components found to undeploy")
88 # This seems like important info so set it to warning so that it shows up
89 log.warn("Undeployed components: {0}".format(len(results)))
92 def undeploy_component(user, cname, cver, catalog):
93 '''Undeploys a component based on the component type'''
94 cname, cver = catalog.verify_component(cname, cver)
95 ctype = catalog.get_component_type(cname, cver)
96 profile = profiles.get_profile()
97 # Get *all* instances of the component whether running healthy or in a bad partial
99 instances = get_healthy_instances(user, cname, cver) + get_defective_instances(user, cname, cver)
101 if ctype == 'docker':
102 client = du.get_docker_client(profile)
103 image = catalog.get_docker_image(cname, cver)
104 undeploy_func = partial(du.undeploy_component, client, image)
105 elif ctype == 'cdap':
106 undeploy_func = partial(undeploy_cdap_component, profile)
108 raise DcaeException("Unsupported component type for undeploy")
110 log.warn("Undeploying components: {0}".format(len(instances)))
111 _handler_report(*_handler([undeploy_func, remove_config], instances))