# 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.
|
r"""Reconnect entry point.
|
|
Reconnect will:
|
- re-establish ssh tunnels for adb/vnc port forwarding for a remote instance
|
- adb connect to forwarded ssh port for remote instance
|
- restart vnc for remote/local instances
|
"""
|
|
from __future__ import print_function
|
|
import getpass
|
import re
|
|
from acloud.delete import delete
|
from acloud.internal.lib import auth
|
from acloud.internal.lib import android_compute_client
|
from acloud.internal.lib import utils
|
from acloud.internal.lib.adb_tools import AdbTools
|
from acloud.list import list as list_instance
|
from acloud.public import config
|
|
_RE_DISPLAY = re.compile(r"([\d]+)x([\d]+)\s.*")
|
_VNC_STARTED_PATTERN = "ssvnc vnc://127.0.0.1:%(vnc_port)d"
|
|
|
def StartVnc(vnc_port, display):
|
"""Start vnc connect to AVD.
|
|
Confirm whether there is already a connection before VNC connection.
|
If there is a connection, it will not be connected. If not, connect it.
|
Before reconnecting, clear old disconnect ssvnc viewer.
|
|
Args:
|
vnc_port: Integer of vnc port number.
|
display: String, vnc connection resolution. e.g., 1080x720 (240)
|
"""
|
vnc_started_pattern = _VNC_STARTED_PATTERN % {"vnc_port": vnc_port}
|
if not utils.IsCommandRunning(vnc_started_pattern):
|
#clean old disconnect ssvnc viewer.
|
delete.CleanupSSVncviewer(vnc_port)
|
|
match = _RE_DISPLAY.match(display)
|
if match:
|
utils.LaunchVncClient(vnc_port, match.group(1), match.group(2))
|
else:
|
utils.LaunchVncClient(vnc_port)
|
|
|
def AddPublicSshRsaToInstance(cfg, user, instance_name):
|
"""Add the public rsa key to the instance's metadata.
|
|
When the public key doesn't exist in the metadata, it will add it.
|
|
Args:
|
cfg: An AcloudConfig instance.
|
user: String, the ssh username to access instance.
|
instance_name: String, instance name.
|
"""
|
credentials = auth.CreateCredentials(cfg)
|
compute_client = android_compute_client.AndroidComputeClient(
|
cfg, credentials)
|
compute_client.AddSshRsaInstanceMetadata(
|
cfg.zone,
|
user,
|
cfg.ssh_public_key_path,
|
instance_name)
|
|
|
def ReconnectInstance(ssh_private_key_path, instance):
|
"""Reconnect adb/vnc/ssh to the specified instance.
|
|
Args:
|
ssh_private_key_path: Path to the private key file.
|
e.g. ~/.ssh/acloud_rsa
|
instance: list.Instance() object.
|
"""
|
adb_cmd = AdbTools(instance.forwarding_adb_port)
|
vnc_port = instance.forwarding_vnc_port
|
# ssh tunnel is up but device is disconnected on adb
|
if instance.ssh_tunnel_is_connected and not adb_cmd.IsAdbConnectionAlive():
|
adb_cmd.DisconnectAdb()
|
adb_cmd.ConnectAdb()
|
# ssh tunnel is down and it's a remote instance
|
elif not instance.ssh_tunnel_is_connected and not instance.islocal:
|
adb_cmd.DisconnectAdb()
|
forwarded_ports = utils.AutoConnect(
|
instance.ip,
|
ssh_private_key_path,
|
utils.AVD_PORT_DICT[instance.avd_type].vnc_port,
|
utils.AVD_PORT_DICT[instance.avd_type].adb_port,
|
getpass.getuser())
|
vnc_port = forwarded_ports.vnc_port
|
|
if vnc_port:
|
StartVnc(vnc_port, instance.display)
|
|
|
def Run(args):
|
"""Run reconnect.
|
|
Args:
|
args: Namespace object from argparse.parse_args.
|
"""
|
cfg = config.GetAcloudConfig(args)
|
instances_to_reconnect = []
|
if args.instance_names is not None:
|
# user input instance name to get instance object.
|
instances_to_reconnect = list_instance.GetInstancesFromInstanceNames(
|
cfg, args.instance_names)
|
if not instances_to_reconnect:
|
instances_to_reconnect = list_instance.ChooseInstances(cfg, args.all)
|
for instance in instances_to_reconnect:
|
AddPublicSshRsaToInstance(cfg, getpass.getuser(), instance.name)
|
ReconnectInstance(cfg.ssh_private_key_path, instance)
|