acloud: Support acloud reconnect command.
Bug: 118648283
Test: m acloud && atest acloud_test && acloud reconnect
1. remote instance, no ssh tunnel established.
- tunnel established , adb connect and vnc started.
2. remote instance, ssh tunnel established, no adb connect/vnc started.
- adb connect and vnc started.
3. remote instance, ssh tunnel established, adb connected but no vnc started.
- vnc started.
4. remote instance, ssh tunnel established, no connected but vnc started.
- adb started.
5. local instance, no adb connected/vnc started.
- adb connect and vnc started.
6. local instance, no adb connected but vnc started.
- adb connect.
7.local instance, adb connected but no vnc started.
- vnc started.
Change-Id: I19e3fea1d312666907deeb3e2069cae2458107ea
diff --git a/list/instance.py b/list/instance.py
index 87e4efd..1e202ce 100644
--- a/list/instance.py
+++ b/list/instance.py
@@ -35,7 +35,6 @@
logger = logging.getLogger(__name__)
-_COMMAND_PS = ["ps", "aux"]
_RE_GROUP_ADB = "local_adb_port"
_RE_GROUP_VNC = "local_vnc_port"
_RE_SSH_TUNNEL_PATTERN = (r"((.*\s*-L\s)(?P<%s>\d+):127.0.0.1:%s)"
@@ -65,7 +64,7 @@
self._ip = None
self._adb_port = None # adb port which is forwarding to remote
self._vnc_port = None # vnc port which is forwarding to remote
- self._is_ssh_tunnel_connected = None # True if ssh tunnel is still connected
+ self._ssh_tunnel_is_connected = None # True if ssh tunnel is still connected
self._createtime = None
self._avd_type = None
self._avd_flavor = None
@@ -131,9 +130,9 @@
return self._vnc_port
@property
- def is_ssh_tunnel_connected(self):
+ def ssh_tunnel_is_connected(self):
"""Return the connect status."""
- return self._is_ssh_tunnel_connected
+ return self._ssh_tunnel_is_connected
@property
def createtime(self):
@@ -190,7 +189,7 @@
local_instance._vnc_port = constants.DEFAULT_VNC_PORT
local_instance._display = ("%sx%s (%s)" % (x_res, y_res, dpi))
local_instance._is_local = True
- local_instance._is_ssh_tunnel_connected = True
+ local_instance._ssh_tunnel_is_connected = True
return local_instance
return None
@@ -239,12 +238,12 @@
self._adb_port = forwarded_ports.adb_port
self._vnc_port = forwarded_ports.vnc_port
if self._adb_port:
- self._is_ssh_tunnel_connected = True
+ self._ssh_tunnel_is_connected = True
self._fullname = (_FULL_NAME_STRING %
{"device_serial": "127.0.0.1:%d" % self._adb_port,
"instance_name": self._name})
else:
- self._is_ssh_tunnel_connected = False
+ self._ssh_tunnel_is_connected = False
self._fullname = (_FULL_NAME_STRING %
{"device_serial": "not connected",
"instance_name": self._name})
@@ -271,7 +270,7 @@
NamedTuple ForwardedPorts(vnc_port, adb_port) holding the ports
used in the ssh forwarded call. Both fields are integers.
"""
- process_output = subprocess.check_output(_COMMAND_PS)
+ process_output = subprocess.check_output(constants.COMMAND_PS)
re_pattern = re.compile(_RE_SSH_TUNNEL_PATTERN %
(_RE_GROUP_VNC, constants.DEFAULT_VNC_PORT,
_RE_GROUP_ADB, constants.DEFAULT_ADB_PORT, ip))
diff --git a/list/instance_test.py b/list/instance_test.py
index 6010d5c..5fd1963 100644
--- a/list/instance_test.py
+++ b/list/instance_test.py
@@ -13,7 +13,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Tests for host_setup_runner."""
+"""Tests for instance class."""
import collections
import subprocess
@@ -87,22 +87,22 @@
"GetAdbVncPortFromSSHTunnel",
return_value=forwarded_ports(vnc_port=fake_vnc, adb_port=fake_adb))
- # test is_ssh_tunnel_connected will be true if ssh tunnel connection is found
+ # test ssh_tunnel_is_connected will be true if ssh tunnel connection is found
instance_info = instance.RemoteInstance(gce_instance)
- self.assertTrue(instance_info.is_ssh_tunnel_connected)
+ self.assertTrue(instance_info.ssh_tunnel_is_connected)
self.assertEqual(instance_info.forwarding_adb_port, fake_adb)
self.assertEqual(instance_info.forwarding_vnc_port, fake_vnc)
expected_full_name = "device serial: 127.0.0.1:%s (%s)" % (fake_adb,
instance_info.name)
self.assertEqual(expected_full_name, instance_info.fullname)
- # test is_ssh_tunnel_connected will be false if ssh tunnel connection is not found
+ # test ssh_tunnel_is_connected will be false if ssh tunnel connection is not found
self.Patch(
instance.RemoteInstance,
"GetAdbVncPortFromSSHTunnel",
return_value=forwarded_ports(vnc_port=None, adb_port=None))
instance_info = instance.RemoteInstance(gce_instance)
- self.assertFalse(instance_info.is_ssh_tunnel_connected)
+ self.assertFalse(instance_info.ssh_tunnel_is_connected)
expected_full_name = ("device serial: not connected (%s)" %
instance_info.name)
self.assertEqual(expected_full_name, instance_info.fullname)
diff --git a/list/list.py b/list/list.py
index ee47c58..9354a99 100644
--- a/list/list.py
+++ b/list/list.py
@@ -21,6 +21,7 @@
import getpass
import logging
+from acloud import errors
from acloud.internal import constants
from acloud.internal.lib import auth
from acloud.internal.lib import gcompute_client
@@ -128,8 +129,8 @@
def ChooseInstances(cfg, select_all_instances=False):
"""Get instances.
- Get remote and local instances and ask user to choose them to use.
- (delete or reconnect)
+ Retrieve all remote/local instances and if there is more than 1 instance
+ found, ask user which instance they'd like.
Args:
cfg: AcloudConfig object.
@@ -149,6 +150,40 @@
return instances_list
+def GetInstancesFromInstanceNames(cfg, instance_names):
+ """Get instances from instance names.
+
+ Turn a list of instance names into a list of Instance().
+
+ Args:
+ cfg: AcloudConfig object.
+ instance_names: list of instance name.
+
+ Returns:
+ List of Instance() object.
+
+ Raises:
+ errors.NoInstancesFound: No instances found.
+ """
+ instance_list = []
+ full_list_of_instance = GetInstances(cfg)
+ for instance_object in full_list_of_instance:
+ if instance_object.name in instance_names:
+ instance_list.append(instance_object)
+
+ #find the missing instance.
+ missing_instances = []
+ instance_list_names = [instance_object.name for instance_object in instance_list]
+ missing_instances = [
+ instance_name for instance_name in instance_names
+ if instance_name not in instance_list_names
+ ]
+ if missing_instances:
+ raise errors.NoInstancesFound("Did not find the following instances: %s" %
+ ' '.join(missing_instances))
+ return instance_list
+
+
def Run(args):
"""Run list.
diff --git a/list/list_test.py b/list/list_test.py
new file mode 100644
index 0000000..5cbe02a
--- /dev/null
+++ b/list/list_test.py
@@ -0,0 +1,66 @@
+# Copyright 2018 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests for list."""
+import unittest
+
+import mock
+
+from acloud import errors
+from acloud.internal.lib import driver_test_lib
+from acloud.list import list as list_instance
+
+
+class InstanceObject(object):
+ """Mock to store data of instance."""
+
+ def __init__(self, name):
+ self.name = name
+
+
+class ListTest(driver_test_lib.BaseDriverTest):
+ """Test list."""
+
+ def testGetInstancesFromInstanceNames(self):
+ """test get instances from instance names."""
+ cfg = mock.MagicMock()
+ instance_names = ["alive_instance1", "alive_local_instance"]
+
+ alive_instance1 = InstanceObject("alive_instance1")
+ alive_instance2 = InstanceObject("alive_instance2")
+ alive_local_instance = InstanceObject("alive_local_instance")
+
+ instance_alive = [alive_instance1, alive_instance2, alive_local_instance]
+ self.Patch(list_instance, "GetInstances", return_value=instance_alive)
+ instances_list = list_instance.GetInstancesFromInstanceNames(cfg, instance_names)
+ instances_name_in_list = [instance_object.name for instance_object in instances_list]
+ self.assertEqual(instances_name_in_list.sort(), instance_names.sort())
+
+ instance_names = ["alive_instance1", "alive_local_instance", "alive_local_instance"]
+ instances_list = list_instance.GetInstancesFromInstanceNames(cfg, instance_names)
+ instances_name_in_list = [instance_object.name for instance_object in instances_list]
+ self.assertEqual(instances_name_in_list.sort(), instance_names.sort())
+
+ # test get instance from instance name error with invalid input.
+ instance_names = ["miss2_local_instance", "alive_instance1"]
+ miss_instance_names = ["miss2_local_instance"]
+ self.assertRaisesRegexp(
+ errors.NoInstancesFound,
+ "Did not find the following instances: %s" % ' '.join(miss_instance_names),
+ list_instance.GetInstancesFromInstanceNames,
+ cfg=cfg,
+ instance_names=instance_names)
+
+
+if __name__ == "__main__":
+ unittest.main()