You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
9.3 KiB
236 lines
9.3 KiB
#!/usr/bin/env python
|
|
#
|
|
# Copyright 2018 - The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
r"""Create entry point.
|
|
|
|
Create will handle all the logic related to creating a local/remote instance
|
|
an Android Virtual Device and the logic related to prepping the local/remote
|
|
image artifacts.
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from acloud import errors
|
|
from acloud.create import avd_spec
|
|
from acloud.create import cheeps_remote_image_remote_instance
|
|
from acloud.create import gce_local_image_remote_instance
|
|
from acloud.create import gce_remote_image_remote_instance
|
|
from acloud.create import goldfish_local_image_local_instance
|
|
from acloud.create import goldfish_remote_image_remote_instance
|
|
from acloud.create import local_image_local_instance
|
|
from acloud.create import local_image_remote_instance
|
|
from acloud.create import local_image_remote_host
|
|
from acloud.create import remote_image_remote_instance
|
|
from acloud.create import remote_image_local_instance
|
|
from acloud.create import remote_image_remote_host
|
|
from acloud.internal import constants
|
|
from acloud.internal.lib import utils
|
|
from acloud.setup import setup
|
|
from acloud.setup import gcp_setup_runner
|
|
from acloud.setup import host_setup_runner
|
|
|
|
|
|
_MAKE_CMD = "build/soong/soong_ui.bash"
|
|
_MAKE_ARG = "--make-mode"
|
|
_YES = "y"
|
|
|
|
_CREATOR_CLASS_DICT = {
|
|
# GCE types
|
|
(constants.TYPE_GCE, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE):
|
|
gce_local_image_remote_instance.GceLocalImageRemoteInstance,
|
|
(constants.TYPE_GCE, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
|
|
gce_remote_image_remote_instance.GceRemoteImageRemoteInstance,
|
|
# CF types
|
|
(constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL):
|
|
local_image_local_instance.LocalImageLocalInstance,
|
|
(constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE):
|
|
local_image_remote_instance.LocalImageRemoteInstance,
|
|
(constants.TYPE_CF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_HOST):
|
|
local_image_remote_host.LocalImageRemoteHost,
|
|
(constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
|
|
remote_image_remote_instance.RemoteImageRemoteInstance,
|
|
(constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_LOCAL):
|
|
remote_image_local_instance.RemoteImageLocalInstance,
|
|
(constants.TYPE_CF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_HOST):
|
|
remote_image_remote_host.RemoteImageRemoteHost,
|
|
# Cheeps types
|
|
(constants.TYPE_CHEEPS, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
|
|
cheeps_remote_image_remote_instance.CheepsRemoteImageRemoteInstance,
|
|
# GF types
|
|
(constants.TYPE_GF, constants.IMAGE_SRC_REMOTE, constants.INSTANCE_TYPE_REMOTE):
|
|
goldfish_remote_image_remote_instance.GoldfishRemoteImageRemoteInstance,
|
|
(constants.TYPE_GF, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_LOCAL):
|
|
goldfish_local_image_local_instance.GoldfishLocalImageLocalInstance,
|
|
# FVP types
|
|
(constants.TYPE_FVP, constants.IMAGE_SRC_LOCAL, constants.INSTANCE_TYPE_REMOTE):
|
|
local_image_remote_instance.LocalImageRemoteInstance,
|
|
}
|
|
|
|
|
|
def GetAvdCreatorClass(avd_type, instance_type, image_source):
|
|
"""Return the creator class for the specified spec.
|
|
|
|
Based on the image source and the instance type, return the proper
|
|
creator class.
|
|
|
|
Args:
|
|
avd_type: String, the AVD type(cuttlefish, gce).
|
|
instance_type: String, the AVD instance type (local or remote).
|
|
image_source: String, the source of the image (local or remote).
|
|
|
|
Returns:
|
|
An AVD creator class (e.g. LocalImageRemoteInstance).
|
|
|
|
Raises:
|
|
UnsupportedInstanceImageType if argments didn't match _CREATOR_CLASS_DICT.
|
|
"""
|
|
creator_class = _CREATOR_CLASS_DICT.get(
|
|
(avd_type, image_source, instance_type))
|
|
|
|
if not creator_class:
|
|
raise errors.UnsupportedInstanceImageType(
|
|
"unsupported creation of avd type: %s, instance type: %s, "
|
|
"image source: %s" % (avd_type, instance_type, image_source))
|
|
return creator_class
|
|
|
|
def _CheckForAutoconnect(args):
|
|
"""Check that we have all prerequisites for autoconnect.
|
|
|
|
Autoconnect requires adb and ssh, we'll just check for adb for now and
|
|
assume ssh is everywhere. If adb isn't around, ask the user if they want us
|
|
to build it, if not we'll disable autoconnect.
|
|
|
|
Args:
|
|
args: Namespace object from argparse.parse_args.
|
|
"""
|
|
if not args.autoconnect or utils.FindExecutable(constants.ADB_BIN):
|
|
return
|
|
|
|
disable_autoconnect = False
|
|
answer = _YES if args.no_prompt else utils.InteractWithQuestion(
|
|
"adb is required for autoconnect, without it autoconnect will be "
|
|
"disabled, would you like acloud to build it[y/N]? ")
|
|
if answer in constants.USER_ANSWER_YES:
|
|
utils.PrintColorString("Building adb ... ", end="")
|
|
android_build_top = os.environ.get(
|
|
constants.ENV_ANDROID_BUILD_TOP)
|
|
if not android_build_top:
|
|
utils.PrintColorString("Fail! (Not in a lunch'd env)",
|
|
utils.TextColors.FAIL)
|
|
disable_autoconnect = True
|
|
else:
|
|
make_cmd = os.path.join(android_build_top, _MAKE_CMD)
|
|
build_adb_cmd = [make_cmd, _MAKE_ARG, "adb"]
|
|
try:
|
|
with open(os.devnull, "w") as dev_null:
|
|
subprocess.check_call(build_adb_cmd, stderr=dev_null,
|
|
stdout=dev_null)
|
|
utils.PrintColorString("OK!", utils.TextColors.OKGREEN)
|
|
except subprocess.CalledProcessError:
|
|
utils.PrintColorString("Fail! (build failed)",
|
|
utils.TextColors.FAIL)
|
|
disable_autoconnect = True
|
|
else:
|
|
disable_autoconnect = True
|
|
|
|
if disable_autoconnect:
|
|
utils.PrintColorString("Disabling autoconnect",
|
|
utils.TextColors.WARNING)
|
|
args.autoconnect = False
|
|
|
|
|
|
def _CheckForSetup(args):
|
|
"""Check that host is setup to run the create commands.
|
|
|
|
We'll check we have the necessary bits setup to do what the user wants, and
|
|
if not, tell them what they need to do before running create again.
|
|
|
|
Args:
|
|
args: Namespace object from argparse.parse_args.
|
|
"""
|
|
# Need to set all these so if we need to run setup, it won't barf on us
|
|
# because of some missing fields.
|
|
args.gcp_init = False
|
|
args.host = False
|
|
args.host_base = False
|
|
args.force = False
|
|
args.update_config = None
|
|
# Remote image/instance requires the GCP config setup.
|
|
if args.local_instance is None or args.local_image is None:
|
|
gcp_setup = gcp_setup_runner.GcpTaskRunner(args.config_file)
|
|
if gcp_setup.ShouldRun():
|
|
args.gcp_init = True
|
|
|
|
# Local instance requires host to be setup. We'll assume that if the
|
|
# packages were installed, then the user was added into the groups. This
|
|
# avoids the scenario where a user runs setup and creates a local instance.
|
|
# The following local instance create will trigger this if statment and go
|
|
# through the whole setup again even though it's already done because the
|
|
# user groups aren't set until the user logs out and back in.
|
|
if args.local_instance is not None:
|
|
host_pkg_setup = host_setup_runner.AvdPkgInstaller()
|
|
if host_pkg_setup.ShouldRun():
|
|
args.host = True
|
|
|
|
# Install base packages if we haven't already.
|
|
host_base_setup = host_setup_runner.HostBasePkgInstaller()
|
|
if host_base_setup.ShouldRun():
|
|
args.host_base = True
|
|
|
|
run_setup = args.force or args.gcp_init or args.host or args.host_base
|
|
|
|
if run_setup:
|
|
answer = utils.InteractWithQuestion("Missing necessary acloud setup, "
|
|
"would you like to run setup[y/N]?")
|
|
if answer in constants.USER_ANSWER_YES:
|
|
setup.Run(args)
|
|
else:
|
|
print("Please run '#acloud setup' so we can get your host setup")
|
|
sys.exit(constants.EXIT_BY_USER)
|
|
|
|
|
|
def PreRunCheck(args):
|
|
"""Do some pre-run checks to ensure a smooth create experience.
|
|
|
|
Args:
|
|
args: Namespace object from argparse.parse_args.
|
|
"""
|
|
_CheckForSetup(args)
|
|
_CheckForAutoconnect(args)
|
|
|
|
|
|
def Run(args):
|
|
"""Run create.
|
|
|
|
Args:
|
|
args: Namespace object from argparse.parse_args.
|
|
|
|
Returns:
|
|
A Report instance.
|
|
"""
|
|
if not args.skip_pre_run_check:
|
|
PreRunCheck(args)
|
|
spec = avd_spec.AVDSpec(args)
|
|
avd_creator_class = GetAvdCreatorClass(spec.avd_type,
|
|
spec.instance_type,
|
|
spec.image_source)
|
|
avd_creator = avd_creator_class()
|
|
report = avd_creator.Create(spec, args.no_prompt)
|
|
return report
|