Merge "Retry for checking ssh connection."
diff --git a/create/cheeps_remote_image_remote_instance_test.py b/create/cheeps_remote_image_remote_instance_test.py
index 0837401..626da4a 100644
--- a/create/cheeps_remote_image_remote_instance_test.py
+++ b/create/cheeps_remote_image_remote_instance_test.py
@@ -11,13 +11,13 @@
from acloud.internal.lib import auth
from acloud.internal.lib import cheeps_compute_client
from acloud.internal.lib import driver_test_lib
-from acloud.internal.lib import gcompute_client
+from acloud.internal.lib import ssh
class CheepsRemoteImageRemoteInstanceTest(driver_test_lib.BaseDriverTest):
"""Test cheeps_remote_image_remote_instance."""
- IP = gcompute_client.IP(external="127.0.0.1", internal="10.0.0.1")
+ IP = ssh.IP(external="127.0.0.1", internal="10.0.0.1")
INSTANCE = "fake-instance"
IMAGE = "fake-image"
GPU = "nvidia-tesla-k80"
diff --git a/internal/lib/android_compute_client.py b/internal/lib/android_compute_client.py
index b32c1ab..1bc69bc 100755
--- a/internal/lib/android_compute_client.py
+++ b/internal/lib/android_compute_client.py
@@ -375,7 +375,7 @@
zone: String, representing zone name, e.g. "us-central1-f"
Returns:
- NamedTuple of (internal, external) IP of the instance.
+ ssh.IP object, that stores internal and external ip of the instance.
"""
return super(AndroidComputeClient, self).GetInstanceIP(
instance, zone or self._zone)
diff --git a/internal/lib/cvd_compute_client_multi_stage.py b/internal/lib/cvd_compute_client_multi_stage.py
index 17f2379..44c0e90 100644
--- a/internal/lib/cvd_compute_client_multi_stage.py
+++ b/internal/lib/cvd_compute_client_multi_stage.py
@@ -49,7 +49,6 @@
from acloud.internal.lib import gcompute_client
from acloud.internal.lib import utils
from acloud.internal.lib.ssh import Ssh
-from acloud.internal.lib.ssh import IP
from acloud.pull import pull
@@ -166,7 +165,7 @@
ip = self._CreateGceInstance(instance, image_name, image_project,
extra_scopes, boot_disk_size_gb,
avd_spec)
- self._ssh = Ssh(ip=IP(internal=ip.internal, external=ip.external),
+ self._ssh = Ssh(ip=ip,
gce_user=constants.GCE_USER,
ssh_private_key_path=self._ssh_private_key_path,
extra_args_ssh_tunnel=self._extra_args_ssh_tunnel,
@@ -298,7 +297,7 @@
"""Launch CVD.
Launch AVD with launch_cvd. If the process is failed, acloud would show
- error messages and atuo download log files from remote instance.
+ error messages and auto download log files from remote instance.
Args:
instance: String, instance name.
@@ -379,7 +378,7 @@
avd_spec: An AVDSpec instance.
Returns:
- Namedtuple of (internal, external) IP of the instance.
+ ssh.IP object, that stores internal and external ip of the instance.
"""
timestart = time.time()
metadata = self._metadata.copy()
diff --git a/internal/lib/gcompute_client.py b/internal/lib/gcompute_client.py
index 945a14c..8c56ea7 100755
--- a/internal/lib/gcompute_client.py
+++ b/internal/lib/gcompute_client.py
@@ -26,7 +26,6 @@
generic, and only knows how to talk to Compute Engine APIs.
"""
# pylint: disable=too-many-lines
-import collections
import copy
import functools
import getpass
@@ -37,6 +36,7 @@
from acloud.internal import constants
from acloud.internal.lib import base_cloud_client
from acloud.internal.lib import utils
+from acloud.internal.lib.ssh import IP
logger = logging.getLogger(__name__)
@@ -56,8 +56,6 @@
"initializeParams": {},
}
-IP = collections.namedtuple("IP", ["external", "internal"])
-
class OperationScope(object):
"""Represents operation scope enum."""
@@ -1382,7 +1380,7 @@
zone: String, name of the zone.
Returns:
- NamedTuple of (internal, external) IP of the instance.
+ ssh.IP object, that stores internal and external ip of the instance.
"""
instance = self.GetInstance(instance, zone)
internal_ip = instance["networkInterfaces"][0]["networkIP"]
diff --git a/public/actions/common_operations_test.py b/public/actions/common_operations_test.py
index 18275c1..eba74b8 100644
--- a/public/actions/common_operations_test.py
+++ b/public/actions/common_operations_test.py
@@ -26,14 +26,14 @@
from acloud.internal.lib import android_compute_client
from acloud.internal.lib import auth
from acloud.internal.lib import driver_test_lib
-from acloud.internal.lib import gcompute_client
+from acloud.internal.lib import ssh
from acloud.public import report
from acloud.public.actions import common_operations
class CommonOperationsTest(driver_test_lib.BaseDriverTest):
"""Test Common Operations."""
- IP = gcompute_client.IP(external="127.0.0.1", internal="10.0.0.1")
+ IP = ssh.IP(external="127.0.0.1", internal="10.0.0.1")
INSTANCE = "fake-instance"
CMD = "test-cmd"
AVD_TYPE = "fake-type"
diff --git a/public/actions/create_cuttlefish_action_test.py b/public/actions/create_cuttlefish_action_test.py
index 728d6e0..f4788c5 100644
--- a/public/actions/create_cuttlefish_action_test.py
+++ b/public/actions/create_cuttlefish_action_test.py
@@ -29,14 +29,14 @@
from acloud.internal.lib import cvd_compute_client
from acloud.internal.lib import cvd_compute_client_multi_stage
from acloud.internal.lib import driver_test_lib
-from acloud.internal.lib import gcompute_client
+from acloud.internal.lib import ssh
from acloud.public.actions import create_cuttlefish_action
class CreateCuttlefishActionTest(driver_test_lib.BaseDriverTest):
"""Test create_cuttlefish_action."""
- IP = gcompute_client.IP(external="127.0.0.1", internal="10.0.0.1")
+ IP = ssh.IP(external="127.0.0.1", internal="10.0.0.1")
INSTANCE = "fake-instance"
IMAGE = "fake-image"
BUILD_TARGET = "fake-build-target"
diff --git a/public/actions/create_goldfish_action_test.py b/public/actions/create_goldfish_action_test.py
index 35f96ab..fa04ee2 100644
--- a/public/actions/create_goldfish_action_test.py
+++ b/public/actions/create_goldfish_action_test.py
@@ -23,15 +23,15 @@
from acloud.internal.lib import android_compute_client
from acloud.internal.lib import auth
from acloud.internal.lib import driver_test_lib
-from acloud.internal.lib import gcompute_client
from acloud.internal.lib import goldfish_compute_client
+from acloud.internal.lib import ssh
from acloud.public.actions import create_goldfish_action
class CreateGoldfishActionTest(driver_test_lib.BaseDriverTest):
"""Tests create_goldfish_action."""
- IP = gcompute_client.IP(external="127.0.0.1", internal="10.0.0.1")
+ IP = ssh.IP(external="127.0.0.1", internal="10.0.0.1")
INSTANCE = "fake-instance"
IMAGE = "fake-image"
BUILD_TARGET = "fake-build-target"
diff --git a/public/actions/remote_instance_cf_device_factory.py b/public/actions/remote_instance_cf_device_factory.py
index 57447cf..8a539c1 100644
--- a/public/actions/remote_instance_cf_device_factory.py
+++ b/public/actions/remote_instance_cf_device_factory.py
@@ -44,7 +44,7 @@
connecting from another GCE instance.
credentials: An oauth2client.OAuth2Credentials instance.
compute_client: An object of cvd_compute_client.CvdComputeClient.
- ip: Namedtuple of (internal, external) IP of the instance.
+ ssh: An Ssh object.
"""
def __init__(self, avd_spec, local_image_artifact=None,
cvd_host_package_artifact=None):
@@ -166,7 +166,7 @@
blank_data_disk_size_gb=self._cfg.extra_data_disk_size_gb,
avd_spec=self._avd_spec)
ip = self._compute_client.GetInstanceIP(instance)
- self._ssh = ssh.Ssh(ip=ssh.IP(internal=ip.internal, external=ip.external),
+ self._ssh = ssh.Ssh(ip=ip,
gce_user=constants.GCE_USER,
ssh_private_key_path=self._cfg.ssh_private_key_path,
extra_args_ssh_tunnel=self._cfg.extra_args_ssh_tunnel,
diff --git a/public/device_driver_test.py b/public/device_driver_test.py
index 42bb5c9..237d3ea 100644
--- a/public/device_driver_test.py
+++ b/public/device_driver_test.py
@@ -29,8 +29,8 @@
from acloud.internal.lib import android_build_client
from acloud.internal.lib import android_compute_client
from acloud.internal.lib import driver_test_lib
-from acloud.internal.lib import gcompute_client
from acloud.internal.lib import gstorage_client
+from acloud.internal.lib import ssh
from acloud.public import device_driver
@@ -81,7 +81,7 @@
"""Test CreateGCETypeAVD."""
cfg = _CreateCfg()
fake_gs_url = "fake_gs_url"
- fake_ip = gcompute_client.IP(external="140.1.1.1", internal="10.1.1.1")
+ fake_ip = ssh.IP(external="140.1.1.1", internal="10.1.1.1")
fake_instance = "fake-instance"
fake_image = "fake-image"
fake_build_target = "fake_target"
@@ -136,7 +136,7 @@
def testCreateGCETypeAVDInternalIP(self):
"""Test CreateGCETypeAVD with internal IP."""
cfg = _CreateCfg()
- fake_ip = gcompute_client.IP(external="140.1.1.1", internal="10.1.1.1")
+ fake_ip = ssh.IP(external="140.1.1.1", internal="10.1.1.1")
fake_instance = "fake-instance"
fake_build_target = "fake_target"
fake_build_id = "12345"
diff --git a/pull/pull.py b/pull/pull.py
index 60c2074..1f99c5c 100644
--- a/pull/pull.py
+++ b/pull/pull.py
@@ -41,7 +41,7 @@
_IMG_FILE_EXTENSION = ".img"
-def PullFileFromInstance(cfg, instance):
+def PullFileFromInstance(cfg, instance, file_name=None, no_prompts=False):
"""Pull file from remote CF instance.
1. Download log files to temp folder.
@@ -51,6 +51,8 @@
Args:
cfg: AcloudConfig object.
instance: list.Instance() object.
+ file_name: String of file name.
+ no_prompts: Boolean, True to skip the prompt about file streaming.
Returns:
A Report instance.
@@ -59,11 +61,11 @@
gce_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)
+ log_files = SelectLogFileToPull(ssh, file_name)
download_folder = GetDownloadLogFolder(instance.name)
PullLogs(ssh, log_files, download_folder)
if len(log_files) == 1:
- DisplayLog(ssh, log_files[0])
+ DisplayLog(ssh, log_files[0], no_prompts)
return report.Report(command="pull")
@@ -81,17 +83,18 @@
_DisplayPullResult(download_folder)
-def DisplayLog(ssh, log_file):
+def DisplayLog(ssh, log_file, no_prompts=False):
"""Display the content of log file in the screen.
Args:
ssh: Ssh object.
log_file: String of the log file path.
+ no_prompts: Boolean, True to skip all prompts.
"""
warning_msg = ("It will stream log to show on screen. If you want to stop "
"streaming, please press CTRL-C to exit.\nPress 'y' to show "
"log or read log by myself[y/N]:")
- if utils.GetUserAnswerYes(warning_msg):
+ if no_prompts or utils.GetUserAnswerYes(warning_msg):
ssh.Run("tail -f -n +1 %s" % log_file, show_output=True)
@@ -122,22 +125,29 @@
return log_folder
-def SelectLogFileToPull(ssh):
+def SelectLogFileToPull(ssh, file_name=None):
"""Select one log file or all log files to downalod.
1. Get all log file paths as selection list
- 2. Get user selected file path
+ 2. Get user selected file path or user provided file name.
Args:
ssh: Ssh object.
-
- Raises:
- errors.CheckPathError: Can't find log files.
+ file_name: String of file name.
Returns:
List of selected file paths.
+
+ Raises:
+ errors.CheckPathError: Can't find log files.
"""
log_files = GetAllLogFilePaths(ssh)
+ if file_name:
+ file_path = os.path.join(_REMOTE_LOG_FOLDER, file_name)
+ if file_path in log_files:
+ return [file_path]
+ raise errors.CheckPathError("Can't find this log file(%s) from remote "
+ "instance." % file_path)
if len(log_files) == 1:
return log_files
@@ -147,7 +157,7 @@
return utils.GetAnswerFromList(log_files, enable_choose_all=True)
raise errors.CheckPathError("Can't find any log file in folder(%s) from "
- "remote instance" % _REMOTE_LOG_FOLDER)
+ "remote instance." % _REMOTE_LOG_FOLDER)
def GetAllLogFilePaths(ssh):
@@ -207,5 +217,8 @@
if args.instance_name:
instance = list_instances.GetInstancesFromInstanceNames(
cfg, [args.instance_name])
- return PullFileFromInstance(cfg, instance[0])
- return PullFileFromInstance(cfg, list_instances.ChooseOneRemoteInstance(cfg))
+ return PullFileFromInstance(cfg, instance[0], args.file_name, args.no_prompt)
+ return PullFileFromInstance(cfg,
+ list_instances.ChooseOneRemoteInstance(cfg),
+ args.file_name,
+ args.no_prompt)
diff --git a/pull/pull_args.py b/pull/pull_args.py
index 62a28d4..7ab6172 100644
--- a/pull/pull_args.py
+++ b/pull/pull_args.py
@@ -39,5 +39,19 @@
type=str,
required=False,
help="The name of the remote instance that need to pull log files.")
+ pull_parser.add_argument(
+ "--file-name",
+ dest="file_name",
+ type=str,
+ required=False,
+ help="The log file name to pull from the remote instance, "
+ "e.g. launcher.log, kernel.log.")
+ pull_parser.add_argument(
+ "--yes", "-y",
+ action="store_true",
+ dest="no_prompt",
+ required=False,
+ help="Assume 'yes' as an answer to the prompt when asking users about "
+ "file streaming.")
return pull_parser
diff --git a/pull/pull_test.py b/pull/pull_test.py
index 458bb87..c82f12f 100644
--- a/pull/pull_test.py
+++ b/pull/pull_test.py
@@ -48,6 +48,22 @@
expected_result = ["file2.log"]
self.assertEqual(pull.SelectLogFileToPull(ssh), expected_result)
+ # Test user provided file name exist.
+ log_files = ["/home/vsoc-01/cuttlefish_runtime/file1.log",
+ "/home/vsoc-01/cuttlefish_runtime/file2.log"]
+ input_file = "file1.log"
+ self.Patch(pull, "GetAllLogFilePaths", return_value=log_files)
+ expected_result = ["/home/vsoc-01/cuttlefish_runtime/file1.log"]
+ self.assertEqual(pull.SelectLogFileToPull(ssh, input_file), expected_result)
+
+ # Test user provided file name not exist.
+ log_files = ["/home/vsoc-01/cuttlefish_runtime/file1.log",
+ "/home/vsoc-01/cuttlefish_runtime/file2.log"]
+ input_file = "not_exist.log"
+ self.Patch(pull, "GetAllLogFilePaths", return_value=log_files)
+ with self.assertRaises(errors.CheckPathError):
+ pull.SelectLogFileToPull(ssh, input_file)
+
def testFilterLogfiles(self):
"""test filer log file from black list."""
# Filter out file name is "kernel".