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