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 os 21 22from acloud import errors 23from acloud.create import create_common 24from acloud.internal import constants 25from acloud.internal.lib import utils 26 27 28CMD_CREATE = "create" 29 30 31# TODO: Add this into main create args once create_cf/gf is deprecated. 32def AddCommonCreateArgs(parser): 33 """Adds arguments common to create parsers. 34 35 Args: 36 parser: ArgumentParser object, used to parse flags. 37 """ 38 parser.add_argument( 39 "--num", 40 type=int, 41 dest="num", 42 required=False, 43 default=1, 44 help="Number of instances to create.") 45 parser.add_argument( 46 "--serial-log-file", 47 type=str, 48 dest="serial_log_file", 49 required=False, 50 help="Path to a *tar.gz file where serial logs will be saved " 51 "when a device fails on boot.") 52 parser.add_argument( 53 "--autoconnect", 54 type=str, 55 nargs="?", 56 const=constants.INS_KEY_VNC, 57 dest="autoconnect", 58 required=False, 59 choices=[constants.INS_KEY_VNC, constants.INS_KEY_ADB, 60 constants.INS_KEY_WEBRTC], 61 help="Determines to establish a tunnel forwarding adb/vnc and " 62 "launch VNC/webrtc. Establish a tunnel forwarding adb and vnc " 63 "then launch vnc if --autoconnect vnc is provided. Establish a " 64 "tunnel forwarding adb if --autoconnect adb is provided. " 65 "Establish a tunnel forwarding adb and auto-launch on the browser " 66 "if --autoconnect webrtc is provided. For local goldfish " 67 "instance, create a window.") 68 parser.add_argument( 69 "--no-autoconnect", 70 action="store_false", 71 dest="autoconnect", 72 required=False, 73 help="Will not automatically create ssh tunnels forwarding adb & vnc " 74 "when instance created.") 75 parser.set_defaults(autoconnect=constants.INS_KEY_VNC) 76 parser.add_argument( 77 "--unlock", 78 action="store_true", 79 dest="unlock_screen", 80 required=False, 81 default=False, 82 help="This can unlock screen after invoke vnc client.") 83 parser.add_argument( 84 "--report-internal-ip", 85 action="store_true", 86 dest="report_internal_ip", 87 required=False, 88 help="Report internal ip of the created instance instead of external " 89 "ip. Using the internal ip is used when connecting from another " 90 "GCE instance.") 91 parser.add_argument( 92 "--network", 93 type=str, 94 dest="network", 95 required=False, 96 help="Set the network the GCE instance will utilize.") 97 parser.add_argument( 98 "--skip-pre-run-check", 99 action="store_true", 100 dest="skip_pre_run_check", 101 required=False, 102 help="Skip the pre-run check.") 103 parser.add_argument( 104 "--boot-timeout", 105 dest="boot_timeout_secs", 106 type=int, 107 required=False, 108 help="The maximum time in seconds used to wait for the AVD to boot.") 109 parser.add_argument( 110 "--wait-for-ins-stable", 111 dest="ins_timeout_secs", 112 type=int, 113 required=False, 114 help="The maximum time in seconds used to wait for the instance boot " 115 "up. The default value to wait for instance up time is 300 secs.") 116 parser.add_argument( 117 "--build-target", 118 type=str, 119 dest="build_target", 120 help="Android build target, e.g. aosp_cf_x86_phone-userdebug, " 121 "or short names: phone, tablet, or tablet_mobile.") 122 parser.add_argument( 123 "--branch", 124 type=str, 125 dest="branch", 126 help="Android branch, e.g. mnc-dev or git_mnc-dev") 127 parser.add_argument( 128 "--build-id", 129 type=str, 130 dest="build_id", 131 help="Android build id, e.g. 2145099, P2804227") 132 parser.add_argument( 133 "--kernel-build-id", 134 type=str, 135 dest="kernel_build_id", 136 required=False, 137 help="Android kernel build id, e.g. 4586590. This is to test a new" 138 " kernel build with a particular Android build (--build-id). If neither" 139 " kernel-branch nor kernel-build-id are specified, the kernel that's" 140 " bundled with the Android build would be used.") 141 parser.add_argument( 142 "--kernel-branch", 143 type=str, 144 dest="kernel_branch", 145 required=False, 146 help="Android kernel build branch name, e.g." 147 " kernel-common-android-4.14. This is to test a new kernel build with a" 148 " particular Android build (--build-id). If specified without" 149 " specifying kernel-build-id, the last green build in the branch will" 150 " be used. If neither kernel-branch nor kernel-build-id are specified," 151 " the kernel that's bundled with the Android build would be used.") 152 parser.add_argument( 153 "--kernel-build-target", 154 type=str, 155 dest="kernel_build_target", 156 default="kernel", 157 help="Kernel build target, specify if different from 'kernel'") 158 parser.add_argument( 159 "--system-branch", 160 type=str, 161 dest="system_branch", 162 help="'cuttlefish only' Branch to consume the system image (system.img) " 163 "from, will default to what is defined by --branch. " 164 "That feature allows to (automatically) test various combinations " 165 "of vendor.img (CF, e.g.) and system images (GSI, e.g.). ", 166 required=False) 167 parser.add_argument( 168 "--system-build-id", 169 type=str, 170 dest="system_build_id", 171 help="'cuttlefish only' System image build id, e.g. 2145099, P2804227", 172 required=False) 173 parser.add_argument( 174 "--system-build-target", 175 type=str, 176 dest="system_build_target", 177 help="'cuttlefish only' System image build target, specify if different " 178 "from --build-target", 179 required=False) 180 # TODO(146314062): Remove --multi-stage-launch after infra don't use this 181 # args. 182 parser.add_argument( 183 "--multi-stage-launch", 184 dest="multi_stage_launch", 185 action="store_true", 186 required=False, 187 default=True, 188 help="Enable the multi-stage cuttlefish launch.") 189 parser.add_argument( 190 "--no-multi-stage-launch", 191 dest="multi_stage_launch", 192 action="store_false", 193 required=False, 194 default=None, 195 help="Disable the multi-stage cuttlefish launch.") 196 parser.add_argument( 197 "--no-pull-log", 198 dest="no_pull_log", 199 action="store_true", 200 required=False, 201 default=None, 202 help="Disable auto download logs when AVD booting up failed.") 203 # TODO(147335651): Add gpu in user config. 204 # TODO(147335651): Support "--gpu" without giving any value. 205 parser.add_argument( 206 "--gpu", 207 type=str, 208 dest="gpu", 209 required=False, 210 default=None, 211 help="GPU accelerator to use if any. e.g. nvidia-tesla-k80.") 212 213 # TODO(b/118439885): Old arg formats to support transition, delete when 214 # transistion is done. 215 parser.add_argument( 216 "--serial_log_file", 217 type=str, 218 dest="serial_log_file", 219 required=False, 220 help=argparse.SUPPRESS) 221 parser.add_argument( 222 "--build_id", 223 type=str, 224 dest="build_id", 225 required=False, 226 help=argparse.SUPPRESS) 227 parser.add_argument( 228 "--build_target", 229 type=str, 230 dest="build_target", 231 required=False, 232 help=argparse.SUPPRESS) 233 parser.add_argument( 234 "--system_branch", 235 type=str, 236 dest="system_branch", 237 required=False, 238 help=argparse.SUPPRESS) 239 parser.add_argument( 240 "--system_build_id", 241 type=str, 242 dest="system_build_id", 243 required=False, 244 help=argparse.SUPPRESS) 245 parser.add_argument( 246 "--system_build_target", 247 type=str, 248 dest="system_build_target", 249 required=False, 250 help=argparse.SUPPRESS) 251 parser.add_argument( 252 "--kernel_build_id", 253 type=str, 254 dest="kernel_build_id", 255 required=False, 256 help=argparse.SUPPRESS) 257 parser.add_argument( 258 "--kernel_branch", 259 type=str, 260 dest="kernel_branch", 261 required=False, 262 help=argparse.SUPPRESS) 263 parser.add_argument( 264 "--kernel_build_target", 265 type=str, 266 dest="kernel_build_target", 267 default="kernel", 268 help=argparse.SUPPRESS) 269 270 271def GetCreateArgParser(subparser): 272 """Return the create arg parser. 273 274 Args: 275 subparser: argparse.ArgumentParser that is attached to main acloud cmd. 276 277 Returns: 278 argparse.ArgumentParser with create options defined. 279 """ 280 create_parser = subparser.add_parser(CMD_CREATE) 281 create_parser.required = False 282 create_parser.set_defaults(which=CMD_CREATE) 283 # Use default=0 to distinguish remote instance or local. The instance type 284 # will be remote if arg --local-instance is not provided. 285 create_parser.add_argument( 286 "--local-instance", 287 type=int, 288 const=1, 289 nargs="?", 290 dest="local_instance", 291 required=False, 292 help="Create a local AVD instance with the option to specify the local " 293 "instance ID (primarily for infra usage).") 294 create_parser.add_argument( 295 "--adb-port", "-p", 296 type=int, 297 default=None, 298 dest="adb_port", 299 required=False, 300 help="Specify port for adb forwarding.") 301 create_parser.add_argument( 302 "--avd-type", 303 type=str, 304 dest="avd_type", 305 default=constants.TYPE_CF, 306 choices=[constants.TYPE_GCE, constants.TYPE_CF, constants.TYPE_GF, constants.TYPE_CHEEPS], 307 help="Android Virtual Device type (default %s)." % constants.TYPE_CF) 308 create_parser.add_argument( 309 "--flavor", 310 type=str, 311 dest="flavor", 312 help="The device flavor of the AVD (default %s)." % constants.FLAVOR_PHONE) 313 create_parser.add_argument( 314 "--local-image", 315 type=str, 316 dest="local_image", 317 nargs="?", 318 default="", 319 required=False, 320 help="Use the locally built image for the AVD. Look for the image " 321 "artifact in $ANDROID_PRODUCT_OUT if no args value is provided." 322 "e.g --local-image or --local-image /path/to/dir or --local-image " 323 "/path/to/file") 324 create_parser.add_argument( 325 "--local-system-image", 326 type=str, 327 dest="local_system_image", 328 nargs="?", 329 default="", 330 required=False, 331 help="Use the locally built system images for the AVD. Look for the " 332 "images in $ANDROID_PRODUCT_OUT if no args value is provided. " 333 "e.g., --local-system-image or --local-system-image /path/to/dir") 334 create_parser.add_argument( 335 "--local-tool", 336 type=str, 337 dest="local_tool", 338 action="append", 339 default=[], 340 required=False, 341 help="Use the tools in the specified directory to create local " 342 "instances. The directory structure follows $ANDROID_HOST_OUT or " 343 "$ANDROID_EMULATOR_PREBUILTS.") 344 create_parser.add_argument( 345 "--image-download-dir", 346 type=str, 347 dest="image_download_dir", 348 required=False, 349 help="Define remote image download directory, e.g. /usr/local/dl.") 350 create_parser.add_argument( 351 "--yes", "-y", 352 action="store_true", 353 dest="no_prompt", 354 required=False, 355 help=("Automatic yes to prompts. Assume 'yes' as answer to all prompts " 356 "and run non-interactively.")) 357 create_parser.add_argument( 358 "--reuse-gce", 359 type=str, 360 const=constants.SELECT_ONE_GCE_INSTANCE, 361 nargs="?", 362 dest="reuse_gce", 363 required=False, 364 help="'cuttlefish only' This can help users use their own instance. " 365 "Reusing specific gce instance if --reuse-gce [instance_name] is " 366 "provided. Select one gce instance to reuse if --reuse-gce is " 367 "provided.") 368 create_parser.add_argument( 369 "--host", 370 type=str, 371 dest="remote_host", 372 default=None, 373 help="'cuttlefish only' Provide host name to clean up the remote host. " 374 "For example: '--host 1.1.1.1'") 375 create_parser.add_argument( 376 "--host-user", 377 type=str, 378 dest="host_user", 379 default=constants.GCE_USER, 380 help="'remote host only' Provide host user for logging in to the host. " 381 "The default value is vsoc-01. For example: '--host 1.1.1.1 --host-user " 382 "vsoc-02'") 383 create_parser.add_argument( 384 "--host-ssh-private-key-path", 385 type=str, 386 dest="host_ssh_private_key_path", 387 default=None, 388 help="'remote host only' Provide host key for login on on this host.") 389 # User should not specify --spec and --hw_property at the same time. 390 hw_spec_group = create_parser.add_mutually_exclusive_group() 391 hw_spec_group.add_argument( 392 "--hw-property", 393 type=str, 394 dest="hw_property", 395 required=False, 396 help="Supported HW properties and example values: %s" % 397 constants.HW_PROPERTIES_CMD_EXAMPLE) 398 hw_spec_group.add_argument( 399 "--spec", 400 type=str, 401 dest="spec", 402 required=False, 403 choices=constants.SPEC_NAMES, 404 help="The name of a pre-configured device spec that we are " 405 "going to use.") 406 # Arguments for goldfish type. 407 # TODO(b/118439885): Verify args that are used in wrong avd_type. 408 # e.g. $acloud create --avd-type cuttlefish --emulator-build-id 409 create_parser.add_argument( 410 "--emulator-build-id", 411 type=int, 412 dest="emulator_build_id", 413 required=False, 414 help="'goldfish only' Emulator build used to run the images. " 415 "e.g. 4669466.") 416 417 # Arguments for cheeps type. 418 create_parser.add_argument( 419 "--stable-cheeps-host-image-name", 420 type=str, 421 dest="stable_cheeps_host_image_name", 422 required=False, 423 default=None, 424 help=("'cheeps only' The Cheeps host image from which instances are " 425 "launched. If specified here, the value set in Acloud config " 426 "file will be overridden.")) 427 create_parser.add_argument( 428 "--stable-cheeps-host-image-project", 429 type=str, 430 dest="stable_cheeps_host_image_project", 431 required=False, 432 default=None, 433 help=("'cheeps only' The project hosting the specified Cheeps host " 434 "image. If specified here, the value set in Acloud config file " 435 "will be overridden.")) 436 create_parser.add_argument( 437 "--user", 438 type=str, 439 dest="username", 440 required=False, 441 default=None, 442 help="'cheeps only' username to log in to Chrome OS as.") 443 create_parser.add_argument( 444 "--password", 445 type=str, 446 dest="password", 447 required=False, 448 default=None, 449 help="'cheeps only' password to log in to Chrome OS with.") 450 451 AddCommonCreateArgs(create_parser) 452 return create_parser 453 454 455def _VerifyLocalArgs(args): 456 """Verify args starting with --local. 457 458 Args: 459 args: Namespace object from argparse.parse_args. 460 461 Raises: 462 errors.CheckPathError: Image path doesn't exist. 463 errors.UnsupportedCreateArgs: The specified avd type does not support 464 --local-system-image. 465 errors.UnsupportedLocalInstanceId: Local instance ID is invalid. 466 """ 467 if args.local_image and not os.path.exists(args.local_image): 468 raise errors.CheckPathError( 469 "Specified path doesn't exist: %s" % args.local_image) 470 471 # TODO(b/133211308): Support TYPE_CF. 472 if args.local_system_image != "" and args.avd_type != constants.TYPE_GF: 473 raise errors.UnsupportedCreateArgs("%s instance does not support " 474 "--local-system-image" % 475 args.avd_type) 476 477 if (args.local_system_image and 478 not os.path.exists(args.local_system_image)): 479 raise errors.CheckPathError( 480 "Specified path doesn't exist: %s" % args.local_system_image) 481 482 if args.local_instance is not None and args.local_instance < 1: 483 raise errors.UnsupportedLocalInstanceId("Local instance id can not be " 484 "less than 1. Actually passed:%d" 485 % args.local_instance) 486 487 for tool_dir in args.local_tool: 488 if not os.path.exists(tool_dir): 489 raise errors.CheckPathError( 490 "Specified path doesn't exist: %s" % tool_dir) 491 492 if args.autoconnect == constants.INS_KEY_WEBRTC: 493 if args.avd_type != constants.TYPE_CF: 494 raise errors.UnsupportedCreateArgs( 495 "'--autoconnect webrtc' only support cuttlefish.") 496 497 498def _VerifyHostArgs(args): 499 """Verify args starting with --host. 500 501 Args: 502 args: Namespace object from argparse.parse_args. 503 504 Raises: 505 errors.UnsupportedCreateArgs: When a create arg is specified but 506 unsupported for remote host mode. 507 """ 508 if args.remote_host and args.local_instance is not None: 509 raise errors.UnsupportedCreateArgs( 510 "--host is not supported for local instance.") 511 512 if args.remote_host and args.num > 1: 513 raise errors.UnsupportedCreateArgs( 514 "--num is not supported for remote host.") 515 516 if args.host_user != constants.GCE_USER and args.remote_host is None: 517 raise errors.UnsupportedCreateArgs( 518 "--host-user only support for remote host.") 519 520 if args.host_ssh_private_key_path and args.remote_host is None: 521 raise errors.UnsupportedCreateArgs( 522 "--host-ssh-private-key-path only support for remote host.") 523 524 525def VerifyArgs(args): 526 """Verify args. 527 528 Args: 529 args: Namespace object from argparse.parse_args. 530 531 Raises: 532 errors.UnsupportedFlavor: Flavor doesn't support. 533 errors.UnsupportedMultiAdbPort: multi adb port doesn't support. 534 errors.UnsupportedCreateArgs: When a create arg is specified but 535 unsupported for a particular avd type. 536 (e.g. --system-build-id for gf) 537 """ 538 # Verify that user specified flavor name is in support list. 539 # We don't use argparse's builtin validation because we need to be able to 540 # tell when a user doesn't specify a flavor. 541 if args.flavor and args.flavor not in constants.ALL_FLAVORS: 542 raise errors.UnsupportedFlavor( 543 "Flavor[%s] isn't in support list: %s" % (args.flavor, 544 constants.ALL_FLAVORS)) 545 if args.avd_type != constants.TYPE_CF: 546 if args.system_branch or args.system_build_id or args.system_build_target: 547 raise errors.UnsupportedCreateArgs( 548 "--system-* args are not supported for AVD type: %s" 549 % args.avd_type) 550 551 if args.num > 1 and args.adb_port: 552 raise errors.UnsupportedMultiAdbPort( 553 "--adb-port is not supported for multi-devices.") 554 555 if args.num > 1 and args.local_instance is not None: 556 raise errors.UnsupportedCreateArgs( 557 "--num is not supported for local instance.") 558 559 if args.adb_port: 560 utils.CheckPortFree(args.adb_port) 561 562 hw_properties = create_common.ParseHWPropertyArgs(args.hw_property) 563 for key in hw_properties: 564 if key not in constants.HW_PROPERTIES: 565 raise errors.InvalidHWPropertyError( 566 "[%s] is an invalid hw property, supported values are:%s. " 567 % (key, constants.HW_PROPERTIES)) 568 569 if args.avd_type != constants.TYPE_CHEEPS and ( 570 args.stable_cheeps_host_image_name or 571 args.stable_cheeps_host_image_project or 572 args.username or args.password): 573 raise errors.UnsupportedCreateArgs( 574 "--stable-cheeps-*, --username and --password are only valid with " 575 "avd_type == %s" % constants.TYPE_CHEEPS) 576 if (args.username or args.password) and not (args.username and args.password): 577 raise ValueError("--username and --password must both be set") 578 if not args.autoconnect and args.unlock_screen: 579 raise ValueError("--no-autoconnect and --unlock couldn't be " 580 "passed in together.") 581 582 _VerifyLocalArgs(args) 583 _VerifyHostArgs(args) 584