blob: 696cf07d5e6717bd3dcf872476eda95d0bc0a62d [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 -070025from distutils.spawn import find_executable
26import os
27import subprocess
Kevin Chengcc6bf0d2018-10-10 14:18:47 -070028import sys
29
Kevin Cheng3ce4b452018-08-23 14:47:22 -070030from acloud import errors
Kevin Chengc3d0d5e2018-08-14 14:22:44 -070031from acloud.create import avd_spec
Richard Fung97503b22019-02-06 13:43:38 -080032from acloud.create import cheeps_remote_image_remote_instance
chojoyce7a361732018-11-26 16:26:13 +080033from acloud.create import gce_local_image_remote_instance
34from acloud.create import gce_remote_image_remote_instance
Hsin-Yi Chen7ba49962019-09-25 18:58:56 +080035from acloud.create import goldfish_local_image_local_instance
herbertxue494891e2019-01-19 13:50:53 +080036from acloud.create import goldfish_remote_image_remote_instance
Kevin Cheng3ce4b452018-08-23 14:47:22 -070037from acloud.create import local_image_local_instance
38from acloud.create import local_image_remote_instance
cyland43f2932019-11-26 17:37:28 +080039from acloud.create import local_image_remote_host
herbertxuedf01c422018-09-06 19:52:52 +080040from acloud.create import remote_image_remote_instance
chojoycecd004bc2018-09-13 10:39:00 +080041from acloud.create import remote_image_local_instance
cyland43f2932019-11-26 17:37:28 +080042from acloud.create import remote_image_remote_host
Kevin Cheng3ce4b452018-08-23 14:47:22 -070043from acloud.internal import constants
Kevin Chengcc6bf0d2018-10-10 14:18:47 -070044from acloud.internal.lib import utils
45from acloud.setup import setup
46from acloud.setup import gcp_setup_runner
47from acloud.setup import host_setup_runner
Kevin Cheng3ce4b452018-08-23 14:47:22 -070048
herbertxue1512f8a2019-06-27 13:56:23 +080049
Kevin Cheng835a4152018-10-11 10:46:57 -070050_MAKE_CMD = "build/soong/soong_ui.bash"
51_MAKE_ARG = "--make-mode"
52
chojoyce7a361732018-11-26 16:26:13 +080053_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,
cyland43f2932019-11-26 17:37:28 +080064 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_HOST):
65 local_image_remote_host.LocalImageRemoteHost,
chojoyce7a361732018-11-26 16:26:13 +080066 (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,
cyland43f2932019-11-26 17:37:28 +080070 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_HOST):
71 remote_image_remote_host.RemoteImageRemoteHost,
Richard Fung97503b22019-02-06 13:43:38 -080072 # Cheeps types
73 (constants.TYPE_CHEEPS, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
74 cheeps_remote_image_remote_instance.CheepsRemoteImageRemoteInstance,
herbertxue494891e2019-01-19 13:50:53 +080075 # GF types
76 (constants.TYPE_GF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
77 goldfish_remote_image_remote_instance.GoldfishRemoteImageRemoteInstance,
Hsin-Yi Chen7ba49962019-09-25 18:58:56 +080078 (constants.TYPE_GF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL):
79 goldfish_local_image_local_instance.GoldfishLocalImageLocalInstance,
chojoyce7a361732018-11-26 16:26:13 +080080}
Kevin Cheng3ce4b452018-08-23 14:47:22 -070081
chojoyce7a361732018-11-26 16:26:13 +080082
83def GetAvdCreatorClass(avd_type, instance_type, image_source):
Kevin Cheng3ce4b452018-08-23 14:47:22 -070084 """Return the creator class for the specified spec.
85
86 Based on the image source and the instance type, return the proper
87 creator class.
88
89 Args:
chojoyce7a361732018-11-26 16:26:13 +080090 avd_type: String, the AVD type(cuttlefish, gce).
Kevin Cheng3ce4b452018-08-23 14:47:22 -070091 instance_type: String, the AVD instance type (local or remote).
92 image_source: String, the source of the image (local or remote).
93
94 Returns:
95 An AVD creator class (e.g. LocalImageRemoteInstance).
chojoyce7a361732018-11-26 16:26:13 +080096
97 Raises:
98 UnsupportedInstanceImageType if argments didn't match _CREATOR_CLASS_DICT.
Kevin Cheng3ce4b452018-08-23 14:47:22 -070099 """
chojoyce7a361732018-11-26 16:26:13 +0800100 creator_class = _CREATOR_CLASS_DICT.get(
101 (avd_type, image_source, instance_type))
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700102
chojoyce7a361732018-11-26 16:26:13 +0800103 if not creator_class:
104 raise errors.UnsupportedInstanceImageType(
105 "unsupported creation of avd type: %s, instance type: %s, "
106 "image source: %s" % (avd_type, instance_type, image_source))
107 return creator_class
Kevin Cheng3087af52018-08-13 13:26:50 -0700108
Kevin Cheng835a4152018-10-11 10:46:57 -0700109def _CheckForAutoconnect(args):
110 """Check that we have all prerequisites for autoconnect.
111
112 Autoconnect requires adb and ssh, we'll just check for adb for now and
113 assume ssh is everywhere. If adb isn't around, ask the user if they want us
114 to build it, if not we'll disable autoconnect.
115
116 Args:
117 args: Namespace object from argparse.parse_args.
118 """
119 if not args.autoconnect or find_executable(constants.ADB_BIN):
120 return
121
122 disable_autoconnect = False
123 answer = utils.InteractWithQuestion(
124 "adb is required for autoconnect, without it autoconnect will be "
Sam Chiu705b9012019-01-19 12:11:35 +0800125 "disabled, would you like acloud to build it[y/N]? ")
Kevin Cheng835a4152018-10-11 10:46:57 -0700126 if answer in constants.USER_ANSWER_YES:
127 utils.PrintColorString("Building adb ... ", end="")
128 android_build_top = os.environ.get(
129 constants.ENV_ANDROID_BUILD_TOP)
130 if not android_build_top:
131 utils.PrintColorString("Fail! (Not in a lunch'd env)",
132 utils.TextColors.FAIL)
133 disable_autoconnect = True
134 else:
135 make_cmd = os.path.join(android_build_top, _MAKE_CMD)
136 build_adb_cmd = [make_cmd, _MAKE_ARG, "adb"]
137 try:
138 with open(os.devnull, "w") as dev_null:
139 subprocess.check_call(build_adb_cmd, stderr=dev_null,
140 stdout=dev_null)
141 utils.PrintColorString("OK!", utils.TextColors.OKGREEN)
142 except subprocess.CalledProcessError:
143 utils.PrintColorString("Fail! (build failed)",
144 utils.TextColors.FAIL)
145 disable_autoconnect = True
146 else:
147 disable_autoconnect = True
148
149 if disable_autoconnect:
150 utils.PrintColorString("Disabling autoconnect",
151 utils.TextColors.WARNING)
152 args.autoconnect = False
153
154
155def _CheckForSetup(args):
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700156 """Check that host is setup to run the create commands.
157
158 We'll check we have the necessary bits setup to do what the user wants, and
159 if not, tell them what they need to do before running create again.
160
161 Args:
162 args: Namespace object from argparse.parse_args.
163 """
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700164 # Need to set all these so if we need to run setup, it won't barf on us
165 # because of some missing fields.
166 args.gcp_init = False
167 args.host = False
Kevin Chengeb997272019-06-05 14:53:18 -0700168 args.host_base = False
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700169 args.force = False
170 # Remote image/instance requires the GCP config setup.
171 if not args.local_instance or args.local_image == "":
172 gcp_setup = gcp_setup_runner.GcpTaskRunner(args.config_file)
173 if gcp_setup.ShouldRun():
174 args.gcp_init = True
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700175
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700176 # Local instance requires host to be setup. We'll assume that if the
177 # packages were installed, then the user was added into the groups. This
178 # avoids the scenario where a user runs setup and creates a local instance.
179 # The following local instance create will trigger this if statment and go
180 # through the whole setup again even though it's already done because the
181 # user groups aren't set until the user logs out and back in.
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700182 if args.local_instance:
183 host_pkg_setup = host_setup_runner.AvdPkgInstaller()
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700184 if host_pkg_setup.ShouldRun():
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700185 args.host = True
Kevin Chengeb997272019-06-05 14:53:18 -0700186
187 # Install base packages if we haven't already.
188 host_base_setup = host_setup_runner.HostBasePkgInstaller()
189 if host_base_setup.ShouldRun():
190 args.host_base = True
191
192 run_setup = args.force or args.gcp_init or args.host or args.host_base
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700193
194 if run_setup:
195 answer = utils.InteractWithQuestion("Missing necessary acloud setup, "
Sam Chiu705b9012019-01-19 12:11:35 +0800196 "would you like to run setup[y/N]?")
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700197 if answer in constants.USER_ANSWER_YES:
198 setup.Run(args)
199 else:
200 print("Please run '#acloud setup' so we can get your host setup")
Sam Chiue791f602019-05-03 15:18:10 +0800201 sys.exit(constants.EXIT_BY_USER)
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700202
203
Kevin Cheng835a4152018-10-11 10:46:57 -0700204def PreRunCheck(args):
205 """Do some pre-run checks to ensure a smooth create experience.
206
207 Args:
208 args: Namespace object from argparse.parse_args.
209 """
210 _CheckForSetup(args)
211 _CheckForAutoconnect(args)
212
213
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700214def Run(args):
Kevin Cheng3087af52018-08-13 13:26:50 -0700215 """Run create.
216
217 Args:
218 args: Namespace object from argparse.parse_args.
219 """
Kevin Chengfab8cfc2019-06-27 14:01:37 -0700220 if not args.skip_pre_run_check:
221 PreRunCheck(args)
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700222 spec = avd_spec.AVDSpec(args)
chojoyce7a361732018-11-26 16:26:13 +0800223 avd_creator_class = GetAvdCreatorClass(spec.avd_type,
224 spec.instance_type,
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700225 spec.image_source)
226 avd_creator = avd_creator_class()
herbertxue7ef23b22019-02-27 09:34:24 +0800227 report = avd_creator.Create(spec, args.no_prompt)
herbertxuedf01c422018-09-06 19:52:52 +0800228 if report and args.report_file:
229 report.Dump(args.report_file)