1*800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python 2*800a58d9SAndroid Build Coastguard Worker# 3*800a58d9SAndroid Build Coastguard Worker# Copyright 2018 - The Android Open Source Project 4*800a58d9SAndroid Build Coastguard Worker# 5*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*800a58d9SAndroid Build Coastguard Worker# 9*800a58d9SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*800a58d9SAndroid Build Coastguard Worker# 11*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*800a58d9SAndroid Build Coastguard Worker# limitations under the License. 16*800a58d9SAndroid Build Coastguard Workerr"""RemoteImageRemoteInstance class. 17*800a58d9SAndroid Build Coastguard Worker 18*800a58d9SAndroid Build Coastguard WorkerCreate class that is responsible for creating a remote instance AVD with a 19*800a58d9SAndroid Build Coastguard Workerremote image. 20*800a58d9SAndroid Build Coastguard Worker""" 21*800a58d9SAndroid Build Coastguard Worker 22*800a58d9SAndroid Build Coastguard Workerimport logging 23*800a58d9SAndroid Build Coastguard Workerimport re 24*800a58d9SAndroid Build Coastguard Workerimport subprocess 25*800a58d9SAndroid Build Coastguard Workerimport time 26*800a58d9SAndroid Build Coastguard Worker 27*800a58d9SAndroid Build Coastguard Workerfrom acloud.create import base_avd_create 28*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants 29*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import oxygen_client 30*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils 31*800a58d9SAndroid Build Coastguard Workerfrom acloud.public.actions import common_operations 32*800a58d9SAndroid Build Coastguard Workerfrom acloud.public.actions import remote_instance_cf_device_factory 33*800a58d9SAndroid Build Coastguard Workerfrom acloud.public.actions import remote_instance_trusty_device_factory 34*800a58d9SAndroid Build Coastguard Workerfrom acloud.public import report 35*800a58d9SAndroid Build Coastguard Worker 36*800a58d9SAndroid Build Coastguard Worker 37*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 38*800a58d9SAndroid Build Coastguard Worker_DEVICE = "device" 39*800a58d9SAndroid Build Coastguard Worker_DEVICES = "devices" 40*800a58d9SAndroid Build Coastguard Worker_LAUNCH_CVD_TIME = "launch_cvd_time" 41*800a58d9SAndroid Build Coastguard Worker_RE_SESSION_ID = re.compile(r".*session_id:\"(?P<session_id>[^\"]+)") 42*800a58d9SAndroid Build Coastguard Worker_RE_SERVER_URL = re.compile(r".*server_url:\"(?P<server_url>[^\"]+)") 43*800a58d9SAndroid Build Coastguard Worker_RE_OXYGEN_LEASE_ERROR = re.compile( 44*800a58d9SAndroid Build Coastguard Worker r".*Error received while trying to lease device: (?P<error>.*)$", re.DOTALL) 45*800a58d9SAndroid Build Coastguard Worker 46*800a58d9SAndroid Build Coastguard Worker 47*800a58d9SAndroid Build Coastguard Workerclass RemoteImageRemoteInstance(base_avd_create.BaseAVDCreate): 48*800a58d9SAndroid Build Coastguard Worker """Create class for a remote image remote instance AVD.""" 49*800a58d9SAndroid Build Coastguard Worker 50*800a58d9SAndroid Build Coastguard Worker @utils.TimeExecute(function_description="Total time: ", 51*800a58d9SAndroid Build Coastguard Worker print_before_call=False, print_status=False) 52*800a58d9SAndroid Build Coastguard Worker def _CreateAVD(self, avd_spec, no_prompts): 53*800a58d9SAndroid Build Coastguard Worker """Create the AVD. 54*800a58d9SAndroid Build Coastguard Worker 55*800a58d9SAndroid Build Coastguard Worker Args: 56*800a58d9SAndroid Build Coastguard Worker avd_spec: AVDSpec object that tells us what we're going to create. 57*800a58d9SAndroid Build Coastguard Worker no_prompts: Boolean, True to skip all prompts. 58*800a58d9SAndroid Build Coastguard Worker 59*800a58d9SAndroid Build Coastguard Worker Returns: 60*800a58d9SAndroid Build Coastguard Worker A Report instance. 61*800a58d9SAndroid Build Coastguard Worker """ 62*800a58d9SAndroid Build Coastguard Worker if avd_spec.oxygen: 63*800a58d9SAndroid Build Coastguard Worker return self._LeaseOxygenAVD(avd_spec) 64*800a58d9SAndroid Build Coastguard Worker if avd_spec.gce_only: 65*800a58d9SAndroid Build Coastguard Worker return self._CreateGceInstance(avd_spec) 66*800a58d9SAndroid Build Coastguard Worker if avd_spec.avd_type == constants.TYPE_CF: 67*800a58d9SAndroid Build Coastguard Worker command = "create_cf" 68*800a58d9SAndroid Build Coastguard Worker device_factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory( 69*800a58d9SAndroid Build Coastguard Worker avd_spec) 70*800a58d9SAndroid Build Coastguard Worker elif avd_spec.avd_type == constants.TYPE_TRUSTY: 71*800a58d9SAndroid Build Coastguard Worker command = "create_trusty" 72*800a58d9SAndroid Build Coastguard Worker device_factory = remote_instance_trusty_device_factory.RemoteInstanceDeviceFactory( 73*800a58d9SAndroid Build Coastguard Worker avd_spec) 74*800a58d9SAndroid Build Coastguard Worker else: 75*800a58d9SAndroid Build Coastguard Worker # This type isn't correctly registered in create.py. 76*800a58d9SAndroid Build Coastguard Worker raise ValueError(f"Unsupported AVD type: {avd_spec.avd_type}") 77*800a58d9SAndroid Build Coastguard Worker create_report = common_operations.CreateDevices( 78*800a58d9SAndroid Build Coastguard Worker command, avd_spec.cfg, device_factory, avd_spec.num, 79*800a58d9SAndroid Build Coastguard Worker report_internal_ip=avd_spec.report_internal_ip, 80*800a58d9SAndroid Build Coastguard Worker autoconnect=avd_spec.autoconnect, 81*800a58d9SAndroid Build Coastguard Worker avd_type=avd_spec.avd_type, 82*800a58d9SAndroid Build Coastguard Worker boot_timeout_secs=avd_spec.boot_timeout_secs, 83*800a58d9SAndroid Build Coastguard Worker unlock_screen=avd_spec.unlock_screen, 84*800a58d9SAndroid Build Coastguard Worker wait_for_boot=False, 85*800a58d9SAndroid Build Coastguard Worker connect_webrtc=avd_spec.connect_webrtc, 86*800a58d9SAndroid Build Coastguard Worker client_adb_port=avd_spec.client_adb_port) 87*800a58d9SAndroid Build Coastguard Worker if create_report.status == report.Status.SUCCESS: 88*800a58d9SAndroid Build Coastguard Worker if avd_spec.connect_vnc: 89*800a58d9SAndroid Build Coastguard Worker utils.LaunchVNCFromReport(create_report, avd_spec, no_prompts) 90*800a58d9SAndroid Build Coastguard Worker if avd_spec.connect_webrtc: 91*800a58d9SAndroid Build Coastguard Worker utils.LaunchBrowserFromReport(create_report) 92*800a58d9SAndroid Build Coastguard Worker 93*800a58d9SAndroid Build Coastguard Worker return create_report 94*800a58d9SAndroid Build Coastguard Worker 95*800a58d9SAndroid Build Coastguard Worker def _LeaseOxygenAVD(self, avd_spec): 96*800a58d9SAndroid Build Coastguard Worker """Lease the AVD from the AVD pool. 97*800a58d9SAndroid Build Coastguard Worker 98*800a58d9SAndroid Build Coastguard Worker Args: 99*800a58d9SAndroid Build Coastguard Worker avd_spec: AVDSpec object that tells us what we're going to create. 100*800a58d9SAndroid Build Coastguard Worker 101*800a58d9SAndroid Build Coastguard Worker Returns: 102*800a58d9SAndroid Build Coastguard Worker A Report instance. 103*800a58d9SAndroid Build Coastguard Worker """ 104*800a58d9SAndroid Build Coastguard Worker timestart = time.time() 105*800a58d9SAndroid Build Coastguard Worker session_id = None 106*800a58d9SAndroid Build Coastguard Worker server_url = None 107*800a58d9SAndroid Build Coastguard Worker try: 108*800a58d9SAndroid Build Coastguard Worker response = oxygen_client.OxygenClient.LeaseDevice( 109*800a58d9SAndroid Build Coastguard Worker avd_spec.remote_image[constants.BUILD_TARGET], 110*800a58d9SAndroid Build Coastguard Worker avd_spec.remote_image[constants.BUILD_ID], 111*800a58d9SAndroid Build Coastguard Worker avd_spec.remote_image[constants.BUILD_BRANCH], 112*800a58d9SAndroid Build Coastguard Worker avd_spec.system_build_info[constants.BUILD_TARGET], 113*800a58d9SAndroid Build Coastguard Worker avd_spec.system_build_info[constants.BUILD_ID], 114*800a58d9SAndroid Build Coastguard Worker avd_spec.kernel_build_info[constants.BUILD_TARGET], 115*800a58d9SAndroid Build Coastguard Worker avd_spec.kernel_build_info[constants.BUILD_ID], 116*800a58d9SAndroid Build Coastguard Worker avd_spec.cfg.oxygen_client, 117*800a58d9SAndroid Build Coastguard Worker avd_spec.cfg.oxygen_lease_args) 118*800a58d9SAndroid Build Coastguard Worker session_id, server_url = self._GetDeviceInfoFromResponse(response) 119*800a58d9SAndroid Build Coastguard Worker execution_time = round(time.time() - timestart, 2) 120*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 121*800a58d9SAndroid Build Coastguard Worker logger.error("Failed to lease device from Oxygen, error: %s", 122*800a58d9SAndroid Build Coastguard Worker e.output) 123*800a58d9SAndroid Build Coastguard Worker response = e.output 124*800a58d9SAndroid Build Coastguard Worker 125*800a58d9SAndroid Build Coastguard Worker reporter = report.Report(command="create_cf") 126*800a58d9SAndroid Build Coastguard Worker if session_id and server_url: 127*800a58d9SAndroid Build Coastguard Worker reporter.SetStatus(report.Status.SUCCESS) 128*800a58d9SAndroid Build Coastguard Worker device_data = {"instance_name": session_id, 129*800a58d9SAndroid Build Coastguard Worker "ip": server_url} 130*800a58d9SAndroid Build Coastguard Worker device_data[_LAUNCH_CVD_TIME] = execution_time 131*800a58d9SAndroid Build Coastguard Worker dict_devices = {_DEVICES: [device_data]} 132*800a58d9SAndroid Build Coastguard Worker reporter.UpdateData(dict_devices) 133*800a58d9SAndroid Build Coastguard Worker else: 134*800a58d9SAndroid Build Coastguard Worker # Try to parse client error 135*800a58d9SAndroid Build Coastguard Worker match = _RE_OXYGEN_LEASE_ERROR.match(response) 136*800a58d9SAndroid Build Coastguard Worker if match: 137*800a58d9SAndroid Build Coastguard Worker response = match.group("error").strip() 138*800a58d9SAndroid Build Coastguard Worker 139*800a58d9SAndroid Build Coastguard Worker reporter.SetStatus(report.Status.FAIL) 140*800a58d9SAndroid Build Coastguard Worker reporter.SetErrorType(constants.ACLOUD_OXYGEN_LEASE_ERROR) 141*800a58d9SAndroid Build Coastguard Worker reporter.AddError(response) 142*800a58d9SAndroid Build Coastguard Worker 143*800a58d9SAndroid Build Coastguard Worker return reporter 144*800a58d9SAndroid Build Coastguard Worker 145*800a58d9SAndroid Build Coastguard Worker @staticmethod 146*800a58d9SAndroid Build Coastguard Worker def _GetDeviceInfoFromResponse(response): 147*800a58d9SAndroid Build Coastguard Worker """Get session id and server url from response. 148*800a58d9SAndroid Build Coastguard Worker 149*800a58d9SAndroid Build Coastguard Worker Args: 150*800a58d9SAndroid Build Coastguard Worker response: String of the response from oxygen proxy client. 151*800a58d9SAndroid Build Coastguard Worker e.g. "2021/08/02 11:28:52 session_id: "74b6b835" 152*800a58d9SAndroid Build Coastguard Worker server_url: "0.0.0.34" port:{type:WATERFALL ..." 153*800a58d9SAndroid Build Coastguard Worker 154*800a58d9SAndroid Build Coastguard Worker Returns: 155*800a58d9SAndroid Build Coastguard Worker The session id and the server url of leased device. 156*800a58d9SAndroid Build Coastguard Worker """ 157*800a58d9SAndroid Build Coastguard Worker session_id = "" 158*800a58d9SAndroid Build Coastguard Worker for line in response.splitlines(): 159*800a58d9SAndroid Build Coastguard Worker session_id_match = _RE_SESSION_ID.match(line) 160*800a58d9SAndroid Build Coastguard Worker if session_id_match: 161*800a58d9SAndroid Build Coastguard Worker session_id = session_id_match.group("session_id") 162*800a58d9SAndroid Build Coastguard Worker break 163*800a58d9SAndroid Build Coastguard Worker 164*800a58d9SAndroid Build Coastguard Worker server_url = "" 165*800a58d9SAndroid Build Coastguard Worker for line in response.splitlines(): 166*800a58d9SAndroid Build Coastguard Worker server_url_match = _RE_SERVER_URL.match(line) 167*800a58d9SAndroid Build Coastguard Worker if server_url_match: 168*800a58d9SAndroid Build Coastguard Worker server_url = server_url_match.group("server_url") 169*800a58d9SAndroid Build Coastguard Worker break 170*800a58d9SAndroid Build Coastguard Worker return session_id, server_url 171*800a58d9SAndroid Build Coastguard Worker 172*800a58d9SAndroid Build Coastguard Worker @staticmethod 173*800a58d9SAndroid Build Coastguard Worker def _CreateGceInstance(avd_spec): 174*800a58d9SAndroid Build Coastguard Worker """Create the GCE instance. 175*800a58d9SAndroid Build Coastguard Worker 176*800a58d9SAndroid Build Coastguard Worker Args: 177*800a58d9SAndroid Build Coastguard Worker avd_spec: AVDSpec object. 178*800a58d9SAndroid Build Coastguard Worker 179*800a58d9SAndroid Build Coastguard Worker Returns: 180*800a58d9SAndroid Build Coastguard Worker A Report instance. 181*800a58d9SAndroid Build Coastguard Worker """ 182*800a58d9SAndroid Build Coastguard Worker device_factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory( 183*800a58d9SAndroid Build Coastguard Worker avd_spec) 184*800a58d9SAndroid Build Coastguard Worker instance = device_factory.CreateGceInstance() 185*800a58d9SAndroid Build Coastguard Worker compute_client = device_factory.GetComputeClient() 186*800a58d9SAndroid Build Coastguard Worker ip = compute_client.GetInstanceIP(instance) 187*800a58d9SAndroid Build Coastguard Worker reporter = report.Report(command="create_cf") 188*800a58d9SAndroid Build Coastguard Worker reporter.SetStatus(report.Status.SUCCESS) 189*800a58d9SAndroid Build Coastguard Worker device_data = {"instance_name": instance, 190*800a58d9SAndroid Build Coastguard Worker "ip": ip.internal if avd_spec.report_internal_ip 191*800a58d9SAndroid Build Coastguard Worker else ip.external} 192*800a58d9SAndroid Build Coastguard Worker dict_devices = {_DEVICES: [device_data]} 193*800a58d9SAndroid Build Coastguard Worker reporter.UpdateData(dict_devices) 194*800a58d9SAndroid Build Coastguard Worker return reporter 195