blob: 2c2dbee53c41dd3da54c9f96f91f51867261383d [file] [log] [blame]
Kevin Cheng3087af52018-08-13 13:26:50 -07001#!/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
Kevin Chengcc6bf0d2018-10-10 14:18:47 -070023from __future__ import print_function
24
Kevin Cheng835a4152018-10-11 10:46:57 -070025import os
26import subprocess
Kevin Chengcc6bf0d2018-10-10 14:18:47 -070027import sys
28
Kevin Cheng3ce4b452018-08-23 14:47:22 -070029from acloud import errors
Kevin Chengc3d0d5e2018-08-14 14:22:44 -070030from acloud.create import avd_spec
Richard Fung97503b22019-02-06 13:43:38 -080031from acloud.create import cheeps_remote_image_remote_instance
chojoyce7a361732018-11-26 16:26:13 +080032from acloud.create import gce_local_image_remote_instance
33from acloud.create import gce_remote_image_remote_instance
Hsin-Yi Chen7ba49962019-09-25 18:58:56 +080034from acloud.create import goldfish_local_image_local_instance
herbertxue494891e2019-01-19 13:50:53 +080035from acloud.create import goldfish_remote_image_remote_instance
Kevin Cheng3ce4b452018-08-23 14:47:22 -070036from acloud.create import local_image_local_instance
37from acloud.create import local_image_remote_instance
cyland43f2932019-11-26 17:37:28 +080038from acloud.create import local_image_remote_host
herbertxuedf01c422018-09-06 19:52:52 +080039from acloud.create import remote_image_remote_instance
chojoycecd004bc2018-09-13 10:39:00 +080040from acloud.create import remote_image_local_instance
cyland43f2932019-11-26 17:37:28 +080041from acloud.create import remote_image_remote_host
Kevin Cheng3ce4b452018-08-23 14:47:22 -070042from acloud.internal import constants
Kevin Chengcc6bf0d2018-10-10 14:18:47 -070043from acloud.internal.lib import utils
44from acloud.setup import setup
45from acloud.setup import gcp_setup_runner
46from acloud.setup import host_setup_runner
Kevin Cheng3ce4b452018-08-23 14:47:22 -070047
herbertxue1512f8a2019-06-27 13:56:23 +080048
Kevin Cheng835a4152018-10-11 10:46:57 -070049_MAKE_CMD = "build/soong/soong_ui.bash"
50_MAKE_ARG = "--make-mode"
51
chojoyce7a361732018-11-26 16:26:13 +080052_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,
cyland43f2932019-11-26 17:37:28 +080063 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_HOST):
64 local_image_remote_host.LocalImageRemoteHost,
chojoyce7a361732018-11-26 16:26:13 +080065 (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,
cyland43f2932019-11-26 17:37:28 +080069 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_HOST):
70 remote_image_remote_host.RemoteImageRemoteHost,
Richard Fung97503b22019-02-06 13:43:38 -080071 # Cheeps types
72 (constants.TYPE_CHEEPS, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
73 cheeps_remote_image_remote_instance.CheepsRemoteImageRemoteInstance,
herbertxue494891e2019-01-19 13:50:53 +080074 # GF types
75 (constants.TYPE_GF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
76 goldfish_remote_image_remote_instance.GoldfishRemoteImageRemoteInstance,
Hsin-Yi Chen7ba49962019-09-25 18:58:56 +080077 (constants.TYPE_GF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL):
78 goldfish_local_image_local_instance.GoldfishLocalImageLocalInstance,
Peter Collingbournedce6d722020-05-07 15:29:21 -070079 # FVP types
80 (constants.TYPE_FVP, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE):
81 local_image_remote_instance.LocalImageRemoteInstance,
chojoyce7a361732018-11-26 16:26:13 +080082}
Kevin Cheng3ce4b452018-08-23 14:47:22 -070083
chojoyce7a361732018-11-26 16:26:13 +080084
85def GetAvdCreatorClass(avd_type, instance_type, image_source):
Kevin Cheng3ce4b452018-08-23 14:47:22 -070086 """Return the creator class for the specified spec.
87
88 Based on the image source and the instance type, return the proper
89 creator class.
90
91 Args:
chojoyce7a361732018-11-26 16:26:13 +080092 avd_type: String, the AVD type(cuttlefish, gce).
Kevin Cheng3ce4b452018-08-23 14:47:22 -070093 instance_type: String, the AVD instance type (local or remote).
94 image_source: String, the source of the image (local or remote).
95
96 Returns:
97 An AVD creator class (e.g. LocalImageRemoteInstance).
chojoyce7a361732018-11-26 16:26:13 +080098
99 Raises:
100 UnsupportedInstanceImageType if argments didn't match _CREATOR_CLASS_DICT.
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700101 """
chojoyce7a361732018-11-26 16:26:13 +0800102 creator_class = _CREATOR_CLASS_DICT.get(
103 (avd_type, image_source, instance_type))
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700104
chojoyce7a361732018-11-26 16:26:13 +0800105 if not creator_class:
106 raise errors.UnsupportedInstanceImageType(
107 "unsupported creation of avd type: %s, instance type: %s, "
108 "image source: %s" % (avd_type, instance_type, image_source))
109 return creator_class
Kevin Cheng3087af52018-08-13 13:26:50 -0700110
Kevin Cheng835a4152018-10-11 10:46:57 -0700111def _CheckForAutoconnect(args):
112 """Check that we have all prerequisites for autoconnect.
113
114 Autoconnect requires adb and ssh, we'll just check for adb for now and
115 assume ssh is everywhere. If adb isn't around, ask the user if they want us
116 to build it, if not we'll disable autoconnect.
117
118 Args:
119 args: Namespace object from argparse.parse_args.
120 """
chojoyce6e30cc52019-11-04 16:18:09 +0800121 if not args.autoconnect or utils.FindExecutable(constants.ADB_BIN):
Kevin Cheng835a4152018-10-11 10:46:57 -0700122 return
123
124 disable_autoconnect = False
125 answer = utils.InteractWithQuestion(
126 "adb is required for autoconnect, without it autoconnect will be "
Sam Chiu705b9012019-01-19 12:11:35 +0800127 "disabled, would you like acloud to build it[y/N]? ")
Kevin Cheng835a4152018-10-11 10:46:57 -0700128 if answer in constants.USER_ANSWER_YES:
129 utils.PrintColorString("Building adb ... ", end="")
130 android_build_top = os.environ.get(
131 constants.ENV_ANDROID_BUILD_TOP)
132 if not android_build_top:
133 utils.PrintColorString("Fail! (Not in a lunch'd env)",
134 utils.TextColors.FAIL)
135 disable_autoconnect = True
136 else:
137 make_cmd = os.path.join(android_build_top, _MAKE_CMD)
138 build_adb_cmd = [make_cmd, _MAKE_ARG, "adb"]
139 try:
140 with open(os.devnull, "w") as dev_null:
141 subprocess.check_call(build_adb_cmd, stderr=dev_null,
142 stdout=dev_null)
143 utils.PrintColorString("OK!", utils.TextColors.OKGREEN)
144 except subprocess.CalledProcessError:
145 utils.PrintColorString("Fail! (build failed)",
146 utils.TextColors.FAIL)
147 disable_autoconnect = True
148 else:
149 disable_autoconnect = True
150
151 if disable_autoconnect:
152 utils.PrintColorString("Disabling autoconnect",
153 utils.TextColors.WARNING)
154 args.autoconnect = False
155
156
157def _CheckForSetup(args):
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700158 """Check that host is setup to run the create commands.
159
160 We'll check we have the necessary bits setup to do what the user wants, and
161 if not, tell them what they need to do before running create again.
162
163 Args:
164 args: Namespace object from argparse.parse_args.
165 """
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700166 # Need to set all these so if we need to run setup, it won't barf on us
167 # because of some missing fields.
168 args.gcp_init = False
169 args.host = False
Kevin Chengeb997272019-06-05 14:53:18 -0700170 args.host_base = False
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700171 args.force = False
172 # Remote image/instance requires the GCP config setup.
173 if not args.local_instance or args.local_image == "":
174 gcp_setup = gcp_setup_runner.GcpTaskRunner(args.config_file)
175 if gcp_setup.ShouldRun():
176 args.gcp_init = True
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700177
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700178 # Local instance requires host to be setup. We'll assume that if the
179 # packages were installed, then the user was added into the groups. This
180 # avoids the scenario where a user runs setup and creates a local instance.
181 # The following local instance create will trigger this if statment and go
182 # through the whole setup again even though it's already done because the
183 # user groups aren't set until the user logs out and back in.
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700184 if args.local_instance:
185 host_pkg_setup = host_setup_runner.AvdPkgInstaller()
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700186 if host_pkg_setup.ShouldRun():
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700187 args.host = True
Kevin Chengeb997272019-06-05 14:53:18 -0700188
189 # Install base packages if we haven't already.
190 host_base_setup = host_setup_runner.HostBasePkgInstaller()
191 if host_base_setup.ShouldRun():
192 args.host_base = True
193
194 run_setup = args.force or args.gcp_init or args.host or args.host_base
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700195
196 if run_setup:
197 answer = utils.InteractWithQuestion("Missing necessary acloud setup, "
Sam Chiu705b9012019-01-19 12:11:35 +0800198 "would you like to run setup[y/N]?")
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700199 if answer in constants.USER_ANSWER_YES:
200 setup.Run(args)
201 else:
202 print("Please run '#acloud setup' so we can get your host setup")
Sam Chiue791f602019-05-03 15:18:10 +0800203 sys.exit(constants.EXIT_BY_USER)
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700204
205
Kevin Cheng835a4152018-10-11 10:46:57 -0700206def PreRunCheck(args):
207 """Do some pre-run checks to ensure a smooth create experience.
208
209 Args:
210 args: Namespace object from argparse.parse_args.
211 """
212 _CheckForSetup(args)
213 _CheckForAutoconnect(args)
214
215
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700216def Run(args):
Kevin Cheng3087af52018-08-13 13:26:50 -0700217 """Run create.
218
219 Args:
220 args: Namespace object from argparse.parse_args.
herbertxue48bba082019-12-31 12:12:16 +0800221
222 Returns:
223 A Report instance.
Kevin Cheng3087af52018-08-13 13:26:50 -0700224 """
Kevin Chengfab8cfc2019-06-27 14:01:37 -0700225 if not args.skip_pre_run_check:
226 PreRunCheck(args)
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700227 spec = avd_spec.AVDSpec(args)
chojoyce7a361732018-11-26 16:26:13 +0800228 avd_creator_class = GetAvdCreatorClass(spec.avd_type,
229 spec.instance_type,
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700230 spec.image_source)
231 avd_creator = avd_creator_class()
herbertxue7ef23b22019-02-27 09:34:24 +0800232 report = avd_creator.Create(spec, args.no_prompt)
herbertxue48bba082019-12-31 12:12:16 +0800233 return report