• 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
22import posixpath as remote_path
23
24from acloud import errors
25from acloud.create import create_common
26from acloud.internal import constants
27from acloud.internal.lib import utils
28
29logger = logging.getLogger(__name__)
30_DEFAULT_GPU = "default"
31CMD_CREATE = "create"
32
33
34# TODO: Add this into main create args once create_cf/gf is deprecated.
35# pylint: disable=too-many-statements
36def AddCommonCreateArgs(parser):
37    """Adds arguments common to create parsers.
38
39    Args:
40        parser: ArgumentParser object, used to parse flags.
41    """
42    parser.add_argument(
43        "--num",
44        type=int,
45        dest="num",
46        required=False,
47        default=1,
48        help="Number of instances to create.")
49    parser.add_argument(
50        "--serial-log-file",
51        type=str,
52        dest="serial_log_file",
53        required=False,
54        help="Path to a *tar.gz file where serial logs will be saved "
55             "when a device fails on boot.")
56    parser.add_argument(
57        "--autoconnect",
58        type=str,
59        nargs="?",
60        const=constants.INS_KEY_WEBRTC,
61        dest="autoconnect",
62        required=False,
63        choices=[constants.INS_KEY_VNC, constants.INS_KEY_ADB,
64                 constants.INS_KEY_WEBRTC],
65        help="Determines to establish a tunnel forwarding adb/vnc and "
66             "launch VNC/webrtc. Establish a tunnel forwarding adb and vnc "
67             "then launch vnc if --autoconnect vnc is provided. Establish a "
68             "tunnel forwarding adb if --autoconnect adb is provided. "
69             "Establish a tunnel forwarding adb 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-trunk_staging-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        "--android-efi-loader-build-id",
178        type=str,
179        dest="android_efi_loader_build_id",
180        help="'cuttlefish only' Android EFI loader build id, e.g. P2804227",
181        required=False)
182    parser.add_argument(
183        "--android-efi-loader-artifact",
184        type=str,
185        dest="android_efi_loader_artifact",
186        help="'cuttlefish only' Android EFI loader artifact name, e.g. gbl_aarch64.efi",
187        required=False)
188    parser.add_argument(
189        "--kernel-build-id",
190        type=str,
191        dest="kernel_build_id",
192        required=False,
193        help="Android kernel build id, e.g. 4586590. This is to test a new"
194        " kernel build with a particular Android build (--build-id). If neither"
195        " kernel-branch nor kernel-build-id are specified, the kernel that's"
196        " bundled with the Android build would be used.")
197    parser.add_argument(
198        "--kernel-branch",
199        type=str,
200        dest="kernel_branch",
201        required=False,
202        help="Android kernel build branch name, e.g."
203        " kernel-common-android-4.14. This is to test a new kernel build with a"
204        " particular Android build (--build-id). If specified without"
205        " specifying kernel-build-id, the last green build in the branch will"
206        " be used. If neither kernel-branch nor kernel-build-id are specified,"
207        " the kernel that's bundled with the Android build would be used.")
208    parser.add_argument(
209        "--kernel-build-target",
210        type=str,
211        dest="kernel_build_target",
212        default="kernel",
213        help="Kernel build target, specify if different from 'kernel'")
214    parser.add_argument(
215        "--boot-build-id",
216        type=str,
217        dest="boot_build_id",
218        required=False,
219        help="Boot image build ID, e.g., 8747889, 8748012.")
220    parser.add_argument(
221        "--boot-branch",
222        type=str,
223        dest="boot_branch",
224        required=False,
225        help="Boot image branch, e.g., aosp-gki13-boot-release, aosp-main.")
226    parser.add_argument(
227        "--boot-build-target",
228        type=str,
229        dest="boot_build_target",
230        required=False,
231        help="Boot image build target, "
232        "e.g., gki_x86_64-userdebug, aosp_cf_x86_64_phone-trunk_staging-userdebug.")
233    parser.add_argument(
234        "--boot-artifact",
235        type=str,
236        dest="boot_artifact",
237        required=False,
238        help="The name of the boot image to be retrieved from Android build, "
239        "e.g., boot-5.10.img, boot.img.")
240    parser.add_argument(
241        "--ota-branch",
242        type=str,
243        dest="ota_branch",
244        required=False,
245        help="'cuttlefish only' OTA tools branch name. e.g. aosp-main")
246    parser.add_argument(
247        "--ota-build-id",
248        type=str,
249        dest="ota_build_id",
250        required=False,
251        help="'cuttlefish only' OTA tools build id, e.g. 2145099, P2804227")
252    parser.add_argument(
253        "--ota-build-target",
254        type=str,
255        dest="ota_build_target",
256        required=False,
257        help="'cuttlefish only' OTA tools build target, e.g. "
258        "cf_x86_64_phone-trunk_staging-userdebug.")
259    parser.add_argument(
260        "--host-package-branch", "--host_package_branch",
261        type=str,
262        dest="host_package_branch",
263        required=False,
264        help="'cuttlefish and trusty only' Host package branch name. e.g. "
265        "aosp-main")
266    parser.add_argument(
267        "--host-package-build-id", "--host_package_build_id",
268        type=str,
269        dest="host_package_build_id",
270        required=False,
271        help="'cuttlefish and trusty only' Host package build id, e.g. "
272        "2145099, P2804227")
273    parser.add_argument(
274        "--host-package-build-target", "--host_package_build_target",
275        type=str,
276        dest="host_package_build_target",
277        required=False,
278        help="'cuttlefish and trusty only' Host package build target, e.g. "
279        "cf_x86_64_phone-trunk_staging-userdebug.")
280    parser.add_argument(
281        "--system-branch",
282        type=str,
283        dest="system_branch",
284        help="'cuttlefish only' Branch to consume the system image (system.img) "
285        "from, will default to what is defined by --branch. "
286        "That feature allows to (automatically) test various combinations "
287        "of vendor.img (CF, e.g.) and system images (GSI, e.g.). ",
288        required=False)
289    parser.add_argument(
290        "--system-build-id",
291        type=str,
292        dest="system_build_id",
293        help="'cuttlefish only' System image build id, e.g. 2145099, P2804227",
294        required=False)
295    parser.add_argument(
296        "--system-build-target",
297        type=str,
298        dest="system_build_target",
299        help="'cuttlefish only' System image build target, specify if different "
300        "from --build-target",
301        required=False)
302    parser.add_argument(
303        "--launch-args",
304        type=str,
305        dest="launch_args",
306        help="'cuttlefish only' Add extra args to launch_cvd command.",
307        required=False)
308    parser.add_argument(
309        "--pet-name",
310        "--webrtc_device_id",
311        type=str,
312        dest="webrtc_device_id",
313        help="'cuttlefish only' Give the pet name of the instance.",
314        required=False)
315    parser.add_argument(
316        "--gce-metadata",
317        type=str,
318        dest="gce_metadata",
319        default=None,
320        help="'GCE instance only' Record data into GCE instance metadata with "
321        "key-value pair format. e.g. id:12,name:unknown.")
322    parser.add_argument(
323        "--fetch_cvd-build-id",
324        type=str,
325        dest="fetch_cvd_build_id",
326        required=False,
327        help="Deprecated - any values input through this param are ignored")
328    # TODO(146314062): Remove --multi-stage-launch after infra don't use this
329    # args.
330    parser.add_argument(
331        "--multi-stage-launch",
332        dest="multi_stage_launch",
333        action="store_true",
334        required=False,
335        default=True,
336        help="Enable the multi-stage cuttlefish launch.")
337    parser.add_argument(
338        "--no-multi-stage-launch",
339        dest="multi_stage_launch",
340        action="store_false",
341        required=False,
342        default=None,
343        help="Disable the multi-stage cuttlefish launch.")
344    parser.add_argument(
345        "--no-pull-log",
346        dest="no_pull_log",
347        action="store_true",
348        required=False,
349        default=None,
350        help="Disable auto download logs when AVD booting up failed.")
351    parser.add_argument(
352        "--no-mkcert",
353        dest="mkcert",
354        action="store_false",
355        required=False,
356        default=True,
357        help="Disable mkcert setup process on the host.")
358    # TODO(147335651): Add gpu in user config.
359    # TODO(147335651): Support "--gpu" without giving any value.
360    parser.add_argument(
361        "--gpu",
362        type=str,
363        const=_DEFAULT_GPU,
364        nargs="?",
365        dest="gpu",
366        required=False,
367        default=None,
368        help="GPU accelerator to use if any. e.g. nvidia-tesla-k80. For local "
369             "instances, this arg without assigning any value is to enable "
370             "local gpu support.")
371    parser.add_argument(
372        "--num-avds-per-instance",
373        "--num-instances",
374        "--num_instances",
375        type=int,
376        dest="num_avds_per_instance",
377        required=False,
378        default=1,
379        help="'cuttlefish only' Create multiple cuttlefish AVDs in one local "
380             "instance.")
381    parser.add_argument(
382        "--connect-hostname",
383        action="store_true",
384        dest="connect_hostname",
385        required=False,
386        default=False,
387        help="Ssh connects to the GCE instance with hostname.")
388    parser.add_argument(
389        "--gce-only",
390        action="store_true",
391        dest="gce_only",
392        required=False,
393        default=False,
394        help="Only create the GCE instance. It won't create virtual devices.")
395    # Hide following args for users, it is only used in infra.
396    parser.add_argument(
397        "--local-instance-dir",
398        dest="local_instance_dir",
399        required=False,
400        help=argparse.SUPPRESS)
401    parser.add_argument(
402        "--mix-system_dlkm-into-vendor-ramdisk",
403        dest="mix_system_dlkm_into_vendor_ramdisk",
404        action="store_true",
405        required=False,
406        # Extract system_dlkm image and mix it into vendor ramdisk. The mixing
407        # process overwrites some of the modules in the vendor ramdisk. It is
408        # effective only if both --local-boot-image and
409        # --local-system_dlkm-image are specified.
410        help=argparse.SUPPRESS)
411    parser.add_argument(
412        "--remote-image-dir",
413        dest="remote_image_dir",
414        required=False,
415        # 'cuttlefish remote host only' Upload images and cvd host package to
416        # the remote directory instead of the instance's own directory. If the
417        # directory has been initialized, acloud ignores the image arguments
418        # given by command line and reuses the images in the directory.
419        help=argparse.SUPPRESS)
420    parser.add_argument(
421        "--oxygen",
422        action="store_true",
423        dest="oxygen",
424        required=False,
425        help=argparse.SUPPRESS)
426    parser.add_argument(
427        "--zone",
428        type=str,
429        dest="zone",
430        required=False,
431        help=argparse.SUPPRESS)
432
433    # TODO(b/118439885): Old arg formats to support transition, delete when
434    # transistion is done.
435    parser.add_argument(
436        "--serial_log_file",
437        type=str,
438        dest="serial_log_file",
439        required=False,
440        help=argparse.SUPPRESS)
441    parser.add_argument(
442        "--build_id",
443        type=str,
444        dest="build_id",
445        required=False,
446        help=argparse.SUPPRESS)
447    parser.add_argument(
448        "--build_target",
449        type=str,
450        dest="build_target",
451        required=False,
452        help=argparse.SUPPRESS)
453    parser.add_argument(
454        "--system_branch",
455        type=str,
456        dest="system_branch",
457        required=False,
458        help=argparse.SUPPRESS)
459    parser.add_argument(
460        "--system_build_id",
461        type=str,
462        dest="system_build_id",
463        required=False,
464        help=argparse.SUPPRESS)
465    parser.add_argument(
466        "--system_build_target",
467        type=str,
468        dest="system_build_target",
469        required=False,
470        help=argparse.SUPPRESS)
471    parser.add_argument(
472        "--kernel_build_id",
473        type=str,
474        dest="kernel_build_id",
475        required=False,
476        help=argparse.SUPPRESS)
477    parser.add_argument(
478        "--kernel_branch",
479        type=str,
480        dest="kernel_branch",
481        required=False,
482        help=argparse.SUPPRESS)
483    parser.add_argument(
484        "--kernel_build_target",
485        type=str,
486        dest="kernel_build_target",
487        default="kernel",
488        help=argparse.SUPPRESS)
489    parser.add_argument(
490        "--bootloader_branch",
491        type=str,
492        dest="bootloader_branch",
493        help=argparse.SUPPRESS,
494        required=False)
495    parser.add_argument(
496        "--bootloader_build_id",
497        type=str,
498        dest="bootloader_build_id",
499        help=argparse.SUPPRESS,
500        required=False)
501    parser.add_argument(
502        "--bootloader_build_target",
503        type=str,
504        dest="bootloader_build_target",
505        help=argparse.SUPPRESS,
506        required=False)
507    parser.add_argument(
508        "--fetch_cvd_build_id",
509        type=str,
510        dest="fetch_cvd_build_id",
511        help=argparse.SUPPRESS,
512        required=False)
513    parser.add_argument(
514        "--remote-fetch",
515        action="store_true",
516        dest="remote_fetch",
517        required=False,
518        default=None,
519        help="'cuttlefish only' Fetch artifacts in remote host.")
520    parser.add_argument(
521        "--fetch-cvd-wrapper",
522        dest="fetch_cvd_wrapper",
523        type=str,
524        required=False,
525        help="'cuttlefish only' Fetch artifacts in remote host by a"
526        " provided static executable fetch cvd wrapper file. "
527        " (Still in experiment, this flag only works on lab hosts"
528        " with special setup.)")
529    parser.add_argument(
530        "--enable_fetch_local_caching",
531        action="store_true",
532        dest="enable_fetch_local_caching",
533        required=False,
534        help="'cuttlefish only' When enabled, fetched artifacts may be saved "
535        "to a local cache to avoid network requests on repeated fetches of the"
536        " same artifacts."
537    )
538
539
540def GetCreateArgParser(subparser):
541    """Return the create arg parser.
542
543    Args:
544       subparser: argparse.ArgumentParser that is attached to main acloud cmd.
545
546    Returns:
547        argparse.ArgumentParser with create options defined.
548    """
549    create_parser = subparser.add_parser(CMD_CREATE)
550    create_parser.required = False
551    create_parser.set_defaults(which=CMD_CREATE)
552    # Use default=None to distinguish remote instance or local. The instance
553    # type will be remote if the arg is not provided.
554    create_parser.add_argument(
555        "--local-instance",
556        type=_PositiveInteger,
557        const=0,
558        metavar="ID",
559        nargs="?",
560        dest="local_instance",
561        required=False,
562        help="Create a local AVD instance using the resources associated with "
563             "the ID. Choose an unused ID automatically if the value is "
564             "not specified (primarily for infra usage).")
565    create_parser.add_argument(
566        "--adb-port", "-p",
567        type=int,
568        default=None,
569        dest="adb_port",
570        required=False,
571        help="Specify port for adb forwarding.")
572    create_parser.add_argument(
573        "--base-instance-num",
574        type=int,
575        default=None,
576        dest="base_instance_num",
577        required=False,
578        help="'cuttlefish only' The instance number of the created device.")
579    create_parser.add_argument(
580        "--avd-type",
581        type=str,
582        dest="avd_type",
583        default=constants.TYPE_CF,
584        choices=[constants.TYPE_GCE, constants.TYPE_CF, constants.TYPE_GF, constants.TYPE_CHEEPS,
585                 constants.TYPE_FVP, constants.TYPE_TRUSTY],
586        help="Android Virtual Device type (default %s)." % constants.TYPE_CF)
587    create_parser.add_argument(
588        "--config", "--flavor",
589        type=str,
590        dest="flavor",
591        help="The device flavor of the AVD (default %s). e.g. phone, tv, foldable."
592        % constants.FLAVOR_PHONE)
593    create_parser.add_argument(
594        "--local-image",
595        const=constants.FIND_IN_BUILD_ENV,
596        type=str,
597        dest="local_image",
598        nargs="?",
599        required=False,
600        help="Use the locally built image for the AVD. Look for the image "
601        "artifact in $ANDROID_PRODUCT_OUT if no args value is provided."
602        "e.g --local-image or --local-image /path/to/dir or --local-image "
603        "/path/to/file")
604    create_parser.add_argument(
605        "--local-kernel-image", "--local-boot-image",
606        const=constants.FIND_IN_BUILD_ENV,
607        type=str,
608        dest="local_kernel_image",
609        nargs="?",
610        required=False,
611        help="Use the locally built kernel and ramdisk for the AVD. Look "
612        "for boot.img, vendor_boot.img, kernel, initramfs.img, etc. if the "
613        "argument is a directory. Look for the images in $ANDROID_PRODUCT_OUT "
614        "if no argument is provided. e.g., --local-kernel-image, "
615        "--local-kernel-image /path/to/dir, or --local-kernel-image "
616        "/path/to/boot.img")
617    create_parser.add_argument(
618        "--local-system-image",
619        const=constants.FIND_IN_BUILD_ENV,
620        type=str,
621        dest="local_system_image",
622        nargs="?",
623        required=False,
624        help="Use the locally built system images for the AVD. Look for the "
625        "images in $ANDROID_PRODUCT_OUT if no args value is provided. "
626        "e.g., --local-system-image, --local-system-image /path/to/dir, or "
627        "--local-system-image /path/to/img")
628    create_parser.add_argument(
629        "--local-system_dlkm-image",
630        const=constants.FIND_IN_BUILD_ENV,
631        type=str,
632        dest="local_system_dlkm_image",
633        nargs="?",
634        required=False,
635        help="`remote host only` Use the locally built system_dlkm image for "
636        "the AVD. Look for the image in $ANDROID_PRODUCT_OUT if no args value "
637        "is provided.")
638    create_parser.add_argument(
639        "--local-vendor-image",
640        const=constants.FIND_IN_BUILD_ENV,
641        type=str,
642        dest="local_vendor_image",
643        nargs="?",
644        required=False,
645        help="'cuttlefish only' Use the locally built vendor images for the "
646        "AVD. Look for vendor.img, vendor_dlkm.img, odm.img, and odm_dlkm.img "
647        "if the argument is a directory. Look for the images in "
648        "$ANDROID_PRODUCT_OUT if no argument is provided. e.g., "
649        "--local-vendor-image, or --local-vendor-image /path/to/dir")
650    create_parser.add_argument(
651        "--local-vendor_boot-image", "--local-vendor-boot-image",
652        const=constants.FIND_IN_BUILD_ENV,
653        type=str,
654        dest="local_vendor_boot_image",
655        nargs="?",
656        required=False,
657        help="'cuttlefish only' Use the locally built vendor boot image for "
658        "the AVD. Look for the vendor_boot.img in $ANDROID_PRODUCT_OUT "
659        "if no argument is provided. e.g., --local-vendor-boot-image, or "
660        "--local-vendor-boot-image /path/to/dir, or "
661        "--local-vendor-boot-image /path/to/img")
662    create_parser.add_argument(
663        "--local-tool",
664        type=str,
665        dest="local_tool",
666        action="append",
667        default=[],
668        required=False,
669        help="Use the tools in the specified directory to create local "
670        "instances. The directory structure follows $ANDROID_SOONG_HOST_OUT "
671        "or $ANDROID_EMULATOR_PREBUILTS.")
672    create_parser.add_argument(
673        "--cvd-host-package",
674        type=str,
675        dest="cvd_host_package",
676        required=False,
677        help="Use the specified path of the cvd host package to create "
678        "instances. e.g. /path/cvd-host_package_v1.tar.gz")
679    create_parser.add_argument(
680        "--image-download-dir",
681        type=str,
682        dest="image_download_dir",
683        required=False,
684        help="Define remote image download directory, e.g. /usr/local/dl.")
685    create_parser.add_argument(
686        "--yes", "-y",
687        action="store_true",
688        dest="no_prompt",
689        required=False,
690        help=("Automatic yes to prompts. Assume 'yes' as answer to all prompts "
691              "and run non-interactively."))
692    create_parser.add_argument(
693        "--reuse-gce",
694        type=str,
695        const=constants.SELECT_ONE_GCE_INSTANCE,
696        nargs="?",
697        dest="reuse_gce",
698        required=False,
699        help="'cuttlefish only' This can help users use their own instance. "
700        "Reusing specific gce instance if --reuse-gce [instance_name] is "
701        "provided. Select one gce instance to reuse if --reuse-gce is "
702        "provided.")
703    create_parser.add_argument(
704        "--openwrt",
705        action="store_true",
706        dest="openwrt",
707        required=False,
708        help="'cuttlefish only' Create OpenWrt device when launching cuttlefish "
709        "device.")
710    create_parser.add_argument(
711        "--use-launch_cvd",
712        action="store_true",
713        dest="use_launch_cvd",
714        required=False,
715        help="'cuttlefish only' Use launch_cvd to create cuttlefish devices.")
716    create_parser.add_argument(
717        "--host",
718        type=str,
719        dest="remote_host",
720        default=None,
721        help="'cuttlefish only' Provide host name to clean up the remote host. "
722        "For example: '--host 1.1.1.1'")
723    create_parser.add_argument(
724        "--host-user",
725        type=str,
726        dest="host_user",
727        default=constants.GCE_USER,
728        help="'remote host only' Provide host user for logging in to the host. "
729        "The default value is vsoc-01. For example: '--host 1.1.1.1 --host-user "
730        "vsoc-02'")
731    create_parser.add_argument(
732        "--host-ssh-private-key-path",
733        type=str,
734        dest="host_ssh_private_key_path",
735        default=None,
736        help="'remote host only' Provide host key for login on on this host.")
737    # User should not specify --spec and --hw_property at the same time.
738    hw_spec_group = create_parser.add_mutually_exclusive_group()
739    hw_spec_group.add_argument(
740        "--hw-property",
741        type=str,
742        dest="hw_property",
743        required=False,
744        help="Supported HW properties and example values: %s" %
745        constants.HW_PROPERTIES_CMD_EXAMPLE)
746    hw_spec_group.add_argument(
747        "--spec",
748        type=str,
749        dest="spec",
750        required=False,
751        choices=constants.SPEC_NAMES,
752        help="The name of a pre-configured device spec that we are "
753        "going to use.")
754    create_parser.add_argument(
755        "--disk-type",
756        type=str,
757        dest="disk_type",
758        required=False,
759        help="This is used to customize the GCE instance disk type, the "
760        "default disk type is from the stable host image. Use pd-ssd or "
761        "pd-standard to specify instance disk type.")
762    create_parser.add_argument(
763        "--stable-host-image-name",
764        type=str,
765        dest="stable_host_image_name",
766        required=False,
767        default=None,
768        help=("'cuttlefish only' The Cuttlefish host image from which instances "
769              "are launched. If specified here, the value set in Acloud config "
770              "file will be overridden."))
771
772    # Arguments for goldfish type.
773    create_parser.add_argument(
774        "--emulator-build-id",
775        type=str,
776        dest="emulator_build_id",
777        required=False,
778        help="'goldfish only' Emulator build ID used to run the images. "
779        "e.g. 4669466.")
780    create_parser.add_argument(
781        "--emulator-build-target",
782        dest="emulator_build_target",
783        required=False,
784        help="'goldfish remote host only' Emulator build target used to run "
785        "the images. e.g. emulator-linux_x64_nolocationui.")
786    create_parser.add_argument(
787        "--emulator-zip",
788        dest="emulator_zip",
789        required=False,
790        help="'goldfish remote host only' Emulator zip used to run the "
791        "images. e.g., /path/sdk-repo-linux-emulator-1234567.zip.")
792
793    # Arguments for cheeps type.
794    create_parser.add_argument(
795        "--stable-cheeps-host-image-name",
796        type=str,
797        dest="stable_cheeps_host_image_name",
798        required=False,
799        default=None,
800        help=("'cheeps only' The Cheeps host image from which instances are "
801              "launched. If specified here, the value set in Acloud config "
802              "file will be overridden."))
803    create_parser.add_argument(
804        "--stable-cheeps-host-image-project",
805        type=str,
806        dest="stable_cheeps_host_image_project",
807        required=False,
808        default=None,
809        help=("'cheeps only' The project hosting the specified Cheeps host "
810              "image. If specified here, the value set in Acloud config file "
811              "will be overridden."))
812    create_parser.add_argument(
813        "--user",
814        type=str,
815        dest="username",
816        required=False,
817        default=None,
818        help="'cheeps only' username to log in to Chrome OS as.")
819    create_parser.add_argument(
820        "--password",
821        type=str,
822        dest="password",
823        required=False,
824        default=None,
825        help="'cheeps only' password to log in to Chrome OS with.")
826    create_parser.add_argument(
827        "--betty-image",
828        type=str,
829        dest="cheeps_betty_image",
830        required=False,
831        default=None,
832        help=("'cheeps only' The L1 betty version to use. Only makes sense "
833              "when launching a controller image with "
834              "stable-cheeps-host-image"))
835    create_parser.add_argument(
836        "--cheeps-feature",
837        type=str,
838        dest="cheeps_features",
839        required=False,
840        action="append",
841        default=[],
842        help=("'cheeps only' Cheeps feature to enable. Can be repeated."))
843
844    # Arguments for trusty type
845    create_parser.add_argument(
846        "--trusty-host-package",
847        type=str,
848        dest="trusty_host_package",
849        required=False,
850        help="Use the specified path of the trusty host package to create "
851        "instances. e.g. /path/trusty-host_package.tar.gz")
852    create_parser.add_argument(
853        "--local-trusty-image",
854        type=str,
855        dest="local_trusty_image",
856        required=False,
857        help="'trusty only' Use the specified path for the locally built "
858        "trusty emulator images package, built with "
859        "PACKAGE_TRUSTY_IMAGE_TARBALL=true in the Trusty build. E.g., "
860        "/path/trusty_image_package.tar.gz")
861    create_parser.add_argument(
862        "--trusty-build-id",
863        type=str,
864        dest="trusty_build_id",
865        required=False,
866        help="Trusty image package build ID, e.g., 8747889, 8748012.")
867    create_parser.add_argument(
868        "--trusty-branch",
869        type=str,
870        dest="trusty_branch",
871        required=False,
872        help="Trusty image package branch, e.g., aosp-trusty-master.")
873    create_parser.add_argument(
874        "--trusty-build-target",
875        type=str,
876        dest="trusty_build_target",
877        required=False,
878        help="Trusty image package build target, "
879        "e.g., qemu_generic_arm64_test_debug.")
880
881    AddCommonCreateArgs(create_parser)
882    return create_parser
883
884
885def _PositiveInteger(arg):
886    """Convert an argument from a string to a positive integer."""
887    try:
888        value = int(arg)
889    except ValueError as e:
890        raise argparse.ArgumentTypeError(arg + " is not an integer.") from e
891    if value <= 0:
892        raise argparse.ArgumentTypeError(arg + " is not positive.")
893    return value
894
895
896def _VerifyLocalArgs(args):
897    """Verify args starting with --local.
898
899    Args:
900        args: Namespace object from argparse.parse_args.
901
902    Raises:
903        errors.CheckPathError: Image path doesn't exist.
904        errors.UnsupportedCreateArgs: The specified avd type does not support
905                                      a provided argument.
906        errors.UnsupportedLocalInstanceId: Local instance ID is invalid.
907    """
908    for local_path in [args.local_image, args.local_instance_dir,
909                       args.local_kernel_image, args.local_system_image,
910                       args.local_system_dlkm_image, args.local_vendor_image,
911                       args.local_vendor_boot_image] + args.local_tool:
912        if local_path and not os.path.exists(local_path):
913            raise errors.CheckPathError(
914                f"Specified path doesn't exist: {local_path}")
915
916    if args.local_instance_dir and not os.path.exists(args.local_instance_dir):
917        raise errors.CheckPathError(
918            "Specified path doesn't exist: %s" % args.local_instance_dir)
919
920    if args.mix_system_dlkm_into_vendor_ramdisk and (
921            args.local_kernel_image is None or
922            args.local_system_dlkm_image is None):
923        raise errors.UnsupportedCreateArgs(
924            "If --mix-system_dlkm-into-vendor-ramdisk is specified, "
925            "--local-system_dlkm-image and --local-kernel-image must be "
926            "specified.")
927
928    if not (args.local_system_image is None or
929            args.avd_type in (constants.TYPE_CF, constants.TYPE_GF)):
930        raise errors.UnsupportedCreateArgs("%s instance does not support "
931                                           "--local-system-image" %
932                                           args.avd_type)
933    # TODO(b/179340595): To support local image remote instance with kernel build.
934    if args.local_instance is None and args.local_image is not None and (
935            args.kernel_branch or args.kernel_build_id):
936        raise errors.UnsupportedCreateArgs(
937            "Acloud didn't support local image with specific kernel. "
938            "Please download the specific kernel and put it into "
939            "your local image folder: '%s'." % (
940            args.local_image if args.local_image else
941            utils.GetBuildEnvironmentVariable(constants.ENV_ANDROID_PRODUCT_OUT)))
942
943
944def _VerifyHostArgs(args):
945    """Verify args starting with --host.
946
947    Args:
948        args: Namespace object from argparse.parse_args.
949
950    Raises:
951        errors.UnsupportedCreateArgs: When a create arg is specified but
952                                      unsupported for remote host mode.
953    """
954    if args.remote_host and args.local_instance is not None:
955        raise errors.UnsupportedCreateArgs(
956            "--host is not supported for local instance.")
957
958    if args.remote_host and args.num > 1:
959        raise errors.UnsupportedCreateArgs(
960            "--num is not supported for remote host.")
961
962    if args.host_user != constants.GCE_USER and args.remote_host is None:
963        raise errors.UnsupportedCreateArgs(
964            "--host-user is only supported for remote host.")
965
966    if args.host_ssh_private_key_path and args.remote_host is None:
967        raise errors.UnsupportedCreateArgs(
968            "--host-ssh-private-key-path is only supported for remote host.")
969
970    if args.remote_image_dir:
971        if args.remote_host is None:
972            raise errors.UnsupportedCreateArgs(
973                "--remote-image-dir is only supported for remote host.")
974        if remote_path.basename(
975                remote_path.normpath(args.remote_image_dir)) in ("..", "."):
976            raise errors.UnsupportedCreateArgs(
977                "--remote-image-dir must not include the working directory.")
978
979
980def _VerifyGoldfishArgs(args):
981    """Verify goldfish args.
982
983    Args:
984        args: Namespace object from argparse.parse_args.
985
986    Raises:
987        errors.UnsupportedCreateArgs: When a create arg is specified but
988                                      unsupported for goldfish.
989    """
990    goldfish_only_flags = [
991        args.emulator_build_id,
992        args.emulator_build_target,
993        args.emulator_zip,
994        args.mix_system_dlkm_into_vendor_ramdisk,
995    ]
996    if args.avd_type != constants.TYPE_GF and any(goldfish_only_flags):
997        raise errors.UnsupportedCreateArgs(
998            "--emulator-* and --mix-system_dlkm-into-vendor-ramdisk are only "
999            f"valid with avd_type == {constants.TYPE_GF}")
1000
1001    # Exclude kernel_build_target because the default value isn't empty.
1002    remote_kernel_flags = [
1003        args.kernel_build_id,
1004        args.kernel_branch,
1005    ]
1006    if args.avd_type == constants.TYPE_GF and any(remote_kernel_flags):
1007        raise errors.UnsupportedCreateArgs(
1008            "--kernel-* is not supported for goldfish.")
1009
1010    remote_boot_flags = [
1011        args.boot_build_id,
1012        args.boot_build_target,
1013        args.boot_branch,
1014        args.boot_artifact,
1015    ]
1016    if (args.avd_type == constants.TYPE_GF and any(remote_boot_flags) and
1017            not all(remote_boot_flags)):
1018        raise errors.UnsupportedCreateArgs(
1019            "Either none or all of --boot-branch, --boot-build-target, "
1020            "--boot-build-id, and --boot-artifact must be specified for "
1021            "goldfish.")
1022
1023    remote_system_flags = [
1024        args.system_build_target,
1025        args.system_build_id,
1026        args.system_branch,
1027    ]
1028    if (args.avd_type == constants.TYPE_GF and any(remote_system_flags) and
1029            not all(remote_system_flags)):
1030        raise errors.UnsupportedCreateArgs(
1031            "Either none or all of --system-branch, --system-build-target, "
1032            "and --system-build-id must be specified for goldfish.")
1033
1034    remote_host_only_flags = remote_boot_flags + remote_system_flags
1035    if args.avd_type == constants.TYPE_GF and args.remote_host is None and any(
1036            remote_host_only_flags):
1037        raise errors.UnsupportedCreateArgs(
1038            "--boot-* and --system-* for goldfish are only supported for "
1039            "remote host.")
1040
1041
1042def _VerifyTrustyArgs(args):
1043    """Verify trusty args.
1044
1045    Args:
1046        args: Namespace object from argparse.parse_args.
1047
1048    Raises:
1049        errors.UnsupportedCreateArgs: When specified arguments are
1050                                      unsupported for trusty.
1051        errors.CheckPathError: A specified local path does not exist.
1052    """
1053    if args.avd_type != constants.TYPE_TRUSTY:
1054        if args.local_trusty_image:
1055            raise errors.UnsupportedCreateArgs(
1056                "--local-trusty-image is only valid with "
1057                f"avd_type == {constants.TYPE_TRUSTY}")
1058        if args.trusty_host_package:
1059            raise errors.UnsupportedCreateArgs(
1060                "--trusty-host-package is only valid with "
1061                f"avd_type == {constants.TYPE_TRUSTY}")
1062        # Only check these args if AVD type is Trusty
1063        return
1064
1065    for arg_type, unsupported_args in [
1066        (
1067            "--boot-*",
1068            [
1069                args.boot_build_id,
1070                args.boot_build_target,
1071                args.boot_branch,
1072                args.boot_artifact,
1073            ],
1074        ),
1075        (
1076            "--bootloader-*",
1077            [
1078                args.bootloader_build_id,
1079                args.bootloader_build_target,
1080                args.bootloader_branch,
1081            ],
1082        ),
1083        (
1084            "--android-efi-loader-*",
1085            [
1086                args.android_efi_loader_build_id,
1087                args.android_efi_loader_artifact,
1088            ],
1089        ),
1090        (
1091            "--ota-*",
1092            [
1093                args.ota_branch,
1094                args.ota_build_target,
1095                args.ota_build_id,
1096            ],
1097        ),
1098    ]:
1099        if any(unsupported_args):
1100            raise errors.UnsupportedCreateArgs(
1101                f"{arg_type} is not supported for Trusty."
1102            )
1103
1104    if args.local_image is None and not args.build_target:
1105        raise errors.UnsupportedCreateArgs(
1106            "Trusty android build target not provided and cannot be "
1107            "auto-detected, use --build-target to specify a build target, "
1108            "e.g. qemu_trusty_arm64-trunk_staging-userdebug")
1109    if args.local_trusty_image:
1110        if not os.path.exists(args.local_trusty_image):
1111            raise errors.CheckPathError(
1112                f"Specified path doesn't exist: {args.local_trusty_image}")
1113    if args.trusty_host_package:
1114        if not os.path.exists(args.trusty_host_package):
1115            raise errors.CheckPathError(
1116                f"Specified path doesn't exist: {args.trusty_host_package}")
1117
1118
1119def VerifyArgs(args):
1120    """Verify args.
1121
1122    Args:
1123        args: Namespace object from argparse.parse_args.
1124
1125    Raises:
1126        errors.UnsupportedMultiAdbPort: multi adb port doesn't support.
1127        errors.UnsupportedCreateArgs: When a create arg is specified but
1128                                      unsupported for a particular avd type.
1129                                      (e.g. --system-build-id for gf)
1130    """
1131    # Verify that user specified flavor name is in support list.
1132    # We don't use argparse's builtin validation because we need to be able to
1133    # tell when a user doesn't specify a flavor.
1134    if args.flavor and args.flavor not in constants.ALL_FLAVORS:
1135        logger.debug("Flavor[%s] isn't in default support list: %s",
1136                     args.flavor, constants.ALL_FLAVORS)
1137
1138    if args.avd_type not in (constants.TYPE_CF, constants.TYPE_GF):
1139        if args.system_branch or args.system_build_id or args.system_build_target:
1140            raise errors.UnsupportedCreateArgs(
1141                "--system-* args are not supported for AVD type: %s"
1142                % args.avd_type)
1143
1144    if args.num > 1 and args.adb_port:
1145        raise errors.UnsupportedMultiAdbPort(
1146            "--adb-port is not supported for multi-devices.")
1147
1148    if args.num > 1 and args.local_instance is not None:
1149        raise errors.UnsupportedCreateArgs(
1150            "--num is not supported for local instance.")
1151
1152    if args.local_instance is None and args.gpu == _DEFAULT_GPU:
1153        raise errors.UnsupportedCreateArgs(
1154            "Please assign one gpu model for GCE instance. Reference: "
1155            "https://cloud.google.com/compute/docs/gpus")
1156
1157    if args.adb_port:
1158        utils.CheckPortFree(args.adb_port)
1159
1160    hw_properties = create_common.ParseKeyValuePairArgs(args.hw_property)
1161    for key in hw_properties:
1162        if key not in constants.HW_PROPERTIES:
1163            raise errors.InvalidHWPropertyError(
1164                "[%s] is an invalid hw property, supported values are:%s. "
1165                % (key, constants.HW_PROPERTIES))
1166
1167    cheeps_only_flags = [args.stable_cheeps_host_image_name,
1168                         args.stable_cheeps_host_image_project,
1169                         args.username,
1170                         args.password,
1171                         args.cheeps_betty_image,
1172                         args.cheeps_features]
1173    if args.avd_type != constants.TYPE_CHEEPS and any(cheeps_only_flags):
1174        raise errors.UnsupportedCreateArgs(
1175            "--stable-cheeps-*, --betty-image, --cheeps-feature, --username "
1176            "and --password are only valid with avd_type == %s"
1177            % constants.TYPE_CHEEPS)
1178    if (args.username or args.password) and not (args.username and args.password):
1179        raise ValueError("--username and --password must both be set")
1180    if not args.autoconnect and args.unlock_screen:
1181        raise ValueError("--no-autoconnect and --unlock couldn't be "
1182                         "passed in together.")
1183
1184    _VerifyGoldfishArgs(args)
1185    _VerifyTrustyArgs(args)
1186    _VerifyLocalArgs(args)
1187    _VerifyHostArgs(args)
1188