Merge "Update delete function by instance names."
diff --git a/create/create.py b/create/create.py
index c69b71f..37b7351 100644
--- a/create/create.py
+++ b/create/create.py
@@ -215,6 +215,9 @@
 
     Args:
         args: Namespace object from argparse.parse_args.
+
+    Returns:
+        A Report instance.
     """
     if not args.skip_pre_run_check:
         PreRunCheck(args)
@@ -224,5 +227,4 @@
                                            spec.image_source)
     avd_creator = avd_creator_class()
     report = avd_creator.Create(spec, args.no_prompt)
-    if report and args.report_file:
-        report.Dump(args.report_file)
+    return report
diff --git a/create/create_args.py b/create/create_args.py
index 733215a..11b4354 100644
--- a/create/create_args.py
+++ b/create/create_args.py
@@ -341,14 +341,16 @@
         type=str,
         dest="remote_host",
         default=None,
-        help="'cuttlefish only' Provide host name for launch AVD on this "
-        "devices.")
+        help="'cuttlefish only' Provide host name to clean up the remote host. "
+        "For example: '--host 1.1.1.1'")
     create_parser.add_argument(
         "--host-user",
         type=str,
         dest="host_user",
-        default=None,
-        help="'remote host only' Provide host user for login on this host.")
+        default=constants.GCE_USER,
+        help="'remote host only' Provide host user for logging in to the host. "
+        "The default value is vsoc-01. For example: '--host 1.1.1.1 --host-user "
+        "vsoc-02'")
     create_parser.add_argument(
         "--host-ssh-private-key-path",
         type=str,
@@ -462,7 +464,7 @@
         raise errors.UnsupportedCreateArgs(
             "--num is not supported for remote host.")
 
-    if args.host_user and args.remote_host is None:
+    if args.host_user != constants.GCE_USER and args.remote_host is None:
         raise errors.UnsupportedCreateArgs(
             "--host-user only support for remote host.")
 
diff --git a/create/local_image_local_instance.py b/create/local_image_local_instance.py
index 6787b2f..03b3ca6 100644
--- a/create/local_image_local_instance.py
+++ b/create/local_image_local_instance.py
@@ -34,7 +34,6 @@
 [CUTTLEFISH_CONFIG_FILE] which is pointing to the runtime cuttlefish json.
 """
 
-from __future__ import print_function
 import json
 import logging
 import os
diff --git a/create/remote_image_local_instance.py b/create/remote_image_local_instance.py
index b782b12..9f97907 100644
--- a/create/remote_image_local_instance.py
+++ b/create/remote_image_local_instance.py
@@ -18,7 +18,6 @@
 Create class that is responsible for creating a local instance AVD with a
 remote image.
 """
-from __future__ import print_function
 import logging
 import os
 import sys
diff --git a/delete/delete.py b/delete/delete.py
index 1c3890a..d231367 100644
--- a/delete/delete.py
+++ b/delete/delete.py
@@ -225,7 +225,7 @@
     return delete_report
 
 
-def CleanUpRemoteHost(cfg, remote_host, host_user=None,
+def CleanUpRemoteHost(cfg, remote_host, host_user,
                       host_ssh_private_key_path=None):
     """Clean up the remote host.
 
@@ -246,12 +246,11 @@
         oauth2_credentials=credentials)
     ssh = ssh_object.Ssh(
         ip=ssh_object.IP(ip=remote_host),
-        gce_user=host_user or constants.GCE_USER,
+        user=host_user,
         ssh_private_key_path=(
             host_ssh_private_key_path or cfg.ssh_private_key_path))
     try:
-        compute_client.InitRemoteHost(ssh, remote_host, host_user or
-                                      constants.GCE_USER)
+        compute_client.InitRemoteHost(ssh, remote_host, host_user)
         delete_report.SetStatus(report.Status.SUCCESS)
         device_driver.AddDeletionResultToReport(
             delete_report, [remote_host], failed=[],
diff --git a/delete/delete_args.py b/delete/delete_args.py
index 6e92cbc..867194f 100644
--- a/delete/delete_args.py
+++ b/delete/delete_args.py
@@ -19,6 +19,9 @@
 """
 import argparse
 
+from acloud.internal import constants
+
+
 CMD_DELETE = "delete"
 
 
@@ -71,9 +74,10 @@
         "--host-user",
         type=str,
         dest="host_user",
-        default=None,
-        help="'remote host only' Provide host user for logging in to the host"
-        "For example: '--host 1.1.1.1 --host-user vsoc-02'")
+        default=constants.GCE_USER,
+        help="'remote host only' Provide host user for logging in to the host. "
+        "The default value is vsoc-01. For example: '--host 1.1.1.1 --host-user "
+        "vsoc-02'")
     delete_parser.add_argument(
         "--host-ssh-private-key-path",
         type=str,
diff --git a/internal/lib/cvd_compute_client_multi_stage.py b/internal/lib/cvd_compute_client_multi_stage.py
index 165ee83..f69330c 100644
--- a/internal/lib/cvd_compute_client_multi_stage.py
+++ b/internal/lib/cvd_compute_client_multi_stage.py
@@ -54,6 +54,7 @@
 
 logger = logging.getLogger(__name__)
 
+_DECOMPRESS_KERNEL_ARG = "-decompress_kernel=true"
 _DEFAULT_BRANCH = "aosp-master"
 _FETCHER_BUILD_TARGET = "aosp_cf_x86_phone-userdebug"
 _FETCHER_NAME = "fetch_cvd"
@@ -191,7 +192,7 @@
                                                extra_scopes, boot_disk_size_gb,
                                                avd_spec)
         self._ssh = Ssh(ip=self._ip,
-                        gce_user=constants.GCE_USER,
+                        user=constants.GCE_USER,
                         ssh_private_key_path=self._ssh_private_key_path,
                         extra_args_ssh_tunnel=self._extra_args_ssh_tunnel,
                         report_internal_ip=self._report_internal_ip)
@@ -223,13 +224,14 @@
             return instance
 
     def _GetLaunchCvdArgs(self, avd_spec=None, blank_data_disk_size_gb=None,
-                          kernel_build=None):
+                          kernel_build=None, decompress_kernel=None):
         """Get launch_cvd args.
 
         Args:
             avd_spec: An AVDSpec instance.
             blank_data_disk_size_gb: Size of the blank data disk in GB.
             kernel_build: String, kernel build info.
+            decompress_kernel: Boolean, if true decompress the kernel.
 
         Returns:
             String, args of launch_cvd.
@@ -272,6 +274,10 @@
 
         if self._launch_args:
             launch_cvd_args.append(self._launch_args)
+
+        if decompress_kernel:
+            launch_cvd_args.append(_DECOMPRESS_KERNEL_ARG)
+
         return launch_cvd_args
 
     @staticmethod
@@ -347,11 +353,10 @@
         error_msg = ""
         launch_cvd_args = self._GetLaunchCvdArgs(avd_spec,
                                                  blank_data_disk_size_gb,
-                                                 kernel_build)
+                                                 kernel_build,
+                                                 decompress_kernel)
         boot_timeout_secs = boot_timeout_secs or self.BOOT_TIMEOUT_SECS
         ssh_command = "./bin/launch_cvd -daemon " + " ".join(launch_cvd_args)
-        if decompress_kernel:
-            ssh_command = ssh_command + " " + "-decompress_kernel=true"
         try:
             self._ssh.Run(ssh_command, boot_timeout_secs)
         except (subprocess.CalledProcessError, errors.DeviceConnectionError) as e:
diff --git a/internal/lib/ota_tools.py b/internal/lib/ota_tools.py
index 1c47fbd..9fc2a18 100644
--- a/internal/lib/ota_tools.py
+++ b/internal/lib/ota_tools.py
@@ -35,7 +35,7 @@
 
 _BUILD_SUPER_IMAGE_TIMEOUT_SECS = 30
 _AVBTOOL_TIMEOUT_SECS = 30
-_MK_COMBINED_IMG_TIMEOUT_SECS = 60
+_MK_COMBINED_IMG_TIMEOUT_SECS = 180
 
 _MISSING_OTA_TOOLS_MSG = ("%(tool_name)s does not exist. Try `make otatools` "
                           "in build environment, or setting ANDROID_HOST_OUT "
diff --git a/internal/lib/ssh.py b/internal/lib/ssh.py
index ddb0f9b..c8c4fd6 100755
--- a/internal/lib/ssh.py
+++ b/internal/lib/ssh.py
@@ -154,14 +154,14 @@
 
     Attributes:
         _ip: an IP object.
-        _gce_user: String of user login into the instance.
+        _user: String of user login into the instance.
         _ssh_private_key_path: Path to the private key file.
         _extra_args_ssh_tunnel: String, extra args for ssh or scp.
     """
-    def __init__(self, ip, gce_user, ssh_private_key_path,
+    def __init__(self, ip, user, ssh_private_key_path,
                  extra_args_ssh_tunnel=None, report_internal_ip=False):
         self._ip = ip.internal if report_internal_ip else ip.external
-        self._gce_user = gce_user
+        self._user = user
         self._ssh_private_key_path = ssh_private_key_path
         self._extra_args_ssh_tunnel = extra_args_ssh_tunnel
 
@@ -210,7 +210,7 @@
 
         if execute_bin == constants.SSH_BIN:
             base_cmd.append(_SSH_IDENTITY %
-                            {"login_user":self._gce_user, "ip_addr":self._ip})
+                            {"login_user":self._user, "ip_addr":self._ip})
             return " ".join(base_cmd)
         if execute_bin == constants.SCP_BIN:
             return " ".join(base_cmd)
@@ -266,7 +266,7 @@
         """
         scp_command = [self.GetBaseCmd(constants.SCP_BIN)]
         scp_command.append(src_file)
-        scp_command.append("%s@%s:%s" %(self._gce_user, self._ip, dst_file))
+        scp_command.append("%s@%s:%s" %(self._user, self._ip, dst_file))
         ShellCmdWithRetry(" ".join(scp_command))
 
     def ScpPullFile(self, src_file, dst_file):
@@ -277,6 +277,6 @@
             dst_file: The destination file path the file is pulled to.
         """
         scp_command = [self.GetBaseCmd(constants.SCP_BIN)]
-        scp_command.append("%s@%s:%s" %(self._gce_user, self._ip, src_file))
+        scp_command.append("%s@%s:%s" %(self._user, self._ip, src_file))
         scp_command.append(dst_file)
         ShellCmdWithRetry(" ".join(scp_command))
diff --git a/internal/lib/ssh_test.py b/internal/lib/ssh_test.py
index bddefd5..c443a62 100644
--- a/internal/lib/ssh_test.py
+++ b/internal/lib/ssh_test.py
@@ -56,7 +56,7 @@
     def testGetBaseCmdWithInternalIP(self):
         """Test get base command with internal ip."""
         ssh_object = ssh.Ssh(ip=self.FAKE_IP,
-                             gce_user=self.FAKE_SSH_USER,
+                             user=self.FAKE_SSH_USER,
                              ssh_private_key_path=self.FAKE_SSH_PRIVATE_KEY_PATH,
                              report_internal_ip=self.FAKE_REPORT_INTERNAL_IP)
         expected_ssh_cmd = ("/usr/bin/ssh -i /fake/acloud_rea -q -o UserKnownHostsFile=/dev/null "
@@ -173,7 +173,7 @@
         """Test IP class to get ip address."""
         # Internal ip case.
         ssh_object = ssh.Ssh(ip=ssh.IP(external="1.1.1.1", internal="10.1.1.1"),
-                             gce_user=self.FAKE_SSH_USER,
+                             user=self.FAKE_SSH_USER,
                              ssh_private_key_path=self.FAKE_SSH_PRIVATE_KEY_PATH,
                              report_internal_ip=True)
         expected_ip = "10.1.1.1"
@@ -181,14 +181,14 @@
 
         # External ip case.
         ssh_object = ssh.Ssh(ip=ssh.IP(external="1.1.1.1", internal="10.1.1.1"),
-                             gce_user=self.FAKE_SSH_USER,
+                             user=self.FAKE_SSH_USER,
                              ssh_private_key_path=self.FAKE_SSH_PRIVATE_KEY_PATH)
         expected_ip = "1.1.1.1"
         self.assertEqual(ssh_object._ip, expected_ip)
 
         # Only one ip case.
         ssh_object = ssh.Ssh(ip=ssh.IP(ip="1.1.1.1"),
-                             gce_user=self.FAKE_SSH_USER,
+                             user=self.FAKE_SSH_USER,
                              ssh_private_key_path=self.FAKE_SSH_PRIVATE_KEY_PATH)
         expected_ip = "1.1.1.1"
         self.assertEqual(ssh_object._ip, expected_ip)
@@ -196,7 +196,7 @@
     def testWaitForSsh(self):
         """Test WaitForSsh."""
         ssh_object = ssh.Ssh(ip=self.FAKE_IP,
-                             gce_user=self.FAKE_SSH_USER,
+                             user=self.FAKE_SSH_USER,
                              ssh_private_key_path=self.FAKE_SSH_PRIVATE_KEY_PATH,
                              report_internal_ip=self.FAKE_REPORT_INTERNAL_IP)
         self.Patch(ssh, "_SshCall", return_value=-1)
diff --git a/public/acloud_main.py b/public/acloud_main.py
index f6511d8..f622661 100644
--- a/public/acloud_main.py
+++ b/public/acloud_main.py
@@ -127,6 +127,7 @@
 
 LOGGING_FMT = "%(asctime)s |%(levelname)s| %(module)s:%(lineno)s| %(message)s"
 ACLOUD_LOGGER = "acloud"
+NO_ERROR_MESSAGE = ""
 
 # Commands
 CMD_CREATE_CUTTLEFISH = "create_cf"
@@ -344,7 +345,8 @@
         argv: A list of system arguments.
 
     Returns:
-        0 if success. None-zero if fails.
+        Job status: Integer, 0 if success. None-zero if fails.
+        Stack trace: String of errors.
     """
     if argv is None:
         argv = sys.argv[1:]
@@ -360,7 +362,7 @@
 
     report = None
     if args.which == create_args.CMD_CREATE:
-        create.Run(args)
+        report = create.Run(args)
     elif args.which == CMD_CREATE_CUTTLEFISH:
         report = create_cuttlefish_action.CreateDevices(
             cfg=cfg,
@@ -407,16 +409,17 @@
     elif args.which == setup_args.CMD_SETUP:
         setup.Run(args)
     else:
-        sys.stderr.write("Invalid command %s" % args.which)
-        return constants.EXIT_BY_WRONG_CMD
+        error_msg = "Invalid command %s" % args.which
+        sys.stderr.write(error_msg)
+        return constants.EXIT_BY_WRONG_CMD, error_msg
 
     if report and args.report_file:
         report.Dump(args.report_file)
     if report and report.errors:
-        msg = "\n".join(report.errors)
-        sys.stderr.write("Encountered the following errors:\n%s\n" % msg)
-        return constants.EXIT_BY_FAIL_REPORT
-    return constants.EXIT_SUCCESS
+        error_msg = "\n".join(report.errors)
+        sys.stderr.write("Encountered the following errors:\n%s\n" % error_msg)
+        return constants.EXIT_BY_FAIL_REPORT, error_msg
+    return constants.EXIT_SUCCESS, NO_ERROR_MESSAGE
 
 
 if __name__ == "__main__":
@@ -425,7 +428,7 @@
     EXCEPTION_LOG = None
     LOG_METRICS = metrics.LogUsage(sys.argv[1:])
     try:
-        EXIT_CODE = main(sys.argv[1:])
+        EXIT_CODE, EXCEPTION_STACKTRACE = main(sys.argv[1:])
     except Exception as e:
         EXIT_CODE = constants.EXIT_BY_ERROR
         EXCEPTION_STACKTRACE = traceback.format_exc()
diff --git a/public/actions/common_operations.py b/public/actions/common_operations.py
index 3b32334..65c0471 100644
--- a/public/actions/common_operations.py
+++ b/public/actions/common_operations.py
@@ -20,7 +20,6 @@
 directly.
 """
 
-from __future__ import print_function
 import logging
 import os
 
diff --git a/public/actions/common_operations_test.py b/public/actions/common_operations_test.py
index eba74b8..1226b4b 100644
--- a/public/actions/common_operations_test.py
+++ b/public/actions/common_operations_test.py
@@ -17,7 +17,6 @@
 
 from __future__ import absolute_import
 from __future__ import division
-from __future__ import print_function
 
 import unittest
 import mock
diff --git a/public/actions/remote_instance_cf_device_factory.py b/public/actions/remote_instance_cf_device_factory.py
index 1c33d1f..82ab5fe 100644
--- a/public/actions/remote_instance_cf_device_factory.py
+++ b/public/actions/remote_instance_cf_device_factory.py
@@ -15,7 +15,6 @@
 """RemoteInstanceDeviceFactory provides basic interface to create a cuttlefish
 device factory."""
 
-from __future__ import print_function
 import glob
 import logging
 import os
@@ -133,7 +132,7 @@
         ip = ssh.IP(ip=self._avd_spec.remote_host)
         self._ssh = ssh.Ssh(
             ip=ip,
-            gce_user=self._avd_spec.host_user or constants.GCE_USER,
+            user=self._avd_spec.host_user,
             ssh_private_key_path=(self._avd_spec.host_ssh_private_key_path or
                                   self._cfg.ssh_private_key_path),
             extra_args_ssh_tunnel=self._cfg.extra_args_ssh_tunnel,
@@ -243,7 +242,7 @@
             avd_spec=self._avd_spec)
         ip = self._compute_client.GetInstanceIP(instance)
         self._ssh = ssh.Ssh(ip=ip,
-                            gce_user=constants.GCE_USER,
+                            user=constants.GCE_USER,
                             ssh_private_key_path=self._cfg.ssh_private_key_path,
                             extra_args_ssh_tunnel=self._cfg.extra_args_ssh_tunnel,
                             report_internal_ip=self._report_internal_ip)
@@ -268,8 +267,6 @@
             images_dir: String, directory of local images which build
                         from 'm'.
         """
-        # TODO(b/133461252) Deprecate acloud create with local image zip.
-        # Upload local image zip file
         if local_image_zip:
             remote_cmd = ("/usr/bin/install_zip.sh . < %s" % local_image_zip)
             logger.debug("remote_cmd:\n %s", remote_cmd)
diff --git a/public/actions/remote_instance_cf_device_factory_test.py b/public/actions/remote_instance_cf_device_factory_test.py
index 992239d..448b93f 100644
--- a/public/actions/remote_instance_cf_device_factory_test.py
+++ b/public/actions/remote_instance_cf_device_factory_test.py
@@ -255,7 +255,7 @@
             fake_image,
             fake_host_package)
         factory._ssh = ssh.Ssh(ip=fake_ip,
-                               gce_user=constants.GCE_USER,
+                               user=constants.GCE_USER,
                                ssh_private_key_path="/fake/acloud_rea")
         factory._UploadArtifacts(fake_image, fake_host_package, fake_local_image_dir)
         expected_cmd1 = ("/usr/bin/install_zip.sh . < %s" % fake_image)
diff --git a/pull/pull.py b/pull/pull.py
index 1f99c5c..5da45d5 100644
--- a/pull/pull.py
+++ b/pull/pull.py
@@ -58,7 +58,7 @@
         A Report instance.
     """
     ssh = Ssh(ip=IP(ip=instance.ip),
-              gce_user=constants.GCE_USER,
+              user=constants.GCE_USER,
               ssh_private_key_path=cfg.ssh_private_key_path,
               extra_args_ssh_tunnel=cfg.extra_args_ssh_tunnel)
     log_files = SelectLogFileToPull(ssh, file_name)
diff --git a/pull/pull_test.py b/pull/pull_test.py
index 6af9644..f57c6c4 100644
--- a/pull/pull_test.py
+++ b/pull/pull_test.py
@@ -70,7 +70,7 @@
         """Test DisplayLog."""
         fake_ip = ssh.IP(external="1.1.1.1", internal="10.1.1.1")
         _ssh = ssh.Ssh(ip=fake_ip,
-                       gce_user=constants.GCE_USER,
+                       user=constants.GCE_USER,
                        ssh_private_key_path="/fake/acloud_rea")
         self.Patch(utils, "GetUserAnswerYes", return_value="Y")
         log_file = "file1.log"
diff --git a/reconnect/reconnect.py b/reconnect/reconnect.py
index c87269f..1be9567 100644
--- a/reconnect/reconnect.py
+++ b/reconnect/reconnect.py
@@ -19,8 +19,6 @@
  - restart vnc for remote/local instances
 """
 
-from __future__ import print_function
-
 import re
 
 from acloud import errors