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 os 26import subprocess 27import sys 28 29from acloud import errors 30from acloud.create import avd_spec 31from acloud.create import cheeps_remote_image_remote_instance 32from acloud.create import gce_local_image_remote_instance 33from acloud.create import gce_remote_image_remote_instance 34from acloud.create import goldfish_local_image_local_instance 35from acloud.create import goldfish_remote_image_remote_instance 36from acloud.create import local_image_local_instance 37from acloud.create import local_image_remote_instance 38from acloud.create import local_image_remote_host 39from acloud.create import remote_image_remote_instance 40from acloud.create import remote_image_local_instance 41from acloud.create import remote_image_remote_host 42from acloud.internal import constants 43from acloud.internal.lib import utils 44from acloud.setup import setup 45from acloud.setup import gcp_setup_runner 46from acloud.setup import host_setup_runner 47 48 49_MAKE_CMD = "build/soong/soong_ui.bash" 50_MAKE_ARG = "--make-mode" 51_YES = "y" 52 53_CREATOR_CLASS_DICT = { 54 # GCE types 55 (constants.TYPE_GCE, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE): 56 gce_local_image_remote_instance.GceLocalImageRemoteInstance, 57 (constants.TYPE_GCE, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 58 gce_remote_image_remote_instance.GceRemoteImageRemoteInstance, 59 # CF types 60 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL): 61 local_image_local_instance.LocalImageLocalInstance, 62 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE): 63 local_image_remote_instance.LocalImageRemoteInstance, 64 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_HOST): 65 local_image_remote_host.LocalImageRemoteHost, 66 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 67 remote_image_remote_instance.RemoteImageRemoteInstance, 68 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_LOCAL): 69 remote_image_local_instance.RemoteImageLocalInstance, 70 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_HOST): 71 remote_image_remote_host.RemoteImageRemoteHost, 72 # Cheeps types 73 (constants.TYPE_CHEEPS, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 74 cheeps_remote_image_remote_instance.CheepsRemoteImageRemoteInstance, 75 # GF types 76 (constants.TYPE_GF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE): 77 goldfish_remote_image_remote_instance.GoldfishRemoteImageRemoteInstance, 78 (constants.TYPE_GF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL): 79 goldfish_local_image_local_instance.GoldfishLocalImageLocalInstance, 80 # FVP types 81 (constants.TYPE_FVP, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE): 82 local_image_remote_instance.LocalImageRemoteInstance, 83} 84 85 86def GetAvdCreatorClass(avd_type, instance_type, image_source): 87 """Return the creator class for the specified spec. 88 89 Based on the image source and the instance type, return the proper 90 creator class. 91 92 Args: 93 avd_type: String, the AVD type(cuttlefish, gce). 94 instance_type: String, the AVD instance type (local or remote). 95 image_source: String, the source of the image (local or remote). 96 97 Returns: 98 An AVD creator class (e.g. LocalImageRemoteInstance). 99 100 Raises: 101 UnsupportedInstanceImageType if argments didn't match _CREATOR_CLASS_DICT. 102 """ 103 creator_class = _CREATOR_CLASS_DICT.get( 104 (avd_type, image_source, instance_type)) 105 106 if not creator_class: 107 raise errors.UnsupportedInstanceImageType( 108 "unsupported creation of avd type: %s, instance type: %s, " 109 "image source: %s" % (avd_type, instance_type, image_source)) 110 return creator_class 111 112def _CheckForAutoconnect(args): 113 """Check that we have all prerequisites for autoconnect. 114 115 Autoconnect requires adb and ssh, we'll just check for adb for now and 116 assume ssh is everywhere. If adb isn't around, ask the user if they want us 117 to build it, if not we'll disable autoconnect. 118 119 Args: 120 args: Namespace object from argparse.parse_args. 121 """ 122 if not args.autoconnect or utils.FindExecutable(constants.ADB_BIN): 123 return 124 125 disable_autoconnect = False 126 answer = _YES if args.no_prompt else utils.InteractWithQuestion( 127 "adb is required for autoconnect, without it autoconnect will be " 128 "disabled, would you like acloud to build it[y/N]? ") 129 if answer in constants.USER_ANSWER_YES: 130 utils.PrintColorString("Building adb ... ", end="") 131 android_build_top = os.environ.get( 132 constants.ENV_ANDROID_BUILD_TOP) 133 if not android_build_top: 134 utils.PrintColorString("Fail! (Not in a lunch'd env)", 135 utils.TextColors.FAIL) 136 disable_autoconnect = True 137 else: 138 make_cmd = os.path.join(android_build_top, _MAKE_CMD) 139 build_adb_cmd = [make_cmd, _MAKE_ARG, "adb"] 140 try: 141 with open(os.devnull, "w") as dev_null: 142 subprocess.check_call(build_adb_cmd, stderr=dev_null, 143 stdout=dev_null) 144 utils.PrintColorString("OK!", utils.TextColors.OKGREEN) 145 except subprocess.CalledProcessError: 146 utils.PrintColorString("Fail! (build failed)", 147 utils.TextColors.FAIL) 148 disable_autoconnect = True 149 else: 150 disable_autoconnect = True 151 152 if disable_autoconnect: 153 utils.PrintColorString("Disabling autoconnect", 154 utils.TextColors.WARNING) 155 args.autoconnect = False 156 157 158def _CheckForSetup(args): 159 """Check that host is setup to run the create commands. 160 161 We'll check we have the necessary bits setup to do what the user wants, and 162 if not, tell them what they need to do before running create again. 163 164 Args: 165 args: Namespace object from argparse.parse_args. 166 """ 167 # Need to set all these so if we need to run setup, it won't barf on us 168 # because of some missing fields. 169 args.gcp_init = False 170 args.host = False 171 args.host_base = False 172 args.force = False 173 args.update_config = None 174 # Remote image/instance requires the GCP config setup. 175 if args.local_instance is None or args.local_image is None: 176 gcp_setup = gcp_setup_runner.GcpTaskRunner(args.config_file) 177 if gcp_setup.ShouldRun(): 178 args.gcp_init = True 179 180 # Local instance requires host to be setup. We'll assume that if the 181 # packages were installed, then the user was added into the groups. This 182 # avoids the scenario where a user runs setup and creates a local instance. 183 # The following local instance create will trigger this if statment and go 184 # through the whole setup again even though it's already done because the 185 # user groups aren't set until the user logs out and back in. 186 if args.local_instance is not None: 187 host_pkg_setup = host_setup_runner.AvdPkgInstaller() 188 if host_pkg_setup.ShouldRun(): 189 args.host = True 190 191 # Install base packages if we haven't already. 192 host_base_setup = host_setup_runner.HostBasePkgInstaller() 193 if host_base_setup.ShouldRun(): 194 args.host_base = True 195 196 run_setup = args.force or args.gcp_init or args.host or args.host_base 197 198 if run_setup: 199 answer = utils.InteractWithQuestion("Missing necessary acloud setup, " 200 "would you like to run setup[y/N]?") 201 if answer in constants.USER_ANSWER_YES: 202 setup.Run(args) 203 else: 204 print("Please run '#acloud setup' so we can get your host setup") 205 sys.exit(constants.EXIT_BY_USER) 206 207 208def PreRunCheck(args): 209 """Do some pre-run checks to ensure a smooth create experience. 210 211 Args: 212 args: Namespace object from argparse.parse_args. 213 """ 214 _CheckForSetup(args) 215 _CheckForAutoconnect(args) 216 217 218def Run(args): 219 """Run create. 220 221 Args: 222 args: Namespace object from argparse.parse_args. 223 224 Returns: 225 A Report instance. 226 """ 227 if not args.skip_pre_run_check: 228 PreRunCheck(args) 229 spec = avd_spec.AVDSpec(args) 230 avd_creator_class = GetAvdCreatorClass(spec.avd_type, 231 spec.instance_type, 232 spec.image_source) 233 avd_creator = avd_creator_class() 234 report = avd_creator.Create(spec, args.no_prompt) 235 return report 236