1#!/usr/bin/env python 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16r"""Create entry point. 17 18Create will handle all the logic related to creating a local/remote instance 19an Android Virtual Device and the logic related to prepping the local/remote 20image artifacts. 21""" 22 23from __future__ import print_function 24 25import logging 26import os 27import subprocess 28import sys 29 30from acloud import errors 31from acloud.create import avd_spec 32from acloud.create import cheeps_remote_image_remote_instance 33from acloud.create import gce_local_image_remote_instance 34from acloud.create import gce_remote_image_remote_instance 35from acloud.create import goldfish_local_image_local_instance 36from acloud.create import goldfish_remote_host 37from acloud.create import goldfish_remote_image_remote_instance 38from acloud.create import local_image_local_instance 39from acloud.create import local_image_remote_instance 40from acloud.create import local_image_remote_host 41from acloud.create import remote_image_remote_instance 42from acloud.create import remote_image_local_instance 43from acloud.create import remote_image_remote_host 44from acloud.internal import constants 45from acloud.internal.lib import utils 46from acloud.setup import setup 47from acloud.setup import gcp_setup_runner 48from acloud.setup import host_setup_runner 49 50 51logger = logging.getLogger(__name__) 52 53_MAKE_CMD = "build/soong/soong_ui.bash" 54_MAKE_ARG = "--make-mode" 55_YES = "y" 56 57_CREATOR_CLASS_DICT = { 58 # GCE types 59 (constants.TYPE_GCE, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE): 60 gce_local_image_remote_instance.GceLocalImageRemoteInstance, 61 (constants.TYPE_GCE, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 62 gce_remote_image_remote_instance.GceRemoteImageRemoteInstance, 63 # CF types 64 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL): 65 local_image_local_instance.LocalImageLocalInstance, 66 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE): 67 local_image_remote_instance.LocalImageRemoteInstance, 68 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_HOST): 69 local_image_remote_host.LocalImageRemoteHost, 70 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 71 remote_image_remote_instance.RemoteImageRemoteInstance, 72 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_LOCAL): 73 remote_image_local_instance.RemoteImageLocalInstance, 74 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_HOST): 75 remote_image_remote_host.RemoteImageRemoteHost, 76 # Cheeps types 77 (constants.TYPE_CHEEPS, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 78 cheeps_remote_image_remote_instance.CheepsRemoteImageRemoteInstance, 79 # GF types 80 (constants.TYPE_GF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 81 goldfish_remote_image_remote_instance.GoldfishRemoteImageRemoteInstance, 82 (constants.TYPE_GF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL): 83 goldfish_local_image_local_instance.GoldfishLocalImageLocalInstance, 84 (constants.TYPE_GF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_HOST): 85 goldfish_remote_host.GoldfishRemoteHost, 86 (constants.TYPE_GF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_HOST): 87 goldfish_remote_host.GoldfishRemoteHost, 88 # FVP types 89 (constants.TYPE_FVP, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE): 90 local_image_remote_instance.LocalImageRemoteInstance, 91 # Trusty types 92 (constants.TYPE_TRUSTY, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE): 93 local_image_remote_instance.LocalImageRemoteInstance, 94 (constants.TYPE_TRUSTY, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 95 remote_image_remote_instance.RemoteImageRemoteInstance, 96} 97 98 99def GetAvdCreatorClass(avd_type, instance_type, image_source): 100 """Return the creator class for the specified spec. 101 102 Based on the image source and the instance type, return the proper 103 creator class. 104 105 Args: 106 avd_type: String, the AVD type(cuttlefish, gce). 107 instance_type: String, the AVD instance type (local or remote). 108 image_source: String, the source of the image (local or remote). 109 110 Returns: 111 An AVD creator class (e.g. LocalImageRemoteInstance). 112 113 Raises: 114 UnsupportedInstanceImageType if argments didn't match _CREATOR_CLASS_DICT. 115 """ 116 creator_class = _CREATOR_CLASS_DICT.get( 117 (avd_type, image_source, instance_type)) 118 119 if not creator_class: 120 raise errors.UnsupportedInstanceImageType( 121 "unsupported creation of avd type: %s, instance type: %s, " 122 "image source: %s" % (avd_type, instance_type, image_source)) 123 return creator_class 124 125def _CheckForAutoconnect(args): 126 """Check that we have all prerequisites for autoconnect. 127 128 Autoconnect requires adb and ssh, we'll just check for adb for now and 129 assume ssh is everywhere. If adb isn't around, ask the user if they want us 130 to build it, if not we'll disable autoconnect. 131 132 Args: 133 args: Namespace object from argparse.parse_args. 134 """ 135 if not args.autoconnect or utils.FindExecutable(constants.ADB_BIN): 136 return 137 138 disable_autoconnect = False 139 answer = _YES if args.no_prompt else utils.InteractWithQuestion( 140 "adb is required for autoconnect, without it autoconnect will be " 141 "disabled, would you like acloud to build it[y/N]? ") 142 if answer in constants.USER_ANSWER_YES: 143 utils.PrintColorString("Building adb ... ", end="") 144 android_build_top = os.environ.get( 145 constants.ENV_ANDROID_BUILD_TOP) 146 if not android_build_top: 147 utils.PrintColorString("Fail! (Not in a lunch'd env)", 148 utils.TextColors.FAIL) 149 disable_autoconnect = True 150 else: 151 make_cmd = os.path.join(android_build_top, _MAKE_CMD) 152 build_adb_cmd = [make_cmd, _MAKE_ARG, "adb"] 153 try: 154 with open(os.devnull, "w") as dev_null: 155 subprocess.check_call(build_adb_cmd, stderr=dev_null, 156 stdout=dev_null) 157 utils.PrintColorString("OK!", utils.TextColors.OKGREEN) 158 except subprocess.CalledProcessError: 159 utils.PrintColorString("Fail! (build failed)", 160 utils.TextColors.FAIL) 161 disable_autoconnect = True 162 else: 163 disable_autoconnect = True 164 165 if disable_autoconnect: 166 utils.PrintColorString("Disabling autoconnect", 167 utils.TextColors.WARNING) 168 args.autoconnect = False 169 170 171def _CheckForSetup(args): 172 """Check that host is setup to run the create commands. 173 174 We'll check we have the necessary bits setup to do what the user wants, and 175 if not, tell them what they need to do before running create again. 176 177 Args: 178 args: Namespace object from argparse.parse_args. 179 """ 180 # Need to set all these so if we need to run setup, it won't barf on us 181 # because of some missing fields. 182 args.gcp_init = False 183 args.host = False 184 args.host_base = False 185 args.force = False 186 args.update_config = None 187 args.host_local_ca = False 188 # Remote image/instance requires the GCP config setup. 189 if args.local_instance is None or args.local_image is None: 190 gcp_setup = gcp_setup_runner.GcpTaskRunner(args.config_file) 191 if gcp_setup.ShouldRun(): 192 args.gcp_init = True 193 logger.debug("Auto-detect to setup GCP config.") 194 195 # Local instance requires host to be setup. We'll assume that if the 196 # packages were installed, then the user was added into the groups. This 197 # avoids the scenario where a user runs setup and creates a local instance. 198 # The following local instance create will trigger this if statment and go 199 # through the whole setup again even though it's already done because the 200 # user groups aren't set until the user logs out and back in. 201 if args.local_instance is not None: 202 host_pkg_setup = host_setup_runner.AvdPkgInstaller() 203 if host_pkg_setup.ShouldRun(): 204 args.host = True 205 logger.debug("Auto-detect to install host packages.") 206 207 user_groups_setup = host_setup_runner.CuttlefishHostSetup() 208 if user_groups_setup.ShouldRun(): 209 args.host = True 210 logger.debug("Auto-detect to setup user groups.") 211 212 if args.mkcert and args.autoconnect == constants.INS_KEY_WEBRTC: 213 local_ca_setup = host_setup_runner.LocalCAHostSetup() 214 if local_ca_setup.ShouldRun(): 215 args.host_local_ca = True 216 logger.debug("Auto-detect to setup local CA.") 217 218 # Install base packages if we haven't already. 219 host_base_setup = host_setup_runner.HostBasePkgInstaller() 220 if host_base_setup.ShouldRun(): 221 args.host_base = True 222 logger.debug("Auto-detect to install host_base packages.") 223 224 run_setup = any([ 225 args.force, args.gcp_init, args.host, args.host_base, args.host_local_ca]) 226 227 if run_setup: 228 answer = utils.InteractWithQuestion("Missing necessary acloud setup, " 229 "would you like to run setup[y/N]?") 230 if answer in constants.USER_ANSWER_YES: 231 setup.Run(args) 232 else: 233 print("Please run '#acloud setup' so we can get your host setup") 234 sys.exit(constants.EXIT_BY_USER) 235 236 237def PreRunCheck(args): 238 """Do some pre-run checks to ensure a smooth create experience. 239 240 Args: 241 args: Namespace object from argparse.parse_args. 242 """ 243 _CheckForSetup(args) 244 _CheckForAutoconnect(args) 245 246 247def Run(args): 248 """Run create. 249 250 Args: 251 args: Namespace object from argparse.parse_args. 252 253 Returns: 254 A Report instance. 255 """ 256 if not args.skip_pre_run_check: 257 PreRunCheck(args) 258 spec = avd_spec.AVDSpec(args) 259 avd_creator_class = GetAvdCreatorClass(spec.avd_type, 260 spec.instance_type, 261 spec.image_source) 262 avd_creator = avd_creator_class() 263 report = avd_creator.Create(spec, args.no_prompt) 264 return report 265