1*800a58d9SAndroid Build Coastguard Worker# Copyright 2018 - The Android Open Source Project 2*800a58d9SAndroid Build Coastguard Worker# 3*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*800a58d9SAndroid Build Coastguard Worker# 7*800a58d9SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*800a58d9SAndroid Build Coastguard Worker# 9*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*800a58d9SAndroid Build Coastguard Worker# limitations under the License. 14*800a58d9SAndroid Build Coastguard Workerr"""Instance class. 15*800a58d9SAndroid Build Coastguard Worker 16*800a58d9SAndroid Build Coastguard WorkerDefine the instance class used to hold details about an AVD instance. 17*800a58d9SAndroid Build Coastguard Worker 18*800a58d9SAndroid Build Coastguard WorkerThe instance class will hold details about AVD instances (remote/local) used to 19*800a58d9SAndroid Build Coastguard Workerenable users to understand what instances they've created. This will be leveraged 20*800a58d9SAndroid Build Coastguard Workerfor the list, delete, and reconnect commands. 21*800a58d9SAndroid Build Coastguard Worker 22*800a58d9SAndroid Build Coastguard WorkerThe details include: 23*800a58d9SAndroid Build Coastguard Worker- instance name (for remote instances) 24*800a58d9SAndroid Build Coastguard Worker- creation date/instance duration 25*800a58d9SAndroid Build Coastguard Worker- instance image details (branch/target/build id) 26*800a58d9SAndroid Build Coastguard Worker- and more! 27*800a58d9SAndroid Build Coastguard Worker""" 28*800a58d9SAndroid Build Coastguard Worker 29*800a58d9SAndroid Build Coastguard Workerimport collections 30*800a58d9SAndroid Build Coastguard Workerimport datetime 31*800a58d9SAndroid Build Coastguard Workerimport json 32*800a58d9SAndroid Build Coastguard Workerimport logging 33*800a58d9SAndroid Build Coastguard Workerimport os 34*800a58d9SAndroid Build Coastguard Workerimport re 35*800a58d9SAndroid Build Coastguard Workerimport subprocess 36*800a58d9SAndroid Build Coastguard Workerimport tempfile 37*800a58d9SAndroid Build Coastguard Worker 38*800a58d9SAndroid Build Coastguard Worker# pylint: disable=import-error,too-many-lines 39*800a58d9SAndroid Build Coastguard Workerimport dateutil.parser 40*800a58d9SAndroid Build Coastguard Workerimport dateutil.tz 41*800a58d9SAndroid Build Coastguard Worker 42*800a58d9SAndroid Build Coastguard Workerfrom acloud.create import local_image_local_instance 43*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants 44*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import cvd_runtime_config 45*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils 46*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib.adb_tools import AdbTools 47*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib.local_instance_lock import LocalInstanceLock 48*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib.gcompute_client import GetInstanceIP 49*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib.gcompute_client import GetGCEHostName 50*800a58d9SAndroid Build Coastguard Worker 51*800a58d9SAndroid Build Coastguard Worker 52*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 53*800a58d9SAndroid Build Coastguard Worker 54*800a58d9SAndroid Build Coastguard Worker_ACLOUD_CVD_TEMP = os.path.join(tempfile.gettempdir(), "acloud_cvd_temp") 55*800a58d9SAndroid Build Coastguard Worker_CFG_KEY_INSTANCES = "instances" 56*800a58d9SAndroid Build Coastguard Worker_CVD_RUNTIME_FOLDER_NAME = "cuttlefish_runtime" 57*800a58d9SAndroid Build Coastguard Worker_CVD_BIN = "cvd" 58*800a58d9SAndroid Build Coastguard Worker_CVD_BIN_FOLDER = "host_bins/bin" 59*800a58d9SAndroid Build Coastguard Worker_CVD_STATUS_BIN = "cvd_status" 60*800a58d9SAndroid Build Coastguard Worker_CVD_STOP_ERROR_KEYWORDS = "cvd_internal_stop E" 61*800a58d9SAndroid Build Coastguard Worker# Default timeout 30 secs for cvd commands. 62*800a58d9SAndroid Build Coastguard Worker_CVD_TIMEOUT = 30 63*800a58d9SAndroid Build Coastguard Worker# Keywords read from runtime config. 64*800a58d9SAndroid Build Coastguard Worker_ADB_HOST_PORT = "adb_host_port" 65*800a58d9SAndroid Build Coastguard Worker# Keywords read from the output of "cvd status". 66*800a58d9SAndroid Build Coastguard Worker_DISPLAYS = "displays" 67*800a58d9SAndroid Build Coastguard Worker_WEBRTC_PORT = "webrtc_port" 68*800a58d9SAndroid Build Coastguard Worker_ADB_SERIAL = "adb_serial" 69*800a58d9SAndroid Build Coastguard Worker_INSTANCE_ASSEMBLY_DIR = "cuttlefish_assembly" 70*800a58d9SAndroid Build Coastguard Worker_LOCAL_INSTANCE_NAME_FORMAT = "local-instance-%(id)d" 71*800a58d9SAndroid Build Coastguard Worker_LOCAL_INSTANCE_NAME_PATTERN = re.compile(r"^local-instance-(?P<id>\d+)$") 72*800a58d9SAndroid Build Coastguard Worker_ACLOUDWEB_INSTANCE_START_STRING = "cf-" 73*800a58d9SAndroid Build Coastguard Worker_MSG_UNABLE_TO_CALCULATE = "Unable to calculate" 74*800a58d9SAndroid Build Coastguard Worker_NO_ANDROID_ENV = "android source not available" 75*800a58d9SAndroid Build Coastguard Worker_RE_GROUP_ADB = "local_adb_port" 76*800a58d9SAndroid Build Coastguard Worker_RE_GROUP_VNC = "local_vnc_port" 77*800a58d9SAndroid Build Coastguard Worker_RE_SSH_TUNNEL_PATTERN = (r"((.*\s*-L\s)(?P<%s>\d+):127.0.0.1:%s)" 78*800a58d9SAndroid Build Coastguard Worker r"((.*\s*-L\s)(?P<%s>\d+):127.0.0.1:%s)" 79*800a58d9SAndroid Build Coastguard Worker r"(.+(%s|%s))") 80*800a58d9SAndroid Build Coastguard Worker_RE_TIMEZONE = re.compile(r"^(?P<time>[0-9\-\.:T]*)(?P<timezone>[+-]\d+:\d+)$") 81*800a58d9SAndroid Build Coastguard Worker_RE_DEVICE_INFO = re.compile(r"(?s).*(?P<device_info>[{][\s\w\W]+})") 82*800a58d9SAndroid Build Coastguard Worker 83*800a58d9SAndroid Build Coastguard Worker_COMMAND_PS_LAUNCH_CVD = ["ps", "-wweo", "lstart,cmd"] 84*800a58d9SAndroid Build Coastguard Worker_RE_RUN_CVD = re.compile(r"(?P<date_str>^[^/]+)(.*run_cvd)") 85*800a58d9SAndroid Build Coastguard Worker_X_RES = "x_res" 86*800a58d9SAndroid Build Coastguard Worker_Y_RES = "y_res" 87*800a58d9SAndroid Build Coastguard Worker_DPI = "dpi" 88*800a58d9SAndroid Build Coastguard Worker_DISPLAY_STRING = "%(x_res)sx%(y_res)s (%(dpi)s)" 89*800a58d9SAndroid Build Coastguard Worker_RE_ZONE = re.compile(r".+/zones/(?P<zone>.+)$") 90*800a58d9SAndroid Build Coastguard Worker_RE_PROJECT = re.compile(r".+/projects/(?P<project>.+)/zones/.+$") 91*800a58d9SAndroid Build Coastguard Worker_LOCAL_ZONE = "local" 92*800a58d9SAndroid Build Coastguard Worker_INDENT = " " * 3 93*800a58d9SAndroid Build Coastguard WorkerLocalPorts = collections.namedtuple("LocalPorts", [constants.VNC_PORT, 94*800a58d9SAndroid Build Coastguard Worker constants.ADB_PORT]) 95*800a58d9SAndroid Build Coastguard Worker 96*800a58d9SAndroid Build Coastguard Worker 97*800a58d9SAndroid Build Coastguard Workerdef GetDefaultCuttlefishConfig(): 98*800a58d9SAndroid Build Coastguard Worker """Get the path of default cuttlefish instance config. 99*800a58d9SAndroid Build Coastguard Worker 100*800a58d9SAndroid Build Coastguard Worker Return: 101*800a58d9SAndroid Build Coastguard Worker String, path of cf runtime config. 102*800a58d9SAndroid Build Coastguard Worker """ 103*800a58d9SAndroid Build Coastguard Worker cfg_path = os.path.join(os.path.expanduser("~"), _CVD_RUNTIME_FOLDER_NAME, 104*800a58d9SAndroid Build Coastguard Worker constants.CUTTLEFISH_CONFIG_FILE) 105*800a58d9SAndroid Build Coastguard Worker if os.path.isfile(cfg_path): 106*800a58d9SAndroid Build Coastguard Worker return cfg_path 107*800a58d9SAndroid Build Coastguard Worker return None 108*800a58d9SAndroid Build Coastguard Worker 109*800a58d9SAndroid Build Coastguard Worker 110*800a58d9SAndroid Build Coastguard Workerdef GetLocalInstanceName(local_instance_id): 111*800a58d9SAndroid Build Coastguard Worker """Get local cuttlefish instance name by instance id. 112*800a58d9SAndroid Build Coastguard Worker 113*800a58d9SAndroid Build Coastguard Worker Args: 114*800a58d9SAndroid Build Coastguard Worker local_instance_id: Integer of instance id. 115*800a58d9SAndroid Build Coastguard Worker 116*800a58d9SAndroid Build Coastguard Worker Return: 117*800a58d9SAndroid Build Coastguard Worker String, the instance name. 118*800a58d9SAndroid Build Coastguard Worker """ 119*800a58d9SAndroid Build Coastguard Worker return _LOCAL_INSTANCE_NAME_FORMAT % {"id": local_instance_id} 120*800a58d9SAndroid Build Coastguard Worker 121*800a58d9SAndroid Build Coastguard Worker 122*800a58d9SAndroid Build Coastguard Workerdef GetLocalInstanceIdByName(name): 123*800a58d9SAndroid Build Coastguard Worker """Get local cuttlefish instance id by name. 124*800a58d9SAndroid Build Coastguard Worker 125*800a58d9SAndroid Build Coastguard Worker Args: 126*800a58d9SAndroid Build Coastguard Worker name: String of instance name. 127*800a58d9SAndroid Build Coastguard Worker 128*800a58d9SAndroid Build Coastguard Worker Return: 129*800a58d9SAndroid Build Coastguard Worker The instance id as an integer if the name is in valid format. 130*800a58d9SAndroid Build Coastguard Worker None if the name does not represent a local cuttlefish instance. 131*800a58d9SAndroid Build Coastguard Worker """ 132*800a58d9SAndroid Build Coastguard Worker match = _LOCAL_INSTANCE_NAME_PATTERN.match(name) 133*800a58d9SAndroid Build Coastguard Worker if match: 134*800a58d9SAndroid Build Coastguard Worker return int(match.group("id")) 135*800a58d9SAndroid Build Coastguard Worker return None 136*800a58d9SAndroid Build Coastguard Worker 137*800a58d9SAndroid Build Coastguard Worker 138*800a58d9SAndroid Build Coastguard Workerdef GetLocalInstanceConfigPath(local_instance_id): 139*800a58d9SAndroid Build Coastguard Worker """Get the path of instance config. 140*800a58d9SAndroid Build Coastguard Worker 141*800a58d9SAndroid Build Coastguard Worker Args: 142*800a58d9SAndroid Build Coastguard Worker local_instance_id: Integer of instance id. 143*800a58d9SAndroid Build Coastguard Worker 144*800a58d9SAndroid Build Coastguard Worker Return: 145*800a58d9SAndroid Build Coastguard Worker String, path of cf runtime config. 146*800a58d9SAndroid Build Coastguard Worker """ 147*800a58d9SAndroid Build Coastguard Worker ins_assembly_dir = os.path.join(GetLocalInstanceHomeDir(local_instance_id), 148*800a58d9SAndroid Build Coastguard Worker _INSTANCE_ASSEMBLY_DIR) 149*800a58d9SAndroid Build Coastguard Worker return os.path.join(ins_assembly_dir, constants.CUTTLEFISH_CONFIG_FILE) 150*800a58d9SAndroid Build Coastguard Worker 151*800a58d9SAndroid Build Coastguard Worker 152*800a58d9SAndroid Build Coastguard Workerdef GetLocalInstanceConfig(local_instance_id): 153*800a58d9SAndroid Build Coastguard Worker """Get the path of existed config from local instance. 154*800a58d9SAndroid Build Coastguard Worker 155*800a58d9SAndroid Build Coastguard Worker Args: 156*800a58d9SAndroid Build Coastguard Worker local_instance_id: Integer of instance id. 157*800a58d9SAndroid Build Coastguard Worker 158*800a58d9SAndroid Build Coastguard Worker Return: 159*800a58d9SAndroid Build Coastguard Worker String, path of cf runtime config. None for config not exist. 160*800a58d9SAndroid Build Coastguard Worker """ 161*800a58d9SAndroid Build Coastguard Worker cfg_path = GetLocalInstanceConfigPath(local_instance_id) 162*800a58d9SAndroid Build Coastguard Worker if os.path.isfile(cfg_path): 163*800a58d9SAndroid Build Coastguard Worker return cfg_path 164*800a58d9SAndroid Build Coastguard Worker return None 165*800a58d9SAndroid Build Coastguard Worker 166*800a58d9SAndroid Build Coastguard Workerdef GetInstanceId(cfg_path): 167*800a58d9SAndroid Build Coastguard Worker """Get the cuttlefish ID from config file. 168*800a58d9SAndroid Build Coastguard Worker 169*800a58d9SAndroid Build Coastguard Worker Args: 170*800a58d9SAndroid Build Coastguard Worker cfg_path: Path to config file. 171*800a58d9SAndroid Build Coastguard Worker 172*800a58d9SAndroid Build Coastguard Worker Return: 173*800a58d9SAndroid Build Coastguard Worker Cuttlefish ID. 174*800a58d9SAndroid Build Coastguard Worker """ 175*800a58d9SAndroid Build Coastguard Worker with open(cfg_path, "r") as cf_config: 176*800a58d9SAndroid Build Coastguard Worker config_dict = json.load(cf_config) 177*800a58d9SAndroid Build Coastguard Worker instances = config_dict.get(_CFG_KEY_INSTANCES) 178*800a58d9SAndroid Build Coastguard Worker ins_id = int(min(instances.keys())) if instances else 1 179*800a58d9SAndroid Build Coastguard Worker return ins_id 180*800a58d9SAndroid Build Coastguard Worker 181*800a58d9SAndroid Build Coastguard Workerdef GetAllLocalInstanceConfigs(): 182*800a58d9SAndroid Build Coastguard Worker """Get all cuttlefish runtime configs from the known locations. 183*800a58d9SAndroid Build Coastguard Worker 184*800a58d9SAndroid Build Coastguard Worker Return: 185*800a58d9SAndroid Build Coastguard Worker List of tuples. Each tuple consists of an instance id and a config 186*800a58d9SAndroid Build Coastguard Worker path. 187*800a58d9SAndroid Build Coastguard Worker """ 188*800a58d9SAndroid Build Coastguard Worker id_cfg_pairs = [] 189*800a58d9SAndroid Build Coastguard Worker id_set = set() 190*800a58d9SAndroid Build Coastguard Worker # Check if any instance config is under home folder. 191*800a58d9SAndroid Build Coastguard Worker cfg_path = GetDefaultCuttlefishConfig() 192*800a58d9SAndroid Build Coastguard Worker if cfg_path: 193*800a58d9SAndroid Build Coastguard Worker ins_id = GetInstanceId(cfg_path) 194*800a58d9SAndroid Build Coastguard Worker 195*800a58d9SAndroid Build Coastguard Worker # skip redundant id in HOME and /tmp 196*800a58d9SAndroid Build Coastguard Worker if ins_id not in id_set: 197*800a58d9SAndroid Build Coastguard Worker id_set.add(ins_id) 198*800a58d9SAndroid Build Coastguard Worker id_cfg_pairs.append((ins_id, cfg_path)) 199*800a58d9SAndroid Build Coastguard Worker 200*800a58d9SAndroid Build Coastguard Worker # Check if any instance config is under acloud cvd temp folder. 201*800a58d9SAndroid Build Coastguard Worker if os.path.exists(_ACLOUD_CVD_TEMP): 202*800a58d9SAndroid Build Coastguard Worker for ins_name in os.listdir(_ACLOUD_CVD_TEMP): 203*800a58d9SAndroid Build Coastguard Worker ins_id = GetLocalInstanceIdByName(ins_name) 204*800a58d9SAndroid Build Coastguard Worker if ins_id is not None and ins_id not in id_set: 205*800a58d9SAndroid Build Coastguard Worker cfg_path = GetLocalInstanceConfig(ins_id) 206*800a58d9SAndroid Build Coastguard Worker if cfg_path: 207*800a58d9SAndroid Build Coastguard Worker id_set.add(ins_id) 208*800a58d9SAndroid Build Coastguard Worker id_cfg_pairs.append((ins_id, cfg_path)) 209*800a58d9SAndroid Build Coastguard Worker return id_cfg_pairs 210*800a58d9SAndroid Build Coastguard Worker 211*800a58d9SAndroid Build Coastguard Worker 212*800a58d9SAndroid Build Coastguard Workerdef GetLocalInstanceHomeDir(local_instance_id): 213*800a58d9SAndroid Build Coastguard Worker """Get local instance home dir according to instance id. 214*800a58d9SAndroid Build Coastguard Worker 215*800a58d9SAndroid Build Coastguard Worker Args: 216*800a58d9SAndroid Build Coastguard Worker local_instance_id: Integer of instance id. 217*800a58d9SAndroid Build Coastguard Worker 218*800a58d9SAndroid Build Coastguard Worker Return: 219*800a58d9SAndroid Build Coastguard Worker String, path of instance home dir. 220*800a58d9SAndroid Build Coastguard Worker """ 221*800a58d9SAndroid Build Coastguard Worker return os.path.join(_ACLOUD_CVD_TEMP, 222*800a58d9SAndroid Build Coastguard Worker GetLocalInstanceName(local_instance_id)) 223*800a58d9SAndroid Build Coastguard Worker 224*800a58d9SAndroid Build Coastguard Worker 225*800a58d9SAndroid Build Coastguard Workerdef GetLocalInstanceLock(local_instance_id): 226*800a58d9SAndroid Build Coastguard Worker """Get local instance lock. 227*800a58d9SAndroid Build Coastguard Worker 228*800a58d9SAndroid Build Coastguard Worker Args: 229*800a58d9SAndroid Build Coastguard Worker local_instance_id: Integer of instance id. 230*800a58d9SAndroid Build Coastguard Worker 231*800a58d9SAndroid Build Coastguard Worker Returns: 232*800a58d9SAndroid Build Coastguard Worker LocalInstanceLock object. 233*800a58d9SAndroid Build Coastguard Worker """ 234*800a58d9SAndroid Build Coastguard Worker file_path = os.path.join(_ACLOUD_CVD_TEMP, 235*800a58d9SAndroid Build Coastguard Worker GetLocalInstanceName(local_instance_id) + ".lock") 236*800a58d9SAndroid Build Coastguard Worker return LocalInstanceLock(file_path) 237*800a58d9SAndroid Build Coastguard Worker 238*800a58d9SAndroid Build Coastguard Worker 239*800a58d9SAndroid Build Coastguard Workerdef GetLocalInstanceRuntimeDir(local_instance_id): 240*800a58d9SAndroid Build Coastguard Worker """Get instance runtime dir 241*800a58d9SAndroid Build Coastguard Worker 242*800a58d9SAndroid Build Coastguard Worker Args: 243*800a58d9SAndroid Build Coastguard Worker local_instance_id: Integer of instance id. 244*800a58d9SAndroid Build Coastguard Worker 245*800a58d9SAndroid Build Coastguard Worker Return: 246*800a58d9SAndroid Build Coastguard Worker String, path of instance runtime dir. 247*800a58d9SAndroid Build Coastguard Worker """ 248*800a58d9SAndroid Build Coastguard Worker return os.path.join(GetLocalInstanceHomeDir(local_instance_id), 249*800a58d9SAndroid Build Coastguard Worker _CVD_RUNTIME_FOLDER_NAME) 250*800a58d9SAndroid Build Coastguard Worker 251*800a58d9SAndroid Build Coastguard Worker 252*800a58d9SAndroid Build Coastguard Workerdef GetCuttleFishLocalInstances(cf_config_path): 253*800a58d9SAndroid Build Coastguard Worker """Get all instances information from cf runtime config. 254*800a58d9SAndroid Build Coastguard Worker 255*800a58d9SAndroid Build Coastguard Worker Args: 256*800a58d9SAndroid Build Coastguard Worker cf_config_path: String, path to the cf runtime config. 257*800a58d9SAndroid Build Coastguard Worker 258*800a58d9SAndroid Build Coastguard Worker Returns: 259*800a58d9SAndroid Build Coastguard Worker List of LocalInstance object. 260*800a58d9SAndroid Build Coastguard Worker """ 261*800a58d9SAndroid Build Coastguard Worker cf_runtime_cfg = cvd_runtime_config.CvdRuntimeConfig(cf_config_path) 262*800a58d9SAndroid Build Coastguard Worker local_instances = [] 263*800a58d9SAndroid Build Coastguard Worker for ins_id in cf_runtime_cfg.instance_ids: 264*800a58d9SAndroid Build Coastguard Worker local_instances.append(LocalInstance(cf_config_path, ins_id)) 265*800a58d9SAndroid Build Coastguard Worker return local_instances 266*800a58d9SAndroid Build Coastguard Worker 267*800a58d9SAndroid Build Coastguard Worker 268*800a58d9SAndroid Build Coastguard Workerdef _GetCurrentLocalTime(): 269*800a58d9SAndroid Build Coastguard Worker """Return a datetime object for current time in local time zone.""" 270*800a58d9SAndroid Build Coastguard Worker return datetime.datetime.now(dateutil.tz.tzlocal()).replace(microsecond=0) 271*800a58d9SAndroid Build Coastguard Worker 272*800a58d9SAndroid Build Coastguard Worker 273*800a58d9SAndroid Build Coastguard Workerdef _GetElapsedTime(start_time): 274*800a58d9SAndroid Build Coastguard Worker """Calculate the elapsed time from start_time till now. 275*800a58d9SAndroid Build Coastguard Worker 276*800a58d9SAndroid Build Coastguard Worker Args: 277*800a58d9SAndroid Build Coastguard Worker start_time: String of instance created time. 278*800a58d9SAndroid Build Coastguard Worker 279*800a58d9SAndroid Build Coastguard Worker Returns: 280*800a58d9SAndroid Build Coastguard Worker datetime.timedelta of elapsed time, _MSG_UNABLE_TO_CALCULATE for 281*800a58d9SAndroid Build Coastguard Worker datetime can't parse cases. 282*800a58d9SAndroid Build Coastguard Worker """ 283*800a58d9SAndroid Build Coastguard Worker match = _RE_TIMEZONE.match(start_time) 284*800a58d9SAndroid Build Coastguard Worker try: 285*800a58d9SAndroid Build Coastguard Worker # Check start_time has timezone or not. If timezone can't be found, 286*800a58d9SAndroid Build Coastguard Worker # use local timezone to get elapsed time. 287*800a58d9SAndroid Build Coastguard Worker if match: 288*800a58d9SAndroid Build Coastguard Worker return _GetCurrentLocalTime() - dateutil.parser.parse( 289*800a58d9SAndroid Build Coastguard Worker start_time).replace(microsecond=0) 290*800a58d9SAndroid Build Coastguard Worker 291*800a58d9SAndroid Build Coastguard Worker return _GetCurrentLocalTime() - dateutil.parser.parse( 292*800a58d9SAndroid Build Coastguard Worker start_time).replace(tzinfo=dateutil.tz.tzlocal(), microsecond=0) 293*800a58d9SAndroid Build Coastguard Worker except ValueError: 294*800a58d9SAndroid Build Coastguard Worker logger.debug(("Can't parse datetime string(%s)."), start_time) 295*800a58d9SAndroid Build Coastguard Worker return _MSG_UNABLE_TO_CALCULATE 296*800a58d9SAndroid Build Coastguard Worker 297*800a58d9SAndroid Build Coastguard Workerdef _GetDeviceFullName(device_serial, instance_name, elapsed_time, 298*800a58d9SAndroid Build Coastguard Worker webrtc_device_id=None): 299*800a58d9SAndroid Build Coastguard Worker """Get the full name of device. 300*800a58d9SAndroid Build Coastguard Worker 301*800a58d9SAndroid Build Coastguard Worker The full name is composed with device serial, webrtc device id, instance 302*800a58d9SAndroid Build Coastguard Worker name, and elapsed_time. 303*800a58d9SAndroid Build Coastguard Worker 304*800a58d9SAndroid Build Coastguard Worker Args: 305*800a58d9SAndroid Build Coastguard Worker device_serial: String of device serial. e.g. 127.0.0.1:6520 306*800a58d9SAndroid Build Coastguard Worker instance_name: String of instance name. 307*800a58d9SAndroid Build Coastguard Worker elapsed time: String of elapsed time. 308*800a58d9SAndroid Build Coastguard Worker webrtc_device_id: String of webrtc device id. 309*800a58d9SAndroid Build Coastguard Worker 310*800a58d9SAndroid Build Coastguard Worker Returns: 311*800a58d9SAndroid Build Coastguard Worker String of device full name. 312*800a58d9SAndroid Build Coastguard Worker """ 313*800a58d9SAndroid Build Coastguard Worker if webrtc_device_id: 314*800a58d9SAndroid Build Coastguard Worker return (f"device serial: {device_serial} {webrtc_device_id} " 315*800a58d9SAndroid Build Coastguard Worker f"({instance_name}) elapsed time: {elapsed_time}") 316*800a58d9SAndroid Build Coastguard Worker 317*800a58d9SAndroid Build Coastguard Worker return (f"device serial: {device_serial} ({instance_name}) " 318*800a58d9SAndroid Build Coastguard Worker f"elapsed time: {elapsed_time}") 319*800a58d9SAndroid Build Coastguard Worker 320*800a58d9SAndroid Build Coastguard Worker 321*800a58d9SAndroid Build Coastguard Workerdef _IsProcessRunning(process): 322*800a58d9SAndroid Build Coastguard Worker """Check if this process is running. 323*800a58d9SAndroid Build Coastguard Worker 324*800a58d9SAndroid Build Coastguard Worker Returns: 325*800a58d9SAndroid Build Coastguard Worker Boolean, True for this process is running. 326*800a58d9SAndroid Build Coastguard Worker """ 327*800a58d9SAndroid Build Coastguard Worker match_pattern = re.compile(f"(.+)({process} )(.+)") 328*800a58d9SAndroid Build Coastguard Worker process_output = utils.CheckOutput(constants.COMMAND_PS) 329*800a58d9SAndroid Build Coastguard Worker for line in process_output.splitlines(): 330*800a58d9SAndroid Build Coastguard Worker process_match = match_pattern.match(line) 331*800a58d9SAndroid Build Coastguard Worker if process_match: 332*800a58d9SAndroid Build Coastguard Worker return True 333*800a58d9SAndroid Build Coastguard Worker return False 334*800a58d9SAndroid Build Coastguard Worker 335*800a58d9SAndroid Build Coastguard Worker 336*800a58d9SAndroid Build Coastguard Worker# pylint: disable=useless-object-inheritance 337*800a58d9SAndroid Build Coastguard Workerclass Instance(object): 338*800a58d9SAndroid Build Coastguard Worker """Class to store data of instance.""" 339*800a58d9SAndroid Build Coastguard Worker 340*800a58d9SAndroid Build Coastguard Worker # pylint: disable=too-many-locals 341*800a58d9SAndroid Build Coastguard Worker def __init__(self, name, fullname, display, ip, status=None, adb_port=None, 342*800a58d9SAndroid Build Coastguard Worker vnc_port=None, ssh_tunnel_is_connected=None, createtime=None, 343*800a58d9SAndroid Build Coastguard Worker elapsed_time=None, avd_type=None, avd_flavor=None, 344*800a58d9SAndroid Build Coastguard Worker is_local=False, device_information=None, zone=None, 345*800a58d9SAndroid Build Coastguard Worker webrtc_port=None, webrtc_forward_port=None): 346*800a58d9SAndroid Build Coastguard Worker self._name = name 347*800a58d9SAndroid Build Coastguard Worker self._fullname = fullname 348*800a58d9SAndroid Build Coastguard Worker self._status = status 349*800a58d9SAndroid Build Coastguard Worker self._display = display # Resolution and dpi 350*800a58d9SAndroid Build Coastguard Worker self._ip = ip 351*800a58d9SAndroid Build Coastguard Worker self._adb_port = adb_port # adb port which is forwarding to remote 352*800a58d9SAndroid Build Coastguard Worker self._vnc_port = vnc_port # vnc port which is forwarding to remote 353*800a58d9SAndroid Build Coastguard Worker self._webrtc_port = webrtc_port 354*800a58d9SAndroid Build Coastguard Worker self._webrtc_forward_port = webrtc_forward_port 355*800a58d9SAndroid Build Coastguard Worker # True if ssh tunnel is still connected 356*800a58d9SAndroid Build Coastguard Worker self._ssh_tunnel_is_connected = ssh_tunnel_is_connected 357*800a58d9SAndroid Build Coastguard Worker self._createtime = createtime 358*800a58d9SAndroid Build Coastguard Worker self._elapsed_time = elapsed_time 359*800a58d9SAndroid Build Coastguard Worker self._avd_type = avd_type 360*800a58d9SAndroid Build Coastguard Worker self._avd_flavor = avd_flavor 361*800a58d9SAndroid Build Coastguard Worker self._is_local = is_local # True if this is a local instance 362*800a58d9SAndroid Build Coastguard Worker self._device_information = device_information 363*800a58d9SAndroid Build Coastguard Worker self._zone = zone 364*800a58d9SAndroid Build Coastguard Worker self._autoconnect = self._GetAutoConnect() 365*800a58d9SAndroid Build Coastguard Worker 366*800a58d9SAndroid Build Coastguard Worker def __repr__(self): 367*800a58d9SAndroid Build Coastguard Worker """Return full name property for print.""" 368*800a58d9SAndroid Build Coastguard Worker return self._fullname 369*800a58d9SAndroid Build Coastguard Worker 370*800a58d9SAndroid Build Coastguard Worker def Summary(self): 371*800a58d9SAndroid Build Coastguard Worker """Let's make it easy to see what this class is holding.""" 372*800a58d9SAndroid Build Coastguard Worker representation = [] 373*800a58d9SAndroid Build Coastguard Worker representation.append(" name: %s" % self._name) 374*800a58d9SAndroid Build Coastguard Worker representation.append("%s IP: %s" % (_INDENT, self._ip)) 375*800a58d9SAndroid Build Coastguard Worker representation.append("%s create time: %s" % (_INDENT, self._createtime)) 376*800a58d9SAndroid Build Coastguard Worker representation.append("%s elapse time: %s" % (_INDENT, self._elapsed_time)) 377*800a58d9SAndroid Build Coastguard Worker representation.append("%s status: %s" % (_INDENT, self._status)) 378*800a58d9SAndroid Build Coastguard Worker representation.append("%s avd type: %s" % (_INDENT, self._avd_type)) 379*800a58d9SAndroid Build Coastguard Worker representation.append("%s display: %s" % (_INDENT, self._display)) 380*800a58d9SAndroid Build Coastguard Worker representation.append("%s vnc: 127.0.0.1:%s" % (_INDENT, self._vnc_port)) 381*800a58d9SAndroid Build Coastguard Worker representation.append("%s zone: %s" % (_INDENT, self._zone)) 382*800a58d9SAndroid Build Coastguard Worker representation.append("%s autoconnect: %s" % (_INDENT, self._autoconnect)) 383*800a58d9SAndroid Build Coastguard Worker representation.append("%s webrtc port: %s" % (_INDENT, self._webrtc_port)) 384*800a58d9SAndroid Build Coastguard Worker representation.append("%s webrtc forward port: %s" % 385*800a58d9SAndroid Build Coastguard Worker (_INDENT, self._webrtc_forward_port)) 386*800a58d9SAndroid Build Coastguard Worker 387*800a58d9SAndroid Build Coastguard Worker if self._adb_port and self._device_information: 388*800a58d9SAndroid Build Coastguard Worker serial_ip = self._ip if self._ip == "0.0.0.0" else "127.0.0.1" 389*800a58d9SAndroid Build Coastguard Worker representation.append("%s adb serial: %s:%s" % 390*800a58d9SAndroid Build Coastguard Worker (_INDENT, serial_ip, self._adb_port)) 391*800a58d9SAndroid Build Coastguard Worker representation.append("%s product: %s" % ( 392*800a58d9SAndroid Build Coastguard Worker _INDENT, self._device_information["product"])) 393*800a58d9SAndroid Build Coastguard Worker representation.append("%s model: %s" % ( 394*800a58d9SAndroid Build Coastguard Worker _INDENT, self._device_information["model"])) 395*800a58d9SAndroid Build Coastguard Worker representation.append("%s device: %s" % ( 396*800a58d9SAndroid Build Coastguard Worker _INDENT, self._device_information["device"])) 397*800a58d9SAndroid Build Coastguard Worker representation.append("%s transport_id: %s" % ( 398*800a58d9SAndroid Build Coastguard Worker _INDENT, self._device_information["transport_id"])) 399*800a58d9SAndroid Build Coastguard Worker else: 400*800a58d9SAndroid Build Coastguard Worker representation.append("%s adb serial: disconnected" % _INDENT) 401*800a58d9SAndroid Build Coastguard Worker 402*800a58d9SAndroid Build Coastguard Worker return "\n".join(representation) 403*800a58d9SAndroid Build Coastguard Worker 404*800a58d9SAndroid Build Coastguard Worker def AdbConnected(self): 405*800a58d9SAndroid Build Coastguard Worker """Check AVD adb connected. 406*800a58d9SAndroid Build Coastguard Worker 407*800a58d9SAndroid Build Coastguard Worker Returns: 408*800a58d9SAndroid Build Coastguard Worker Boolean, True when adb status of AVD is connected. 409*800a58d9SAndroid Build Coastguard Worker """ 410*800a58d9SAndroid Build Coastguard Worker if self._adb_port and self._device_information: 411*800a58d9SAndroid Build Coastguard Worker return True 412*800a58d9SAndroid Build Coastguard Worker return False 413*800a58d9SAndroid Build Coastguard Worker 414*800a58d9SAndroid Build Coastguard Worker def _GetAutoConnect(self): 415*800a58d9SAndroid Build Coastguard Worker """Get the autoconnect of instance. 416*800a58d9SAndroid Build Coastguard Worker 417*800a58d9SAndroid Build Coastguard Worker Returns: 418*800a58d9SAndroid Build Coastguard Worker String of autoconnect type. None for no autoconnect. 419*800a58d9SAndroid Build Coastguard Worker """ 420*800a58d9SAndroid Build Coastguard Worker if self._webrtc_port or self._webrtc_forward_port: 421*800a58d9SAndroid Build Coastguard Worker return constants.INS_KEY_WEBRTC 422*800a58d9SAndroid Build Coastguard Worker if self._vnc_port: 423*800a58d9SAndroid Build Coastguard Worker return constants.INS_KEY_VNC 424*800a58d9SAndroid Build Coastguard Worker if self._adb_port: 425*800a58d9SAndroid Build Coastguard Worker return constants.INS_KEY_ADB 426*800a58d9SAndroid Build Coastguard Worker return None 427*800a58d9SAndroid Build Coastguard Worker 428*800a58d9SAndroid Build Coastguard Worker @property 429*800a58d9SAndroid Build Coastguard Worker def name(self): 430*800a58d9SAndroid Build Coastguard Worker """Return the instance name.""" 431*800a58d9SAndroid Build Coastguard Worker return self._name 432*800a58d9SAndroid Build Coastguard Worker 433*800a58d9SAndroid Build Coastguard Worker @property 434*800a58d9SAndroid Build Coastguard Worker def fullname(self): 435*800a58d9SAndroid Build Coastguard Worker """Return the instance full name.""" 436*800a58d9SAndroid Build Coastguard Worker return self._fullname 437*800a58d9SAndroid Build Coastguard Worker 438*800a58d9SAndroid Build Coastguard Worker @property 439*800a58d9SAndroid Build Coastguard Worker def ip(self): 440*800a58d9SAndroid Build Coastguard Worker """Return the ip.""" 441*800a58d9SAndroid Build Coastguard Worker return self._ip 442*800a58d9SAndroid Build Coastguard Worker 443*800a58d9SAndroid Build Coastguard Worker @property 444*800a58d9SAndroid Build Coastguard Worker def status(self): 445*800a58d9SAndroid Build Coastguard Worker """Return status.""" 446*800a58d9SAndroid Build Coastguard Worker return self._status 447*800a58d9SAndroid Build Coastguard Worker 448*800a58d9SAndroid Build Coastguard Worker @property 449*800a58d9SAndroid Build Coastguard Worker def display(self): 450*800a58d9SAndroid Build Coastguard Worker """Return display.""" 451*800a58d9SAndroid Build Coastguard Worker return self._display 452*800a58d9SAndroid Build Coastguard Worker 453*800a58d9SAndroid Build Coastguard Worker @property 454*800a58d9SAndroid Build Coastguard Worker def ssh_tunnel_is_connected(self): 455*800a58d9SAndroid Build Coastguard Worker """Return the connect status.""" 456*800a58d9SAndroid Build Coastguard Worker return self._ssh_tunnel_is_connected 457*800a58d9SAndroid Build Coastguard Worker 458*800a58d9SAndroid Build Coastguard Worker @property 459*800a58d9SAndroid Build Coastguard Worker def createtime(self): 460*800a58d9SAndroid Build Coastguard Worker """Return create time.""" 461*800a58d9SAndroid Build Coastguard Worker return self._createtime 462*800a58d9SAndroid Build Coastguard Worker 463*800a58d9SAndroid Build Coastguard Worker @property 464*800a58d9SAndroid Build Coastguard Worker def avd_type(self): 465*800a58d9SAndroid Build Coastguard Worker """Return avd_type.""" 466*800a58d9SAndroid Build Coastguard Worker return self._avd_type 467*800a58d9SAndroid Build Coastguard Worker 468*800a58d9SAndroid Build Coastguard Worker @property 469*800a58d9SAndroid Build Coastguard Worker def avd_flavor(self): 470*800a58d9SAndroid Build Coastguard Worker """Return avd_flavor.""" 471*800a58d9SAndroid Build Coastguard Worker return self._avd_flavor 472*800a58d9SAndroid Build Coastguard Worker 473*800a58d9SAndroid Build Coastguard Worker @property 474*800a58d9SAndroid Build Coastguard Worker def islocal(self): 475*800a58d9SAndroid Build Coastguard Worker """Return if it is a local instance.""" 476*800a58d9SAndroid Build Coastguard Worker return self._is_local 477*800a58d9SAndroid Build Coastguard Worker 478*800a58d9SAndroid Build Coastguard Worker @property 479*800a58d9SAndroid Build Coastguard Worker def adb_port(self): 480*800a58d9SAndroid Build Coastguard Worker """Return adb_port.""" 481*800a58d9SAndroid Build Coastguard Worker return self._adb_port 482*800a58d9SAndroid Build Coastguard Worker 483*800a58d9SAndroid Build Coastguard Worker @property 484*800a58d9SAndroid Build Coastguard Worker def vnc_port(self): 485*800a58d9SAndroid Build Coastguard Worker """Return vnc_port.""" 486*800a58d9SAndroid Build Coastguard Worker return self._vnc_port 487*800a58d9SAndroid Build Coastguard Worker 488*800a58d9SAndroid Build Coastguard Worker @property 489*800a58d9SAndroid Build Coastguard Worker def webrtc_port(self): 490*800a58d9SAndroid Build Coastguard Worker """Return webrtc_port.""" 491*800a58d9SAndroid Build Coastguard Worker return self._webrtc_port 492*800a58d9SAndroid Build Coastguard Worker 493*800a58d9SAndroid Build Coastguard Worker @property 494*800a58d9SAndroid Build Coastguard Worker def webrtc_forward_port(self): 495*800a58d9SAndroid Build Coastguard Worker """Return webrtc_forward_port.""" 496*800a58d9SAndroid Build Coastguard Worker return self._webrtc_forward_port 497*800a58d9SAndroid Build Coastguard Worker 498*800a58d9SAndroid Build Coastguard Worker @property 499*800a58d9SAndroid Build Coastguard Worker def zone(self): 500*800a58d9SAndroid Build Coastguard Worker """Return zone.""" 501*800a58d9SAndroid Build Coastguard Worker return self._zone 502*800a58d9SAndroid Build Coastguard Worker 503*800a58d9SAndroid Build Coastguard Worker @property 504*800a58d9SAndroid Build Coastguard Worker def autoconnect(self): 505*800a58d9SAndroid Build Coastguard Worker """Return autoconnect.""" 506*800a58d9SAndroid Build Coastguard Worker return self._autoconnect 507*800a58d9SAndroid Build Coastguard Worker 508*800a58d9SAndroid Build Coastguard Worker 509*800a58d9SAndroid Build Coastguard Workerclass LocalInstance(Instance): 510*800a58d9SAndroid Build Coastguard Worker """Class to store data of local cuttlefish instance.""" 511*800a58d9SAndroid Build Coastguard Worker def __init__(self, cf_config_path, ins_id=None): 512*800a58d9SAndroid Build Coastguard Worker """Initialize a localInstance object. 513*800a58d9SAndroid Build Coastguard Worker 514*800a58d9SAndroid Build Coastguard Worker Args: 515*800a58d9SAndroid Build Coastguard Worker cf_config_path: String, path to the cf runtime config. 516*800a58d9SAndroid Build Coastguard Worker ins_id: Integer, the id to specify the instance information. 517*800a58d9SAndroid Build Coastguard Worker """ 518*800a58d9SAndroid Build Coastguard Worker self._cf_runtime_cfg = cvd_runtime_config.CvdRuntimeConfig(cf_config_path) 519*800a58d9SAndroid Build Coastguard Worker self._instance_dir = self._cf_runtime_cfg.instance_dir 520*800a58d9SAndroid Build Coastguard Worker self._virtual_disk_paths = self._cf_runtime_cfg.virtual_disk_paths 521*800a58d9SAndroid Build Coastguard Worker self._local_instance_id = int(ins_id or self._cf_runtime_cfg.instance_id) 522*800a58d9SAndroid Build Coastguard Worker self._instance_home = GetLocalInstanceHomeDir(self._local_instance_id) 523*800a58d9SAndroid Build Coastguard Worker if self._cf_runtime_cfg.root_dir: 524*800a58d9SAndroid Build Coastguard Worker self._instance_home = os.path.dirname(self._cf_runtime_cfg.root_dir) 525*800a58d9SAndroid Build Coastguard Worker 526*800a58d9SAndroid Build Coastguard Worker ins_info = self._cf_runtime_cfg.instances.get(ins_id, {}) 527*800a58d9SAndroid Build Coastguard Worker adb_port = ins_info.get(_ADB_HOST_PORT) or self._cf_runtime_cfg.adb_port 528*800a58d9SAndroid Build Coastguard Worker webrtc_device_id = (ins_info.get(constants.INS_KEY_WEBRTC_DEVICE_ID) 529*800a58d9SAndroid Build Coastguard Worker or f"cvd-{self._local_instance_id}") 530*800a58d9SAndroid Build Coastguard Worker adb_serial = f"0.0.0.0:{adb_port}" 531*800a58d9SAndroid Build Coastguard Worker display = [] 532*800a58d9SAndroid Build Coastguard Worker for display_config in self._cf_runtime_cfg.display_configs: 533*800a58d9SAndroid Build Coastguard Worker display.append(_DISPLAY_STRING % {"x_res": display_config.get(_X_RES), 534*800a58d9SAndroid Build Coastguard Worker "y_res": display_config.get(_Y_RES), 535*800a58d9SAndroid Build Coastguard Worker "dpi": display_config.get(_DPI)}) 536*800a58d9SAndroid Build Coastguard Worker # TODO(143063678), there's no createtime info in 537*800a58d9SAndroid Build Coastguard Worker # cuttlefish_config.json so far. 538*800a58d9SAndroid Build Coastguard Worker webrtc_port = local_image_local_instance.LocalImageLocalInstance.GetWebrtcSigServerPort( 539*800a58d9SAndroid Build Coastguard Worker self._local_instance_id) 540*800a58d9SAndroid Build Coastguard Worker cvd_status_info = self._GetDevidInfoFromCvdStatus() 541*800a58d9SAndroid Build Coastguard Worker if cvd_status_info: 542*800a58d9SAndroid Build Coastguard Worker display = cvd_status_info.get(_DISPLAYS) 543*800a58d9SAndroid Build Coastguard Worker webrtc_port = int(cvd_status_info.get(_WEBRTC_PORT)) 544*800a58d9SAndroid Build Coastguard Worker adb_serial = cvd_status_info.get(_ADB_SERIAL) 545*800a58d9SAndroid Build Coastguard Worker 546*800a58d9SAndroid Build Coastguard Worker name = GetLocalInstanceName(self._local_instance_id) 547*800a58d9SAndroid Build Coastguard Worker fullname = _GetDeviceFullName(adb_serial, name, None, webrtc_device_id) 548*800a58d9SAndroid Build Coastguard Worker adb_device = AdbTools(device_serial=adb_serial) 549*800a58d9SAndroid Build Coastguard Worker device_information = None 550*800a58d9SAndroid Build Coastguard Worker if adb_device.IsAdbConnected(): 551*800a58d9SAndroid Build Coastguard Worker device_information = adb_device.device_information 552*800a58d9SAndroid Build Coastguard Worker 553*800a58d9SAndroid Build Coastguard Worker super().__init__( 554*800a58d9SAndroid Build Coastguard Worker name=name, fullname=fullname, display=display, ip="0.0.0.0", 555*800a58d9SAndroid Build Coastguard Worker status=constants.INS_STATUS_RUNNING, 556*800a58d9SAndroid Build Coastguard Worker adb_port=adb_port, 557*800a58d9SAndroid Build Coastguard Worker vnc_port=self._cf_runtime_cfg.vnc_port, 558*800a58d9SAndroid Build Coastguard Worker createtime=None, elapsed_time=None, avd_type=constants.TYPE_CF, 559*800a58d9SAndroid Build Coastguard Worker is_local=True, device_information=device_information, 560*800a58d9SAndroid Build Coastguard Worker zone=_LOCAL_ZONE, webrtc_port=webrtc_port) 561*800a58d9SAndroid Build Coastguard Worker 562*800a58d9SAndroid Build Coastguard Worker def Summary(self): 563*800a58d9SAndroid Build Coastguard Worker """Return the string that this class is holding.""" 564*800a58d9SAndroid Build Coastguard Worker instance_home = "%s instance home: %s" % (_INDENT, self._instance_dir) 565*800a58d9SAndroid Build Coastguard Worker return "%s\n%s" % (super().Summary(), instance_home) 566*800a58d9SAndroid Build Coastguard Worker 567*800a58d9SAndroid Build Coastguard Worker def _GetCvdEnv(self): 568*800a58d9SAndroid Build Coastguard Worker """Get the environment to run cvd commands. 569*800a58d9SAndroid Build Coastguard Worker 570*800a58d9SAndroid Build Coastguard Worker Returns: 571*800a58d9SAndroid Build Coastguard Worker os.environ with cuttlefish variables updated. 572*800a58d9SAndroid Build Coastguard Worker """ 573*800a58d9SAndroid Build Coastguard Worker cvd_env = os.environ.copy() 574*800a58d9SAndroid Build Coastguard Worker cvd_env[constants.ENV_ANDROID_HOST_OUT] = os.path.dirname( 575*800a58d9SAndroid Build Coastguard Worker self._cf_runtime_cfg.cvd_tools_path) 576*800a58d9SAndroid Build Coastguard Worker cvd_env[constants.ENV_ANDROID_SOONG_HOST_OUT] = os.path.dirname( 577*800a58d9SAndroid Build Coastguard Worker self._cf_runtime_cfg.cvd_tools_path) 578*800a58d9SAndroid Build Coastguard Worker cvd_env[constants.ENV_CUTTLEFISH_CONFIG_FILE] = self._cf_runtime_cfg.config_path 579*800a58d9SAndroid Build Coastguard Worker cvd_env[constants.ENV_CVD_HOME] = self._instance_home 580*800a58d9SAndroid Build Coastguard Worker cvd_env[constants.ENV_CUTTLEFISH_INSTANCE] = str(self._local_instance_id) 581*800a58d9SAndroid Build Coastguard Worker return cvd_env 582*800a58d9SAndroid Build Coastguard Worker 583*800a58d9SAndroid Build Coastguard Worker def _GetDevidInfoFromCvdStatus(self): 584*800a58d9SAndroid Build Coastguard Worker """Get device information from 'cvd status'. 585*800a58d9SAndroid Build Coastguard Worker 586*800a58d9SAndroid Build Coastguard Worker Execute 'cvd status --print -instance_name=name' cmd to get devices 587*800a58d9SAndroid Build Coastguard Worker information. 588*800a58d9SAndroid Build Coastguard Worker 589*800a58d9SAndroid Build Coastguard Worker Returns 590*800a58d9SAndroid Build Coastguard Worker Output of 'cvd status'. None for fail to run 'cvd status'. 591*800a58d9SAndroid Build Coastguard Worker """ 592*800a58d9SAndroid Build Coastguard Worker try: 593*800a58d9SAndroid Build Coastguard Worker cvd_tool = os.path.join(self._instance_home, _CVD_BIN_FOLDER, _CVD_BIN) 594*800a58d9SAndroid Build Coastguard Worker ins_name = f"cvd-{self._local_instance_id}" 595*800a58d9SAndroid Build Coastguard Worker cvd_status_cmd = f"{cvd_tool} status -print -instance_name={ins_name}" 596*800a58d9SAndroid Build Coastguard Worker if not os.path.exists(cvd_tool): 597*800a58d9SAndroid Build Coastguard Worker logger.warning("Cvd tools path doesn't exist:%s", cvd_tool) 598*800a58d9SAndroid Build Coastguard Worker return None 599*800a58d9SAndroid Build Coastguard Worker logger.debug("Running cmd [%s] to get device info.", cvd_status_cmd) 600*800a58d9SAndroid Build Coastguard Worker process = subprocess.Popen(cvd_status_cmd, shell=True, text=True, 601*800a58d9SAndroid Build Coastguard Worker env=self._GetCvdEnv(), 602*800a58d9SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 603*800a58d9SAndroid Build Coastguard Worker stderr=subprocess.PIPE) 604*800a58d9SAndroid Build Coastguard Worker stdout, _ = process.communicate(timeout=_CVD_TIMEOUT) 605*800a58d9SAndroid Build Coastguard Worker logger.debug("Output of cvd status: %s", stdout) 606*800a58d9SAndroid Build Coastguard Worker return json.loads(self._ParsingCvdFleetOutput(stdout)) 607*800a58d9SAndroid Build Coastguard Worker except (subprocess.CalledProcessError, subprocess.TimeoutExpired, 608*800a58d9SAndroid Build Coastguard Worker json.JSONDecodeError) as error: 609*800a58d9SAndroid Build Coastguard Worker logger.error("Failed to run 'cvd status': %s", str(error)) 610*800a58d9SAndroid Build Coastguard Worker return None 611*800a58d9SAndroid Build Coastguard Worker 612*800a58d9SAndroid Build Coastguard Worker @staticmethod 613*800a58d9SAndroid Build Coastguard Worker def _ParsingCvdFleetOutput(output): 614*800a58d9SAndroid Build Coastguard Worker """Parsing the output of cvd fleet. 615*800a58d9SAndroid Build Coastguard Worker 616*800a58d9SAndroid Build Coastguard Worker The output example: 617*800a58d9SAndroid Build Coastguard Worker WARNING: cvd_server client version (8245608) does not match. 618*800a58d9SAndroid Build Coastguard Worker { 619*800a58d9SAndroid Build Coastguard Worker "adb_serial" : "0.0.0.0:6520", 620*800a58d9SAndroid Build Coastguard Worker "assembly_dir" : "/home/cuttlefish_runtime/assembly", 621*800a58d9SAndroid Build Coastguard Worker "displays" : ["720 x 1280 ( 320 )"], 622*800a58d9SAndroid Build Coastguard Worker "instance_dir" : "/home/cuttlefish_runtime/instances/cvd-1", 623*800a58d9SAndroid Build Coastguard Worker "instance_name" : "cvd-1", 624*800a58d9SAndroid Build Coastguard Worker "status" : "Running", 625*800a58d9SAndroid Build Coastguard Worker "web_access" : "https://0.0.0.0:8443/client.html?deviceId=cvd-1", 626*800a58d9SAndroid Build Coastguard Worker "webrtc_port" : "8443" 627*800a58d9SAndroid Build Coastguard Worker } 628*800a58d9SAndroid Build Coastguard Worker 629*800a58d9SAndroid Build Coastguard Worker Returns: 630*800a58d9SAndroid Build Coastguard Worker Parsed output filtered warning message. 631*800a58d9SAndroid Build Coastguard Worker """ 632*800a58d9SAndroid Build Coastguard Worker device_match = _RE_DEVICE_INFO.match(output) 633*800a58d9SAndroid Build Coastguard Worker if device_match: 634*800a58d9SAndroid Build Coastguard Worker return device_match.group("device_info") 635*800a58d9SAndroid Build Coastguard Worker return "" 636*800a58d9SAndroid Build Coastguard Worker 637*800a58d9SAndroid Build Coastguard Worker def CvdStatus(self): 638*800a58d9SAndroid Build Coastguard Worker """check if local instance is active. 639*800a58d9SAndroid Build Coastguard Worker 640*800a58d9SAndroid Build Coastguard Worker Execute cvd_status cmd to check if it exit without error. 641*800a58d9SAndroid Build Coastguard Worker 642*800a58d9SAndroid Build Coastguard Worker Returns 643*800a58d9SAndroid Build Coastguard Worker True if instance is active. 644*800a58d9SAndroid Build Coastguard Worker """ 645*800a58d9SAndroid Build Coastguard Worker if not self._cf_runtime_cfg.cvd_tools_path: 646*800a58d9SAndroid Build Coastguard Worker logger.debug("No cvd tools path found from config:%s", 647*800a58d9SAndroid Build Coastguard Worker self._cf_runtime_cfg.config_path) 648*800a58d9SAndroid Build Coastguard Worker return False 649*800a58d9SAndroid Build Coastguard Worker try: 650*800a58d9SAndroid Build Coastguard Worker cvd_status_cmd = os.path.join(self._cf_runtime_cfg.cvd_tools_path, 651*800a58d9SAndroid Build Coastguard Worker _CVD_STATUS_BIN) 652*800a58d9SAndroid Build Coastguard Worker # TODO(b/150575261): Change the cvd home and cvd artifact path to 653*800a58d9SAndroid Build Coastguard Worker # another place instead of /tmp to prevent from the file not 654*800a58d9SAndroid Build Coastguard Worker # found exception. 655*800a58d9SAndroid Build Coastguard Worker if not os.path.exists(cvd_status_cmd): 656*800a58d9SAndroid Build Coastguard Worker logger.warning("Cvd tools path doesn't exist:%s", cvd_status_cmd) 657*800a58d9SAndroid Build Coastguard Worker for env_host_out in [constants.ENV_ANDROID_SOONG_HOST_OUT, 658*800a58d9SAndroid Build Coastguard Worker constants.ENV_ANDROID_HOST_OUT]: 659*800a58d9SAndroid Build Coastguard Worker if os.environ.get(env_host_out, _NO_ANDROID_ENV) in cvd_status_cmd: 660*800a58d9SAndroid Build Coastguard Worker logger.warning( 661*800a58d9SAndroid Build Coastguard Worker "Can't find the cvd_status tool (Try lunching a " 662*800a58d9SAndroid Build Coastguard Worker "cuttlefish target like aosp_cf_x86_64_phone-userdebug " 663*800a58d9SAndroid Build Coastguard Worker "and running 'make hosttar' before list/delete local " 664*800a58d9SAndroid Build Coastguard Worker "instances)") 665*800a58d9SAndroid Build Coastguard Worker return False 666*800a58d9SAndroid Build Coastguard Worker logger.debug("Running cmd[%s] to check cvd status.", cvd_status_cmd) 667*800a58d9SAndroid Build Coastguard Worker process = subprocess.Popen(cvd_status_cmd, 668*800a58d9SAndroid Build Coastguard Worker stdin=None, 669*800a58d9SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 670*800a58d9SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, 671*800a58d9SAndroid Build Coastguard Worker env=self._GetCvdEnv()) 672*800a58d9SAndroid Build Coastguard Worker stdout, _ = process.communicate() 673*800a58d9SAndroid Build Coastguard Worker if process.returncode != 0: 674*800a58d9SAndroid Build Coastguard Worker if stdout: 675*800a58d9SAndroid Build Coastguard Worker logger.debug("Local instance[%s] is not active: %s", 676*800a58d9SAndroid Build Coastguard Worker self.name, stdout.strip()) 677*800a58d9SAndroid Build Coastguard Worker return False 678*800a58d9SAndroid Build Coastguard Worker return True 679*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as cpe: 680*800a58d9SAndroid Build Coastguard Worker logger.error("Failed to run cvd_status: %s", cpe.output) 681*800a58d9SAndroid Build Coastguard Worker return False 682*800a58d9SAndroid Build Coastguard Worker 683*800a58d9SAndroid Build Coastguard Worker def Delete(self): 684*800a58d9SAndroid Build Coastguard Worker """Execute "cvd stop" to stop local cuttlefish instance. 685*800a58d9SAndroid Build Coastguard Worker 686*800a58d9SAndroid Build Coastguard Worker - We should get the same host tool used to delete instance. 687*800a58d9SAndroid Build Coastguard Worker - Add CUTTLEFISH_CONFIG_FILE env variable to tell cvd which cvd need to 688*800a58d9SAndroid Build Coastguard Worker be deleted. 689*800a58d9SAndroid Build Coastguard Worker - Stop adb since local instance use the fixed adb port and could be 690*800a58d9SAndroid Build Coastguard Worker reused again soon. 691*800a58d9SAndroid Build Coastguard Worker """ 692*800a58d9SAndroid Build Coastguard Worker ins_home_dir = GetLocalInstanceHomeDir(self._local_instance_id) 693*800a58d9SAndroid Build Coastguard Worker cvd_tool = os.path.join(ins_home_dir, _CVD_BIN_FOLDER, _CVD_BIN) 694*800a58d9SAndroid Build Coastguard Worker stop_cvd_cmd = f"{cvd_tool} stop" 695*800a58d9SAndroid Build Coastguard Worker logger.debug("Running cmd[%s] to delete local cvd", stop_cvd_cmd) 696*800a58d9SAndroid Build Coastguard Worker if not self.instance_dir: 697*800a58d9SAndroid Build Coastguard Worker logger.error("instance_dir is null!! instance[%d] might not be" 698*800a58d9SAndroid Build Coastguard Worker " deleted", self._local_instance_id) 699*800a58d9SAndroid Build Coastguard Worker try: 700*800a58d9SAndroid Build Coastguard Worker output = subprocess.check_output( 701*800a58d9SAndroid Build Coastguard Worker utils.AddUserGroupsToCmd(stop_cvd_cmd, 702*800a58d9SAndroid Build Coastguard Worker constants.LIST_CF_USER_GROUPS), 703*800a58d9SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, shell=True, env=self._GetCvdEnv(), 704*800a58d9SAndroid Build Coastguard Worker text=True, timeout=_CVD_TIMEOUT) 705*800a58d9SAndroid Build Coastguard Worker # TODO: Remove workaround of stop_cvd when 'cvd stop' is stable. 706*800a58d9SAndroid Build Coastguard Worker if _CVD_STOP_ERROR_KEYWORDS in output: 707*800a58d9SAndroid Build Coastguard Worker logger.debug("Fail to stop cvd: %s", output) 708*800a58d9SAndroid Build Coastguard Worker self._ExecuteStopCvd(os.path.join(ins_home_dir, _CVD_BIN_FOLDER)) 709*800a58d9SAndroid Build Coastguard Worker except (subprocess.TimeoutExpired, subprocess.CalledProcessError) as e: 710*800a58d9SAndroid Build Coastguard Worker logger.debug("'cvd stop' error: %s", str(e)) 711*800a58d9SAndroid Build Coastguard Worker self._ExecuteStopCvd(os.path.join(ins_home_dir, _CVD_BIN_FOLDER)) 712*800a58d9SAndroid Build Coastguard Worker 713*800a58d9SAndroid Build Coastguard Worker adb_cmd = AdbTools(self.adb_port) 714*800a58d9SAndroid Build Coastguard Worker # When relaunch a local instance, we need to pass in retry=True to make 715*800a58d9SAndroid Build Coastguard Worker # sure adb device is completely gone since it will use the same adb port 716*800a58d9SAndroid Build Coastguard Worker adb_cmd.DisconnectAdb(retry=True) 717*800a58d9SAndroid Build Coastguard Worker 718*800a58d9SAndroid Build Coastguard Worker def _ExecuteStopCvd(self, dir_path): 719*800a58d9SAndroid Build Coastguard Worker """Execute "stop_cvd" to stop local cuttlefish instance. 720*800a58d9SAndroid Build Coastguard Worker 721*800a58d9SAndroid Build Coastguard Worker Args: 722*800a58d9SAndroid Build Coastguard Worker bin_dir: String, directory path of "stop_cvd". 723*800a58d9SAndroid Build Coastguard Worker """ 724*800a58d9SAndroid Build Coastguard Worker stop_cvd_cmd = os.path.join(dir_path, constants.CMD_STOP_CVD) 725*800a58d9SAndroid Build Coastguard Worker subprocess.check_call( 726*800a58d9SAndroid Build Coastguard Worker utils.AddUserGroupsToCmd( 727*800a58d9SAndroid Build Coastguard Worker stop_cvd_cmd, constants.LIST_CF_USER_GROUPS), 728*800a58d9SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, shell=True, env=self._GetCvdEnv()) 729*800a58d9SAndroid Build Coastguard Worker 730*800a58d9SAndroid Build Coastguard Worker def GetLock(self): 731*800a58d9SAndroid Build Coastguard Worker """Return the LocalInstanceLock for this object.""" 732*800a58d9SAndroid Build Coastguard Worker return GetLocalInstanceLock(self._local_instance_id) 733*800a58d9SAndroid Build Coastguard Worker 734*800a58d9SAndroid Build Coastguard Worker @property 735*800a58d9SAndroid Build Coastguard Worker def instance_dir(self): 736*800a58d9SAndroid Build Coastguard Worker """Return _instance_dir.""" 737*800a58d9SAndroid Build Coastguard Worker return self._instance_dir 738*800a58d9SAndroid Build Coastguard Worker 739*800a58d9SAndroid Build Coastguard Worker @property 740*800a58d9SAndroid Build Coastguard Worker def instance_id(self): 741*800a58d9SAndroid Build Coastguard Worker """Return _local_instance_id.""" 742*800a58d9SAndroid Build Coastguard Worker return self._local_instance_id 743*800a58d9SAndroid Build Coastguard Worker 744*800a58d9SAndroid Build Coastguard Worker @property 745*800a58d9SAndroid Build Coastguard Worker def virtual_disk_paths(self): 746*800a58d9SAndroid Build Coastguard Worker """Return virtual_disk_paths""" 747*800a58d9SAndroid Build Coastguard Worker return self._virtual_disk_paths 748*800a58d9SAndroid Build Coastguard Worker 749*800a58d9SAndroid Build Coastguard Worker @property 750*800a58d9SAndroid Build Coastguard Worker def cf_runtime_cfg(self): 751*800a58d9SAndroid Build Coastguard Worker """Return _cf_runtime_cfg""" 752*800a58d9SAndroid Build Coastguard Worker return self._cf_runtime_cfg 753*800a58d9SAndroid Build Coastguard Worker 754*800a58d9SAndroid Build Coastguard Worker 755*800a58d9SAndroid Build Coastguard Workerclass LocalGoldfishInstance(Instance): 756*800a58d9SAndroid Build Coastguard Worker """Class to store data of local goldfish instance. 757*800a58d9SAndroid Build Coastguard Worker 758*800a58d9SAndroid Build Coastguard Worker A goldfish instance binds to a console port and an adb port. The console 759*800a58d9SAndroid Build Coastguard Worker port is for `adb emu` to send emulator-specific commands. The adb port is 760*800a58d9SAndroid Build Coastguard Worker for `adb connect` to start a TCP connection. By convention, the console 761*800a58d9SAndroid Build Coastguard Worker port is an even number, and the adb port is the console port + 1. The first 762*800a58d9SAndroid Build Coastguard Worker instance uses port 5554 and 5555, the second instance uses 5556 and 5557, 763*800a58d9SAndroid Build Coastguard Worker and so on. 764*800a58d9SAndroid Build Coastguard Worker """ 765*800a58d9SAndroid Build Coastguard Worker 766*800a58d9SAndroid Build Coastguard Worker _INSTANCE_NAME_PATTERN = re.compile( 767*800a58d9SAndroid Build Coastguard Worker r"^local-goldfish-instance-(?P<id>\d+)$") 768*800a58d9SAndroid Build Coastguard Worker _INSTANCE_NAME_FORMAT = "local-goldfish-instance-%(id)s" 769*800a58d9SAndroid Build Coastguard Worker _EMULATOR_DEFAULT_CONSOLE_PORT = 5554 770*800a58d9SAndroid Build Coastguard Worker _DEFAULT_ADB_LOCAL_TRANSPORT_MAX_PORT = 5585 771*800a58d9SAndroid Build Coastguard Worker _DEVICE_SERIAL_FORMAT = "emulator-%(console_port)s" 772*800a58d9SAndroid Build Coastguard Worker _DEVICE_SERIAL_PATTERN = re.compile(r"^emulator-(?P<console_port>\d+)$") 773*800a58d9SAndroid Build Coastguard Worker 774*800a58d9SAndroid Build Coastguard Worker def __init__(self, local_instance_id, avd_flavor=None, create_time=None, 775*800a58d9SAndroid Build Coastguard Worker x_res=None, y_res=None, dpi=None): 776*800a58d9SAndroid Build Coastguard Worker """Initialize a LocalGoldfishInstance object. 777*800a58d9SAndroid Build Coastguard Worker 778*800a58d9SAndroid Build Coastguard Worker Args: 779*800a58d9SAndroid Build Coastguard Worker local_instance_id: Integer of instance id. 780*800a58d9SAndroid Build Coastguard Worker avd_flavor: String, the flavor of the virtual device. 781*800a58d9SAndroid Build Coastguard Worker create_time: String, the creation date and time. 782*800a58d9SAndroid Build Coastguard Worker x_res: Integer of x dimension. 783*800a58d9SAndroid Build Coastguard Worker y_res: Integer of y dimension. 784*800a58d9SAndroid Build Coastguard Worker dpi: Integer of dpi. 785*800a58d9SAndroid Build Coastguard Worker """ 786*800a58d9SAndroid Build Coastguard Worker self._id = local_instance_id 787*800a58d9SAndroid Build Coastguard Worker adb_port = self.console_port + 1 788*800a58d9SAndroid Build Coastguard Worker self._adb = AdbTools(adb_port=adb_port, 789*800a58d9SAndroid Build Coastguard Worker device_serial=self.device_serial) 790*800a58d9SAndroid Build Coastguard Worker 791*800a58d9SAndroid Build Coastguard Worker name = self._INSTANCE_NAME_FORMAT % {"id": local_instance_id} 792*800a58d9SAndroid Build Coastguard Worker 793*800a58d9SAndroid Build Coastguard Worker elapsed_time = _GetElapsedTime(create_time) if create_time else None 794*800a58d9SAndroid Build Coastguard Worker 795*800a58d9SAndroid Build Coastguard Worker fullname = _GetDeviceFullName(self.device_serial, name, elapsed_time) 796*800a58d9SAndroid Build Coastguard Worker 797*800a58d9SAndroid Build Coastguard Worker if x_res and y_res and dpi: 798*800a58d9SAndroid Build Coastguard Worker display = _DISPLAY_STRING % {"x_res": x_res, "y_res": y_res, 799*800a58d9SAndroid Build Coastguard Worker "dpi": dpi} 800*800a58d9SAndroid Build Coastguard Worker else: 801*800a58d9SAndroid Build Coastguard Worker display = "unknown" 802*800a58d9SAndroid Build Coastguard Worker 803*800a58d9SAndroid Build Coastguard Worker device_information = (self._adb.device_information if 804*800a58d9SAndroid Build Coastguard Worker self._adb.device_information else None) 805*800a58d9SAndroid Build Coastguard Worker 806*800a58d9SAndroid Build Coastguard Worker super().__init__( 807*800a58d9SAndroid Build Coastguard Worker name=name, fullname=fullname, display=display, ip="127.0.0.1", 808*800a58d9SAndroid Build Coastguard Worker status=None, adb_port=adb_port, avd_type=constants.TYPE_GF, 809*800a58d9SAndroid Build Coastguard Worker createtime=create_time, elapsed_time=elapsed_time, 810*800a58d9SAndroid Build Coastguard Worker avd_flavor=avd_flavor, is_local=True, 811*800a58d9SAndroid Build Coastguard Worker device_information=device_information) 812*800a58d9SAndroid Build Coastguard Worker 813*800a58d9SAndroid Build Coastguard Worker @staticmethod 814*800a58d9SAndroid Build Coastguard Worker def _GetInstanceDirRoot(): 815*800a58d9SAndroid Build Coastguard Worker """Return the root directory of all instance directories.""" 816*800a58d9SAndroid Build Coastguard Worker return os.path.join(tempfile.gettempdir(), "acloud_gf_temp") 817*800a58d9SAndroid Build Coastguard Worker 818*800a58d9SAndroid Build Coastguard Worker @property 819*800a58d9SAndroid Build Coastguard Worker def adb(self): 820*800a58d9SAndroid Build Coastguard Worker """Return the AdbTools to send emulator commands to this instance.""" 821*800a58d9SAndroid Build Coastguard Worker return self._adb 822*800a58d9SAndroid Build Coastguard Worker 823*800a58d9SAndroid Build Coastguard Worker @property 824*800a58d9SAndroid Build Coastguard Worker def console_port(self): 825*800a58d9SAndroid Build Coastguard Worker """Return the console port as an integer.""" 826*800a58d9SAndroid Build Coastguard Worker # Emulator requires the console port to be an even number. 827*800a58d9SAndroid Build Coastguard Worker return self._EMULATOR_DEFAULT_CONSOLE_PORT + (self._id - 1) * 2 828*800a58d9SAndroid Build Coastguard Worker 829*800a58d9SAndroid Build Coastguard Worker @property 830*800a58d9SAndroid Build Coastguard Worker def device_serial(self): 831*800a58d9SAndroid Build Coastguard Worker """Return the serial number that contains the console port.""" 832*800a58d9SAndroid Build Coastguard Worker return self._DEVICE_SERIAL_FORMAT % {"console_port": self.console_port} 833*800a58d9SAndroid Build Coastguard Worker 834*800a58d9SAndroid Build Coastguard Worker @property 835*800a58d9SAndroid Build Coastguard Worker def instance_dir(self): 836*800a58d9SAndroid Build Coastguard Worker """Return the path to instance directory.""" 837*800a58d9SAndroid Build Coastguard Worker return os.path.join(self._GetInstanceDirRoot(), 838*800a58d9SAndroid Build Coastguard Worker self._INSTANCE_NAME_FORMAT % {"id": self._id}) 839*800a58d9SAndroid Build Coastguard Worker 840*800a58d9SAndroid Build Coastguard Worker @classmethod 841*800a58d9SAndroid Build Coastguard Worker def GetIdByName(cls, name): 842*800a58d9SAndroid Build Coastguard Worker """Get id by name. 843*800a58d9SAndroid Build Coastguard Worker 844*800a58d9SAndroid Build Coastguard Worker Args: 845*800a58d9SAndroid Build Coastguard Worker name: String of instance name. 846*800a58d9SAndroid Build Coastguard Worker 847*800a58d9SAndroid Build Coastguard Worker Return: 848*800a58d9SAndroid Build Coastguard Worker The instance id as an integer if the name is in valid format. 849*800a58d9SAndroid Build Coastguard Worker None if the name does not represent a local goldfish instance. 850*800a58d9SAndroid Build Coastguard Worker """ 851*800a58d9SAndroid Build Coastguard Worker match = cls._INSTANCE_NAME_PATTERN.match(name) 852*800a58d9SAndroid Build Coastguard Worker if match: 853*800a58d9SAndroid Build Coastguard Worker return int(match.group("id")) 854*800a58d9SAndroid Build Coastguard Worker return None 855*800a58d9SAndroid Build Coastguard Worker 856*800a58d9SAndroid Build Coastguard Worker @classmethod 857*800a58d9SAndroid Build Coastguard Worker def GetLockById(cls, instance_id): 858*800a58d9SAndroid Build Coastguard Worker """Get LocalInstanceLock by id.""" 859*800a58d9SAndroid Build Coastguard Worker lock_path = os.path.join( 860*800a58d9SAndroid Build Coastguard Worker cls._GetInstanceDirRoot(), 861*800a58d9SAndroid Build Coastguard Worker (cls._INSTANCE_NAME_FORMAT % {"id": instance_id}) + ".lock") 862*800a58d9SAndroid Build Coastguard Worker return LocalInstanceLock(lock_path) 863*800a58d9SAndroid Build Coastguard Worker 864*800a58d9SAndroid Build Coastguard Worker def GetLock(self): 865*800a58d9SAndroid Build Coastguard Worker """Return the LocalInstanceLock for this object.""" 866*800a58d9SAndroid Build Coastguard Worker return self.GetLockById(self._id) 867*800a58d9SAndroid Build Coastguard Worker 868*800a58d9SAndroid Build Coastguard Worker @classmethod 869*800a58d9SAndroid Build Coastguard Worker def GetExistingInstances(cls): 870*800a58d9SAndroid Build Coastguard Worker """Get the list of instances that adb can send emu commands to.""" 871*800a58d9SAndroid Build Coastguard Worker instances = [] 872*800a58d9SAndroid Build Coastguard Worker for serial in AdbTools.GetDeviceSerials(): 873*800a58d9SAndroid Build Coastguard Worker match = cls._DEVICE_SERIAL_PATTERN.match(serial) 874*800a58d9SAndroid Build Coastguard Worker if not match: 875*800a58d9SAndroid Build Coastguard Worker continue 876*800a58d9SAndroid Build Coastguard Worker port = int(match.group("console_port")) 877*800a58d9SAndroid Build Coastguard Worker instance_id = (port - cls._EMULATOR_DEFAULT_CONSOLE_PORT) // 2 + 1 878*800a58d9SAndroid Build Coastguard Worker instances.append(LocalGoldfishInstance(instance_id)) 879*800a58d9SAndroid Build Coastguard Worker return instances 880*800a58d9SAndroid Build Coastguard Worker 881*800a58d9SAndroid Build Coastguard Worker @classmethod 882*800a58d9SAndroid Build Coastguard Worker def GetMaxNumberOfInstances(cls): 883*800a58d9SAndroid Build Coastguard Worker """Get number of emulators that adb can detect.""" 884*800a58d9SAndroid Build Coastguard Worker max_port = os.environ.get("ADB_LOCAL_TRANSPORT_MAX_PORT", 885*800a58d9SAndroid Build Coastguard Worker cls._DEFAULT_ADB_LOCAL_TRANSPORT_MAX_PORT) 886*800a58d9SAndroid Build Coastguard Worker try: 887*800a58d9SAndroid Build Coastguard Worker max_port = int(max_port) 888*800a58d9SAndroid Build Coastguard Worker except ValueError: 889*800a58d9SAndroid Build Coastguard Worker max_port = cls._DEFAULT_ADB_LOCAL_TRANSPORT_MAX_PORT 890*800a58d9SAndroid Build Coastguard Worker if (max_port < cls._EMULATOR_DEFAULT_CONSOLE_PORT or 891*800a58d9SAndroid Build Coastguard Worker max_port > constants.MAX_PORT): 892*800a58d9SAndroid Build Coastguard Worker max_port = cls._DEFAULT_ADB_LOCAL_TRANSPORT_MAX_PORT 893*800a58d9SAndroid Build Coastguard Worker return (max_port + 1 - cls._EMULATOR_DEFAULT_CONSOLE_PORT) // 2 894*800a58d9SAndroid Build Coastguard Worker 895*800a58d9SAndroid Build Coastguard Worker 896*800a58d9SAndroid Build Coastguard Workerclass RemoteInstance(Instance): 897*800a58d9SAndroid Build Coastguard Worker """Class to store data of remote instance.""" 898*800a58d9SAndroid Build Coastguard Worker 899*800a58d9SAndroid Build Coastguard Worker # pylint: disable=too-many-locals 900*800a58d9SAndroid Build Coastguard Worker def __init__(self, gce_instance): 901*800a58d9SAndroid Build Coastguard Worker """Process the args into class vars. 902*800a58d9SAndroid Build Coastguard Worker 903*800a58d9SAndroid Build Coastguard Worker RemoteInstace initialized by gce dict object. We parse the required data 904*800a58d9SAndroid Build Coastguard Worker from gce_instance to local variables. 905*800a58d9SAndroid Build Coastguard Worker Reference: 906*800a58d9SAndroid Build Coastguard Worker https://cloud.google.com/compute/docs/reference/rest/v1/instances/get 907*800a58d9SAndroid Build Coastguard Worker 908*800a58d9SAndroid Build Coastguard Worker We also gather more details on client side including the forwarding adb 909*800a58d9SAndroid Build Coastguard Worker port and vnc port which will be used to determine the status of ssh 910*800a58d9SAndroid Build Coastguard Worker tunnel connection. 911*800a58d9SAndroid Build Coastguard Worker 912*800a58d9SAndroid Build Coastguard Worker The status of gce instance will be displayed in _fullname property: 913*800a58d9SAndroid Build Coastguard Worker - Connected: If gce instance and ssh tunnel and adb connection are all 914*800a58d9SAndroid Build Coastguard Worker active. 915*800a58d9SAndroid Build Coastguard Worker - No connected: If ssh tunnel or adb connection is not found. 916*800a58d9SAndroid Build Coastguard Worker - Terminated: If we can't retrieve the public ip from gce instance. 917*800a58d9SAndroid Build Coastguard Worker 918*800a58d9SAndroid Build Coastguard Worker Args: 919*800a58d9SAndroid Build Coastguard Worker gce_instance: dict object queried from gce. 920*800a58d9SAndroid Build Coastguard Worker """ 921*800a58d9SAndroid Build Coastguard Worker name = gce_instance.get(constants.INS_KEY_NAME) 922*800a58d9SAndroid Build Coastguard Worker 923*800a58d9SAndroid Build Coastguard Worker create_time = gce_instance.get(constants.INS_KEY_CREATETIME) 924*800a58d9SAndroid Build Coastguard Worker elapsed_time = _GetElapsedTime(create_time) 925*800a58d9SAndroid Build Coastguard Worker status = gce_instance.get(constants.INS_KEY_STATUS) 926*800a58d9SAndroid Build Coastguard Worker zone = self._GetZoneName(gce_instance.get(constants.INS_KEY_ZONE)) 927*800a58d9SAndroid Build Coastguard Worker 928*800a58d9SAndroid Build Coastguard Worker instance_ip = GetInstanceIP(gce_instance) 929*800a58d9SAndroid Build Coastguard Worker ip = instance_ip.external or instance_ip.internal 930*800a58d9SAndroid Build Coastguard Worker project = self._GetProjectName(gce_instance.get(constants.INS_KEY_ZONE)) 931*800a58d9SAndroid Build Coastguard Worker hostname = GetGCEHostName(project, name, zone) 932*800a58d9SAndroid Build Coastguard Worker 933*800a58d9SAndroid Build Coastguard Worker # Get metadata, webrtc_port will be removed if "cvd fleet" show it. 934*800a58d9SAndroid Build Coastguard Worker display = None 935*800a58d9SAndroid Build Coastguard Worker avd_type = None 936*800a58d9SAndroid Build Coastguard Worker avd_flavor = None 937*800a58d9SAndroid Build Coastguard Worker webrtc_port = None 938*800a58d9SAndroid Build Coastguard Worker webrtc_device_id = None 939*800a58d9SAndroid Build Coastguard Worker for metadata in gce_instance.get("metadata", {}).get("items", []): 940*800a58d9SAndroid Build Coastguard Worker key = metadata["key"] 941*800a58d9SAndroid Build Coastguard Worker value = metadata["value"] 942*800a58d9SAndroid Build Coastguard Worker if key == constants.INS_KEY_DISPLAY: 943*800a58d9SAndroid Build Coastguard Worker display = value 944*800a58d9SAndroid Build Coastguard Worker elif key == constants.INS_KEY_AVD_TYPE: 945*800a58d9SAndroid Build Coastguard Worker avd_type = value 946*800a58d9SAndroid Build Coastguard Worker elif key == constants.INS_KEY_AVD_FLAVOR: 947*800a58d9SAndroid Build Coastguard Worker avd_flavor = value 948*800a58d9SAndroid Build Coastguard Worker elif key == constants.INS_KEY_WEBRTC_PORT: 949*800a58d9SAndroid Build Coastguard Worker webrtc_port = value 950*800a58d9SAndroid Build Coastguard Worker elif key == constants.INS_KEY_WEBRTC_DEVICE_ID: 951*800a58d9SAndroid Build Coastguard Worker webrtc_device_id = value 952*800a58d9SAndroid Build Coastguard Worker # TODO(176884236): Insert avd information into metadata of instance. 953*800a58d9SAndroid Build Coastguard Worker if not avd_type and name.startswith(_ACLOUDWEB_INSTANCE_START_STRING): 954*800a58d9SAndroid Build Coastguard Worker avd_type = constants.TYPE_CF 955*800a58d9SAndroid Build Coastguard Worker 956*800a58d9SAndroid Build Coastguard Worker # Find ssl tunnel info. 957*800a58d9SAndroid Build Coastguard Worker adb_port = None 958*800a58d9SAndroid Build Coastguard Worker vnc_port = None 959*800a58d9SAndroid Build Coastguard Worker webrtc_forward_port = None 960*800a58d9SAndroid Build Coastguard Worker device_information = None 961*800a58d9SAndroid Build Coastguard Worker if ip: 962*800a58d9SAndroid Build Coastguard Worker forwarded_ports = self.GetAdbVncPortFromSSHTunnel(ip, hostname, avd_type) 963*800a58d9SAndroid Build Coastguard Worker adb_port = forwarded_ports.adb_port 964*800a58d9SAndroid Build Coastguard Worker vnc_port = forwarded_ports.vnc_port 965*800a58d9SAndroid Build Coastguard Worker ssh_tunnel_is_connected = adb_port is not None 966*800a58d9SAndroid Build Coastguard Worker webrtc_forward_port = utils.GetWebrtcPortFromSSHTunnel(ip) 967*800a58d9SAndroid Build Coastguard Worker 968*800a58d9SAndroid Build Coastguard Worker adb_device = AdbTools(adb_port) 969*800a58d9SAndroid Build Coastguard Worker if adb_device.IsAdbConnected(): 970*800a58d9SAndroid Build Coastguard Worker device_information = adb_device.device_information 971*800a58d9SAndroid Build Coastguard Worker fullname = _GetDeviceFullName("127.0.0.1:%d" % adb_port, name, 972*800a58d9SAndroid Build Coastguard Worker elapsed_time, webrtc_device_id) 973*800a58d9SAndroid Build Coastguard Worker else: 974*800a58d9SAndroid Build Coastguard Worker fullname = _GetDeviceFullName("not connected", name, 975*800a58d9SAndroid Build Coastguard Worker elapsed_time, webrtc_device_id) 976*800a58d9SAndroid Build Coastguard Worker # If instance is terminated, its ip is None. 977*800a58d9SAndroid Build Coastguard Worker else: 978*800a58d9SAndroid Build Coastguard Worker ssh_tunnel_is_connected = False 979*800a58d9SAndroid Build Coastguard Worker fullname = _GetDeviceFullName("terminated", name, elapsed_time, 980*800a58d9SAndroid Build Coastguard Worker webrtc_device_id) 981*800a58d9SAndroid Build Coastguard Worker 982*800a58d9SAndroid Build Coastguard Worker super().__init__( 983*800a58d9SAndroid Build Coastguard Worker name=name, fullname=fullname, display=display, ip=ip, status=status, 984*800a58d9SAndroid Build Coastguard Worker adb_port=adb_port, vnc_port=vnc_port, 985*800a58d9SAndroid Build Coastguard Worker ssh_tunnel_is_connected=ssh_tunnel_is_connected, 986*800a58d9SAndroid Build Coastguard Worker createtime=create_time, elapsed_time=elapsed_time, avd_type=avd_type, 987*800a58d9SAndroid Build Coastguard Worker avd_flavor=avd_flavor, is_local=False, 988*800a58d9SAndroid Build Coastguard Worker device_information=device_information, 989*800a58d9SAndroid Build Coastguard Worker zone=zone, webrtc_port=webrtc_port, 990*800a58d9SAndroid Build Coastguard Worker webrtc_forward_port=webrtc_forward_port) 991*800a58d9SAndroid Build Coastguard Worker 992*800a58d9SAndroid Build Coastguard Worker @staticmethod 993*800a58d9SAndroid Build Coastguard Worker def _GetZoneName(zone_info): 994*800a58d9SAndroid Build Coastguard Worker """Get the zone name from the zone information of gce instance. 995*800a58d9SAndroid Build Coastguard Worker 996*800a58d9SAndroid Build Coastguard Worker Zone information is like: 997*800a58d9SAndroid Build Coastguard Worker "https://www.googleapis.com/compute/v1/projects/project/zones/us-central1-c" 998*800a58d9SAndroid Build Coastguard Worker We want to get "us-central1-c" as zone name. 999*800a58d9SAndroid Build Coastguard Worker 1000*800a58d9SAndroid Build Coastguard Worker Args: 1001*800a58d9SAndroid Build Coastguard Worker zone_info: String, zone information of gce instance. 1002*800a58d9SAndroid Build Coastguard Worker 1003*800a58d9SAndroid Build Coastguard Worker Returns: 1004*800a58d9SAndroid Build Coastguard Worker Zone name of gce instance. None if zone name can't find. 1005*800a58d9SAndroid Build Coastguard Worker """ 1006*800a58d9SAndroid Build Coastguard Worker zone_match = _RE_ZONE.match(zone_info) 1007*800a58d9SAndroid Build Coastguard Worker if zone_match: 1008*800a58d9SAndroid Build Coastguard Worker return zone_match.group("zone") 1009*800a58d9SAndroid Build Coastguard Worker 1010*800a58d9SAndroid Build Coastguard Worker logger.debug("Can't get zone name from %s.", zone_info) 1011*800a58d9SAndroid Build Coastguard Worker return None 1012*800a58d9SAndroid Build Coastguard Worker 1013*800a58d9SAndroid Build Coastguard Worker @staticmethod 1014*800a58d9SAndroid Build Coastguard Worker def _GetProjectName(zone_info): 1015*800a58d9SAndroid Build Coastguard Worker """Get the project name from the zone information of gce instance. 1016*800a58d9SAndroid Build Coastguard Worker 1017*800a58d9SAndroid Build Coastguard Worker Zone information is like: 1018*800a58d9SAndroid Build Coastguard Worker "https://www.googleapis.com/compute/v1/projects/project/zones/us-central1-c" 1019*800a58d9SAndroid Build Coastguard Worker We want to get "project" as project name. 1020*800a58d9SAndroid Build Coastguard Worker 1021*800a58d9SAndroid Build Coastguard Worker Args: 1022*800a58d9SAndroid Build Coastguard Worker zone_info: String, zone information of gce instance. 1023*800a58d9SAndroid Build Coastguard Worker 1024*800a58d9SAndroid Build Coastguard Worker Returns: 1025*800a58d9SAndroid Build Coastguard Worker Project name of gce instance. None if project name can't find. 1026*800a58d9SAndroid Build Coastguard Worker """ 1027*800a58d9SAndroid Build Coastguard Worker project_match = _RE_PROJECT.match(zone_info) 1028*800a58d9SAndroid Build Coastguard Worker if project_match: 1029*800a58d9SAndroid Build Coastguard Worker return project_match.group("project") 1030*800a58d9SAndroid Build Coastguard Worker 1031*800a58d9SAndroid Build Coastguard Worker logger.debug("Can't get project name from %s.", zone_info) 1032*800a58d9SAndroid Build Coastguard Worker return None 1033*800a58d9SAndroid Build Coastguard Worker 1034*800a58d9SAndroid Build Coastguard Worker @staticmethod 1035*800a58d9SAndroid Build Coastguard Worker def GetAdbVncPortFromSSHTunnel(ip, hostname, avd_type): 1036*800a58d9SAndroid Build Coastguard Worker """Get forwarding adb and vnc port from ssh tunnel. 1037*800a58d9SAndroid Build Coastguard Worker 1038*800a58d9SAndroid Build Coastguard Worker Args: 1039*800a58d9SAndroid Build Coastguard Worker ip: String, ip address. 1040*800a58d9SAndroid Build Coastguard Worker hostname: String, hostname of GCE instance. 1041*800a58d9SAndroid Build Coastguard Worker avd_type: String, the AVD type. 1042*800a58d9SAndroid Build Coastguard Worker 1043*800a58d9SAndroid Build Coastguard Worker Returns: 1044*800a58d9SAndroid Build Coastguard Worker NamedTuple ForwardedPorts(vnc_port, adb_port) holding the ports 1045*800a58d9SAndroid Build Coastguard Worker used in the ssh forwarded call. Both fields are integers. 1046*800a58d9SAndroid Build Coastguard Worker """ 1047*800a58d9SAndroid Build Coastguard Worker if avd_type not in utils.AVD_PORT_DICT: 1048*800a58d9SAndroid Build Coastguard Worker return utils.ForwardedPorts(vnc_port=None, adb_port=None) 1049*800a58d9SAndroid Build Coastguard Worker 1050*800a58d9SAndroid Build Coastguard Worker default_vnc_port = utils.AVD_PORT_DICT[avd_type].vnc_port 1051*800a58d9SAndroid Build Coastguard Worker default_adb_port = utils.AVD_PORT_DICT[avd_type].adb_port 1052*800a58d9SAndroid Build Coastguard Worker # TODO(165888525): Align the SSH tunnel for the order of adb port and 1053*800a58d9SAndroid Build Coastguard Worker # vnc port. 1054*800a58d9SAndroid Build Coastguard Worker re_pattern = re.compile(_RE_SSH_TUNNEL_PATTERN % 1055*800a58d9SAndroid Build Coastguard Worker (_RE_GROUP_ADB, default_adb_port, 1056*800a58d9SAndroid Build Coastguard Worker _RE_GROUP_VNC, default_vnc_port, ip, hostname)) 1057*800a58d9SAndroid Build Coastguard Worker adb_port = None 1058*800a58d9SAndroid Build Coastguard Worker vnc_port = None 1059*800a58d9SAndroid Build Coastguard Worker process_output = utils.CheckOutput(constants.COMMAND_PS) 1060*800a58d9SAndroid Build Coastguard Worker for line in process_output.splitlines(): 1061*800a58d9SAndroid Build Coastguard Worker match = re_pattern.match(line) 1062*800a58d9SAndroid Build Coastguard Worker if match: 1063*800a58d9SAndroid Build Coastguard Worker adb_port = int(match.group(_RE_GROUP_ADB)) 1064*800a58d9SAndroid Build Coastguard Worker vnc_port = int(match.group(_RE_GROUP_VNC)) 1065*800a58d9SAndroid Build Coastguard Worker break 1066*800a58d9SAndroid Build Coastguard Worker 1067*800a58d9SAndroid Build Coastguard Worker logger.debug(("gathering detail for ssh tunnel. " 1068*800a58d9SAndroid Build Coastguard Worker "IP:%s, forwarding (adb:%s, vnc:%s)"), ip, adb_port, 1069*800a58d9SAndroid Build Coastguard Worker vnc_port) 1070*800a58d9SAndroid Build Coastguard Worker 1071*800a58d9SAndroid Build Coastguard Worker return utils.ForwardedPorts(vnc_port=vnc_port, adb_port=adb_port) 1072