• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 - The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14r"""Create args.
15
16Defines the create arg parser that holds create specific args.
17"""
18
19import argparse
20import logging
21import os
22
23from acloud import errors
24from acloud.create import create_common
25from acloud.internal import constants
26from acloud.internal.lib import utils
27
28logger = logging.getLogger(__name__)
29_DEFAULT_GPU = "default"
30CMD_CREATE = "create"
31
32
33# TODO: Add this into main create args once create_cf/gf is deprecated.
34# pylint: disable=too-many-statements
35def AddCommonCreateArgs(parser):
36    """Adds arguments common to create parsers.
37
38    Args:
39        parser: ArgumentParser object, used to parse flags.
40    """
41    parser.add_argument(
42        "--num",
43        type=int,
44        dest="num",
45        required=False,
46        default=1,
47        help="Number of instances to create.")
48    parser.add_argument(
49        "--serial-log-file",
50        type=str,
51        dest="serial_log_file",
52        required=False,
53        help="Path to a *tar.gz file where serial logs will be saved "
54             "when a device fails on boot.")
55    parser.add_argument(
56        "--autoconnect",
57        type=str,
58        nargs="?",
59        const=constants.INS_KEY_WEBRTC,
60        dest="autoconnect",
61        required=False,
62        choices=[constants.INS_KEY_VNC, constants.INS_KEY_ADB,
63                 constants.INS_KEY_WEBRTC],
64        help="Determines to establish a tunnel forwarding adb/vnc and "
65             "launch VNC/webrtc. Establish a tunnel forwarding adb and vnc "
66             "then launch vnc if --autoconnect vnc is provided. Establish a "
67             "tunnel forwarding adb if --autoconnect adb is provided. "
68             "Establish a tunnel forwarding adb and auto-launch on the browser "
69             "if --autoconnect webrtc is provided. For local goldfish "
70             "instance, create a window.")
71    parser.add_argument(
72        "--no-autoconnect",
73        action="store_false",
74        dest="autoconnect",
75        required=False,
76        help="Will not automatically create ssh tunnels forwarding adb & vnc "
77             "when instance created.")
78    parser.set_defaults(autoconnect=constants.INS_KEY_WEBRTC)
79    parser.add_argument(
80        "--unlock",
81        action="store_true",
82        dest="unlock_screen",
83        required=False,
84        default=False,
85        help="This can unlock screen after invoke vnc client.")
86    parser.add_argument(
87        "--report-internal-ip",
88        action="store_true",
89        dest="report_internal_ip",
90        required=False,
91        help="Report internal ip of the created instance instead of external "
92             "ip. Using the internal ip is used when connecting from another "
93             "GCE instance.")
94    parser.add_argument(
95        "--disable-external-ip",
96        action="store_true",
97        dest="disable_external_ip",
98        required=False,
99        help="Disable the external ip of the created instance.")
100    parser.add_argument(
101        "--extra-files",
102        nargs='+',
103        type=str,
104        dest="extra_files",
105        required=False,
106        help="Upload the extra files into GCE instance. e.g. "
107             "/path/to/file_in_local,/path/to/file_in_gce")
108    parser.add_argument(
109        "--network",
110        type=str,
111        dest="network",
112        required=False,
113        help="Set the network the GCE instance will utilize.")
114    parser.add_argument(
115        "--skip-pre-run-check",
116        action="store_true",
117        dest="skip_pre_run_check",
118        required=False,
119        help="Skip the pre-run check.")
120    parser.add_argument(
121        "--force-sync",
122        action="store_true",
123        dest="force_sync",
124        required=False,
125        help="Force to sync image files from Android Build servers even if "
126             "they are already existed for local instance mode.")
127    parser.add_argument(
128        "--boot-timeout",
129        dest="boot_timeout_secs",
130        type=int,
131        required=False,
132        help="The maximum time in seconds used to wait for the AVD to download "
133             "artifacts and boot.")
134    parser.add_argument(
135        "--wait-for-ins-stable",
136        dest="ins_timeout_secs",
137        type=int,
138        required=False,
139        help="The maximum time in seconds used to wait for the instance boot "
140             "up. The default value to wait for instance up time is 300 secs.")
141    parser.add_argument(
142        "--build-target",
143        type=str,
144        dest="build_target",
145        help="Android build target, e.g. aosp_cf_x86_64_phone-userdebug, "
146             "or short names: phone, tablet, or tablet_mobile.")
147    parser.add_argument(
148        "--branch",
149        type=str,
150        dest="branch",
151        help="Android branch, e.g. mnc-dev or git_mnc-dev")
152    parser.add_argument(
153        "--build-id",
154        type=str,
155        dest="build_id",
156        help="Android build id, e.g. 2145099, P2804227")
157    parser.add_argument(
158        "--bootloader-branch",
159        type=str,
160        dest="bootloader_branch",
161        help="'cuttlefish only' Branch to consume the bootloader from.",
162        required=False)
163    parser.add_argument(
164        "--bootloader-build-id",
165        type=str,
166        dest="bootloader_build_id",
167        help="'cuttlefish only' Bootloader build id, e.g. P2804227",
168        required=False)
169    parser.add_argument(
170        "--bootloader-build-target",
171        type=str,
172        dest="bootloader_build_target",
173        help="'cuttlefish only' Bootloader build target.",
174        required=False)
175    parser.add_argument(
176        "--kernel-build-id",
177        type=str,
178        dest="kernel_build_id",
179        required=False,
180        help="Android kernel build id, e.g. 4586590. This is to test a new"
181        " kernel build with a particular Android build (--build-id). If neither"
182        " kernel-branch nor kernel-build-id are specified, the kernel that's"
183        " bundled with the Android build would be used.")
184    parser.add_argument(
185        "--kernel-branch",
186        type=str,
187        dest="kernel_branch",
188        required=False,
189        help="Android kernel build branch name, e.g."
190        " kernel-common-android-4.14. This is to test a new kernel build with a"
191        " particular Android build (--build-id). If specified without"
192        " specifying kernel-build-id, the last green build in the branch will"
193        " be used. If neither kernel-branch nor kernel-build-id are specified,"
194        " the kernel that's bundled with the Android build would be used.")
195    parser.add_argument(
196        "--kernel-build-target",
197        type=str,
198        dest="kernel_build_target",
199        default="kernel",
200        help="Kernel build target, specify if different from 'kernel'")
201    parser.add_argument(
202        "--kernel-artifact",
203        type=str,
204        dest="kernel_artifact",
205        required=False,
206        help="Goldfish remote host only. The name of the boot image to be "
207        "retrieved from Android build, e.g., boot-5.10.img.")
208    parser.add_argument(
209        "--ota-branch",
210        type=str,
211        dest="ota_branch",
212        required=False,
213        help="'cuttlefish only' OTA tools branch name. e.g. aosp-master")
214    parser.add_argument(
215        "--ota-build-id",
216        type=str,
217        dest="ota_build_id",
218        required=False,
219        help="'cuttlefish only' OTA tools build id, e.g. 2145099, P2804227")
220    parser.add_argument(
221        "--ota-build-target",
222        type=str,
223        dest="ota_build_target",
224        required=False,
225        help="'cuttlefish only' OTA tools build target, e.g. "
226        "cf_x86_64_phone-userdebug.")
227    parser.add_argument(
228        "--system-branch",
229        type=str,
230        dest="system_branch",
231        help="'cuttlefish only' Branch to consume the system image (system.img) "
232        "from, will default to what is defined by --branch. "
233        "That feature allows to (automatically) test various combinations "
234        "of vendor.img (CF, e.g.) and system images (GSI, e.g.). ",
235        required=False)
236    parser.add_argument(
237        "--system-build-id",
238        type=str,
239        dest="system_build_id",
240        help="'cuttlefish only' System image build id, e.g. 2145099, P2804227",
241        required=False)
242    parser.add_argument(
243        "--system-build-target",
244        type=str,
245        dest="system_build_target",
246        help="'cuttlefish only' System image build target, specify if different "
247        "from --build-target",
248        required=False)
249    parser.add_argument(
250        "--launch-args",
251        type=str,
252        dest="launch_args",
253        help="'cuttlefish only' Add extra args to launch_cvd command.",
254        required=False)
255    parser.add_argument(
256        "--gce-metadata",
257        type=str,
258        dest="gce_metadata",
259        default=None,
260        help="'GCE instance only' Record data into GCE instance metadata with "
261        "key-value pair format. e.g. id:12,name:unknown.")
262    # TODO(146314062): Remove --multi-stage-launch after infra don't use this
263    # args.
264    parser.add_argument(
265        "--multi-stage-launch",
266        dest="multi_stage_launch",
267        action="store_true",
268        required=False,
269        default=True,
270        help="Enable the multi-stage cuttlefish launch.")
271    parser.add_argument(
272        "--no-multi-stage-launch",
273        dest="multi_stage_launch",
274        action="store_false",
275        required=False,
276        default=None,
277        help="Disable the multi-stage cuttlefish launch.")
278    parser.add_argument(
279        "--no-pull-log",
280        dest="no_pull_log",
281        action="store_true",
282        required=False,
283        default=None,
284        help="Disable auto download logs when AVD booting up failed.")
285    parser.add_argument(
286        "--no-mkcert",
287        dest="mkcert",
288        action="store_false",
289        required=False,
290        default=True,
291        help="Disable mkcert setup process on the host.")
292    # TODO(147335651): Add gpu in user config.
293    # TODO(147335651): Support "--gpu" without giving any value.
294    parser.add_argument(
295        "--gpu",
296        type=str,
297        const=_DEFAULT_GPU,
298        nargs="?",
299        dest="gpu",
300        required=False,
301        default=None,
302        help="GPU accelerator to use if any. e.g. nvidia-tesla-k80. For local "
303             "instances, this arg without assigning any value is to enable "
304             "local gpu support.")
305    # Hide following args for users, it is only used in infra.
306    parser.add_argument(
307        "--local-instance-dir",
308        dest="local_instance_dir",
309        required=False,
310        help=argparse.SUPPRESS)
311    parser.add_argument(
312        "--num-avds-per-instance",
313        type=int,
314        dest="num_avds_per_instance",
315        required=False,
316        default=1,
317        help=argparse.SUPPRESS)
318    parser.add_argument(
319        "--oxygen",
320        action="store_true",
321        dest="oxygen",
322        required=False,
323        help=argparse.SUPPRESS)
324    parser.add_argument(
325        "--zone",
326        type=str,
327        dest="zone",
328        required=False,
329        help=argparse.SUPPRESS)
330
331    # TODO(b/118439885): Old arg formats to support transition, delete when
332    # transistion is done.
333    parser.add_argument(
334        "--serial_log_file",
335        type=str,
336        dest="serial_log_file",
337        required=False,
338        help=argparse.SUPPRESS)
339    parser.add_argument(
340        "--build_id",
341        type=str,
342        dest="build_id",
343        required=False,
344        help=argparse.SUPPRESS)
345    parser.add_argument(
346        "--build_target",
347        type=str,
348        dest="build_target",
349        required=False,
350        help=argparse.SUPPRESS)
351    parser.add_argument(
352        "--system_branch",
353        type=str,
354        dest="system_branch",
355        required=False,
356        help=argparse.SUPPRESS)
357    parser.add_argument(
358        "--system_build_id",
359        type=str,
360        dest="system_build_id",
361        required=False,
362        help=argparse.SUPPRESS)
363    parser.add_argument(
364        "--system_build_target",
365        type=str,
366        dest="system_build_target",
367        required=False,
368        help=argparse.SUPPRESS)
369    parser.add_argument(
370        "--kernel_build_id",
371        type=str,
372        dest="kernel_build_id",
373        required=False,
374        help=argparse.SUPPRESS)
375    parser.add_argument(
376        "--kernel_branch",
377        type=str,
378        dest="kernel_branch",
379        required=False,
380        help=argparse.SUPPRESS)
381    parser.add_argument(
382        "--kernel_build_target",
383        type=str,
384        dest="kernel_build_target",
385        default="kernel",
386        help=argparse.SUPPRESS)
387    parser.add_argument(
388        "--bootloader_branch",
389        type=str,
390        dest="bootloader_branch",
391        help=argparse.SUPPRESS,
392        required=False)
393    parser.add_argument(
394        "--bootloader_build_id",
395        type=str,
396        dest="bootloader_build_id",
397        help=argparse.SUPPRESS,
398        required=False)
399    parser.add_argument(
400        "--bootloader_build_target",
401        type=str,
402        dest="bootloader_build_target",
403        help=argparse.SUPPRESS,
404        required=False)
405
406
407def GetCreateArgParser(subparser):
408    """Return the create arg parser.
409
410    Args:
411       subparser: argparse.ArgumentParser that is attached to main acloud cmd.
412
413    Returns:
414        argparse.ArgumentParser with create options defined.
415    """
416    create_parser = subparser.add_parser(CMD_CREATE)
417    create_parser.required = False
418    create_parser.set_defaults(which=CMD_CREATE)
419    # Use default=None to distinguish remote instance or local. The instance
420    # type will be remote if the arg is not provided.
421    create_parser.add_argument(
422        "--local-instance",
423        type=_PositiveInteger,
424        const=0,
425        metavar="ID",
426        nargs="?",
427        dest="local_instance",
428        required=False,
429        help="Create a local AVD instance using the resources associated with "
430             "the ID. Choose an unused ID automatically if the value is "
431             "not specified (primarily for infra usage).")
432    create_parser.add_argument(
433        "--adb-port", "-p",
434        type=int,
435        default=None,
436        dest="adb_port",
437        required=False,
438        help="Specify port for adb forwarding.")
439    create_parser.add_argument(
440        "--base-instance-num",
441        type=int,
442        default=None,
443        dest="base_instance_num",
444        required=False,
445        help="'cuttlefish only' The instance number of the created device.")
446    create_parser.add_argument(
447        "--avd-type",
448        type=str,
449        dest="avd_type",
450        default=constants.TYPE_CF,
451        choices=[constants.TYPE_GCE, constants.TYPE_CF, constants.TYPE_GF, constants.TYPE_CHEEPS,
452                 constants.TYPE_FVP],
453        help="Android Virtual Device type (default %s)." % constants.TYPE_CF)
454    create_parser.add_argument(
455        "--config", "--flavor",
456        type=str,
457        dest="flavor",
458        help="The device flavor of the AVD (default %s). e.g. phone, tv, foldable."
459        % constants.FLAVOR_PHONE)
460    create_parser.add_argument(
461        "--local-image",
462        const=constants.FIND_IN_BUILD_ENV,
463        type=str,
464        dest="local_image",
465        nargs="?",
466        required=False,
467        help="Use the locally built image for the AVD. Look for the image "
468        "artifact in $ANDROID_PRODUCT_OUT if no args value is provided."
469        "e.g --local-image or --local-image /path/to/dir or --local-image "
470        "/path/to/file")
471    create_parser.add_argument(
472        "--local-kernel-image", "--local-boot-image",
473        const=constants.FIND_IN_BUILD_ENV,
474        type=str,
475        dest="local_kernel_image",
476        nargs="?",
477        required=False,
478        help="Use the locally built kernel image for the AVD. Look for "
479        "boot.img or boot-*.img if the argument is a directory. Look for the "
480        "image in $ANDROID_PRODUCT_OUT if no argument is provided. e.g., "
481        "--local-kernel-image, --local-kernel-image /path/to/dir, or "
482        "--local-kernel-image /path/to/img")
483    create_parser.add_argument(
484        "--local-system-image",
485        const=constants.FIND_IN_BUILD_ENV,
486        type=str,
487        dest="local_system_image",
488        nargs="?",
489        required=False,
490        help="Use the locally built system images for the AVD. Look for the "
491        "images in $ANDROID_PRODUCT_OUT if no args value is provided. "
492        "e.g., --local-system-image, --local-system-image /path/to/dir, or "
493        "--local-system-image /path/to/img")
494    create_parser.add_argument(
495        "--local-tool",
496        type=str,
497        dest="local_tool",
498        action="append",
499        default=[],
500        required=False,
501        help="Use the tools in the specified directory to create local "
502        "instances. The directory structure follows $ANDROID_SOONG_HOST_OUT "
503        "or $ANDROID_EMULATOR_PREBUILTS.")
504    create_parser.add_argument(
505        "--cvd-host-package",
506        type=str,
507        dest="cvd_host_package",
508        required=False,
509        help="Use the specified path of the cvd host package to create "
510        "instances. e.g. /path/cvd-host_package_v1.tar.gz")
511    create_parser.add_argument(
512        "--image-download-dir",
513        type=str,
514        dest="image_download_dir",
515        required=False,
516        help="Define remote image download directory, e.g. /usr/local/dl.")
517    create_parser.add_argument(
518        "--yes", "-y",
519        action="store_true",
520        dest="no_prompt",
521        required=False,
522        help=("Automatic yes to prompts. Assume 'yes' as answer to all prompts "
523              "and run non-interactively."))
524    create_parser.add_argument(
525        "--reuse-gce",
526        type=str,
527        const=constants.SELECT_ONE_GCE_INSTANCE,
528        nargs="?",
529        dest="reuse_gce",
530        required=False,
531        help="'cuttlefish only' This can help users use their own instance. "
532        "Reusing specific gce instance if --reuse-gce [instance_name] is "
533        "provided. Select one gce instance to reuse if --reuse-gce is "
534        "provided.")
535    create_parser.add_argument(
536        "--openwrt",
537        action="store_true",
538        dest="openwrt",
539        required=False,
540        help="'cuttlefish only' Create OpenWrt device when launching cuttlefish "
541        "device.")
542    create_parser.add_argument(
543        "--use-launch_cvd",
544        action="store_true",
545        dest="use_launch_cvd",
546        required=False,
547        help="'cuttlefish only' Use launch_cvd to create cuttlefish devices.")
548    create_parser.add_argument(
549        "--host",
550        type=str,
551        dest="remote_host",
552        default=None,
553        help="'cuttlefish only' Provide host name to clean up the remote host. "
554        "For example: '--host 1.1.1.1'")
555    create_parser.add_argument(
556        "--host-user",
557        type=str,
558        dest="host_user",
559        default=constants.GCE_USER,
560        help="'remote host only' Provide host user for logging in to the host. "
561        "The default value is vsoc-01. For example: '--host 1.1.1.1 --host-user "
562        "vsoc-02'")
563    create_parser.add_argument(
564        "--host-ssh-private-key-path",
565        type=str,
566        dest="host_ssh_private_key_path",
567        default=None,
568        help="'remote host only' Provide host key for login on on this host.")
569    # User should not specify --spec and --hw_property at the same time.
570    hw_spec_group = create_parser.add_mutually_exclusive_group()
571    hw_spec_group.add_argument(
572        "--hw-property",
573        type=str,
574        dest="hw_property",
575        required=False,
576        help="Supported HW properties and example values: %s" %
577        constants.HW_PROPERTIES_CMD_EXAMPLE)
578    hw_spec_group.add_argument(
579        "--spec",
580        type=str,
581        dest="spec",
582        required=False,
583        choices=constants.SPEC_NAMES,
584        help="The name of a pre-configured device spec that we are "
585        "going to use.")
586    create_parser.add_argument(
587        "--disk-type",
588        type=str,
589        dest="disk_type",
590        required=False,
591        help="This is used to customize the GCE instance disk type, the "
592        "default disk type is from the stable host image. Use pd-ssd or "
593        "pd-standard to specify instance disk type.")
594    create_parser.add_argument(
595        "--stable-host-image-name",
596        type=str,
597        dest="stable_host_image_name",
598        required=False,
599        default=None,
600        help=("'cuttlefish only' The Cuttlefish host image from which instances "
601              "are launched. If specified here, the value set in Acloud config "
602              "file will be overridden."))
603
604    # Arguments for goldfish type.
605    create_parser.add_argument(
606        "--emulator-build-id",
607        type=int,
608        dest="emulator_build_id",
609        required=False,
610        help="'goldfish only' Emulator build ID used to run the images. "
611        "e.g. 4669466.")
612    create_parser.add_argument(
613        "--emulator-build-target",
614        dest="emulator_build_target",
615        required=False,
616        help="'goldfish remote host only' Emulator build target used to run "
617        "the images. e.g. sdk_tools_linux.")
618
619    # Arguments for cheeps type.
620    create_parser.add_argument(
621        "--stable-cheeps-host-image-name",
622        type=str,
623        dest="stable_cheeps_host_image_name",
624        required=False,
625        default=None,
626        help=("'cheeps only' The Cheeps host image from which instances are "
627              "launched. If specified here, the value set in Acloud config "
628              "file will be overridden."))
629    create_parser.add_argument(
630        "--stable-cheeps-host-image-project",
631        type=str,
632        dest="stable_cheeps_host_image_project",
633        required=False,
634        default=None,
635        help=("'cheeps only' The project hosting the specified Cheeps host "
636              "image. If specified here, the value set in Acloud config file "
637              "will be overridden."))
638    create_parser.add_argument(
639        "--user",
640        type=str,
641        dest="username",
642        required=False,
643        default=None,
644        help="'cheeps only' username to log in to Chrome OS as.")
645    create_parser.add_argument(
646        "--password",
647        type=str,
648        dest="password",
649        required=False,
650        default=None,
651        help="'cheeps only' password to log in to Chrome OS with.")
652    create_parser.add_argument(
653        "--betty-image",
654        type=str,
655        dest="cheeps_betty_image",
656        required=False,
657        default=None,
658        help=("'cheeps only' The L1 betty version to use. Only makes sense "
659              "when launching a controller image with "
660              "stable-cheeps-host-image"))
661    create_parser.add_argument(
662        "--cheeps-feature",
663        type=str,
664        dest="cheeps_features",
665        required=False,
666        action="append",
667        default=[],
668        help=("'cheeps only' Cheeps feature to enable. Can be repeated."))
669
670    AddCommonCreateArgs(create_parser)
671    return create_parser
672
673
674def _PositiveInteger(arg):
675    """Convert an argument from a string to a positive integer."""
676    try:
677        value = int(arg)
678    except ValueError as e:
679        raise argparse.ArgumentTypeError(arg + " is not an integer.") from e
680    if value <= 0:
681        raise argparse.ArgumentTypeError(arg + " is not positive.")
682    return value
683
684
685def _VerifyLocalArgs(args):
686    """Verify args starting with --local.
687
688    Args:
689        args: Namespace object from argparse.parse_args.
690
691    Raises:
692        errors.CheckPathError: Image path doesn't exist.
693        errors.UnsupportedCreateArgs: The specified avd type does not support
694                                      --local-system-image.
695        errors.UnsupportedLocalInstanceId: Local instance ID is invalid.
696    """
697    if args.local_image and not os.path.exists(args.local_image):
698        raise errors.CheckPathError(
699            "Specified path doesn't exist: %s" % args.local_image)
700
701    if args.local_instance_dir and not os.path.exists(args.local_instance_dir):
702        raise errors.CheckPathError(
703            "Specified path doesn't exist: %s" % args.local_instance_dir)
704
705    if not (args.local_system_image is None or
706            args.avd_type in (constants.TYPE_CF, constants.TYPE_GF)):
707        raise errors.UnsupportedCreateArgs("%s instance does not support "
708                                           "--local-system-image" %
709                                           args.avd_type)
710    # TODO(b/179340595): To support local image remote instance with kernel build.
711    if args.local_instance is None and args.local_image is not None and (
712            args.kernel_branch or args.kernel_build_id):
713        raise errors.UnsupportedCreateArgs(
714            "Acloud didn't support local image with specific kernel. "
715            "Please download the specific kernel and put it into "
716            "your local image folder: '%s'." % (
717            args.local_image if args.local_image else
718            utils.GetBuildEnvironmentVariable(constants.ENV_ANDROID_PRODUCT_OUT)))
719
720    if (args.local_system_image and
721            not os.path.exists(args.local_system_image)):
722        raise errors.CheckPathError(
723            "Specified path doesn't exist: %s" % args.local_system_image)
724
725    for tool_dir in args.local_tool:
726        if not os.path.exists(tool_dir):
727            raise errors.CheckPathError(
728                "Specified path doesn't exist: %s" % tool_dir)
729
730
731def _VerifyHostArgs(args):
732    """Verify args starting with --host.
733
734    Args:
735        args: Namespace object from argparse.parse_args.
736
737    Raises:
738        errors.UnsupportedCreateArgs: When a create arg is specified but
739                                      unsupported for remote host mode.
740    """
741    if args.remote_host and args.local_instance is not None:
742        raise errors.UnsupportedCreateArgs(
743            "--host is not supported for local instance.")
744
745    if args.remote_host and args.num > 1:
746        raise errors.UnsupportedCreateArgs(
747            "--num is not supported for remote host.")
748
749    if args.host_user != constants.GCE_USER and args.remote_host is None:
750        raise errors.UnsupportedCreateArgs(
751            "--host-user only support for remote host.")
752
753    if args.host_ssh_private_key_path and args.remote_host is None:
754        raise errors.UnsupportedCreateArgs(
755            "--host-ssh-private-key-path only support for remote host.")
756
757
758def _VerifyGoldfishArgs(args):
759    """Verify goldfish args.
760
761    Args:
762        args: Namespace object from argparse.parse_args.
763
764    Raises:
765        errors.UnsupportedCreateArgs: When a create arg is specified but
766                                      unsupported for goldfish.
767    """
768    goldfish_only_flags = [
769        args.emulator_build_id,
770        args.emulator_build_target,
771        args.kernel_artifact
772    ]
773    if args.avd_type != constants.TYPE_GF and any(goldfish_only_flags):
774        raise errors.UnsupportedCreateArgs(
775            "--emulator-* and --kernel-artifact are only valid with "
776            "avd_type == %s" % constants.TYPE_GF)
777
778    # Exclude kernel_build_target because the default value isn't empty.
779    remote_kernel_flags = [
780        args.kernel_build_id,
781        args.kernel_branch,
782        args.kernel_artifact,
783    ]
784    if (args.avd_type == constants.TYPE_GF and any(remote_kernel_flags) and
785            not all(remote_kernel_flags)):
786        raise errors.UnsupportedCreateArgs(
787            "Either none or all of --kernel-branch, --kernel-build-target, "
788            "--kernel-build-id, and --kernel-artifact must be specified for "
789            "goldfish.")
790
791    remote_system_flags = [
792        args.system_build_target,
793        args.system_build_id,
794        args.system_branch,
795    ]
796    if (args.avd_type == constants.TYPE_GF and any(remote_system_flags) and
797            not all(remote_system_flags)):
798        raise errors.UnsupportedCreateArgs(
799            "Either none or all of --system-branch, --system-build-target, "
800            "and --system-build-id must be specified for goldfish.")
801
802    remote_host_only_flags = ([args.emulator_build_target] +
803                              remote_kernel_flags + remote_system_flags)
804    if args.avd_type == constants.TYPE_GF and args.remote_host is None and any(
805            remote_host_only_flags):
806        raise errors.UnsupportedCreateArgs(
807            "--kernel-*, --system-*, and --emulator-build-target for goldfish "
808            "are only supported for remote host.")
809
810
811def VerifyArgs(args):
812    """Verify args.
813
814    Args:
815        args: Namespace object from argparse.parse_args.
816
817    Raises:
818        errors.UnsupportedMultiAdbPort: multi adb port doesn't support.
819        errors.UnsupportedCreateArgs: When a create arg is specified but
820                                      unsupported for a particular avd type.
821                                      (e.g. --system-build-id for gf)
822    """
823    # Verify that user specified flavor name is in support list.
824    # We don't use argparse's builtin validation because we need to be able to
825    # tell when a user doesn't specify a flavor.
826    if args.flavor and args.flavor not in constants.ALL_FLAVORS:
827        logger.debug("Flavor[%s] isn't in default support list: %s",
828                     args.flavor, constants.ALL_FLAVORS)
829
830    if args.avd_type not in (constants.TYPE_CF, constants.TYPE_GF):
831        if args.system_branch or args.system_build_id or args.system_build_target:
832            raise errors.UnsupportedCreateArgs(
833                "--system-* args are not supported for AVD type: %s"
834                % args.avd_type)
835
836    if args.num > 1 and args.adb_port:
837        raise errors.UnsupportedMultiAdbPort(
838            "--adb-port is not supported for multi-devices.")
839
840    if args.num > 1 and args.local_instance is not None:
841        raise errors.UnsupportedCreateArgs(
842            "--num is not supported for local instance.")
843
844    if args.local_instance is None and args.gpu == _DEFAULT_GPU:
845        raise errors.UnsupportedCreateArgs(
846            "Please assign one gpu model for GCE instance. Reference: "
847            "https://cloud.google.com/compute/docs/gpus")
848
849    if args.adb_port:
850        utils.CheckPortFree(args.adb_port)
851
852    hw_properties = create_common.ParseKeyValuePairArgs(args.hw_property)
853    for key in hw_properties:
854        if key not in constants.HW_PROPERTIES:
855            raise errors.InvalidHWPropertyError(
856                "[%s] is an invalid hw property, supported values are:%s. "
857                % (key, constants.HW_PROPERTIES))
858
859    cheeps_only_flags = [args.stable_cheeps_host_image_name,
860                         args.stable_cheeps_host_image_project,
861                         args.username,
862                         args.password,
863                         args.cheeps_betty_image,
864                         args.cheeps_features]
865    if args.avd_type != constants.TYPE_CHEEPS and any(cheeps_only_flags):
866        raise errors.UnsupportedCreateArgs(
867            "--stable-cheeps-*, --betty-image, --cheeps-feature, --username "
868            "and --password are only valid with avd_type == %s"
869            % constants.TYPE_CHEEPS)
870    if (args.username or args.password) and not (args.username and args.password):
871        raise ValueError("--username and --password must both be set")
872    if not args.autoconnect and args.unlock_screen:
873        raise ValueError("--no-autoconnect and --unlock couldn't be "
874                         "passed in together.")
875
876    _VerifyGoldfishArgs(args)
877    _VerifyLocalArgs(args)
878    _VerifyHostArgs(args)
879