blob: 208ba3b23982847e61cfa91f18cfff81bcdd8e32 [file] [log] [blame]
Kevin Chengeb85e862018-10-09 15:35:13 -07001# Copyright 2018 - The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14r"""Delete entry point.
15
16Delete will handle all the logic related to deleting a local/remote instance
17of an Android Virtual Device.
18"""
19
20from __future__ import print_function
herbertxue07293a32018-11-05 20:40:11 +080021from distutils.spawn import find_executable
Kevin Chengeb85e862018-10-09 15:35:13 -070022import logging
herbertxue07293a32018-11-05 20:40:11 +080023import os
24import re
25import subprocess
Kevin Chengeb85e862018-10-09 15:35:13 -070026
herbertxue07293a32018-11-05 20:40:11 +080027from acloud import errors
28from acloud.internal import constants
Kevin Chengeb85e862018-10-09 15:35:13 -070029from acloud.internal.lib import utils
Sam Chiu99dfee32018-11-20 10:19:17 +080030from acloud.list import list as list_instances
Kevin Chengeb85e862018-10-09 15:35:13 -070031from acloud.public import config
32from acloud.public import device_driver
herbertxue07293a32018-11-05 20:40:11 +080033from acloud.public import report
Kevin Chengeb85e862018-10-09 15:35:13 -070034
35logger = logging.getLogger(__name__)
36
herbertxue07293a32018-11-05 20:40:11 +080037_COMMAND_GET_PROCESS_ID = ["pgrep", "launch_cvd"]
38_COMMAND_GET_PROCESS_COMMAND = ["ps", "-o", "command", "-p"]
herbertxue07293a32018-11-05 20:40:11 +080039_RE_LAUNCH_CVD = re.compile(r"^(?P<launch_cvd>.+launch_cvd)(.*--daemon ).+")
herbertxue9e1e27a2018-12-12 16:25:27 +080040_SSVNC_VIEWER_PATTERN = "vnc://127.0.0.1:%(vnc_port)d"
herbertxue07293a32018-11-05 20:40:11 +080041
Kevin Chengeb85e862018-10-09 15:35:13 -070042
herbertxue07293a32018-11-05 20:40:11 +080043def _GetStopCvd():
44 """Get stop_cvd path.
45
46 "stop_cvd" and "launch_cvd" are in the same folder(host package folder).
47 Try to get directory of "launch_cvd" by "ps -o command -p <pid>." command.
48 For example: "/tmp/bin/launch_cvd --daemon --cpus 2 ..."
49
50 Raises:
51 errors.NoExecuteCmd: Can't find stop_cvd.
52
53 Returns:
54 String of stop_cvd file path.
55 """
56 process_id = subprocess.check_output(_COMMAND_GET_PROCESS_ID)
57 process_info = subprocess.check_output(
58 _COMMAND_GET_PROCESS_COMMAND + process_id.splitlines())
59 for process in process_info.splitlines():
60 match = _RE_LAUNCH_CVD.match(process)
61 if match:
62 launch_cvd_path = match.group("launch_cvd")
63 stop_cvd_cmd = os.path.join(os.path.dirname(launch_cvd_path),
64 constants.CMD_STOP_CVD)
65 if os.path.exists(stop_cvd_cmd):
66 logger.debug("stop_cvd command: %s", stop_cvd_cmd)
67 return stop_cvd_cmd
68
69 default_stop_cvd = find_executable(constants.CMD_STOP_CVD)
70 if default_stop_cvd:
71 return default_stop_cvd
72
Sam Chiu99dfee32018-11-20 10:19:17 +080073 raise errors.NoExecuteCmd("Cannot find stop_cvd binary.")
herbertxue07293a32018-11-05 20:40:11 +080074
75
herbertxue9e1e27a2018-12-12 16:25:27 +080076def CleanupSSVncviewer(vnc_port):
77 """Cleanup the old disconnected ssvnc viewer.
78
79 Args:
80 vnc_port: Integer, port number of vnc.
81 """
82 ssvnc_viewer_pattern = _SSVNC_VIEWER_PATTERN % {"vnc_port":vnc_port}
83 utils.CleanupProcess(ssvnc_viewer_pattern)
84
85
herbertxue07293a32018-11-05 20:40:11 +080086def DeleteInstances(cfg, instances_to_delete):
87 """Delete instances according to instances_to_delete.
88
herbertxue07293a32018-11-05 20:40:11 +080089 Args:
90 cfg: AcloudConfig object.
Sam Chiu99dfee32018-11-20 10:19:17 +080091 instances_to_delete: List of list.Instance() object.
herbertxue07293a32018-11-05 20:40:11 +080092
93 Returns:
94 Report instance if there are instances to delete, None otherwise.
95 """
herbertxue07293a32018-11-05 20:40:11 +080096 if not instances_to_delete:
97 print("No instances to delete")
98 return None
99
herbertxue07293a32018-11-05 20:40:11 +0800100 delete_report = None
Sam Chiu99dfee32018-11-20 10:19:17 +0800101 remote_instance_list = []
102 for instance in instances_to_delete:
103 if instance.islocal:
104 delete_report = DeleteLocalInstance()
105 else:
106 remote_instance_list.append(instance.name)
herbertxue9e1e27a2018-12-12 16:25:27 +0800107 # Delete ssvnc viewer
108 if instance.forwarding_vnc_port:
109 CleanupSSVncviewer(instance.forwarding_vnc_port)
herbertxue07293a32018-11-05 20:40:11 +0800110
Sam Chiu99dfee32018-11-20 10:19:17 +0800111 if remote_instance_list:
herbertxue07293a32018-11-05 20:40:11 +0800112 # TODO(119283708): We should move DeleteAndroidVirtualDevices into
113 # delete.py after gce is deprecated.
114 # Stop remote instances.
Sam Chiu99dfee32018-11-20 10:19:17 +0800115 return DeleteRemoteInstances(cfg, remote_instance_list, delete_report)
herbertxue07293a32018-11-05 20:40:11 +0800116
herbertxue07293a32018-11-05 20:40:11 +0800117 return delete_report
118
119
Sam Chiu99dfee32018-11-20 10:19:17 +0800120@utils.TimeExecute(function_description="Deleting remote instances",
121 result_evaluator=utils.ReportEvaluator,
122 display_waiting_dots=False)
123def DeleteRemoteInstances(cfg, instances_to_delete, delete_report=None):
124 """Delete remote instances.
125
126 Args:
127 cfg: AcloudConfig object.
128 instances_to_delete: List of instance names(string).
129 delete_report: Report object.
130
131 Returns:
132 Report instance if there are instances to delete, None otherwise.
133 """
134 utils.PrintColorString("")
135 for instance in instances_to_delete:
136 utils.PrintColorString(" - %s" % instance, utils.TextColors.WARNING)
137 utils.PrintColorString("")
138 utils.PrintColorString("status: waiting...", end="")
139
140 # TODO(119283708): We should move DeleteAndroidVirtualDevices into
141 # delete.py after gce is deprecated.
142 # Stop remote instances.
143 delete_report = device_driver.DeleteAndroidVirtualDevices(
144 cfg, instances_to_delete, delete_report)
145
146 return delete_report
147
148
149@utils.TimeExecute(function_description="Deleting local instances",
150 result_evaluator=utils.ReportEvaluator)
herbertxue07293a32018-11-05 20:40:11 +0800151def DeleteLocalInstance():
152 """Delete local instance.
153
154 Delete local instance with stop_cvd command and write delete instance
155 information to report.
156
herbertxue07293a32018-11-05 20:40:11 +0800157 Returns:
158 A Report instance.
159 """
160 delete_report = report.Report(command="delete")
161 try:
162 with open(os.devnull, "w") as dev_null:
163 subprocess.check_call(
164 utils.AddUserGroupsToCmd(_GetStopCvd(),
165 constants.LIST_CF_USER_GROUPS),
166 stderr=dev_null, stdout=dev_null, shell=True)
167 delete_report.SetStatus(report.Status.SUCCESS)
168 device_driver.AddDeletionResultToReport(
Sam Chiu99dfee32018-11-20 10:19:17 +0800169 delete_report, [constants.LOCAL_INS_NAME], failed=[],
170 error_msgs=[],
herbertxue07293a32018-11-05 20:40:11 +0800171 resource_name="instance")
172 except subprocess.CalledProcessError as e:
173 delete_report.AddError(str(e))
174 delete_report.SetStatus(report.Status.FAIL)
175
176 return delete_report
Kevin Chengeb85e862018-10-09 15:35:13 -0700177
178
179def Run(args):
180 """Run delete.
181
182 Args:
183 args: Namespace object from argparse.parse_args.
Sam Chiu99dfee32018-11-20 10:19:17 +0800184
185 Returns:
186 A Report instance.
Kevin Chengeb85e862018-10-09 15:35:13 -0700187 """
herbertxue07293a32018-11-05 20:40:11 +0800188 cfg = config.GetAcloudConfig(args)
Sam Chiu99dfee32018-11-20 10:19:17 +0800189 remote_instances_to_delete = args.instance_names
190
191 if remote_instances_to_delete:
192 return DeleteRemoteInstances(cfg, remote_instances_to_delete)
193
194 # Provide instances list to user and let user choose what to delete if user
195 # didn't specific instance name in args.
196 return DeleteInstances(cfg, list_instances.ChooseInstances(cfg, args.all))