1*800a58d9SAndroid Build Coastguard Worker# Copyright 2016 - 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 Worker"""Common Utilities.""" 15*800a58d9SAndroid Build Coastguard Worker# pylint: disable=too-many-lines 16*800a58d9SAndroid Build Coastguard Workerfrom __future__ import print_function 17*800a58d9SAndroid Build Coastguard Worker 18*800a58d9SAndroid Build Coastguard Workerimport base64 19*800a58d9SAndroid Build Coastguard Workerimport binascii 20*800a58d9SAndroid Build Coastguard Workerimport collections 21*800a58d9SAndroid Build Coastguard Workerimport errno 22*800a58d9SAndroid Build Coastguard Workerimport getpass 23*800a58d9SAndroid Build Coastguard Workerimport grp 24*800a58d9SAndroid Build Coastguard Workerimport logging 25*800a58d9SAndroid Build Coastguard Workerimport os 26*800a58d9SAndroid Build Coastguard Workerimport platform 27*800a58d9SAndroid Build Coastguard Workerimport re 28*800a58d9SAndroid Build Coastguard Workerimport shlex 29*800a58d9SAndroid Build Coastguard Workerimport shutil 30*800a58d9SAndroid Build Coastguard Workerimport signal 31*800a58d9SAndroid Build Coastguard Workerimport struct 32*800a58d9SAndroid Build Coastguard Workerimport socket 33*800a58d9SAndroid Build Coastguard Workerimport stat 34*800a58d9SAndroid Build Coastguard Workerimport subprocess 35*800a58d9SAndroid Build Coastguard Workerimport sys 36*800a58d9SAndroid Build Coastguard Workerimport tarfile 37*800a58d9SAndroid Build Coastguard Workerimport tempfile 38*800a58d9SAndroid Build Coastguard Workerimport time 39*800a58d9SAndroid Build Coastguard Workerimport uuid 40*800a58d9SAndroid Build Coastguard Workerimport webbrowser 41*800a58d9SAndroid Build Coastguard Workerimport zipfile 42*800a58d9SAndroid Build Coastguard Worker 43*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors 44*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants 45*800a58d9SAndroid Build Coastguard Worker 46*800a58d9SAndroid Build Coastguard Worker 47*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 48*800a58d9SAndroid Build Coastguard Worker 49*800a58d9SAndroid Build Coastguard WorkerSSH_KEYGEN_CMD = ["ssh-keygen", "-t", "rsa", "-b", "4096"] 50*800a58d9SAndroid Build Coastguard WorkerSSH_KEYGEN_PUB_CMD = ["ssh-keygen", "-y"] 51*800a58d9SAndroid Build Coastguard WorkerSSH_ARGS = ["-o", "UserKnownHostsFile=/dev/null", 52*800a58d9SAndroid Build Coastguard Worker "-o", "StrictHostKeyChecking=no"] 53*800a58d9SAndroid Build Coastguard WorkerSSH_CMD = ["ssh"] + SSH_ARGS 54*800a58d9SAndroid Build Coastguard WorkerSCP_CMD = ["scp"] + SSH_ARGS 55*800a58d9SAndroid Build Coastguard WorkerGET_BUILD_VAR_CMD = ["build/soong/soong_ui.bash", "--dumpvar-mode"] 56*800a58d9SAndroid Build Coastguard WorkerDEFAULT_RETRY_BACKOFF_FACTOR = 1 57*800a58d9SAndroid Build Coastguard WorkerDEFAULT_SLEEP_MULTIPLIER = 0 58*800a58d9SAndroid Build Coastguard Worker 59*800a58d9SAndroid Build Coastguard Worker_SSH_TUNNEL_ARGS = ( 60*800a58d9SAndroid Build Coastguard Worker "-i %(rsa_key_file)s -o ControlPath=none -o UserKnownHostsFile=/dev/null " 61*800a58d9SAndroid Build Coastguard Worker "-o StrictHostKeyChecking=no " 62*800a58d9SAndroid Build Coastguard Worker "%(port_mapping)s" 63*800a58d9SAndroid Build Coastguard Worker "-N -f -l %(ssh_user)s %(ip_addr)s") 64*800a58d9SAndroid Build Coastguard Worker_SSH_COMMAND_PS = ( 65*800a58d9SAndroid Build Coastguard Worker "exec %(ssh_bin)s -i %(rsa_key_file)s -o ControlPath=none " 66*800a58d9SAndroid Build Coastguard Worker "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no " 67*800a58d9SAndroid Build Coastguard Worker "%(extra_args)s -l %(ssh_user)s %(ip_addr)s ps aux") 68*800a58d9SAndroid Build Coastguard WorkerPORT_MAPPING = "-L %(local_port)d:127.0.0.1:%(target_port)d " 69*800a58d9SAndroid Build Coastguard Worker_RELEASE_PORT_CMD = "kill $(lsof -t -i :%d)" 70*800a58d9SAndroid Build Coastguard Worker_WEBRTC_OPERATOR_PATTERN = re.compile(r"(.+)(webrtc_operator )(.+)") 71*800a58d9SAndroid Build Coastguard Worker_PORT_8443 = 8443 72*800a58d9SAndroid Build Coastguard Worker_PORT_1443 = 1443 73*800a58d9SAndroid Build Coastguard WorkerPortMapping = collections.namedtuple("PortMapping", ["local", "target"]) 74*800a58d9SAndroid Build Coastguard Worker# Acloud uses only part of default webrtc port range to support both local and remote. 75*800a58d9SAndroid Build Coastguard Worker# The default webrtc port range is [15550, 15599]. 76*800a58d9SAndroid Build Coastguard WorkerWEBRTC_PORT_START = 15555 77*800a58d9SAndroid Build Coastguard WorkerWEBRTC_PORT_END = 15579 78*800a58d9SAndroid Build Coastguard WorkerWEBRTC_PORTS_MAPPING = [PortMapping(port, port) for port in range(WEBRTC_PORT_START, WEBRTC_PORT_END + 1)] 79*800a58d9SAndroid Build Coastguard Worker_RE_GROUP_WEBRTC = "local_webrtc_port" 80*800a58d9SAndroid Build Coastguard Worker_RE_WEBRTC_SSH_TUNNEL_PATTERN = ( 81*800a58d9SAndroid Build Coastguard Worker r"((.*-L\s)(?P<local_webrtc_port>\d+):127.0.0.1:%s)(.+%s)") 82*800a58d9SAndroid Build Coastguard Worker_ADB_CONNECT_ARGS = "connect 127.0.0.1:%(adb_port)d" 83*800a58d9SAndroid Build Coastguard Worker# Store the ports that vnc/adb are forwarded to, both are integers. 84*800a58d9SAndroid Build Coastguard WorkerForwardedPorts = collections.namedtuple("ForwardedPorts", [constants.VNC_PORT, 85*800a58d9SAndroid Build Coastguard Worker constants.ADB_PORT]) 86*800a58d9SAndroid Build Coastguard Worker 87*800a58d9SAndroid Build Coastguard WorkerAVD_PORT_DICT = { 88*800a58d9SAndroid Build Coastguard Worker constants.TYPE_GCE: ForwardedPorts(constants.GCE_VNC_PORT, 89*800a58d9SAndroid Build Coastguard Worker constants.GCE_ADB_PORT), 90*800a58d9SAndroid Build Coastguard Worker constants.TYPE_CF: ForwardedPorts(constants.CF_VNC_PORT, 91*800a58d9SAndroid Build Coastguard Worker constants.CF_ADB_PORT), 92*800a58d9SAndroid Build Coastguard Worker constants.TYPE_GF: ForwardedPorts(constants.GF_VNC_PORT, 93*800a58d9SAndroid Build Coastguard Worker constants.GF_ADB_PORT), 94*800a58d9SAndroid Build Coastguard Worker constants.TYPE_CHEEPS: ForwardedPorts(constants.CHEEPS_VNC_PORT, 95*800a58d9SAndroid Build Coastguard Worker constants.CHEEPS_ADB_PORT), 96*800a58d9SAndroid Build Coastguard Worker constants.TYPE_FVP: ForwardedPorts(None, constants.FVP_ADB_PORT), 97*800a58d9SAndroid Build Coastguard Worker constants.TYPE_TRUSTY: ForwardedPorts(None, constants.TRUSTY_ADB_PORT), 98*800a58d9SAndroid Build Coastguard Worker} 99*800a58d9SAndroid Build Coastguard Worker 100*800a58d9SAndroid Build Coastguard Worker_VNC_BIN = "ssvnc" 101*800a58d9SAndroid Build Coastguard Worker# search_dirs and the files can be symbolic links. The -H flag makes the 102*800a58d9SAndroid Build Coastguard Worker# command skip the links except search_dirs. The returned files are unique. 103*800a58d9SAndroid Build Coastguard Worker_CMD_FIND_FILES = "find -H %(search_dirs)s -type f" 104*800a58d9SAndroid Build Coastguard Worker_CMD_KILL = ["pkill", "-9", "-f"] 105*800a58d9SAndroid Build Coastguard Worker_CMD_SG = "sg " 106*800a58d9SAndroid Build Coastguard Worker_CMD_START_VNC = "%(bin)s vnc://127.0.0.1:%(port)d" 107*800a58d9SAndroid Build Coastguard Worker_CMD_INSTALL_SSVNC = "sudo apt-get --assume-yes install ssvnc" 108*800a58d9SAndroid Build Coastguard Worker_ENV_DISPLAY = "DISPLAY" 109*800a58d9SAndroid Build Coastguard Worker_SSVNC_ENV_VARS = {"SSVNC_NO_ENC_WARN": "1", "SSVNC_SCALE": "auto", "VNCVIEWER_X11CURSOR": "1"} 110*800a58d9SAndroid Build Coastguard Worker_DEFAULT_DISPLAY_SCALE = 1.0 111*800a58d9SAndroid Build Coastguard Worker_DIST_DIR = "DIST_DIR" 112*800a58d9SAndroid Build Coastguard Worker 113*800a58d9SAndroid Build Coastguard Worker# For webrtc 114*800a58d9SAndroid Build Coastguard Worker_WEBRTC_URL = "https://%(webrtc_ip)s:%(webrtc_port)d" 115*800a58d9SAndroid Build Coastguard Worker 116*800a58d9SAndroid Build Coastguard Worker_CONFIRM_CONTINUE = ("In order to display the screen to the AVD, we'll need to " 117*800a58d9SAndroid Build Coastguard Worker "install a vnc client (ssvnc). \nWould you like acloud to " 118*800a58d9SAndroid Build Coastguard Worker "install it for you? (%s) \nPress 'y' to continue or " 119*800a58d9SAndroid Build Coastguard Worker "anything else to abort it[y/N]: ") % _CMD_INSTALL_SSVNC 120*800a58d9SAndroid Build Coastguard Worker_EvaluatedResult = collections.namedtuple("EvaluatedResult", 121*800a58d9SAndroid Build Coastguard Worker ["is_result_ok", "result_message"]) 122*800a58d9SAndroid Build Coastguard Worker# dict of supported system and their distributions. 123*800a58d9SAndroid Build Coastguard Worker_SUPPORTED_SYSTEMS_AND_DISTS = {"Linux": ["Ubuntu", "ubuntu", "Debian", "debian"]} 124*800a58d9SAndroid Build Coastguard Worker_DEFAULT_TIMEOUT_ERR = "Function did not complete within %d secs." 125*800a58d9SAndroid Build Coastguard Worker_SSVNC_VIEWER_PATTERN = "vnc://127.0.0.1:%(vnc_port)d" 126*800a58d9SAndroid Build Coastguard Worker 127*800a58d9SAndroid Build Coastguard Worker# Determine the environment whether to support kvm. 128*800a58d9SAndroid Build Coastguard Worker_KVM_PATH = "/dev/kvm" 129*800a58d9SAndroid Build Coastguard Worker 130*800a58d9SAndroid Build Coastguard Worker 131*800a58d9SAndroid Build Coastguard Workerclass TempDir: 132*800a58d9SAndroid Build Coastguard Worker """A context manager that ceates a temporary directory. 133*800a58d9SAndroid Build Coastguard Worker 134*800a58d9SAndroid Build Coastguard Worker Attributes: 135*800a58d9SAndroid Build Coastguard Worker path: The path of the temporary directory. 136*800a58d9SAndroid Build Coastguard Worker """ 137*800a58d9SAndroid Build Coastguard Worker 138*800a58d9SAndroid Build Coastguard Worker def __init__(self): 139*800a58d9SAndroid Build Coastguard Worker self.path = tempfile.mkdtemp() 140*800a58d9SAndroid Build Coastguard Worker os.chmod(self.path, 0o700) 141*800a58d9SAndroid Build Coastguard Worker logger.debug("Created temporary dir %s", self.path) 142*800a58d9SAndroid Build Coastguard Worker 143*800a58d9SAndroid Build Coastguard Worker def __enter__(self): 144*800a58d9SAndroid Build Coastguard Worker """Enter.""" 145*800a58d9SAndroid Build Coastguard Worker return self.path 146*800a58d9SAndroid Build Coastguard Worker 147*800a58d9SAndroid Build Coastguard Worker def __exit__(self, exc_type, exc_value, traceback): 148*800a58d9SAndroid Build Coastguard Worker """Exit. 149*800a58d9SAndroid Build Coastguard Worker 150*800a58d9SAndroid Build Coastguard Worker Args: 151*800a58d9SAndroid Build Coastguard Worker exc_type: Exception type raised within the context manager. 152*800a58d9SAndroid Build Coastguard Worker None if no execption is raised. 153*800a58d9SAndroid Build Coastguard Worker exc_value: Exception instance raised within the context manager. 154*800a58d9SAndroid Build Coastguard Worker None if no execption is raised. 155*800a58d9SAndroid Build Coastguard Worker traceback: Traceback for exeception that is raised within 156*800a58d9SAndroid Build Coastguard Worker the context manager. 157*800a58d9SAndroid Build Coastguard Worker None if no execption is raised. 158*800a58d9SAndroid Build Coastguard Worker Raises: 159*800a58d9SAndroid Build Coastguard Worker EnvironmentError or OSError when failed to delete temp directory. 160*800a58d9SAndroid Build Coastguard Worker """ 161*800a58d9SAndroid Build Coastguard Worker try: 162*800a58d9SAndroid Build Coastguard Worker if self.path: 163*800a58d9SAndroid Build Coastguard Worker shutil.rmtree(self.path) 164*800a58d9SAndroid Build Coastguard Worker logger.debug("Deleted temporary dir %s", self.path) 165*800a58d9SAndroid Build Coastguard Worker except EnvironmentError as e: 166*800a58d9SAndroid Build Coastguard Worker # Ignore error if there is no exception raised 167*800a58d9SAndroid Build Coastguard Worker # within the with-clause and the EnvironementError is 168*800a58d9SAndroid Build Coastguard Worker # about problem that directory or file does not exist. 169*800a58d9SAndroid Build Coastguard Worker if not exc_type and e.errno != errno.ENOENT: 170*800a58d9SAndroid Build Coastguard Worker raise 171*800a58d9SAndroid Build Coastguard Worker except Exception as e: # pylint: disable=W0703 172*800a58d9SAndroid Build Coastguard Worker if exc_type: 173*800a58d9SAndroid Build Coastguard Worker logger.error( 174*800a58d9SAndroid Build Coastguard Worker "Encountered error while deleting %s: %s", 175*800a58d9SAndroid Build Coastguard Worker self.path, 176*800a58d9SAndroid Build Coastguard Worker str(e), 177*800a58d9SAndroid Build Coastguard Worker exc_info=True) 178*800a58d9SAndroid Build Coastguard Worker else: 179*800a58d9SAndroid Build Coastguard Worker raise 180*800a58d9SAndroid Build Coastguard Worker 181*800a58d9SAndroid Build Coastguard Worker 182*800a58d9SAndroid Build Coastguard Workerdef RetryOnException(retry_checker, 183*800a58d9SAndroid Build Coastguard Worker max_retries, 184*800a58d9SAndroid Build Coastguard Worker sleep_multiplier=0, 185*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor=1): 186*800a58d9SAndroid Build Coastguard Worker """Decorater which retries the function call if |retry_checker| returns true. 187*800a58d9SAndroid Build Coastguard Worker 188*800a58d9SAndroid Build Coastguard Worker Args: 189*800a58d9SAndroid Build Coastguard Worker retry_checker: A callback function which should take an exception instance 190*800a58d9SAndroid Build Coastguard Worker and return True if functor(*args, **kwargs) should be retried 191*800a58d9SAndroid Build Coastguard Worker when such exception is raised, and return False if it should 192*800a58d9SAndroid Build Coastguard Worker not be retried. 193*800a58d9SAndroid Build Coastguard Worker max_retries: Maximum number of retries allowed. 194*800a58d9SAndroid Build Coastguard Worker sleep_multiplier: Will sleep sleep_multiplier * attempt_count seconds if 195*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor is 1. Will sleep 196*800a58d9SAndroid Build Coastguard Worker sleep_multiplier * ( 197*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor ** (attempt_count - 1)) 198*800a58d9SAndroid Build Coastguard Worker if retry_backoff_factor != 1. 199*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor: See explanation of sleep_multiplier. 200*800a58d9SAndroid Build Coastguard Worker 201*800a58d9SAndroid Build Coastguard Worker Returns: 202*800a58d9SAndroid Build Coastguard Worker The function wrapper. 203*800a58d9SAndroid Build Coastguard Worker """ 204*800a58d9SAndroid Build Coastguard Worker 205*800a58d9SAndroid Build Coastguard Worker def _Wrapper(func): 206*800a58d9SAndroid Build Coastguard Worker def _FunctionWrapper(*args, **kwargs): 207*800a58d9SAndroid Build Coastguard Worker return Retry(retry_checker, max_retries, func, sleep_multiplier, 208*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor, *args, **kwargs) 209*800a58d9SAndroid Build Coastguard Worker 210*800a58d9SAndroid Build Coastguard Worker return _FunctionWrapper 211*800a58d9SAndroid Build Coastguard Worker 212*800a58d9SAndroid Build Coastguard Worker return _Wrapper 213*800a58d9SAndroid Build Coastguard Worker 214*800a58d9SAndroid Build Coastguard Worker 215*800a58d9SAndroid Build Coastguard Workerdef Retry(retry_checker, max_retries, functor, sleep_multiplier, 216*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor, *args, **kwargs): 217*800a58d9SAndroid Build Coastguard Worker """Conditionally retry a function. 218*800a58d9SAndroid Build Coastguard Worker 219*800a58d9SAndroid Build Coastguard Worker Args: 220*800a58d9SAndroid Build Coastguard Worker retry_checker: A callback function which should take an exception instance 221*800a58d9SAndroid Build Coastguard Worker and return True if functor(*args, **kwargs) should be retried 222*800a58d9SAndroid Build Coastguard Worker when such exception is raised, and return False if it should 223*800a58d9SAndroid Build Coastguard Worker not be retried. 224*800a58d9SAndroid Build Coastguard Worker max_retries: Maximum number of retries allowed. 225*800a58d9SAndroid Build Coastguard Worker functor: The function to call, will call functor(*args, **kwargs). 226*800a58d9SAndroid Build Coastguard Worker sleep_multiplier: Will sleep sleep_multiplier * attempt_count seconds if 227*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor is 1. Will sleep 228*800a58d9SAndroid Build Coastguard Worker sleep_multiplier * ( 229*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor ** (attempt_count - 1)) 230*800a58d9SAndroid Build Coastguard Worker if retry_backoff_factor != 1. 231*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor: See explanation of sleep_multiplier. 232*800a58d9SAndroid Build Coastguard Worker *args: Arguments to pass to the functor. 233*800a58d9SAndroid Build Coastguard Worker **kwargs: Key-val based arguments to pass to the functor. 234*800a58d9SAndroid Build Coastguard Worker 235*800a58d9SAndroid Build Coastguard Worker Returns: 236*800a58d9SAndroid Build Coastguard Worker The return value of the functor. 237*800a58d9SAndroid Build Coastguard Worker 238*800a58d9SAndroid Build Coastguard Worker Raises: 239*800a58d9SAndroid Build Coastguard Worker Exception: The exception that functor(*args, **kwargs) throws. 240*800a58d9SAndroid Build Coastguard Worker """ 241*800a58d9SAndroid Build Coastguard Worker attempt_count = 0 242*800a58d9SAndroid Build Coastguard Worker while attempt_count <= max_retries: 243*800a58d9SAndroid Build Coastguard Worker try: 244*800a58d9SAndroid Build Coastguard Worker attempt_count += 1 245*800a58d9SAndroid Build Coastguard Worker return_value = functor(*args, **kwargs) 246*800a58d9SAndroid Build Coastguard Worker return return_value 247*800a58d9SAndroid Build Coastguard Worker except Exception as e: # pylint: disable=W0703 248*800a58d9SAndroid Build Coastguard Worker if retry_checker(e) and attempt_count <= max_retries: 249*800a58d9SAndroid Build Coastguard Worker if retry_backoff_factor != 1: 250*800a58d9SAndroid Build Coastguard Worker sleep = sleep_multiplier * (retry_backoff_factor** 251*800a58d9SAndroid Build Coastguard Worker (attempt_count - 1)) 252*800a58d9SAndroid Build Coastguard Worker else: 253*800a58d9SAndroid Build Coastguard Worker sleep = sleep_multiplier * attempt_count 254*800a58d9SAndroid Build Coastguard Worker time.sleep(sleep) 255*800a58d9SAndroid Build Coastguard Worker else: 256*800a58d9SAndroid Build Coastguard Worker raise 257*800a58d9SAndroid Build Coastguard Worker 258*800a58d9SAndroid Build Coastguard Worker 259*800a58d9SAndroid Build Coastguard Workerdef RetryExceptionType(exception_types, max_retries, functor, *args, **kwargs): 260*800a58d9SAndroid Build Coastguard Worker """Retry exception if it is one of the given types. 261*800a58d9SAndroid Build Coastguard Worker 262*800a58d9SAndroid Build Coastguard Worker Args: 263*800a58d9SAndroid Build Coastguard Worker exception_types: A tuple of exception types, e.g. (ValueError, KeyError) 264*800a58d9SAndroid Build Coastguard Worker max_retries: Max number of retries allowed. 265*800a58d9SAndroid Build Coastguard Worker functor: The function to call. Will be retried if exception is raised and 266*800a58d9SAndroid Build Coastguard Worker the exception is one of the exception_types. 267*800a58d9SAndroid Build Coastguard Worker *args: Arguments to pass to Retry function. 268*800a58d9SAndroid Build Coastguard Worker **kwargs: Key-val based arguments to pass to Retry functions. 269*800a58d9SAndroid Build Coastguard Worker 270*800a58d9SAndroid Build Coastguard Worker Returns: 271*800a58d9SAndroid Build Coastguard Worker The value returned by calling functor. 272*800a58d9SAndroid Build Coastguard Worker """ 273*800a58d9SAndroid Build Coastguard Worker return Retry(lambda e: isinstance(e, exception_types), max_retries, 274*800a58d9SAndroid Build Coastguard Worker functor, *args, **kwargs) 275*800a58d9SAndroid Build Coastguard Worker 276*800a58d9SAndroid Build Coastguard Worker 277*800a58d9SAndroid Build Coastguard Workerdef PollAndWait(func, expected_return, timeout_exception, timeout_secs, 278*800a58d9SAndroid Build Coastguard Worker sleep_interval_secs, *args, **kwargs): 279*800a58d9SAndroid Build Coastguard Worker """Call a function until the function returns expected value or times out. 280*800a58d9SAndroid Build Coastguard Worker 281*800a58d9SAndroid Build Coastguard Worker Args: 282*800a58d9SAndroid Build Coastguard Worker func: Function to call. 283*800a58d9SAndroid Build Coastguard Worker expected_return: The expected return value. 284*800a58d9SAndroid Build Coastguard Worker timeout_exception: Exception to raise when it hits timeout. 285*800a58d9SAndroid Build Coastguard Worker timeout_secs: Timeout seconds. 286*800a58d9SAndroid Build Coastguard Worker If 0 or less than zero, the function will run once and 287*800a58d9SAndroid Build Coastguard Worker we will not wait on it. 288*800a58d9SAndroid Build Coastguard Worker sleep_interval_secs: Time to sleep between two attemps. 289*800a58d9SAndroid Build Coastguard Worker *args: list of args to pass to func. 290*800a58d9SAndroid Build Coastguard Worker **kwargs: dictionary of keyword based args to pass to func. 291*800a58d9SAndroid Build Coastguard Worker 292*800a58d9SAndroid Build Coastguard Worker Raises: 293*800a58d9SAndroid Build Coastguard Worker timeout_exception: if the run of function times out. 294*800a58d9SAndroid Build Coastguard Worker """ 295*800a58d9SAndroid Build Coastguard Worker # TODO(fdeng): Currently this method does not kill 296*800a58d9SAndroid Build Coastguard Worker # |func|, if |func| takes longer than |timeout_secs|. 297*800a58d9SAndroid Build Coastguard Worker # We can use a more robust version from chromite. 298*800a58d9SAndroid Build Coastguard Worker start = time.time() 299*800a58d9SAndroid Build Coastguard Worker while True: 300*800a58d9SAndroid Build Coastguard Worker return_value = func(*args, **kwargs) 301*800a58d9SAndroid Build Coastguard Worker if return_value == expected_return: 302*800a58d9SAndroid Build Coastguard Worker return 303*800a58d9SAndroid Build Coastguard Worker if time.time() - start > timeout_secs: 304*800a58d9SAndroid Build Coastguard Worker raise timeout_exception 305*800a58d9SAndroid Build Coastguard Worker if sleep_interval_secs > 0: 306*800a58d9SAndroid Build Coastguard Worker time.sleep(sleep_interval_secs) 307*800a58d9SAndroid Build Coastguard Worker 308*800a58d9SAndroid Build Coastguard Worker 309*800a58d9SAndroid Build Coastguard Workerdef GenerateUniqueName(prefix=None, suffix=None): 310*800a58d9SAndroid Build Coastguard Worker """Generate a random unique name using uuid4. 311*800a58d9SAndroid Build Coastguard Worker 312*800a58d9SAndroid Build Coastguard Worker Args: 313*800a58d9SAndroid Build Coastguard Worker prefix: String, desired prefix to prepend to the generated name. 314*800a58d9SAndroid Build Coastguard Worker suffix: String, desired suffix to append to the generated name. 315*800a58d9SAndroid Build Coastguard Worker 316*800a58d9SAndroid Build Coastguard Worker Returns: 317*800a58d9SAndroid Build Coastguard Worker String, a random name. 318*800a58d9SAndroid Build Coastguard Worker """ 319*800a58d9SAndroid Build Coastguard Worker name = uuid.uuid4().hex 320*800a58d9SAndroid Build Coastguard Worker if prefix: 321*800a58d9SAndroid Build Coastguard Worker name = "-".join([prefix, name]) 322*800a58d9SAndroid Build Coastguard Worker if suffix: 323*800a58d9SAndroid Build Coastguard Worker name = "-".join([name, suffix]) 324*800a58d9SAndroid Build Coastguard Worker return name 325*800a58d9SAndroid Build Coastguard Worker 326*800a58d9SAndroid Build Coastguard Worker 327*800a58d9SAndroid Build Coastguard Workerdef MakeTarFile(src_dict, dest): 328*800a58d9SAndroid Build Coastguard Worker """Archive files in tar.gz format to a file named as |dest|. 329*800a58d9SAndroid Build Coastguard Worker 330*800a58d9SAndroid Build Coastguard Worker Args: 331*800a58d9SAndroid Build Coastguard Worker src_dict: A dictionary that maps a path to be archived 332*800a58d9SAndroid Build Coastguard Worker to the corresponding name that appears in the archive. 333*800a58d9SAndroid Build Coastguard Worker dest: String, path to output file, e.g. /tmp/myfile.tar.gz 334*800a58d9SAndroid Build Coastguard Worker """ 335*800a58d9SAndroid Build Coastguard Worker logger.info("Compressing %s into %s.", src_dict.keys(), dest) 336*800a58d9SAndroid Build Coastguard Worker with tarfile.open(dest, "w:gz") as tar: 337*800a58d9SAndroid Build Coastguard Worker for src, arcname in src_dict.items(): 338*800a58d9SAndroid Build Coastguard Worker tar.add(src, arcname=arcname) 339*800a58d9SAndroid Build Coastguard Worker 340*800a58d9SAndroid Build Coastguard Workerdef CreateSshKeyPairIfNotExist(private_key_path, public_key_path): 341*800a58d9SAndroid Build Coastguard Worker """Create the ssh key pair if they don't exist. 342*800a58d9SAndroid Build Coastguard Worker 343*800a58d9SAndroid Build Coastguard Worker Case1. If the private key doesn't exist, we will create both the public key 344*800a58d9SAndroid Build Coastguard Worker and the private key. 345*800a58d9SAndroid Build Coastguard Worker Case2. If the private key exists but public key doesn't, we will create the 346*800a58d9SAndroid Build Coastguard Worker public key by using the private key. 347*800a58d9SAndroid Build Coastguard Worker Case3. If the public key exists but the private key doesn't, we will create 348*800a58d9SAndroid Build Coastguard Worker a new private key and overwrite the public key. 349*800a58d9SAndroid Build Coastguard Worker 350*800a58d9SAndroid Build Coastguard Worker Args: 351*800a58d9SAndroid Build Coastguard Worker private_key_path: Path to the private key file. 352*800a58d9SAndroid Build Coastguard Worker e.g. ~/.ssh/acloud_rsa 353*800a58d9SAndroid Build Coastguard Worker public_key_path: Path to the public key file. 354*800a58d9SAndroid Build Coastguard Worker e.g. ~/.ssh/acloud_rsa.pub 355*800a58d9SAndroid Build Coastguard Worker 356*800a58d9SAndroid Build Coastguard Worker Raises: 357*800a58d9SAndroid Build Coastguard Worker error.DriverError: If failed to create the key pair. 358*800a58d9SAndroid Build Coastguard Worker """ 359*800a58d9SAndroid Build Coastguard Worker public_key_path = os.path.expanduser(public_key_path) 360*800a58d9SAndroid Build Coastguard Worker private_key_path = os.path.expanduser(private_key_path) 361*800a58d9SAndroid Build Coastguard Worker public_key_exist = os.path.exists(public_key_path) 362*800a58d9SAndroid Build Coastguard Worker private_key_exist = os.path.exists(private_key_path) 363*800a58d9SAndroid Build Coastguard Worker if public_key_exist and private_key_exist: 364*800a58d9SAndroid Build Coastguard Worker logger.debug( 365*800a58d9SAndroid Build Coastguard Worker "The ssh private key (%s) and public key (%s) already exist," 366*800a58d9SAndroid Build Coastguard Worker "will not automatically create the key pairs.", private_key_path, 367*800a58d9SAndroid Build Coastguard Worker public_key_path) 368*800a58d9SAndroid Build Coastguard Worker return 369*800a58d9SAndroid Build Coastguard Worker key_folder = os.path.dirname(private_key_path) 370*800a58d9SAndroid Build Coastguard Worker if not os.path.exists(key_folder): 371*800a58d9SAndroid Build Coastguard Worker os.makedirs(key_folder) 372*800a58d9SAndroid Build Coastguard Worker try: 373*800a58d9SAndroid Build Coastguard Worker if private_key_exist: 374*800a58d9SAndroid Build Coastguard Worker cmd = SSH_KEYGEN_PUB_CMD + ["-f", private_key_path] 375*800a58d9SAndroid Build Coastguard Worker with open(public_key_path, 'w') as outfile: 376*800a58d9SAndroid Build Coastguard Worker stream_content = CheckOutput(cmd) 377*800a58d9SAndroid Build Coastguard Worker outfile.write( 378*800a58d9SAndroid Build Coastguard Worker stream_content.rstrip('\n') + " " + getpass.getuser()) 379*800a58d9SAndroid Build Coastguard Worker logger.info( 380*800a58d9SAndroid Build Coastguard Worker "The ssh public key (%s) do not exist, " 381*800a58d9SAndroid Build Coastguard Worker "automatically creating public key, calling: %s", 382*800a58d9SAndroid Build Coastguard Worker public_key_path, " ".join(cmd)) 383*800a58d9SAndroid Build Coastguard Worker else: 384*800a58d9SAndroid Build Coastguard Worker cmd = SSH_KEYGEN_CMD + [ 385*800a58d9SAndroid Build Coastguard Worker "-C", getpass.getuser(), "-f", private_key_path 386*800a58d9SAndroid Build Coastguard Worker ] 387*800a58d9SAndroid Build Coastguard Worker logger.info( 388*800a58d9SAndroid Build Coastguard Worker "Creating public key from private key (%s) via cmd: %s", 389*800a58d9SAndroid Build Coastguard Worker private_key_path, " ".join(cmd)) 390*800a58d9SAndroid Build Coastguard Worker subprocess.check_call(cmd, stdout=sys.stderr, stderr=sys.stdout) 391*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 392*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError("Failed to create ssh key pair: %s" % str(e)) 393*800a58d9SAndroid Build Coastguard Worker except OSError as e: 394*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError( 395*800a58d9SAndroid Build Coastguard Worker "Failed to create ssh key pair, please make sure " 396*800a58d9SAndroid Build Coastguard Worker "'ssh-keygen' is installed: %s" % str(e)) 397*800a58d9SAndroid Build Coastguard Worker 398*800a58d9SAndroid Build Coastguard Worker # By default ssh-keygen will create a public key file 399*800a58d9SAndroid Build Coastguard Worker # by append .pub to the private key file name. Rename it 400*800a58d9SAndroid Build Coastguard Worker # to what's requested by public_key_path. 401*800a58d9SAndroid Build Coastguard Worker default_pub_key_path = "%s.pub" % private_key_path 402*800a58d9SAndroid Build Coastguard Worker try: 403*800a58d9SAndroid Build Coastguard Worker if default_pub_key_path != public_key_path: 404*800a58d9SAndroid Build Coastguard Worker os.rename(default_pub_key_path, public_key_path) 405*800a58d9SAndroid Build Coastguard Worker except OSError as e: 406*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError( 407*800a58d9SAndroid Build Coastguard Worker "Failed to rename %s to %s: %s" % (default_pub_key_path, 408*800a58d9SAndroid Build Coastguard Worker public_key_path, str(e))) 409*800a58d9SAndroid Build Coastguard Worker 410*800a58d9SAndroid Build Coastguard Worker logger.info("Created ssh private key (%s) and public key (%s)", 411*800a58d9SAndroid Build Coastguard Worker private_key_path, public_key_path) 412*800a58d9SAndroid Build Coastguard Worker 413*800a58d9SAndroid Build Coastguard Worker 414*800a58d9SAndroid Build Coastguard Workerdef VerifyRsaPubKey(rsa): 415*800a58d9SAndroid Build Coastguard Worker """Verify the format of rsa public key. 416*800a58d9SAndroid Build Coastguard Worker 417*800a58d9SAndroid Build Coastguard Worker Args: 418*800a58d9SAndroid Build Coastguard Worker rsa: content of rsa public key. It should follow the format of 419*800a58d9SAndroid Build Coastguard Worker ssh-rsa AAAAB3NzaC1yc2EA.... test@test.com 420*800a58d9SAndroid Build Coastguard Worker 421*800a58d9SAndroid Build Coastguard Worker Raises: 422*800a58d9SAndroid Build Coastguard Worker DriverError if the format is not correct. 423*800a58d9SAndroid Build Coastguard Worker """ 424*800a58d9SAndroid Build Coastguard Worker if not rsa or not all(ord(c) < 128 for c in rsa): 425*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError( 426*800a58d9SAndroid Build Coastguard Worker "rsa key is empty or contains non-ascii character: %s" % rsa) 427*800a58d9SAndroid Build Coastguard Worker 428*800a58d9SAndroid Build Coastguard Worker elements = rsa.split() 429*800a58d9SAndroid Build Coastguard Worker if len(elements) != 3: 430*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError("rsa key is invalid, wrong format: %s" % rsa) 431*800a58d9SAndroid Build Coastguard Worker 432*800a58d9SAndroid Build Coastguard Worker key_type, data, _ = elements 433*800a58d9SAndroid Build Coastguard Worker try: 434*800a58d9SAndroid Build Coastguard Worker binary_data = base64.decodebytes(data.encode()) 435*800a58d9SAndroid Build Coastguard Worker # number of bytes of int type 436*800a58d9SAndroid Build Coastguard Worker int_length = 4 437*800a58d9SAndroid Build Coastguard Worker # binary_data is like "7ssh-key..." in a binary format. 438*800a58d9SAndroid Build Coastguard Worker # The first 4 bytes should represent 7, which should be 439*800a58d9SAndroid Build Coastguard Worker # the length of the following string "ssh-key". 440*800a58d9SAndroid Build Coastguard Worker # And the next 7 bytes should be string "ssh-key". 441*800a58d9SAndroid Build Coastguard Worker # We will verify that the rsa conforms to this format. 442*800a58d9SAndroid Build Coastguard Worker # ">I" in the following line means "big-endian unsigned integer". 443*800a58d9SAndroid Build Coastguard Worker type_length = struct.unpack(">I", binary_data[:int_length])[0] 444*800a58d9SAndroid Build Coastguard Worker if binary_data[int_length:int_length + type_length] != key_type.encode(): 445*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError("rsa key is invalid: %s" % rsa) 446*800a58d9SAndroid Build Coastguard Worker except (struct.error, binascii.Error) as e: 447*800a58d9SAndroid Build Coastguard Worker raise errors.DriverError( 448*800a58d9SAndroid Build Coastguard Worker "rsa key is invalid: %s, error: %s" % (rsa, str(e))) 449*800a58d9SAndroid Build Coastguard Worker 450*800a58d9SAndroid Build Coastguard Worker 451*800a58d9SAndroid Build Coastguard Workerdef Decompress(sourcefile, dest=None): 452*800a58d9SAndroid Build Coastguard Worker """Decompress .zip or .tar.gz. 453*800a58d9SAndroid Build Coastguard Worker 454*800a58d9SAndroid Build Coastguard Worker Args: 455*800a58d9SAndroid Build Coastguard Worker sourcefile: A string, a source file path to decompress. 456*800a58d9SAndroid Build Coastguard Worker dest: A string, a folder path as decompress destination. 457*800a58d9SAndroid Build Coastguard Worker 458*800a58d9SAndroid Build Coastguard Worker Raises: 459*800a58d9SAndroid Build Coastguard Worker errors.UnsupportedCompressionFileType: Not supported extension. 460*800a58d9SAndroid Build Coastguard Worker """ 461*800a58d9SAndroid Build Coastguard Worker logger.info("Start to decompress %s!", sourcefile) 462*800a58d9SAndroid Build Coastguard Worker dest_path = dest if dest else "." 463*800a58d9SAndroid Build Coastguard Worker if sourcefile.endswith(".tar.gz"): 464*800a58d9SAndroid Build Coastguard Worker with tarfile.open(sourcefile, "r:gz") as compressor: 465*800a58d9SAndroid Build Coastguard Worker compressor.extractall(dest_path) 466*800a58d9SAndroid Build Coastguard Worker elif sourcefile.endswith(".zip"): 467*800a58d9SAndroid Build Coastguard Worker with zipfile.ZipFile(sourcefile, 'r') as compressor: 468*800a58d9SAndroid Build Coastguard Worker compressor.extractall(dest_path) 469*800a58d9SAndroid Build Coastguard Worker else: 470*800a58d9SAndroid Build Coastguard Worker raise errors.UnsupportedCompressionFileType( 471*800a58d9SAndroid Build Coastguard Worker "Sorry, we could only support compression file type " 472*800a58d9SAndroid Build Coastguard Worker "for zip or tar.gz.") 473*800a58d9SAndroid Build Coastguard Worker 474*800a58d9SAndroid Build Coastguard Worker 475*800a58d9SAndroid Build Coastguard Worker# pylint: disable=no-init 476*800a58d9SAndroid Build Coastguard Workerclass TextColors: 477*800a58d9SAndroid Build Coastguard Worker """A class that defines common color ANSI code.""" 478*800a58d9SAndroid Build Coastguard Worker 479*800a58d9SAndroid Build Coastguard Worker HEADER = "\033[95m" 480*800a58d9SAndroid Build Coastguard Worker OKBLUE = "\033[94m" 481*800a58d9SAndroid Build Coastguard Worker OKGREEN = "\033[92m" 482*800a58d9SAndroid Build Coastguard Worker WARNING = "\033[33m" 483*800a58d9SAndroid Build Coastguard Worker FAIL = "\033[91m" 484*800a58d9SAndroid Build Coastguard Worker ENDC = "\033[0m" 485*800a58d9SAndroid Build Coastguard Worker BOLD = "\033[1m" 486*800a58d9SAndroid Build Coastguard Worker UNDERLINE = "\033[4m" 487*800a58d9SAndroid Build Coastguard Worker 488*800a58d9SAndroid Build Coastguard Worker 489*800a58d9SAndroid Build Coastguard Workerdef PrintColorString(message, colors=TextColors.OKBLUE, **kwargs): 490*800a58d9SAndroid Build Coastguard Worker """A helper function to print out colored text. 491*800a58d9SAndroid Build Coastguard Worker 492*800a58d9SAndroid Build Coastguard Worker Use print function "print(message, end="")" to show message in one line. 493*800a58d9SAndroid Build Coastguard Worker Example code: 494*800a58d9SAndroid Build Coastguard Worker DisplayMessages("Creating GCE instance...", end="") 495*800a58d9SAndroid Build Coastguard Worker # Job execute 20s 496*800a58d9SAndroid Build Coastguard Worker DisplayMessages("Done! (20s)") 497*800a58d9SAndroid Build Coastguard Worker Display: 498*800a58d9SAndroid Build Coastguard Worker Creating GCE instance... 499*800a58d9SAndroid Build Coastguard Worker # After job finished, messages update as following: 500*800a58d9SAndroid Build Coastguard Worker Creating GCE instance...Done! (20s) 501*800a58d9SAndroid Build Coastguard Worker 502*800a58d9SAndroid Build Coastguard Worker Args: 503*800a58d9SAndroid Build Coastguard Worker message: String, the message text. 504*800a58d9SAndroid Build Coastguard Worker colors: String, color code. 505*800a58d9SAndroid Build Coastguard Worker **kwargs: dictionary of keyword based args to pass to func. 506*800a58d9SAndroid Build Coastguard Worker """ 507*800a58d9SAndroid Build Coastguard Worker print(colors + message + TextColors.ENDC, **kwargs) 508*800a58d9SAndroid Build Coastguard Worker sys.stdout.flush() 509*800a58d9SAndroid Build Coastguard Worker 510*800a58d9SAndroid Build Coastguard Worker 511*800a58d9SAndroid Build Coastguard Workerdef InteractWithQuestion(question, colors=TextColors.WARNING): 512*800a58d9SAndroid Build Coastguard Worker """A helper function to define the common way to run interactive cmd. 513*800a58d9SAndroid Build Coastguard Worker 514*800a58d9SAndroid Build Coastguard Worker Args: 515*800a58d9SAndroid Build Coastguard Worker question: String, the question to ask user. 516*800a58d9SAndroid Build Coastguard Worker colors: String, color code. 517*800a58d9SAndroid Build Coastguard Worker 518*800a58d9SAndroid Build Coastguard Worker Returns: 519*800a58d9SAndroid Build Coastguard Worker String, input from user. 520*800a58d9SAndroid Build Coastguard Worker """ 521*800a58d9SAndroid Build Coastguard Worker return str(input(colors + question + TextColors.ENDC).strip()) 522*800a58d9SAndroid Build Coastguard Worker 523*800a58d9SAndroid Build Coastguard Worker 524*800a58d9SAndroid Build Coastguard Workerdef GetUserAnswerYes(question): 525*800a58d9SAndroid Build Coastguard Worker """Ask user about acloud setup question. 526*800a58d9SAndroid Build Coastguard Worker 527*800a58d9SAndroid Build Coastguard Worker Args: 528*800a58d9SAndroid Build Coastguard Worker question: String of question for user. Enter is equivalent to pressing 529*800a58d9SAndroid Build Coastguard Worker n. We should hint user with upper case N surrounded in square 530*800a58d9SAndroid Build Coastguard Worker brackets. 531*800a58d9SAndroid Build Coastguard Worker Ex: "Are you sure to change bucket name[y/N]:" 532*800a58d9SAndroid Build Coastguard Worker 533*800a58d9SAndroid Build Coastguard Worker Returns: 534*800a58d9SAndroid Build Coastguard Worker Boolean, True if answer is "Yes", False otherwise. 535*800a58d9SAndroid Build Coastguard Worker """ 536*800a58d9SAndroid Build Coastguard Worker answer = InteractWithQuestion(question) 537*800a58d9SAndroid Build Coastguard Worker return answer.lower() in constants.USER_ANSWER_YES 538*800a58d9SAndroid Build Coastguard Worker 539*800a58d9SAndroid Build Coastguard Worker 540*800a58d9SAndroid Build Coastguard Workerclass BatchHttpRequestExecutor: 541*800a58d9SAndroid Build Coastguard Worker """A helper class that executes requests in batch with retry. 542*800a58d9SAndroid Build Coastguard Worker 543*800a58d9SAndroid Build Coastguard Worker This executor executes http requests in a batch and retry 544*800a58d9SAndroid Build Coastguard Worker those that have failed. It iteratively updates the dictionary 545*800a58d9SAndroid Build Coastguard Worker self._final_results with latest results, which can be retrieved 546*800a58d9SAndroid Build Coastguard Worker via GetResults. 547*800a58d9SAndroid Build Coastguard Worker """ 548*800a58d9SAndroid Build Coastguard Worker 549*800a58d9SAndroid Build Coastguard Worker def __init__(self, 550*800a58d9SAndroid Build Coastguard Worker execute_once_functor, 551*800a58d9SAndroid Build Coastguard Worker requests, 552*800a58d9SAndroid Build Coastguard Worker retry_http_codes=None, 553*800a58d9SAndroid Build Coastguard Worker max_retry=None, 554*800a58d9SAndroid Build Coastguard Worker sleep=None, 555*800a58d9SAndroid Build Coastguard Worker backoff_factor=None, 556*800a58d9SAndroid Build Coastguard Worker other_retriable_errors=None): 557*800a58d9SAndroid Build Coastguard Worker """Initializes the executor. 558*800a58d9SAndroid Build Coastguard Worker 559*800a58d9SAndroid Build Coastguard Worker Args: 560*800a58d9SAndroid Build Coastguard Worker execute_once_functor: A function that execute requests in batch once. 561*800a58d9SAndroid Build Coastguard Worker It should return a dictionary like 562*800a58d9SAndroid Build Coastguard Worker {request_id: (response, exception)} 563*800a58d9SAndroid Build Coastguard Worker requests: A dictionary where key is request id picked by caller, 564*800a58d9SAndroid Build Coastguard Worker and value is a apiclient.http.HttpRequest. 565*800a58d9SAndroid Build Coastguard Worker retry_http_codes: A list of http codes to retry. 566*800a58d9SAndroid Build Coastguard Worker max_retry: See utils.Retry. 567*800a58d9SAndroid Build Coastguard Worker sleep: See utils.Retry. 568*800a58d9SAndroid Build Coastguard Worker backoff_factor: See utils.Retry. 569*800a58d9SAndroid Build Coastguard Worker other_retriable_errors: A tuple of error types that should be retried 570*800a58d9SAndroid Build Coastguard Worker other than errors.HttpError. 571*800a58d9SAndroid Build Coastguard Worker """ 572*800a58d9SAndroid Build Coastguard Worker self._execute_once_functor = execute_once_functor 573*800a58d9SAndroid Build Coastguard Worker self._requests = requests 574*800a58d9SAndroid Build Coastguard Worker # A dictionary that maps request id to pending request. 575*800a58d9SAndroid Build Coastguard Worker self._pending_requests = {} 576*800a58d9SAndroid Build Coastguard Worker # A dictionary that maps request id to a tuple (response, exception). 577*800a58d9SAndroid Build Coastguard Worker self._final_results = {} 578*800a58d9SAndroid Build Coastguard Worker self._retry_http_codes = retry_http_codes 579*800a58d9SAndroid Build Coastguard Worker self._max_retry = max_retry 580*800a58d9SAndroid Build Coastguard Worker self._sleep = sleep 581*800a58d9SAndroid Build Coastguard Worker self._backoff_factor = backoff_factor 582*800a58d9SAndroid Build Coastguard Worker self._other_retriable_errors = other_retriable_errors 583*800a58d9SAndroid Build Coastguard Worker 584*800a58d9SAndroid Build Coastguard Worker def _ShoudRetry(self, exception): 585*800a58d9SAndroid Build Coastguard Worker """Check if an exception is retriable. 586*800a58d9SAndroid Build Coastguard Worker 587*800a58d9SAndroid Build Coastguard Worker Args: 588*800a58d9SAndroid Build Coastguard Worker exception: An exception instance. 589*800a58d9SAndroid Build Coastguard Worker """ 590*800a58d9SAndroid Build Coastguard Worker if isinstance(exception, self._other_retriable_errors): 591*800a58d9SAndroid Build Coastguard Worker return True 592*800a58d9SAndroid Build Coastguard Worker 593*800a58d9SAndroid Build Coastguard Worker if (isinstance(exception, errors.HttpError) 594*800a58d9SAndroid Build Coastguard Worker and exception.code in self._retry_http_codes): 595*800a58d9SAndroid Build Coastguard Worker return True 596*800a58d9SAndroid Build Coastguard Worker return False 597*800a58d9SAndroid Build Coastguard Worker 598*800a58d9SAndroid Build Coastguard Worker def _ExecuteOnce(self): 599*800a58d9SAndroid Build Coastguard Worker """Executes pending requests and update it with failed, retriable ones. 600*800a58d9SAndroid Build Coastguard Worker 601*800a58d9SAndroid Build Coastguard Worker Raises: 602*800a58d9SAndroid Build Coastguard Worker HasRetriableRequestsError: if some requests fail and are retriable. 603*800a58d9SAndroid Build Coastguard Worker """ 604*800a58d9SAndroid Build Coastguard Worker results = self._execute_once_functor(self._pending_requests) 605*800a58d9SAndroid Build Coastguard Worker # Update final_results with latest results. 606*800a58d9SAndroid Build Coastguard Worker self._final_results.update(results) 607*800a58d9SAndroid Build Coastguard Worker # Clear pending_requests 608*800a58d9SAndroid Build Coastguard Worker self._pending_requests.clear() 609*800a58d9SAndroid Build Coastguard Worker for request_id, result in results.items(): 610*800a58d9SAndroid Build Coastguard Worker exception = result[1] 611*800a58d9SAndroid Build Coastguard Worker if exception is not None and self._ShoudRetry(exception): 612*800a58d9SAndroid Build Coastguard Worker # If this is a retriable exception, put it in pending_requests 613*800a58d9SAndroid Build Coastguard Worker self._pending_requests[request_id] = self._requests[request_id] 614*800a58d9SAndroid Build Coastguard Worker if self._pending_requests: 615*800a58d9SAndroid Build Coastguard Worker # If there is still retriable requests pending, raise an error 616*800a58d9SAndroid Build Coastguard Worker # so that Retry will retry this function with pending_requests. 617*800a58d9SAndroid Build Coastguard Worker raise errors.HasRetriableRequestsError( 618*800a58d9SAndroid Build Coastguard Worker "Retriable errors: %s" % 619*800a58d9SAndroid Build Coastguard Worker [str(results[rid][1]) for rid in self._pending_requests]) 620*800a58d9SAndroid Build Coastguard Worker 621*800a58d9SAndroid Build Coastguard Worker def Execute(self): 622*800a58d9SAndroid Build Coastguard Worker """Executes the requests and retry if necessary. 623*800a58d9SAndroid Build Coastguard Worker 624*800a58d9SAndroid Build Coastguard Worker Will populate self._final_results. 625*800a58d9SAndroid Build Coastguard Worker """ 626*800a58d9SAndroid Build Coastguard Worker 627*800a58d9SAndroid Build Coastguard Worker def _ShouldRetryHandler(exc): 628*800a58d9SAndroid Build Coastguard Worker """Check if |exc| is a retriable exception. 629*800a58d9SAndroid Build Coastguard Worker 630*800a58d9SAndroid Build Coastguard Worker Args: 631*800a58d9SAndroid Build Coastguard Worker exc: An exception. 632*800a58d9SAndroid Build Coastguard Worker 633*800a58d9SAndroid Build Coastguard Worker Returns: 634*800a58d9SAndroid Build Coastguard Worker True if exception is of type HasRetriableRequestsError; False otherwise. 635*800a58d9SAndroid Build Coastguard Worker """ 636*800a58d9SAndroid Build Coastguard Worker should_retry = isinstance(exc, errors.HasRetriableRequestsError) 637*800a58d9SAndroid Build Coastguard Worker if should_retry: 638*800a58d9SAndroid Build Coastguard Worker logger.info("Will retry failed requests.", exc_info=True) 639*800a58d9SAndroid Build Coastguard Worker logger.info("%s", exc) 640*800a58d9SAndroid Build Coastguard Worker return should_retry 641*800a58d9SAndroid Build Coastguard Worker 642*800a58d9SAndroid Build Coastguard Worker try: 643*800a58d9SAndroid Build Coastguard Worker self._pending_requests = self._requests.copy() 644*800a58d9SAndroid Build Coastguard Worker Retry( 645*800a58d9SAndroid Build Coastguard Worker _ShouldRetryHandler, 646*800a58d9SAndroid Build Coastguard Worker max_retries=self._max_retry, 647*800a58d9SAndroid Build Coastguard Worker functor=self._ExecuteOnce, 648*800a58d9SAndroid Build Coastguard Worker sleep_multiplier=self._sleep, 649*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor=self._backoff_factor) 650*800a58d9SAndroid Build Coastguard Worker except errors.HasRetriableRequestsError: 651*800a58d9SAndroid Build Coastguard Worker logger.debug("Some requests did not succeed after retry.") 652*800a58d9SAndroid Build Coastguard Worker 653*800a58d9SAndroid Build Coastguard Worker def GetResults(self): 654*800a58d9SAndroid Build Coastguard Worker """Returns final results. 655*800a58d9SAndroid Build Coastguard Worker 656*800a58d9SAndroid Build Coastguard Worker Returns: 657*800a58d9SAndroid Build Coastguard Worker results, a dictionary in the following format 658*800a58d9SAndroid Build Coastguard Worker {request_id: (response, exception)} 659*800a58d9SAndroid Build Coastguard Worker request_ids are those from requests; response 660*800a58d9SAndroid Build Coastguard Worker is the http response for the request or None on error; 661*800a58d9SAndroid Build Coastguard Worker exception is an instance of DriverError or None if no error. 662*800a58d9SAndroid Build Coastguard Worker """ 663*800a58d9SAndroid Build Coastguard Worker return self._final_results 664*800a58d9SAndroid Build Coastguard Worker 665*800a58d9SAndroid Build Coastguard Worker 666*800a58d9SAndroid Build Coastguard Workerdef DefaultEvaluator(result): 667*800a58d9SAndroid Build Coastguard Worker """Default Evaluator always return result is ok. 668*800a58d9SAndroid Build Coastguard Worker 669*800a58d9SAndroid Build Coastguard Worker Args: 670*800a58d9SAndroid Build Coastguard Worker result:the return value of the target function. 671*800a58d9SAndroid Build Coastguard Worker 672*800a58d9SAndroid Build Coastguard Worker Returns: 673*800a58d9SAndroid Build Coastguard Worker _EvaluatedResults namedtuple. 674*800a58d9SAndroid Build Coastguard Worker """ 675*800a58d9SAndroid Build Coastguard Worker return _EvaluatedResult(is_result_ok=True, result_message=result) 676*800a58d9SAndroid Build Coastguard Worker 677*800a58d9SAndroid Build Coastguard Worker 678*800a58d9SAndroid Build Coastguard Workerdef ReportEvaluator(report): 679*800a58d9SAndroid Build Coastguard Worker """Evalute the acloud operation by the report. 680*800a58d9SAndroid Build Coastguard Worker 681*800a58d9SAndroid Build Coastguard Worker Args: 682*800a58d9SAndroid Build Coastguard Worker report: acloud.public.report() object. 683*800a58d9SAndroid Build Coastguard Worker 684*800a58d9SAndroid Build Coastguard Worker Returns: 685*800a58d9SAndroid Build Coastguard Worker _EvaluatedResults namedtuple. 686*800a58d9SAndroid Build Coastguard Worker """ 687*800a58d9SAndroid Build Coastguard Worker if report is None or report.errors: 688*800a58d9SAndroid Build Coastguard Worker return _EvaluatedResult(is_result_ok=False, 689*800a58d9SAndroid Build Coastguard Worker result_message=report.errors) 690*800a58d9SAndroid Build Coastguard Worker 691*800a58d9SAndroid Build Coastguard Worker return _EvaluatedResult(is_result_ok=True, result_message=None) 692*800a58d9SAndroid Build Coastguard Worker 693*800a58d9SAndroid Build Coastguard Worker 694*800a58d9SAndroid Build Coastguard Workerdef BootEvaluator(boot_dict): 695*800a58d9SAndroid Build Coastguard Worker """Evaluate if the device booted successfully. 696*800a58d9SAndroid Build Coastguard Worker 697*800a58d9SAndroid Build Coastguard Worker Args: 698*800a58d9SAndroid Build Coastguard Worker boot_dict: Dict of instance_name:boot error. 699*800a58d9SAndroid Build Coastguard Worker 700*800a58d9SAndroid Build Coastguard Worker Returns: 701*800a58d9SAndroid Build Coastguard Worker _EvaluatedResults namedtuple. 702*800a58d9SAndroid Build Coastguard Worker """ 703*800a58d9SAndroid Build Coastguard Worker if boot_dict: 704*800a58d9SAndroid Build Coastguard Worker return _EvaluatedResult(is_result_ok=False, result_message=boot_dict) 705*800a58d9SAndroid Build Coastguard Worker return _EvaluatedResult(is_result_ok=True, result_message=None) 706*800a58d9SAndroid Build Coastguard Worker 707*800a58d9SAndroid Build Coastguard Worker 708*800a58d9SAndroid Build Coastguard Workerclass TimeExecute: 709*800a58d9SAndroid Build Coastguard Worker """Count the function execute time.""" 710*800a58d9SAndroid Build Coastguard Worker 711*800a58d9SAndroid Build Coastguard Worker def __init__(self, function_description=None, print_before_call=True, 712*800a58d9SAndroid Build Coastguard Worker print_status=True, result_evaluator=DefaultEvaluator, 713*800a58d9SAndroid Build Coastguard Worker display_waiting_dots=True): 714*800a58d9SAndroid Build Coastguard Worker """Initializes the class. 715*800a58d9SAndroid Build Coastguard Worker 716*800a58d9SAndroid Build Coastguard Worker Args: 717*800a58d9SAndroid Build Coastguard Worker function_description: String that describes function (e.g."Creating 718*800a58d9SAndroid Build Coastguard Worker Instance...") 719*800a58d9SAndroid Build Coastguard Worker print_before_call: Boolean, print the function description before 720*800a58d9SAndroid Build Coastguard Worker calling the function, default True. 721*800a58d9SAndroid Build Coastguard Worker print_status: Boolean, print the status of the function after the 722*800a58d9SAndroid Build Coastguard Worker function has completed, default True ("OK" or "Fail"). 723*800a58d9SAndroid Build Coastguard Worker result_evaluator: Func object. Pass func to evaluate result. 724*800a58d9SAndroid Build Coastguard Worker Default evaluator always report result is ok and 725*800a58d9SAndroid Build Coastguard Worker failed result will be identified only in exception 726*800a58d9SAndroid Build Coastguard Worker case. 727*800a58d9SAndroid Build Coastguard Worker display_waiting_dots: Boolean, if true print the function_description 728*800a58d9SAndroid Build Coastguard Worker followed by waiting dot. 729*800a58d9SAndroid Build Coastguard Worker """ 730*800a58d9SAndroid Build Coastguard Worker self._function_description = function_description 731*800a58d9SAndroid Build Coastguard Worker self._print_before_call = print_before_call 732*800a58d9SAndroid Build Coastguard Worker self._print_status = print_status 733*800a58d9SAndroid Build Coastguard Worker self._result_evaluator = result_evaluator 734*800a58d9SAndroid Build Coastguard Worker self._display_waiting_dots = display_waiting_dots 735*800a58d9SAndroid Build Coastguard Worker 736*800a58d9SAndroid Build Coastguard Worker def __call__(self, func): 737*800a58d9SAndroid Build Coastguard Worker def DecoratorFunction(*args, **kargs): 738*800a58d9SAndroid Build Coastguard Worker """Decorator function. 739*800a58d9SAndroid Build Coastguard Worker 740*800a58d9SAndroid Build Coastguard Worker Args: 741*800a58d9SAndroid Build Coastguard Worker *args: Arguments to pass to the functor. 742*800a58d9SAndroid Build Coastguard Worker **kwargs: Key-val based arguments to pass to the functor. 743*800a58d9SAndroid Build Coastguard Worker 744*800a58d9SAndroid Build Coastguard Worker Raises: 745*800a58d9SAndroid Build Coastguard Worker Exception: The exception that functor(*args, **kwargs) throws. 746*800a58d9SAndroid Build Coastguard Worker """ 747*800a58d9SAndroid Build Coastguard Worker timestart = time.time() 748*800a58d9SAndroid Build Coastguard Worker if self._print_before_call: 749*800a58d9SAndroid Build Coastguard Worker waiting_dots = "..." if self._display_waiting_dots else "" 750*800a58d9SAndroid Build Coastguard Worker PrintColorString("%s %s"% (self._function_description, 751*800a58d9SAndroid Build Coastguard Worker waiting_dots), end="") 752*800a58d9SAndroid Build Coastguard Worker try: 753*800a58d9SAndroid Build Coastguard Worker result = func(*args, **kargs) 754*800a58d9SAndroid Build Coastguard Worker result_time = time.time() - timestart 755*800a58d9SAndroid Build Coastguard Worker if not self._print_before_call: 756*800a58d9SAndroid Build Coastguard Worker PrintColorString("%s (%ds)" % (self._function_description, 757*800a58d9SAndroid Build Coastguard Worker result_time), 758*800a58d9SAndroid Build Coastguard Worker TextColors.OKGREEN) 759*800a58d9SAndroid Build Coastguard Worker if self._print_status: 760*800a58d9SAndroid Build Coastguard Worker evaluated_result = self._result_evaluator(result) 761*800a58d9SAndroid Build Coastguard Worker if evaluated_result.is_result_ok: 762*800a58d9SAndroid Build Coastguard Worker PrintColorString("OK! (%ds)" % (result_time), 763*800a58d9SAndroid Build Coastguard Worker TextColors.OKGREEN) 764*800a58d9SAndroid Build Coastguard Worker else: 765*800a58d9SAndroid Build Coastguard Worker PrintColorString("Fail! (%ds)" % (result_time), 766*800a58d9SAndroid Build Coastguard Worker TextColors.FAIL) 767*800a58d9SAndroid Build Coastguard Worker PrintColorString("Error: %s" % 768*800a58d9SAndroid Build Coastguard Worker evaluated_result.result_message, 769*800a58d9SAndroid Build Coastguard Worker TextColors.FAIL) 770*800a58d9SAndroid Build Coastguard Worker return result 771*800a58d9SAndroid Build Coastguard Worker except: 772*800a58d9SAndroid Build Coastguard Worker if self._print_status: 773*800a58d9SAndroid Build Coastguard Worker PrintColorString("Fail! (%ds)" % (time.time() - timestart), 774*800a58d9SAndroid Build Coastguard Worker TextColors.FAIL) 775*800a58d9SAndroid Build Coastguard Worker raise 776*800a58d9SAndroid Build Coastguard Worker return DecoratorFunction 777*800a58d9SAndroid Build Coastguard Worker 778*800a58d9SAndroid Build Coastguard Worker 779*800a58d9SAndroid Build Coastguard Workerdef PickFreePort(): 780*800a58d9SAndroid Build Coastguard Worker """Helper to pick a free port. 781*800a58d9SAndroid Build Coastguard Worker 782*800a58d9SAndroid Build Coastguard Worker Returns: 783*800a58d9SAndroid Build Coastguard Worker Integer, a free port number. 784*800a58d9SAndroid Build Coastguard Worker """ 785*800a58d9SAndroid Build Coastguard Worker tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 786*800a58d9SAndroid Build Coastguard Worker tcp_socket.bind(("", 0)) 787*800a58d9SAndroid Build Coastguard Worker port = tcp_socket.getsockname()[1] 788*800a58d9SAndroid Build Coastguard Worker tcp_socket.close() 789*800a58d9SAndroid Build Coastguard Worker return port 790*800a58d9SAndroid Build Coastguard Worker 791*800a58d9SAndroid Build Coastguard Worker 792*800a58d9SAndroid Build Coastguard Workerdef CheckPortFree(port): 793*800a58d9SAndroid Build Coastguard Worker """Check the availablity of the tcp port. 794*800a58d9SAndroid Build Coastguard Worker 795*800a58d9SAndroid Build Coastguard Worker Args: 796*800a58d9SAndroid Build Coastguard Worker Integer, a port number. 797*800a58d9SAndroid Build Coastguard Worker 798*800a58d9SAndroid Build Coastguard Worker Raises: 799*800a58d9SAndroid Build Coastguard Worker PortOccupied: This port is not available. 800*800a58d9SAndroid Build Coastguard Worker """ 801*800a58d9SAndroid Build Coastguard Worker tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 802*800a58d9SAndroid Build Coastguard Worker try: 803*800a58d9SAndroid Build Coastguard Worker tcp_socket.bind(("", port)) 804*800a58d9SAndroid Build Coastguard Worker except socket.error as port_error: 805*800a58d9SAndroid Build Coastguard Worker raise errors.PortOccupied("Port (%d) is taken, please choose another " 806*800a58d9SAndroid Build Coastguard Worker "port." % port) from port_error 807*800a58d9SAndroid Build Coastguard Worker tcp_socket.close() 808*800a58d9SAndroid Build Coastguard Worker 809*800a58d9SAndroid Build Coastguard Worker 810*800a58d9SAndroid Build Coastguard Workerdef _ExecuteCommand(cmd, args): 811*800a58d9SAndroid Build Coastguard Worker """Execute command. 812*800a58d9SAndroid Build Coastguard Worker 813*800a58d9SAndroid Build Coastguard Worker Args: 814*800a58d9SAndroid Build Coastguard Worker cmd: Strings of execute binary name. 815*800a58d9SAndroid Build Coastguard Worker args: List of args to pass in with cmd. 816*800a58d9SAndroid Build Coastguard Worker 817*800a58d9SAndroid Build Coastguard Worker Raises: 818*800a58d9SAndroid Build Coastguard Worker errors.NoExecuteBin: Can't find the execute bin file. 819*800a58d9SAndroid Build Coastguard Worker """ 820*800a58d9SAndroid Build Coastguard Worker bin_path = FindExecutable(cmd) 821*800a58d9SAndroid Build Coastguard Worker if not bin_path: 822*800a58d9SAndroid Build Coastguard Worker raise errors.NoExecuteCmd("unable to locate %s" % cmd) 823*800a58d9SAndroid Build Coastguard Worker command = [bin_path] + args 824*800a58d9SAndroid Build Coastguard Worker logger.debug("Running '%s'", ' '.join(command)) 825*800a58d9SAndroid Build Coastguard Worker with open(os.devnull, "w") as dev_null: 826*800a58d9SAndroid Build Coastguard Worker subprocess.check_call(command, stderr=dev_null, stdout=dev_null) 827*800a58d9SAndroid Build Coastguard Worker 828*800a58d9SAndroid Build Coastguard Worker 829*800a58d9SAndroid Build Coastguard Workerdef ReleasePort(port): 830*800a58d9SAndroid Build Coastguard Worker """Release local port. 831*800a58d9SAndroid Build Coastguard Worker 832*800a58d9SAndroid Build Coastguard Worker Args: 833*800a58d9SAndroid Build Coastguard Worker port: Integer of local port number. 834*800a58d9SAndroid Build Coastguard Worker """ 835*800a58d9SAndroid Build Coastguard Worker try: 836*800a58d9SAndroid Build Coastguard Worker with open(os.devnull, "w") as dev_null: 837*800a58d9SAndroid Build Coastguard Worker subprocess.check_call(_RELEASE_PORT_CMD % port, 838*800a58d9SAndroid Build Coastguard Worker stderr=dev_null, stdout=dev_null, shell=True) 839*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 840*800a58d9SAndroid Build Coastguard Worker logger.debug("The port %d is available.", constants.WEBRTC_LOCAL_PORT) 841*800a58d9SAndroid Build Coastguard Worker 842*800a58d9SAndroid Build Coastguard Worker 843*800a58d9SAndroid Build Coastguard Workerdef EstablishSshTunnel(ip_addr, rsa_key_file, ssh_user, 844*800a58d9SAndroid Build Coastguard Worker port_mapping, extra_args_ssh_tunnel=None): 845*800a58d9SAndroid Build Coastguard Worker """Create an ssh tunnel. 846*800a58d9SAndroid Build Coastguard Worker 847*800a58d9SAndroid Build Coastguard Worker Args: 848*800a58d9SAndroid Build Coastguard Worker ip_addr: String, use to build the adb & vnc tunnel between local 849*800a58d9SAndroid Build Coastguard Worker and remote instance. 850*800a58d9SAndroid Build Coastguard Worker rsa_key_file: String, Private key file path to use when creating 851*800a58d9SAndroid Build Coastguard Worker the ssh tunnels. 852*800a58d9SAndroid Build Coastguard Worker ssh_user: String of user login into the instance. 853*800a58d9SAndroid Build Coastguard Worker port_mapping: List of tuples, each tuple is a pair of integers 854*800a58d9SAndroid Build Coastguard Worker representing a local port and a remote port. 855*800a58d9SAndroid Build Coastguard Worker extra_args_ssh_tunnel: String, extra args for ssh tunnel connection. 856*800a58d9SAndroid Build Coastguard Worker 857*800a58d9SAndroid Build Coastguard Worker Raises: 858*800a58d9SAndroid Build Coastguard Worker subprocess.CalledProcessError if the ssh command fails. 859*800a58d9SAndroid Build Coastguard Worker """ 860*800a58d9SAndroid Build Coastguard Worker port_mapping = [PORT_MAPPING % { 861*800a58d9SAndroid Build Coastguard Worker "local_port": ports[0], 862*800a58d9SAndroid Build Coastguard Worker "target_port": ports[1]} for ports in port_mapping] 863*800a58d9SAndroid Build Coastguard Worker ssh_tunnel_args = _SSH_TUNNEL_ARGS % { 864*800a58d9SAndroid Build Coastguard Worker "rsa_key_file": rsa_key_file, 865*800a58d9SAndroid Build Coastguard Worker "ssh_user": ssh_user, 866*800a58d9SAndroid Build Coastguard Worker "ip_addr": ip_addr, 867*800a58d9SAndroid Build Coastguard Worker "port_mapping": " ".join(port_mapping)} 868*800a58d9SAndroid Build Coastguard Worker ssh_tunnel_args_list = shlex.split(ssh_tunnel_args) 869*800a58d9SAndroid Build Coastguard Worker if extra_args_ssh_tunnel: 870*800a58d9SAndroid Build Coastguard Worker ssh_tunnel_args_list.extend(shlex.split(extra_args_ssh_tunnel)) 871*800a58d9SAndroid Build Coastguard Worker _ExecuteCommand(constants.SSH_BIN, ssh_tunnel_args_list) 872*800a58d9SAndroid Build Coastguard Worker 873*800a58d9SAndroid Build Coastguard Worker 874*800a58d9SAndroid Build Coastguard Workerdef EstablishWebRTCSshTunnel(ip_addr, webrtc_local_port, rsa_key_file, ssh_user, 875*800a58d9SAndroid Build Coastguard Worker extra_args_ssh_tunnel=None): 876*800a58d9SAndroid Build Coastguard Worker """Create ssh tunnels for webrtc. 877*800a58d9SAndroid Build Coastguard Worker 878*800a58d9SAndroid Build Coastguard Worker Pick up an available local port to establish one WebRTC tunnel and forward to 879*800a58d9SAndroid Build Coastguard Worker the port of the webrtc operator of the remote instance. 880*800a58d9SAndroid Build Coastguard Worker 881*800a58d9SAndroid Build Coastguard Worker Args: 882*800a58d9SAndroid Build Coastguard Worker ip_addr: String, use to build the adb & vnc tunnel between local 883*800a58d9SAndroid Build Coastguard Worker and remote instance. 884*800a58d9SAndroid Build Coastguard Worker webrtc_local_port: Integer, pick a free port as webrtc local port. 885*800a58d9SAndroid Build Coastguard Worker rsa_key_file: String, Private key file path to use when creating 886*800a58d9SAndroid Build Coastguard Worker the ssh tunnels. 887*800a58d9SAndroid Build Coastguard Worker ssh_user: String of user login into the instance. 888*800a58d9SAndroid Build Coastguard Worker extra_args_ssh_tunnel: String, extra args for ssh tunnel connection. 889*800a58d9SAndroid Build Coastguard Worker 890*800a58d9SAndroid Build Coastguard Worker Raises: 891*800a58d9SAndroid Build Coastguard Worker subprocess.CalledProcessError if the ssh command fails. 892*800a58d9SAndroid Build Coastguard Worker """ 893*800a58d9SAndroid Build Coastguard Worker webrtc_server_port = GetWebRTCServerPort( 894*800a58d9SAndroid Build Coastguard Worker ip_addr, rsa_key_file, ssh_user, extra_args_ssh_tunnel) 895*800a58d9SAndroid Build Coastguard Worker 896*800a58d9SAndroid Build Coastguard Worker # TODO(b/209502647): design a better way to forward webrtc ports. 897*800a58d9SAndroid Build Coastguard Worker if extra_args_ssh_tunnel: 898*800a58d9SAndroid Build Coastguard Worker for webrtc_port in WEBRTC_PORTS_MAPPING: 899*800a58d9SAndroid Build Coastguard Worker ReleasePort(webrtc_port.local) 900*800a58d9SAndroid Build Coastguard Worker port_mapping = (WEBRTC_PORTS_MAPPING + 901*800a58d9SAndroid Build Coastguard Worker [PortMapping(webrtc_local_port, webrtc_server_port)]) 902*800a58d9SAndroid Build Coastguard Worker try: 903*800a58d9SAndroid Build Coastguard Worker EstablishSshTunnel(ip_addr, rsa_key_file, ssh_user, 904*800a58d9SAndroid Build Coastguard Worker port_mapping, extra_args_ssh_tunnel) 905*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 906*800a58d9SAndroid Build Coastguard Worker PrintColorString("\n%s\nFailed to create ssh tunnels, retry with '#acloud " 907*800a58d9SAndroid Build Coastguard Worker "reconnect'." % e, TextColors.FAIL) 908*800a58d9SAndroid Build Coastguard Worker 909*800a58d9SAndroid Build Coastguard Worker 910*800a58d9SAndroid Build Coastguard Workerdef GetWebRTCServerPort(ip_addr, rsa_key_file, ssh_user, 911*800a58d9SAndroid Build Coastguard Worker extra_args_ssh_tunnel=None): 912*800a58d9SAndroid Build Coastguard Worker """Get WebRTC server port. 913*800a58d9SAndroid Build Coastguard Worker 914*800a58d9SAndroid Build Coastguard Worker List all process information to find the "webrtc_operator" process, then 915*800a58d9SAndroid Build Coastguard Worker determine the WebRTC server port is 8443 or 1443. 916*800a58d9SAndroid Build Coastguard Worker 917*800a58d9SAndroid Build Coastguard Worker Args: 918*800a58d9SAndroid Build Coastguard Worker ip_addr: String, use to build the adb & vnc tunnel between local 919*800a58d9SAndroid Build Coastguard Worker and remote instance. 920*800a58d9SAndroid Build Coastguard Worker rsa_key_file: String, Private key file path to use when creating 921*800a58d9SAndroid Build Coastguard Worker the ssh tunnels. 922*800a58d9SAndroid Build Coastguard Worker ssh_user: String of user login into the instance. 923*800a58d9SAndroid Build Coastguard Worker extra_args_ssh_tunnel: String, extra args for ssh tunnel connection. 924*800a58d9SAndroid Build Coastguard Worker 925*800a58d9SAndroid Build Coastguard Worker Returns: 926*800a58d9SAndroid Build Coastguard Worker The WebRTC server port number. 927*800a58d9SAndroid Build Coastguard Worker 928*800a58d9SAndroid Build Coastguard Worker Raises: 929*800a58d9SAndroid Build Coastguard Worker subprocess.CalledProcessError if the ssh command fails. 930*800a58d9SAndroid Build Coastguard Worker """ 931*800a58d9SAndroid Build Coastguard Worker ssh_cmd = _SSH_COMMAND_PS % { 932*800a58d9SAndroid Build Coastguard Worker "ssh_bin": FindExecutable(constants.SSH_BIN), 933*800a58d9SAndroid Build Coastguard Worker "rsa_key_file": rsa_key_file, 934*800a58d9SAndroid Build Coastguard Worker "ssh_user": ssh_user, 935*800a58d9SAndroid Build Coastguard Worker "extra_args": extra_args_ssh_tunnel or "", 936*800a58d9SAndroid Build Coastguard Worker "ip_addr": ip_addr} 937*800a58d9SAndroid Build Coastguard Worker logger.info("Running command \"%s\"", ssh_cmd) 938*800a58d9SAndroid Build Coastguard Worker try: 939*800a58d9SAndroid Build Coastguard Worker process = subprocess.Popen( 940*800a58d9SAndroid Build Coastguard Worker ssh_cmd, shell=True, stdin=None, universal_newlines=True, 941*800a58d9SAndroid Build Coastguard Worker stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 942*800a58d9SAndroid Build Coastguard Worker stdout, _ = process.communicate() 943*800a58d9SAndroid Build Coastguard Worker for line in stdout.splitlines(): 944*800a58d9SAndroid Build Coastguard Worker webrtc_match = _WEBRTC_OPERATOR_PATTERN.match(line) 945*800a58d9SAndroid Build Coastguard Worker if webrtc_match: 946*800a58d9SAndroid Build Coastguard Worker return _PORT_8443 947*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 948*800a58d9SAndroid Build Coastguard Worker logger.debug("Failed to list processes: %s", e) 949*800a58d9SAndroid Build Coastguard Worker return _PORT_1443 950*800a58d9SAndroid Build Coastguard Worker 951*800a58d9SAndroid Build Coastguard Worker 952*800a58d9SAndroid Build Coastguard Workerdef GetWebrtcPortFromSSHTunnel(ip): 953*800a58d9SAndroid Build Coastguard Worker """Get forwarding webrtc port from ssh tunnel. 954*800a58d9SAndroid Build Coastguard Worker 955*800a58d9SAndroid Build Coastguard Worker Args: 956*800a58d9SAndroid Build Coastguard Worker ip: String, ip address. 957*800a58d9SAndroid Build Coastguard Worker 958*800a58d9SAndroid Build Coastguard Worker Returns: 959*800a58d9SAndroid Build Coastguard Worker webrtc local port. 960*800a58d9SAndroid Build Coastguard Worker """ 961*800a58d9SAndroid Build Coastguard Worker re_pattern = re.compile(_RE_WEBRTC_SSH_TUNNEL_PATTERN % 962*800a58d9SAndroid Build Coastguard Worker (constants.WEBRTC_LOCAL_PORT, ip)) 963*800a58d9SAndroid Build Coastguard Worker process_output = CheckOutput(constants.COMMAND_PS) 964*800a58d9SAndroid Build Coastguard Worker for line in process_output.splitlines(): 965*800a58d9SAndroid Build Coastguard Worker match = re_pattern.match(line) 966*800a58d9SAndroid Build Coastguard Worker if match: 967*800a58d9SAndroid Build Coastguard Worker webrtc_port = int(match.group(_RE_GROUP_WEBRTC)) 968*800a58d9SAndroid Build Coastguard Worker return webrtc_port 969*800a58d9SAndroid Build Coastguard Worker 970*800a58d9SAndroid Build Coastguard Worker logger.debug("Can't get webrtc local port from ip %s.", ip) 971*800a58d9SAndroid Build Coastguard Worker return None 972*800a58d9SAndroid Build Coastguard Worker 973*800a58d9SAndroid Build Coastguard Worker 974*800a58d9SAndroid Build Coastguard Worker# TODO(147337696): create ssh tunnels tear down as adb and vnc. 975*800a58d9SAndroid Build Coastguard Worker# pylint: disable=too-many-locals 976*800a58d9SAndroid Build Coastguard Workerdef AutoConnect(ip_addr, rsa_key_file, target_vnc_port, target_adb_port, 977*800a58d9SAndroid Build Coastguard Worker ssh_user, client_adb_port=None, extra_args_ssh_tunnel=None): 978*800a58d9SAndroid Build Coastguard Worker """Autoconnect to an AVD instance. 979*800a58d9SAndroid Build Coastguard Worker 980*800a58d9SAndroid Build Coastguard Worker Args: 981*800a58d9SAndroid Build Coastguard Worker ip_addr: String, use to build the adb & vnc tunnel between local 982*800a58d9SAndroid Build Coastguard Worker and remote instance. 983*800a58d9SAndroid Build Coastguard Worker rsa_key_file: String, Private key file path to use when creating 984*800a58d9SAndroid Build Coastguard Worker the ssh tunnels. 985*800a58d9SAndroid Build Coastguard Worker target_vnc_port: Integer of target vnc port number. 986*800a58d9SAndroid Build Coastguard Worker target_adb_port: Integer of target adb port number. 987*800a58d9SAndroid Build Coastguard Worker ssh_user: String of user login into the instance. 988*800a58d9SAndroid Build Coastguard Worker client_adb_port: Integer, Specified adb port to establish connection. 989*800a58d9SAndroid Build Coastguard Worker extra_args_ssh_tunnel: String, extra args for ssh tunnel connection. 990*800a58d9SAndroid Build Coastguard Worker 991*800a58d9SAndroid Build Coastguard Worker Returns: 992*800a58d9SAndroid Build Coastguard Worker NamedTuple of (vnc_port, adb_port) SSHTUNNEL of the connect, both are 993*800a58d9SAndroid Build Coastguard Worker integers. 994*800a58d9SAndroid Build Coastguard Worker """ 995*800a58d9SAndroid Build Coastguard Worker local_adb_port = client_adb_port or PickFreePort() 996*800a58d9SAndroid Build Coastguard Worker port_mapping = [(local_adb_port, target_adb_port)] 997*800a58d9SAndroid Build Coastguard Worker local_free_vnc_port = None 998*800a58d9SAndroid Build Coastguard Worker if target_vnc_port: 999*800a58d9SAndroid Build Coastguard Worker local_free_vnc_port = PickFreePort() 1000*800a58d9SAndroid Build Coastguard Worker port_mapping.append((local_free_vnc_port, target_vnc_port)) 1001*800a58d9SAndroid Build Coastguard Worker try: 1002*800a58d9SAndroid Build Coastguard Worker EstablishSshTunnel(ip_addr, rsa_key_file, ssh_user, 1003*800a58d9SAndroid Build Coastguard Worker port_mapping, extra_args_ssh_tunnel) 1004*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 1005*800a58d9SAndroid Build Coastguard Worker PrintColorString("\n%s\nFailed to create ssh tunnels, retry with '#acloud " 1006*800a58d9SAndroid Build Coastguard Worker "reconnect'." % e, TextColors.FAIL) 1007*800a58d9SAndroid Build Coastguard Worker return ForwardedPorts(vnc_port=None, adb_port=None) 1008*800a58d9SAndroid Build Coastguard Worker 1009*800a58d9SAndroid Build Coastguard Worker try: 1010*800a58d9SAndroid Build Coastguard Worker adb_connect_args = _ADB_CONNECT_ARGS % {"adb_port": local_adb_port} 1011*800a58d9SAndroid Build Coastguard Worker _ExecuteCommand(constants.ADB_BIN, adb_connect_args.split()) 1012*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 1013*800a58d9SAndroid Build Coastguard Worker PrintColorString("Failed to adb connect, retry with " 1014*800a58d9SAndroid Build Coastguard Worker "'#acloud reconnect'", TextColors.FAIL) 1015*800a58d9SAndroid Build Coastguard Worker 1016*800a58d9SAndroid Build Coastguard Worker return ForwardedPorts(vnc_port=local_free_vnc_port, 1017*800a58d9SAndroid Build Coastguard Worker adb_port=local_adb_port) 1018*800a58d9SAndroid Build Coastguard Worker 1019*800a58d9SAndroid Build Coastguard Worker 1020*800a58d9SAndroid Build Coastguard Workerdef FindRemoteFiles(ssh_obj, search_dirs): 1021*800a58d9SAndroid Build Coastguard Worker """Get all files, except symbolic links, under remote directories. 1022*800a58d9SAndroid Build Coastguard Worker 1023*800a58d9SAndroid Build Coastguard Worker Args: 1024*800a58d9SAndroid Build Coastguard Worker ssh_obj: An Ssh object. 1025*800a58d9SAndroid Build Coastguard Worker search_dirs: A list of strings, the remote directories. 1026*800a58d9SAndroid Build Coastguard Worker 1027*800a58d9SAndroid Build Coastguard Worker Returns: 1028*800a58d9SAndroid Build Coastguard Worker A list of strings, the file paths. 1029*800a58d9SAndroid Build Coastguard Worker 1030*800a58d9SAndroid Build Coastguard Worker Raises: 1031*800a58d9SAndroid Build Coastguard Worker errors.SubprocessFail if the ssh execution returns non-zero. 1032*800a58d9SAndroid Build Coastguard Worker """ 1033*800a58d9SAndroid Build Coastguard Worker if not search_dirs: 1034*800a58d9SAndroid Build Coastguard Worker return [] 1035*800a58d9SAndroid Build Coastguard Worker ssh_cmd = (ssh_obj.GetBaseCmd(constants.SSH_BIN) + " " + 1036*800a58d9SAndroid Build Coastguard Worker _CMD_FIND_FILES % {"search_dirs": " ".join(search_dirs)}) 1037*800a58d9SAndroid Build Coastguard Worker proc = subprocess.run(ssh_cmd, shell=True, capture_output=True, 1038*800a58d9SAndroid Build Coastguard Worker check=False) 1039*800a58d9SAndroid Build Coastguard Worker if proc.returncode != 0: 1040*800a58d9SAndroid Build Coastguard Worker raise errors.SubprocessFail("`%s` returned %d. with standard error: %s" % 1041*800a58d9SAndroid Build Coastguard Worker (ssh_cmd, proc.returncode, proc.stderr.decode())) 1042*800a58d9SAndroid Build Coastguard Worker if proc.stderr: 1043*800a58d9SAndroid Build Coastguard Worker logger.debug("`%s` stderr: %s", ssh_cmd, proc.stderr.decode()) 1044*800a58d9SAndroid Build Coastguard Worker if proc.stdout: 1045*800a58d9SAndroid Build Coastguard Worker return proc.stdout.decode().splitlines() 1046*800a58d9SAndroid Build Coastguard Worker return [] 1047*800a58d9SAndroid Build Coastguard Worker 1048*800a58d9SAndroid Build Coastguard Worker 1049*800a58d9SAndroid Build Coastguard Workerdef GetAnswerFromList(answer_list, enable_choose_all=False): 1050*800a58d9SAndroid Build Coastguard Worker """Get answer from a list. 1051*800a58d9SAndroid Build Coastguard Worker 1052*800a58d9SAndroid Build Coastguard Worker Args: 1053*800a58d9SAndroid Build Coastguard Worker answer_list: list of the answers to choose from. 1054*800a58d9SAndroid Build Coastguard Worker enable_choose_all: True to choose all items from answer list. 1055*800a58d9SAndroid Build Coastguard Worker 1056*800a58d9SAndroid Build Coastguard Worker Return: 1057*800a58d9SAndroid Build Coastguard Worker List holding the answer(s). 1058*800a58d9SAndroid Build Coastguard Worker """ 1059*800a58d9SAndroid Build Coastguard Worker print("[0] to exit.") 1060*800a58d9SAndroid Build Coastguard Worker start_index = 1 1061*800a58d9SAndroid Build Coastguard Worker max_choice = len(answer_list) 1062*800a58d9SAndroid Build Coastguard Worker 1063*800a58d9SAndroid Build Coastguard Worker for num, item in enumerate(answer_list, start_index): 1064*800a58d9SAndroid Build Coastguard Worker print("[%d] %s" % (num, item)) 1065*800a58d9SAndroid Build Coastguard Worker if enable_choose_all: 1066*800a58d9SAndroid Build Coastguard Worker max_choice += 1 1067*800a58d9SAndroid Build Coastguard Worker print("[%d] for all." % max_choice) 1068*800a58d9SAndroid Build Coastguard Worker 1069*800a58d9SAndroid Build Coastguard Worker choice = -1 1070*800a58d9SAndroid Build Coastguard Worker 1071*800a58d9SAndroid Build Coastguard Worker while True: 1072*800a58d9SAndroid Build Coastguard Worker try: 1073*800a58d9SAndroid Build Coastguard Worker choice = input("Enter your choice[0-%d]: " % max_choice) 1074*800a58d9SAndroid Build Coastguard Worker choice = int(choice) 1075*800a58d9SAndroid Build Coastguard Worker except ValueError: 1076*800a58d9SAndroid Build Coastguard Worker print("'%s' is not a valid integer.", choice) 1077*800a58d9SAndroid Build Coastguard Worker continue 1078*800a58d9SAndroid Build Coastguard Worker # Filter out choices 1079*800a58d9SAndroid Build Coastguard Worker if choice == 0: 1080*800a58d9SAndroid Build Coastguard Worker sys.exit(constants.EXIT_BY_USER) 1081*800a58d9SAndroid Build Coastguard Worker if enable_choose_all and choice == max_choice: 1082*800a58d9SAndroid Build Coastguard Worker return answer_list 1083*800a58d9SAndroid Build Coastguard Worker if choice < 0 or choice > max_choice: 1084*800a58d9SAndroid Build Coastguard Worker print("please choose between 0 and %d" % max_choice) 1085*800a58d9SAndroid Build Coastguard Worker else: 1086*800a58d9SAndroid Build Coastguard Worker return [answer_list[choice-start_index]] 1087*800a58d9SAndroid Build Coastguard Worker 1088*800a58d9SAndroid Build Coastguard Worker 1089*800a58d9SAndroid Build Coastguard Workerdef LaunchVNCFromReport(report, avd_spec, no_prompts=False): 1090*800a58d9SAndroid Build Coastguard Worker """Launch vnc client according to the instances report. 1091*800a58d9SAndroid Build Coastguard Worker 1092*800a58d9SAndroid Build Coastguard Worker Args: 1093*800a58d9SAndroid Build Coastguard Worker report: Report object, that stores and generates report. 1094*800a58d9SAndroid Build Coastguard Worker avd_spec: AVDSpec object that tells us what we're going to create. 1095*800a58d9SAndroid Build Coastguard Worker no_prompts: Boolean, True to skip all prompts. 1096*800a58d9SAndroid Build Coastguard Worker """ 1097*800a58d9SAndroid Build Coastguard Worker for device in report.data.get("devices", []): 1098*800a58d9SAndroid Build Coastguard Worker if device.get(constants.VNC_PORT): 1099*800a58d9SAndroid Build Coastguard Worker LaunchVncClient(device.get(constants.VNC_PORT), 1100*800a58d9SAndroid Build Coastguard Worker avd_width=avd_spec.hw_property["x_res"], 1101*800a58d9SAndroid Build Coastguard Worker avd_height=avd_spec.hw_property["y_res"], 1102*800a58d9SAndroid Build Coastguard Worker no_prompts=no_prompts) 1103*800a58d9SAndroid Build Coastguard Worker else: 1104*800a58d9SAndroid Build Coastguard Worker PrintColorString("No VNC port specified, skipping VNC startup.", 1105*800a58d9SAndroid Build Coastguard Worker TextColors.FAIL) 1106*800a58d9SAndroid Build Coastguard Worker 1107*800a58d9SAndroid Build Coastguard Worker 1108*800a58d9SAndroid Build Coastguard Workerdef LaunchBrowserFromReport(report): 1109*800a58d9SAndroid Build Coastguard Worker """Open browser when autoconnect to webrtc according to the instances report. 1110*800a58d9SAndroid Build Coastguard Worker 1111*800a58d9SAndroid Build Coastguard Worker Args: 1112*800a58d9SAndroid Build Coastguard Worker report: Report object, that stores and generates report. 1113*800a58d9SAndroid Build Coastguard Worker """ 1114*800a58d9SAndroid Build Coastguard Worker for device in report.data.get("devices", []): 1115*800a58d9SAndroid Build Coastguard Worker if device.get("ip"): 1116*800a58d9SAndroid Build Coastguard Worker LaunchBrowser(constants.WEBRTC_LOCAL_HOST, 1117*800a58d9SAndroid Build Coastguard Worker device.get(constants.WEBRTC_PORT, 1118*800a58d9SAndroid Build Coastguard Worker constants.WEBRTC_LOCAL_PORT)) 1119*800a58d9SAndroid Build Coastguard Worker 1120*800a58d9SAndroid Build Coastguard Worker 1121*800a58d9SAndroid Build Coastguard Workerdef LaunchBrowser(ip_addr, port): 1122*800a58d9SAndroid Build Coastguard Worker """Launch browser to connect the webrtc AVD. 1123*800a58d9SAndroid Build Coastguard Worker 1124*800a58d9SAndroid Build Coastguard Worker Args: 1125*800a58d9SAndroid Build Coastguard Worker ip_addr: String, use to connect to webrtc AVD on the instance. 1126*800a58d9SAndroid Build Coastguard Worker port: Integer, port number. 1127*800a58d9SAndroid Build Coastguard Worker """ 1128*800a58d9SAndroid Build Coastguard Worker webrtc_link = _WEBRTC_URL % { 1129*800a58d9SAndroid Build Coastguard Worker "webrtc_ip": ip_addr, 1130*800a58d9SAndroid Build Coastguard Worker "webrtc_port": port} 1131*800a58d9SAndroid Build Coastguard Worker PrintColorString("WebRTC AVD URL: %s "% webrtc_link) 1132*800a58d9SAndroid Build Coastguard Worker if os.environ.get(_ENV_DISPLAY, None): 1133*800a58d9SAndroid Build Coastguard Worker webbrowser.open_new_tab(webrtc_link) 1134*800a58d9SAndroid Build Coastguard Worker else: 1135*800a58d9SAndroid Build Coastguard Worker PrintColorString("Remote terminal can't support launch webbrowser.", 1136*800a58d9SAndroid Build Coastguard Worker TextColors.FAIL) 1137*800a58d9SAndroid Build Coastguard Worker 1138*800a58d9SAndroid Build Coastguard Worker 1139*800a58d9SAndroid Build Coastguard Workerdef LaunchVncClient(port, avd_width=None, avd_height=None, no_prompts=False): 1140*800a58d9SAndroid Build Coastguard Worker """Launch ssvnc. 1141*800a58d9SAndroid Build Coastguard Worker 1142*800a58d9SAndroid Build Coastguard Worker Args: 1143*800a58d9SAndroid Build Coastguard Worker port: Integer, port number. 1144*800a58d9SAndroid Build Coastguard Worker avd_width: String, the width of avd. 1145*800a58d9SAndroid Build Coastguard Worker avd_height: String, the height of avd. 1146*800a58d9SAndroid Build Coastguard Worker no_prompts: Boolean, True to skip all prompts. 1147*800a58d9SAndroid Build Coastguard Worker """ 1148*800a58d9SAndroid Build Coastguard Worker try: 1149*800a58d9SAndroid Build Coastguard Worker os.environ[_ENV_DISPLAY] 1150*800a58d9SAndroid Build Coastguard Worker except KeyError: 1151*800a58d9SAndroid Build Coastguard Worker PrintColorString("Remote terminal can't support VNC. " 1152*800a58d9SAndroid Build Coastguard Worker "Skipping VNC startup. " 1153*800a58d9SAndroid Build Coastguard Worker "VNC server is listening at 127.0.0.1:{}.".format(port), 1154*800a58d9SAndroid Build Coastguard Worker TextColors.FAIL) 1155*800a58d9SAndroid Build Coastguard Worker return 1156*800a58d9SAndroid Build Coastguard Worker 1157*800a58d9SAndroid Build Coastguard Worker if IsSupportedPlatform() and not FindExecutable(_VNC_BIN): 1158*800a58d9SAndroid Build Coastguard Worker if no_prompts or GetUserAnswerYes(_CONFIRM_CONTINUE): 1159*800a58d9SAndroid Build Coastguard Worker try: 1160*800a58d9SAndroid Build Coastguard Worker PrintColorString("Installing ssvnc vnc client... ", end="") 1161*800a58d9SAndroid Build Coastguard Worker sys.stdout.flush() 1162*800a58d9SAndroid Build Coastguard Worker CheckOutput(_CMD_INSTALL_SSVNC, shell=True) 1163*800a58d9SAndroid Build Coastguard Worker PrintColorString("Done", TextColors.OKGREEN) 1164*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as cpe: 1165*800a58d9SAndroid Build Coastguard Worker PrintColorString("Failed to install ssvnc: %s" % 1166*800a58d9SAndroid Build Coastguard Worker cpe.output, TextColors.FAIL) 1167*800a58d9SAndroid Build Coastguard Worker return 1168*800a58d9SAndroid Build Coastguard Worker else: 1169*800a58d9SAndroid Build Coastguard Worker return 1170*800a58d9SAndroid Build Coastguard Worker ssvnc_env = os.environ.copy() 1171*800a58d9SAndroid Build Coastguard Worker ssvnc_env.update(_SSVNC_ENV_VARS) 1172*800a58d9SAndroid Build Coastguard Worker # Override SSVNC_SCALE 1173*800a58d9SAndroid Build Coastguard Worker if avd_width or avd_height: 1174*800a58d9SAndroid Build Coastguard Worker scale_ratio = CalculateVNCScreenRatio(avd_width, avd_height) 1175*800a58d9SAndroid Build Coastguard Worker ssvnc_env["SSVNC_SCALE"] = str(scale_ratio) 1176*800a58d9SAndroid Build Coastguard Worker logger.debug("SSVNC_SCALE:%s", scale_ratio) 1177*800a58d9SAndroid Build Coastguard Worker 1178*800a58d9SAndroid Build Coastguard Worker ssvnc_args = _CMD_START_VNC % {"bin": FindExecutable(_VNC_BIN), 1179*800a58d9SAndroid Build Coastguard Worker "port": port} 1180*800a58d9SAndroid Build Coastguard Worker subprocess.Popen(ssvnc_args.split(), env=ssvnc_env) 1181*800a58d9SAndroid Build Coastguard Worker 1182*800a58d9SAndroid Build Coastguard Worker 1183*800a58d9SAndroid Build Coastguard Workerdef PrintDeviceSummary(report): 1184*800a58d9SAndroid Build Coastguard Worker """Display summary of devices. 1185*800a58d9SAndroid Build Coastguard Worker 1186*800a58d9SAndroid Build Coastguard Worker -Display device details from the report instance. 1187*800a58d9SAndroid Build Coastguard Worker report example: 1188*800a58d9SAndroid Build Coastguard Worker 'data': [{'devices':[{'instance_name': 'ins-f6a397-none-53363', 1189*800a58d9SAndroid Build Coastguard Worker 'ip': u'35.234.10.162'}]}] 1190*800a58d9SAndroid Build Coastguard Worker -Display error message from report.error. 1191*800a58d9SAndroid Build Coastguard Worker 1192*800a58d9SAndroid Build Coastguard Worker Args: 1193*800a58d9SAndroid Build Coastguard Worker report: A Report instance. 1194*800a58d9SAndroid Build Coastguard Worker """ 1195*800a58d9SAndroid Build Coastguard Worker PrintColorString("\n") 1196*800a58d9SAndroid Build Coastguard Worker PrintColorString("Device summary:") 1197*800a58d9SAndroid Build Coastguard Worker for device in report.data.get("devices", []): 1198*800a58d9SAndroid Build Coastguard Worker adb_serial = device.get(constants.DEVICE_SERIAL) 1199*800a58d9SAndroid Build Coastguard Worker if not adb_serial: 1200*800a58d9SAndroid Build Coastguard Worker adb_port = device.get("adb_port") 1201*800a58d9SAndroid Build Coastguard Worker if adb_port: 1202*800a58d9SAndroid Build Coastguard Worker adb_serial = constants.LOCALHOST_ADB_SERIAL % adb_port 1203*800a58d9SAndroid Build Coastguard Worker else: 1204*800a58d9SAndroid Build Coastguard Worker adb_serial = "(None)" 1205*800a58d9SAndroid Build Coastguard Worker 1206*800a58d9SAndroid Build Coastguard Worker instance_name = device.get("instance_name") 1207*800a58d9SAndroid Build Coastguard Worker instance_ip = device.get("ip") 1208*800a58d9SAndroid Build Coastguard Worker instance_details = "" if not instance_name else "(%s[%s])" % ( 1209*800a58d9SAndroid Build Coastguard Worker instance_name, instance_ip) 1210*800a58d9SAndroid Build Coastguard Worker PrintColorString(f" - device serial: {adb_serial} {instance_details}") 1211*800a58d9SAndroid Build Coastguard Worker PrintColorString("\n") 1212*800a58d9SAndroid Build Coastguard Worker PrintColorString("Note: To ensure Tradefed uses this AVD, please run:") 1213*800a58d9SAndroid Build Coastguard Worker PrintColorString("\texport ANDROID_SERIAL=%s" % adb_serial) 1214*800a58d9SAndroid Build Coastguard Worker ssh_command = device.get("ssh_command") 1215*800a58d9SAndroid Build Coastguard Worker if ssh_command: 1216*800a58d9SAndroid Build Coastguard Worker PrintColorString("\n") 1217*800a58d9SAndroid Build Coastguard Worker PrintColorString("Note: To ssh connect to the device, please run:") 1218*800a58d9SAndroid Build Coastguard Worker PrintColorString(f"\tssh command: {ssh_command}") 1219*800a58d9SAndroid Build Coastguard Worker screen_command = device.get("screen_command") 1220*800a58d9SAndroid Build Coastguard Worker if screen_command: 1221*800a58d9SAndroid Build Coastguard Worker PrintColorString("\n") 1222*800a58d9SAndroid Build Coastguard Worker PrintColorString("Note: To access the console, please run:") 1223*800a58d9SAndroid Build Coastguard Worker PrintColorString(f"\tscreen command: {screen_command}") 1224*800a58d9SAndroid Build Coastguard Worker 1225*800a58d9SAndroid Build Coastguard Worker # TODO(b/117245508): Help user to delete instance if it got created. 1226*800a58d9SAndroid Build Coastguard Worker if report.errors: 1227*800a58d9SAndroid Build Coastguard Worker error_msg = "\n".join(report.errors) 1228*800a58d9SAndroid Build Coastguard Worker PrintColorString("Fail in:\n%s\n" % error_msg, TextColors.FAIL) 1229*800a58d9SAndroid Build Coastguard Worker 1230*800a58d9SAndroid Build Coastguard Worker 1231*800a58d9SAndroid Build Coastguard Worker# pylint: disable=import-outside-toplevel 1232*800a58d9SAndroid Build Coastguard Workerdef CalculateVNCScreenRatio(avd_width, avd_height): 1233*800a58d9SAndroid Build Coastguard Worker """calculate the vnc screen scale ratio to fit into user's monitor. 1234*800a58d9SAndroid Build Coastguard Worker 1235*800a58d9SAndroid Build Coastguard Worker Args: 1236*800a58d9SAndroid Build Coastguard Worker avd_width: String, the width of avd. 1237*800a58d9SAndroid Build Coastguard Worker avd_height: String, the height of avd. 1238*800a58d9SAndroid Build Coastguard Worker Return: 1239*800a58d9SAndroid Build Coastguard Worker Float, scale ratio for vnc client. 1240*800a58d9SAndroid Build Coastguard Worker """ 1241*800a58d9SAndroid Build Coastguard Worker try: 1242*800a58d9SAndroid Build Coastguard Worker import Tkinter 1243*800a58d9SAndroid Build Coastguard Worker # Some python interpreters may not be configured for Tk, just return default scale ratio. 1244*800a58d9SAndroid Build Coastguard Worker except ImportError: 1245*800a58d9SAndroid Build Coastguard Worker try: 1246*800a58d9SAndroid Build Coastguard Worker import tkinter as Tkinter 1247*800a58d9SAndroid Build Coastguard Worker except ImportError: 1248*800a58d9SAndroid Build Coastguard Worker PrintColorString( 1249*800a58d9SAndroid Build Coastguard Worker "no module named tkinter, vnc display scale were not be fit." 1250*800a58d9SAndroid Build Coastguard Worker "please run 'sudo apt-get install python3-tk' to install it.") 1251*800a58d9SAndroid Build Coastguard Worker return _DEFAULT_DISPLAY_SCALE 1252*800a58d9SAndroid Build Coastguard Worker root = Tkinter.Tk() 1253*800a58d9SAndroid Build Coastguard Worker margin = 100 # leave some space on user's monitor. 1254*800a58d9SAndroid Build Coastguard Worker screen_height = root.winfo_screenheight() - margin 1255*800a58d9SAndroid Build Coastguard Worker screen_width = root.winfo_screenwidth() - margin 1256*800a58d9SAndroid Build Coastguard Worker 1257*800a58d9SAndroid Build Coastguard Worker scale_h = _DEFAULT_DISPLAY_SCALE 1258*800a58d9SAndroid Build Coastguard Worker scale_w = _DEFAULT_DISPLAY_SCALE 1259*800a58d9SAndroid Build Coastguard Worker if float(screen_height) < float(avd_height): 1260*800a58d9SAndroid Build Coastguard Worker scale_h = round(float(screen_height) / float(avd_height), 1) 1261*800a58d9SAndroid Build Coastguard Worker 1262*800a58d9SAndroid Build Coastguard Worker if float(screen_width) < float(avd_width): 1263*800a58d9SAndroid Build Coastguard Worker scale_w = round(float(screen_width) / float(avd_width), 1) 1264*800a58d9SAndroid Build Coastguard Worker 1265*800a58d9SAndroid Build Coastguard Worker logger.debug("scale_h: %s (screen_h: %s/avd_h: %s)," 1266*800a58d9SAndroid Build Coastguard Worker " scale_w: %s (screen_w: %s/avd_w: %s)", 1267*800a58d9SAndroid Build Coastguard Worker scale_h, screen_height, avd_height, 1268*800a58d9SAndroid Build Coastguard Worker scale_w, screen_width, avd_width) 1269*800a58d9SAndroid Build Coastguard Worker 1270*800a58d9SAndroid Build Coastguard Worker # Return the larger scale-down ratio. 1271*800a58d9SAndroid Build Coastguard Worker return scale_h if scale_h < scale_w else scale_w 1272*800a58d9SAndroid Build Coastguard Worker 1273*800a58d9SAndroid Build Coastguard Worker 1274*800a58d9SAndroid Build Coastguard Workerdef IsCommandRunning(command): 1275*800a58d9SAndroid Build Coastguard Worker """Check if command is running. 1276*800a58d9SAndroid Build Coastguard Worker 1277*800a58d9SAndroid Build Coastguard Worker Args: 1278*800a58d9SAndroid Build Coastguard Worker command: String of command name. 1279*800a58d9SAndroid Build Coastguard Worker 1280*800a58d9SAndroid Build Coastguard Worker Returns: 1281*800a58d9SAndroid Build Coastguard Worker Boolean, True if command is running. False otherwise. 1282*800a58d9SAndroid Build Coastguard Worker """ 1283*800a58d9SAndroid Build Coastguard Worker try: 1284*800a58d9SAndroid Build Coastguard Worker with open(os.devnull, "w") as dev_null: 1285*800a58d9SAndroid Build Coastguard Worker subprocess.check_call([constants.CMD_PGREP, "-af", command], 1286*800a58d9SAndroid Build Coastguard Worker stderr=dev_null, stdout=dev_null) 1287*800a58d9SAndroid Build Coastguard Worker return True 1288*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 1289*800a58d9SAndroid Build Coastguard Worker return False 1290*800a58d9SAndroid Build Coastguard Worker 1291*800a58d9SAndroid Build Coastguard Worker 1292*800a58d9SAndroid Build Coastguard Workerdef AddUserGroupsToCmd(cmd, user_groups): 1293*800a58d9SAndroid Build Coastguard Worker """Add the user groups to the command if necessary. 1294*800a58d9SAndroid Build Coastguard Worker 1295*800a58d9SAndroid Build Coastguard Worker As part of local host setup to enable local instance support, the user is 1296*800a58d9SAndroid Build Coastguard Worker added to certain groups. For those settings to take effect systemwide 1297*800a58d9SAndroid Build Coastguard Worker requires the user to log out and log back in. In the scenario where the 1298*800a58d9SAndroid Build Coastguard Worker user has run setup and hasn't logged out, we still want them to be able to 1299*800a58d9SAndroid Build Coastguard Worker launch a local instance so add the user to the groups as part of the 1300*800a58d9SAndroid Build Coastguard Worker command to ensure success. 1301*800a58d9SAndroid Build Coastguard Worker 1302*800a58d9SAndroid Build Coastguard Worker The reason using here-doc instead of '&' is all operations need to be ran in 1303*800a58d9SAndroid Build Coastguard Worker ths same pid. Here's an example cmd: 1304*800a58d9SAndroid Build Coastguard Worker $ sg kvm << EOF 1305*800a58d9SAndroid Build Coastguard Worker sg libvirt 1306*800a58d9SAndroid Build Coastguard Worker sg cvdnetwork 1307*800a58d9SAndroid Build Coastguard Worker launch_cvd --cpus 2 --x_res 1280 --y_res 720 --dpi 160 --memory_mb 4096 1308*800a58d9SAndroid Build Coastguard Worker EOF 1309*800a58d9SAndroid Build Coastguard Worker 1310*800a58d9SAndroid Build Coastguard Worker Args: 1311*800a58d9SAndroid Build Coastguard Worker cmd: String of the command to prepend the user groups to. 1312*800a58d9SAndroid Build Coastguard Worker user_groups: List of user groups name.(String) 1313*800a58d9SAndroid Build Coastguard Worker 1314*800a58d9SAndroid Build Coastguard Worker Returns: 1315*800a58d9SAndroid Build Coastguard Worker String of the command with the user groups prepended to it if necessary, 1316*800a58d9SAndroid Build Coastguard Worker otherwise the same existing command. 1317*800a58d9SAndroid Build Coastguard Worker """ 1318*800a58d9SAndroid Build Coastguard Worker user_group_cmd = "" 1319*800a58d9SAndroid Build Coastguard Worker if not CheckUserInGroups(user_groups): 1320*800a58d9SAndroid Build Coastguard Worker logger.debug("Need to add user groups to the command") 1321*800a58d9SAndroid Build Coastguard Worker for idx, group in enumerate(user_groups): 1322*800a58d9SAndroid Build Coastguard Worker user_group_cmd += _CMD_SG + group 1323*800a58d9SAndroid Build Coastguard Worker if idx == 0: 1324*800a58d9SAndroid Build Coastguard Worker user_group_cmd += " <<EOF\n" 1325*800a58d9SAndroid Build Coastguard Worker else: 1326*800a58d9SAndroid Build Coastguard Worker user_group_cmd += "\n" 1327*800a58d9SAndroid Build Coastguard Worker cmd += "\nEOF" 1328*800a58d9SAndroid Build Coastguard Worker user_group_cmd += cmd 1329*800a58d9SAndroid Build Coastguard Worker logger.debug("user group cmd: %s", user_group_cmd) 1330*800a58d9SAndroid Build Coastguard Worker return user_group_cmd 1331*800a58d9SAndroid Build Coastguard Worker 1332*800a58d9SAndroid Build Coastguard Worker 1333*800a58d9SAndroid Build Coastguard Workerdef CheckUserInGroups(group_name_list): 1334*800a58d9SAndroid Build Coastguard Worker """Check if the current user is in the group. 1335*800a58d9SAndroid Build Coastguard Worker 1336*800a58d9SAndroid Build Coastguard Worker Args: 1337*800a58d9SAndroid Build Coastguard Worker group_name_list: The list of group name. 1338*800a58d9SAndroid Build Coastguard Worker Returns: 1339*800a58d9SAndroid Build Coastguard Worker True if current user is in all the groups. 1340*800a58d9SAndroid Build Coastguard Worker """ 1341*800a58d9SAndroid Build Coastguard Worker logger.info("Checking if user is in following groups: %s", group_name_list) 1342*800a58d9SAndroid Build Coastguard Worker all_groups = [g.gr_name for g in grp.getgrall()] 1343*800a58d9SAndroid Build Coastguard Worker for group in group_name_list: 1344*800a58d9SAndroid Build Coastguard Worker if group not in all_groups: 1345*800a58d9SAndroid Build Coastguard Worker logger.info("This group doesn't exist: %s", group) 1346*800a58d9SAndroid Build Coastguard Worker return False 1347*800a58d9SAndroid Build Coastguard Worker if getpass.getuser() not in grp.getgrnam(group).gr_mem: 1348*800a58d9SAndroid Build Coastguard Worker logger.info("Current user isn't in this group: %s", group) 1349*800a58d9SAndroid Build Coastguard Worker return False 1350*800a58d9SAndroid Build Coastguard Worker return True 1351*800a58d9SAndroid Build Coastguard Worker 1352*800a58d9SAndroid Build Coastguard Worker 1353*800a58d9SAndroid Build Coastguard Workerdef IsSupportedPlatform(print_warning=False): 1354*800a58d9SAndroid Build Coastguard Worker """Check if user's os is the supported platform. 1355*800a58d9SAndroid Build Coastguard Worker 1356*800a58d9SAndroid Build Coastguard Worker platform.version() return such as '#1 SMP Debian 5.6.14-1rodete2...' 1357*800a58d9SAndroid Build Coastguard Worker and use to judge supported or not. 1358*800a58d9SAndroid Build Coastguard Worker 1359*800a58d9SAndroid Build Coastguard Worker Args: 1360*800a58d9SAndroid Build Coastguard Worker print_warning: Boolean, print the unsupported warning 1361*800a58d9SAndroid Build Coastguard Worker if True. 1362*800a58d9SAndroid Build Coastguard Worker Returns: 1363*800a58d9SAndroid Build Coastguard Worker Boolean, True if user is using supported platform. 1364*800a58d9SAndroid Build Coastguard Worker """ 1365*800a58d9SAndroid Build Coastguard Worker system = platform.system() 1366*800a58d9SAndroid Build Coastguard Worker # TODO(b/161085678): After python3 fully migrated, then use distro to fix. 1367*800a58d9SAndroid Build Coastguard Worker platform_supported = False 1368*800a58d9SAndroid Build Coastguard Worker if system in _SUPPORTED_SYSTEMS_AND_DISTS: 1369*800a58d9SAndroid Build Coastguard Worker for dist in _SUPPORTED_SYSTEMS_AND_DISTS[system]: 1370*800a58d9SAndroid Build Coastguard Worker if dist in platform.version(): 1371*800a58d9SAndroid Build Coastguard Worker platform_supported = True 1372*800a58d9SAndroid Build Coastguard Worker break 1373*800a58d9SAndroid Build Coastguard Worker 1374*800a58d9SAndroid Build Coastguard Worker logger.info("Updated supported system and dists: %s", 1375*800a58d9SAndroid Build Coastguard Worker _SUPPORTED_SYSTEMS_AND_DISTS) 1376*800a58d9SAndroid Build Coastguard Worker platform_supported_msg = ("%s[%s] %s supported platform" % 1377*800a58d9SAndroid Build Coastguard Worker (system, 1378*800a58d9SAndroid Build Coastguard Worker platform.version(), 1379*800a58d9SAndroid Build Coastguard Worker "is a" if platform_supported else "is not a")) 1380*800a58d9SAndroid Build Coastguard Worker if print_warning and not platform_supported: 1381*800a58d9SAndroid Build Coastguard Worker PrintColorString(platform_supported_msg, TextColors.WARNING) 1382*800a58d9SAndroid Build Coastguard Worker else: 1383*800a58d9SAndroid Build Coastguard Worker logger.info(platform_supported_msg) 1384*800a58d9SAndroid Build Coastguard Worker 1385*800a58d9SAndroid Build Coastguard Worker return platform_supported 1386*800a58d9SAndroid Build Coastguard Worker 1387*800a58d9SAndroid Build Coastguard Workerdef IsSupportedKvm(): 1388*800a58d9SAndroid Build Coastguard Worker """Check if support kvm. 1389*800a58d9SAndroid Build Coastguard Worker 1390*800a58d9SAndroid Build Coastguard Worker Returns: 1391*800a58d9SAndroid Build Coastguard Worker True if environment supported kvm. 1392*800a58d9SAndroid Build Coastguard Worker """ 1393*800a58d9SAndroid Build Coastguard Worker if os.path.exists(_KVM_PATH): 1394*800a58d9SAndroid Build Coastguard Worker return True 1395*800a58d9SAndroid Build Coastguard Worker 1396*800a58d9SAndroid Build Coastguard Worker PrintColorString( 1397*800a58d9SAndroid Build Coastguard Worker "The environment doesn't support virtualization. Please run " 1398*800a58d9SAndroid Build Coastguard Worker "the remote instance by \"acloud create\" instead. If you want to " 1399*800a58d9SAndroid Build Coastguard Worker "launch AVD on the local instance, Please refer to http://go/" 1400*800a58d9SAndroid Build Coastguard Worker "acloud-cloudtop#acloud-create-local-instance-on-the-cloudtop", 1401*800a58d9SAndroid Build Coastguard Worker TextColors.FAIL) 1402*800a58d9SAndroid Build Coastguard Worker return False 1403*800a58d9SAndroid Build Coastguard Worker 1404*800a58d9SAndroid Build Coastguard Workerdef GetDistDir(): 1405*800a58d9SAndroid Build Coastguard Worker """Return the absolute path to the dist dir.""" 1406*800a58d9SAndroid Build Coastguard Worker android_build_top = os.environ.get(constants.ENV_ANDROID_BUILD_TOP) 1407*800a58d9SAndroid Build Coastguard Worker if not android_build_top: 1408*800a58d9SAndroid Build Coastguard Worker return None 1409*800a58d9SAndroid Build Coastguard Worker dist_cmd = GET_BUILD_VAR_CMD[:] 1410*800a58d9SAndroid Build Coastguard Worker dist_cmd.append(_DIST_DIR) 1411*800a58d9SAndroid Build Coastguard Worker try: 1412*800a58d9SAndroid Build Coastguard Worker dist_dir = CheckOutput(dist_cmd, cwd=android_build_top) 1413*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 1414*800a58d9SAndroid Build Coastguard Worker return None 1415*800a58d9SAndroid Build Coastguard Worker return os.path.join(android_build_top, dist_dir.strip()) 1416*800a58d9SAndroid Build Coastguard Worker 1417*800a58d9SAndroid Build Coastguard Worker 1418*800a58d9SAndroid Build Coastguard Workerdef CleanupProcess(pattern): 1419*800a58d9SAndroid Build Coastguard Worker """Cleanup process with pattern. 1420*800a58d9SAndroid Build Coastguard Worker 1421*800a58d9SAndroid Build Coastguard Worker Args: 1422*800a58d9SAndroid Build Coastguard Worker pattern: String, string of process pattern. 1423*800a58d9SAndroid Build Coastguard Worker """ 1424*800a58d9SAndroid Build Coastguard Worker if IsCommandRunning(pattern): 1425*800a58d9SAndroid Build Coastguard Worker command_kill = _CMD_KILL + [pattern] 1426*800a58d9SAndroid Build Coastguard Worker subprocess.check_call(command_kill) 1427*800a58d9SAndroid Build Coastguard Worker 1428*800a58d9SAndroid Build Coastguard Worker 1429*800a58d9SAndroid Build Coastguard Workerdef TimeoutException(timeout_secs, timeout_error=_DEFAULT_TIMEOUT_ERR): 1430*800a58d9SAndroid Build Coastguard Worker """Decorater which function timeout setup and raise custom exception. 1431*800a58d9SAndroid Build Coastguard Worker 1432*800a58d9SAndroid Build Coastguard Worker Args: 1433*800a58d9SAndroid Build Coastguard Worker timeout_secs: Number of maximum seconds of waiting time. 1434*800a58d9SAndroid Build Coastguard Worker timeout_error: String to describe timeout exception. 1435*800a58d9SAndroid Build Coastguard Worker 1436*800a58d9SAndroid Build Coastguard Worker Returns: 1437*800a58d9SAndroid Build Coastguard Worker The function wrapper. 1438*800a58d9SAndroid Build Coastguard Worker """ 1439*800a58d9SAndroid Build Coastguard Worker if timeout_error == _DEFAULT_TIMEOUT_ERR: 1440*800a58d9SAndroid Build Coastguard Worker timeout_error = timeout_error % timeout_secs 1441*800a58d9SAndroid Build Coastguard Worker 1442*800a58d9SAndroid Build Coastguard Worker def _Wrapper(func): 1443*800a58d9SAndroid Build Coastguard Worker # pylint: disable=unused-argument 1444*800a58d9SAndroid Build Coastguard Worker def _HandleTimeout(signum, frame): 1445*800a58d9SAndroid Build Coastguard Worker raise errors.FunctionTimeoutError(timeout_error) 1446*800a58d9SAndroid Build Coastguard Worker 1447*800a58d9SAndroid Build Coastguard Worker def _FunctionWrapper(*args, **kwargs): 1448*800a58d9SAndroid Build Coastguard Worker signal.signal(signal.SIGALRM, _HandleTimeout) 1449*800a58d9SAndroid Build Coastguard Worker signal.alarm(timeout_secs) 1450*800a58d9SAndroid Build Coastguard Worker try: 1451*800a58d9SAndroid Build Coastguard Worker result = func(*args, **kwargs) 1452*800a58d9SAndroid Build Coastguard Worker finally: 1453*800a58d9SAndroid Build Coastguard Worker signal.alarm(0) 1454*800a58d9SAndroid Build Coastguard Worker return result 1455*800a58d9SAndroid Build Coastguard Worker 1456*800a58d9SAndroid Build Coastguard Worker return _FunctionWrapper 1457*800a58d9SAndroid Build Coastguard Worker 1458*800a58d9SAndroid Build Coastguard Worker return _Wrapper 1459*800a58d9SAndroid Build Coastguard Worker 1460*800a58d9SAndroid Build Coastguard Worker 1461*800a58d9SAndroid Build Coastguard Workerdef GetBuildEnvironmentVariable(variable_name): 1462*800a58d9SAndroid Build Coastguard Worker """Get build environment variable. 1463*800a58d9SAndroid Build Coastguard Worker 1464*800a58d9SAndroid Build Coastguard Worker Args: 1465*800a58d9SAndroid Build Coastguard Worker variable_name: String of variable name. 1466*800a58d9SAndroid Build Coastguard Worker 1467*800a58d9SAndroid Build Coastguard Worker Returns: 1468*800a58d9SAndroid Build Coastguard Worker String, the value of the variable. 1469*800a58d9SAndroid Build Coastguard Worker 1470*800a58d9SAndroid Build Coastguard Worker Raises: 1471*800a58d9SAndroid Build Coastguard Worker errors.GetAndroidBuildEnvVarError: No environment variable found. 1472*800a58d9SAndroid Build Coastguard Worker """ 1473*800a58d9SAndroid Build Coastguard Worker try: 1474*800a58d9SAndroid Build Coastguard Worker return os.environ[variable_name] 1475*800a58d9SAndroid Build Coastguard Worker except KeyError as no_env_error: 1476*800a58d9SAndroid Build Coastguard Worker raise errors.GetAndroidBuildEnvVarError( 1477*800a58d9SAndroid Build Coastguard Worker "Could not get environment var: %s\n" 1478*800a58d9SAndroid Build Coastguard Worker "Try to run 'source build/envsetup.sh && lunch <target>'" 1479*800a58d9SAndroid Build Coastguard Worker % variable_name 1480*800a58d9SAndroid Build Coastguard Worker ) from no_env_error 1481*800a58d9SAndroid Build Coastguard Worker 1482*800a58d9SAndroid Build Coastguard Worker 1483*800a58d9SAndroid Build Coastguard Worker# pylint: disable=no-member,import-outside-toplevel 1484*800a58d9SAndroid Build Coastguard Workerdef FindExecutable(filename): 1485*800a58d9SAndroid Build Coastguard Worker """A compatibility function to find execution file path. 1486*800a58d9SAndroid Build Coastguard Worker 1487*800a58d9SAndroid Build Coastguard Worker Args: 1488*800a58d9SAndroid Build Coastguard Worker filename: String of execution filename. 1489*800a58d9SAndroid Build Coastguard Worker 1490*800a58d9SAndroid Build Coastguard Worker Returns: 1491*800a58d9SAndroid Build Coastguard Worker String: execution file path. 1492*800a58d9SAndroid Build Coastguard Worker """ 1493*800a58d9SAndroid Build Coastguard Worker try: 1494*800a58d9SAndroid Build Coastguard Worker from distutils.spawn import find_executable 1495*800a58d9SAndroid Build Coastguard Worker return find_executable(filename) 1496*800a58d9SAndroid Build Coastguard Worker except ImportError: 1497*800a58d9SAndroid Build Coastguard Worker return shutil.which(filename) 1498*800a58d9SAndroid Build Coastguard Worker 1499*800a58d9SAndroid Build Coastguard Worker 1500*800a58d9SAndroid Build Coastguard Workerdef GetDictItems(namedtuple_object): 1501*800a58d9SAndroid Build Coastguard Worker """A compatibility function to access the OrdereDict object from the given namedtuple object. 1502*800a58d9SAndroid Build Coastguard Worker 1503*800a58d9SAndroid Build Coastguard Worker Args: 1504*800a58d9SAndroid Build Coastguard Worker namedtuple_object: namedtuple object. 1505*800a58d9SAndroid Build Coastguard Worker 1506*800a58d9SAndroid Build Coastguard Worker Returns: 1507*800a58d9SAndroid Build Coastguard Worker collections.namedtuple._asdict().items() when using python3. 1508*800a58d9SAndroid Build Coastguard Worker """ 1509*800a58d9SAndroid Build Coastguard Worker return namedtuple_object._asdict().items() 1510*800a58d9SAndroid Build Coastguard Worker 1511*800a58d9SAndroid Build Coastguard Worker 1512*800a58d9SAndroid Build Coastguard Workerdef CleanupSSVncviewer(vnc_port): 1513*800a58d9SAndroid Build Coastguard Worker """Cleanup the old disconnected ssvnc viewer. 1514*800a58d9SAndroid Build Coastguard Worker 1515*800a58d9SAndroid Build Coastguard Worker Args: 1516*800a58d9SAndroid Build Coastguard Worker vnc_port: Integer, port number of vnc. 1517*800a58d9SAndroid Build Coastguard Worker """ 1518*800a58d9SAndroid Build Coastguard Worker ssvnc_viewer_pattern = _SSVNC_VIEWER_PATTERN % {"vnc_port":vnc_port} 1519*800a58d9SAndroid Build Coastguard Worker CleanupProcess(ssvnc_viewer_pattern) 1520*800a58d9SAndroid Build Coastguard Worker 1521*800a58d9SAndroid Build Coastguard Worker 1522*800a58d9SAndroid Build Coastguard Workerdef CheckOutput(cmd, **kwargs): 1523*800a58d9SAndroid Build Coastguard Worker """Call subprocess.check_output to get output. 1524*800a58d9SAndroid Build Coastguard Worker 1525*800a58d9SAndroid Build Coastguard Worker The subprocess.check_output return type is "bytes" in python 3, we have 1526*800a58d9SAndroid Build Coastguard Worker to convert bytes as string with .decode() in advance. 1527*800a58d9SAndroid Build Coastguard Worker 1528*800a58d9SAndroid Build Coastguard Worker Args: 1529*800a58d9SAndroid Build Coastguard Worker cmd: String of command. 1530*800a58d9SAndroid Build Coastguard Worker **kwargs: dictionary of keyword based args to pass to func. 1531*800a58d9SAndroid Build Coastguard Worker 1532*800a58d9SAndroid Build Coastguard Worker Return: 1533*800a58d9SAndroid Build Coastguard Worker String to command output. 1534*800a58d9SAndroid Build Coastguard Worker """ 1535*800a58d9SAndroid Build Coastguard Worker return subprocess.check_output(cmd, **kwargs).decode() 1536*800a58d9SAndroid Build Coastguard Worker 1537*800a58d9SAndroid Build Coastguard Worker 1538*800a58d9SAndroid Build Coastguard Workerdef Popen(*command, **popen_args): 1539*800a58d9SAndroid Build Coastguard Worker """Execute subprocess.Popen command and log the output. 1540*800a58d9SAndroid Build Coastguard Worker 1541*800a58d9SAndroid Build Coastguard Worker This method waits for the process to terminate. It kills the process 1542*800a58d9SAndroid Build Coastguard Worker if it's interrupted due to timeout. 1543*800a58d9SAndroid Build Coastguard Worker 1544*800a58d9SAndroid Build Coastguard Worker Args: 1545*800a58d9SAndroid Build Coastguard Worker command: Strings, the command. 1546*800a58d9SAndroid Build Coastguard Worker popen_kwargs: The arguments to be passed to subprocess.Popen. 1547*800a58d9SAndroid Build Coastguard Worker 1548*800a58d9SAndroid Build Coastguard Worker Raises: 1549*800a58d9SAndroid Build Coastguard Worker errors.SubprocessFail if the process returns non-zero. 1550*800a58d9SAndroid Build Coastguard Worker """ 1551*800a58d9SAndroid Build Coastguard Worker proc = None 1552*800a58d9SAndroid Build Coastguard Worker try: 1553*800a58d9SAndroid Build Coastguard Worker logger.info("Execute %s", command) 1554*800a58d9SAndroid Build Coastguard Worker popen_args["stdin"] = subprocess.PIPE 1555*800a58d9SAndroid Build Coastguard Worker popen_args["stdout"] = subprocess.PIPE 1556*800a58d9SAndroid Build Coastguard Worker popen_args["stderr"] = subprocess.PIPE 1557*800a58d9SAndroid Build Coastguard Worker 1558*800a58d9SAndroid Build Coastguard Worker # Some OTA tools are Python scripts in different versions. The 1559*800a58d9SAndroid Build Coastguard Worker # PYTHONPATH for acloud may be incompatible with the tools. 1560*800a58d9SAndroid Build Coastguard Worker if "env" not in popen_args and "PYTHONPATH" in os.environ: 1561*800a58d9SAndroid Build Coastguard Worker popen_env = os.environ.copy() 1562*800a58d9SAndroid Build Coastguard Worker del popen_env["PYTHONPATH"] 1563*800a58d9SAndroid Build Coastguard Worker popen_args["env"] = popen_env 1564*800a58d9SAndroid Build Coastguard Worker 1565*800a58d9SAndroid Build Coastguard Worker proc = subprocess.Popen(command, **popen_args) 1566*800a58d9SAndroid Build Coastguard Worker stdout, stderr = proc.communicate() 1567*800a58d9SAndroid Build Coastguard Worker logger.info("%s stdout: %s", command[0], stdout) 1568*800a58d9SAndroid Build Coastguard Worker logger.info("%s stderr: %s", command[0], stderr) 1569*800a58d9SAndroid Build Coastguard Worker 1570*800a58d9SAndroid Build Coastguard Worker if proc.returncode != 0: 1571*800a58d9SAndroid Build Coastguard Worker raise errors.SubprocessFail("%s returned %d." % 1572*800a58d9SAndroid Build Coastguard Worker (command[0], proc.returncode)) 1573*800a58d9SAndroid Build Coastguard Worker finally: 1574*800a58d9SAndroid Build Coastguard Worker if proc and proc.poll() is None: 1575*800a58d9SAndroid Build Coastguard Worker logger.info("Kill %s", command[0]) 1576*800a58d9SAndroid Build Coastguard Worker proc.kill() 1577*800a58d9SAndroid Build Coastguard Worker 1578*800a58d9SAndroid Build Coastguard Worker 1579*800a58d9SAndroid Build Coastguard Workerdef SetExecutable(path): 1580*800a58d9SAndroid Build Coastguard Worker """Grant the persmission to execute a file. 1581*800a58d9SAndroid Build Coastguard Worker 1582*800a58d9SAndroid Build Coastguard Worker Args: 1583*800a58d9SAndroid Build Coastguard Worker path: String, the file path. 1584*800a58d9SAndroid Build Coastguard Worker 1585*800a58d9SAndroid Build Coastguard Worker Raises: 1586*800a58d9SAndroid Build Coastguard Worker OSError if any file operation fails. 1587*800a58d9SAndroid Build Coastguard Worker """ 1588*800a58d9SAndroid Build Coastguard Worker mode = os.stat(path).st_mode 1589*800a58d9SAndroid Build Coastguard Worker os.chmod(path, mode | (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH | 1590*800a58d9SAndroid Build Coastguard Worker stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)) 1591*800a58d9SAndroid Build Coastguard Worker 1592*800a58d9SAndroid Build Coastguard Worker 1593*800a58d9SAndroid Build Coastguard Workerdef SetDirectoryTreeExecutable(dir_path): 1594*800a58d9SAndroid Build Coastguard Worker """Grant the permission to execute all files in a directory. 1595*800a58d9SAndroid Build Coastguard Worker 1596*800a58d9SAndroid Build Coastguard Worker Args: 1597*800a58d9SAndroid Build Coastguard Worker dir_path: String, the directory path. 1598*800a58d9SAndroid Build Coastguard Worker 1599*800a58d9SAndroid Build Coastguard Worker Raises: 1600*800a58d9SAndroid Build Coastguard Worker OSError if any file operation fails. 1601*800a58d9SAndroid Build Coastguard Worker """ 1602*800a58d9SAndroid Build Coastguard Worker for parent_dir, _, file_names in os.walk(dir_path): 1603*800a58d9SAndroid Build Coastguard Worker for name in file_names: 1604*800a58d9SAndroid Build Coastguard Worker SetExecutable(os.path.join(parent_dir, name)) 1605*800a58d9SAndroid Build Coastguard Worker 1606*800a58d9SAndroid Build Coastguard Worker 1607*800a58d9SAndroid Build Coastguard Workerdef GetCvdPorts(): 1608*800a58d9SAndroid Build Coastguard Worker """Get CVD ports 1609*800a58d9SAndroid Build Coastguard Worker 1610*800a58d9SAndroid Build Coastguard Worker 1611*800a58d9SAndroid Build Coastguard Worker Returns: 1612*800a58d9SAndroid Build Coastguard Worker ForwardedPorts: vnc port and adb port. 1613*800a58d9SAndroid Build Coastguard Worker """ 1614*800a58d9SAndroid Build Coastguard Worker return AVD_PORT_DICT[constants.TYPE_CF] 1615*800a58d9SAndroid Build Coastguard Worker 1616*800a58d9SAndroid Build Coastguard Worker 1617*800a58d9SAndroid Build Coastguard Workerdef SetCvdPorts(base_instance_num): 1618*800a58d9SAndroid Build Coastguard Worker """Adjust ports by base_instance_num. 1619*800a58d9SAndroid Build Coastguard Worker 1620*800a58d9SAndroid Build Coastguard Worker Args: 1621*800a58d9SAndroid Build Coastguard Worker base_instance_num: int, cuttlefish base_instance_num. 1622*800a58d9SAndroid Build Coastguard Worker """ 1623*800a58d9SAndroid Build Coastguard Worker offset = (base_instance_num or 1) - 1 1624*800a58d9SAndroid Build Coastguard Worker AVD_PORT_DICT[constants.TYPE_CF] = ForwardedPorts( 1625*800a58d9SAndroid Build Coastguard Worker constants.CF_VNC_PORT + offset, constants.CF_ADB_PORT + offset) 1626*800a58d9SAndroid Build Coastguard Worker 1627*800a58d9SAndroid Build Coastguard Worker # TODO: adjust WebRTC ports 1628