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