blob: 9dfba024d54bd85555086588ef1ce0ecdd2c68df [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
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
herbertxuedf01c422018-09-06 19:52:52 +080038from acloud.create import remote_image_remote_instance
chojoycecd004bc2018-09-13 10:39:00 +080039from acloud.create import remote_image_local_instance
Kevin Cheng3ce4b452018-08-23 14:47:22 -070040from acloud.internal import constants
Kevin Chengcc6bf0d2018-10-10 14:18:47 -070041from acloud.internal.lib import utils
42from acloud.setup import setup
43from acloud.setup import gcp_setup_runner
44from acloud.setup import host_setup_runner
Kevin Cheng3ce4b452018-08-23 14:47:22 -070045
Kevin Cheng835a4152018-10-11 10:46:57 -070046_MAKE_CMD = "build/soong/soong_ui.bash"
47_MAKE_ARG = "--make-mode"
48
chojoyce7a361732018-11-26 16:26:13 +080049_CREATOR_CLASS_DICT = {
50 # GCE types
51 (constants.TYPE_GCE, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE):
52 gce_local_image_remote_instance.GceLocalImageRemoteInstance,
53 (constants.TYPE_GCE, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
54 gce_remote_image_remote_instance.GceRemoteImageRemoteInstance,
55 # CF types
56 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL):
57 local_image_local_instance.LocalImageLocalInstance,
58 (constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE):
59 local_image_remote_instance.LocalImageRemoteInstance,
60 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
61 remote_image_remote_instance.RemoteImageRemoteInstance,
62 (constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_LOCAL):
63 remote_image_local_instance.RemoteImageLocalInstance,
Richard Fung97503b22019-02-06 13:43:38 -080064 # Cheeps types
65 (constants.TYPE_CHEEPS, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
66 cheeps_remote_image_remote_instance.CheepsRemoteImageRemoteInstance,
herbertxue494891e2019-01-19 13:50:53 +080067 # GF types
68 (constants.TYPE_GF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
69 goldfish_remote_image_remote_instance.GoldfishRemoteImageRemoteInstance,
chojoyce7a361732018-11-26 16:26:13 +080070}
Kevin Cheng3ce4b452018-08-23 14:47:22 -070071
chojoyce7a361732018-11-26 16:26:13 +080072
73def GetAvdCreatorClass(avd_type, instance_type, image_source):
Kevin Cheng3ce4b452018-08-23 14:47:22 -070074 """Return the creator class for the specified spec.
75
76 Based on the image source and the instance type, return the proper
77 creator class.
78
79 Args:
chojoyce7a361732018-11-26 16:26:13 +080080 avd_type: String, the AVD type(cuttlefish, gce).
Kevin Cheng3ce4b452018-08-23 14:47:22 -070081 instance_type: String, the AVD instance type (local or remote).
82 image_source: String, the source of the image (local or remote).
83
84 Returns:
85 An AVD creator class (e.g. LocalImageRemoteInstance).
chojoyce7a361732018-11-26 16:26:13 +080086
87 Raises:
88 UnsupportedInstanceImageType if argments didn't match _CREATOR_CLASS_DICT.
Kevin Cheng3ce4b452018-08-23 14:47:22 -070089 """
chojoyce7a361732018-11-26 16:26:13 +080090 creator_class = _CREATOR_CLASS_DICT.get(
91 (avd_type, image_source, instance_type))
Kevin Cheng3ce4b452018-08-23 14:47:22 -070092
chojoyce7a361732018-11-26 16:26:13 +080093 if not creator_class:
94 raise errors.UnsupportedInstanceImageType(
95 "unsupported creation of avd type: %s, instance type: %s, "
96 "image source: %s" % (avd_type, instance_type, image_source))
97 return creator_class
Kevin Cheng3087af52018-08-13 13:26:50 -070098
Kevin Cheng835a4152018-10-11 10:46:57 -070099def _CheckForAutoconnect(args):
100 """Check that we have all prerequisites for autoconnect.
101
102 Autoconnect requires adb and ssh, we'll just check for adb for now and
103 assume ssh is everywhere. If adb isn't around, ask the user if they want us
104 to build it, if not we'll disable autoconnect.
105
106 Args:
107 args: Namespace object from argparse.parse_args.
108 """
109 if not args.autoconnect or find_executable(constants.ADB_BIN):
110 return
111
112 disable_autoconnect = False
113 answer = utils.InteractWithQuestion(
114 "adb is required for autoconnect, without it autoconnect will be "
Sam Chiu705b9012019-01-19 12:11:35 +0800115 "disabled, would you like acloud to build it[y/N]? ")
Kevin Cheng835a4152018-10-11 10:46:57 -0700116 if answer in constants.USER_ANSWER_YES:
117 utils.PrintColorString("Building adb ... ", end="")
118 android_build_top = os.environ.get(
119 constants.ENV_ANDROID_BUILD_TOP)
120 if not android_build_top:
121 utils.PrintColorString("Fail! (Not in a lunch'd env)",
122 utils.TextColors.FAIL)
123 disable_autoconnect = True
124 else:
125 make_cmd = os.path.join(android_build_top, _MAKE_CMD)
126 build_adb_cmd = [make_cmd, _MAKE_ARG, "adb"]
127 try:
128 with open(os.devnull, "w") as dev_null:
129 subprocess.check_call(build_adb_cmd, stderr=dev_null,
130 stdout=dev_null)
131 utils.PrintColorString("OK!", utils.TextColors.OKGREEN)
132 except subprocess.CalledProcessError:
133 utils.PrintColorString("Fail! (build failed)",
134 utils.TextColors.FAIL)
135 disable_autoconnect = True
136 else:
137 disable_autoconnect = True
138
139 if disable_autoconnect:
140 utils.PrintColorString("Disabling autoconnect",
141 utils.TextColors.WARNING)
142 args.autoconnect = False
143
144
145def _CheckForSetup(args):
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700146 """Check that host is setup to run the create commands.
147
148 We'll check we have the necessary bits setup to do what the user wants, and
149 if not, tell them what they need to do before running create again.
150
151 Args:
152 args: Namespace object from argparse.parse_args.
153 """
154 run_setup = False
155 # Need to set all these so if we need to run setup, it won't barf on us
156 # because of some missing fields.
157 args.gcp_init = False
158 args.host = False
159 args.force = False
160 # Remote image/instance requires the GCP config setup.
161 if not args.local_instance or args.local_image == "":
162 gcp_setup = gcp_setup_runner.GcpTaskRunner(args.config_file)
163 if gcp_setup.ShouldRun():
164 args.gcp_init = True
165 run_setup = True
166
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700167 # Local instance requires host to be setup. We'll assume that if the
168 # packages were installed, then the user was added into the groups. This
169 # avoids the scenario where a user runs setup and creates a local instance.
170 # The following local instance create will trigger this if statment and go
171 # through the whole setup again even though it's already done because the
172 # user groups aren't set until the user logs out and back in.
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700173 if args.local_instance:
174 host_pkg_setup = host_setup_runner.AvdPkgInstaller()
Kevin Cheng2aa41da2018-10-11 15:00:48 -0700175 if host_pkg_setup.ShouldRun():
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700176 args.host = True
177 run_setup = True
178
179 if run_setup:
180 answer = utils.InteractWithQuestion("Missing necessary acloud setup, "
Sam Chiu705b9012019-01-19 12:11:35 +0800181 "would you like to run setup[y/N]?")
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700182 if answer in constants.USER_ANSWER_YES:
183 setup.Run(args)
184 else:
185 print("Please run '#acloud setup' so we can get your host setup")
Sam Chiue791f602019-05-03 15:18:10 +0800186 sys.exit(constants.EXIT_BY_USER)
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700187
188
Kevin Cheng835a4152018-10-11 10:46:57 -0700189def PreRunCheck(args):
190 """Do some pre-run checks to ensure a smooth create experience.
191
192 Args:
193 args: Namespace object from argparse.parse_args.
194 """
195 _CheckForSetup(args)
196 _CheckForAutoconnect(args)
197
198
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700199def Run(args):
Kevin Cheng3087af52018-08-13 13:26:50 -0700200 """Run create.
201
202 Args:
203 args: Namespace object from argparse.parse_args.
204 """
Kevin Chengcc6bf0d2018-10-10 14:18:47 -0700205 PreRunCheck(args)
Kevin Chengc3d0d5e2018-08-14 14:22:44 -0700206 spec = avd_spec.AVDSpec(args)
chojoyce7a361732018-11-26 16:26:13 +0800207 avd_creator_class = GetAvdCreatorClass(spec.avd_type,
208 spec.instance_type,
Kevin Cheng3ce4b452018-08-23 14:47:22 -0700209 spec.image_source)
210 avd_creator = avd_creator_class()
herbertxue7ef23b22019-02-27 09:34:24 +0800211 report = avd_creator.Create(spec, args.no_prompt)
herbertxuedf01c422018-09-06 19:52:52 +0800212 if report and args.report_file:
213 report.Dump(args.report_file)