blob: 37b735198ab532bb3e70e0672e35a249c94e5b9a [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,
chojoyce7a361732018-11-26 16:26:13 +080079}
Kevin Cheng3ce4b452018-08-23 14:47:22 -070080
chojoyce7a361732018-11-26 16:26:13 +080081
82def GetAvdCreatorClass(avd_type, instance_type, image_source):
Kevin Cheng3ce4b452018-08-23 14:47:22 -070083 """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:
chojoyce7a361732018-11-26 16:26:13 +080089 avd_type: String, the AVD type(cuttlefish, gce).
Kevin Cheng3ce4b452018-08-23 14:47:22 -070090 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).
chojoyce7a361732018-11-26 16:26:13 +080095
96 Raises:
97 UnsupportedInstanceImageType if argments didn't match _CREATOR_CLASS_DICT.
Kevin Cheng3ce4b452018-08-23 14:47:22 -070098 """
chojoyce7a361732018-11-26 16:26:13 +080099 creator_class = _CREATOR_CLASS_DICT.get(
100 (avd_type, image_source, instance_type))
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700101
chojoyce7a361732018-11-26 16:26:13 +0800102 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
Kevin Cheng3087af52018-08-13 13:26:50 -0700107
Kevin Cheng835a4152018-10-11 10:46:57 -0700108def _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 """
chojoyce6e30cc52019-11-04 16:18:09 +0800118 if not args.autoconnect or utils.FindExecutable(constants.ADB_BIN):
Kevin Cheng835a4152018-10-11 10:46:57 -0700119 return
120
121 disable_autoconnect = False
122 answer = utils.InteractWithQuestion(
123 "adb is required for autoconnect, without it autoconnect will be "
Sam Chiu705b9012019-01-19 12:11:35 +0800124 "disabled, would you like acloud to build it[y/N]? ")
Kevin Cheng835a4152018-10-11 10:46:57 -0700125 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):
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700155 """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 """
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700163 # 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
Kevin Chengeb997272019-06-05 14:53:18 -0700167 args.host_base = False
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700168 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
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700174
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700175 # 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.
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700181 if args.local_instance:
182 host_pkg_setup = host_setup_runner.AvdPkgInstaller()
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700183 if host_pkg_setup.ShouldRun():
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700184 args.host = True
Kevin Chengeb997272019-06-05 14:53:18 -0700185
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
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700192
193 if run_setup:
194 answer = utils.InteractWithQuestion("Missing necessary acloud setup, "
Sam Chiu705b9012019-01-19 12:11:35 +0800195 "would you like to run setup[y/N]?")
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700196 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")
Sam Chiue791f602019-05-03 15:18:10 +0800200 sys.exit(constants.EXIT_BY_USER)
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700201
202
Kevin Cheng835a4152018-10-11 10:46:57 -0700203def 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
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700213def Run(args):
Kevin Cheng3087af52018-08-13 13:26:50 -0700214 """Run create.
215
216 Args:
217 args: Namespace object from argparse.parse_args.
herbertxue48bba082019-12-31 12:12:16 +0800218
219 Returns:
220 A Report instance.
Kevin Cheng3087af52018-08-13 13:26:50 -0700221 """
Kevin Chengfab8cfc2019-06-27 14:01:37 -0700222 if not args.skip_pre_run_check:
223 PreRunCheck(args)
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700224 spec = avd_spec.AVDSpec(args)
chojoyce7a361732018-11-26 16:26:13 +0800225 avd_creator_class = GetAvdCreatorClass(spec.avd_type,
226 spec.instance_type,
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700227 spec.image_source)
228 avd_creator = avd_creator_class()
herbertxue7ef23b22019-02-27 09:34:24 +0800229 report = avd_creator.Create(spec, args.no_prompt)
herbertxue48bba082019-12-31 12:12:16 +0800230 return report