blob: 222283d41f00de549296862d9ea873a972705874 [file] [log] [blame]
# Lint as: python2, python3
"""Client for Autotest side communcations to the TLS SSH Server."""
import grpc
import logging
import six
import time
import common_pb2
import common_pb2_grpc
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import utils
TLS_PORT = 7152
TLS_IP = '10.254.254.254'
class TLSClient(object):
"""The client side connection to Common-TLS service running in a drone."""
def __init__(self, hostname):
"""Configure the grpc channel."""
self.hostname = hostname
self.channel = grpc.insecure_channel('{}:{}'.format(TLS_IP, TLS_PORT))
self.stub = common_pb2_grpc.CommonStub(self.channel)
def __enter__(self):
return self
def __exit__(self, *exc):
self.close()
def run_cmd(self, cmd, stdout_tee=None, stderr_tee=None, timeout=120):
"""
Run a command on the host configured during init.
@param cmd: shell cmd to execute on the DUT
@param: stdout_tee/stderr_tee: objects to write the data from the
respective streams to
@param timeout int(seconds): how long to allow the command to run
before forcefully killing it.
"""
res = utils.CmdResult(command=cmd)
try:
logging.debug(
"Running command %s via TLS ExecDutCommand on host %s",
cmd, self.hostname)
self._run(cmd, stdout_tee, stderr_tee, res, timeout)
except grpc.RpcError as e:
if e.code().name == "DEADLINE_EXCEEDED":
raise error.CmdTimeoutError(
cmd, res,
"Command(s) did not complete within %d seconds" % timeout)
raise e
except Exception as e:
raise e
return res
def _run(self, cmd, stdout_tee, stderr_tee, res, timeout):
"""Run the provided cmd, populate the res and return it."""
start_time = time.time()
response = self._send_cmd(cmd, timeout)
stdout_buf = six.StringIO()
stderr_buf = six.StringIO()
last_status = 0
if response:
for item in response:
last_status = item.exit_info.status
_parse_item_and_log(item.stdout, stdout_buf, stdout_tee)
_parse_item_and_log(item.stderr, stderr_buf, stderr_tee)
res.stdout = stdout_buf.getvalue()
res.stderr = stderr_buf.getvalue()
res.exit_status = last_status
res.duration = time.time() - start_time
def _send_cmd(self, cmd, timeout):
"""Serialize and send the cmd to the TLS service."""
formatted_cmd = common_pb2.ExecDutCommandRequest(name=self.hostname,
command=cmd)
return self.stub.ExecDutCommand(formatted_cmd, timeout=timeout)
def close(self):
"""Close the grpc channel."""
self.channel.close()
def _parse_item_and_log(item, buf, tee):
"""
Parse the provided item.
If the item exists, append the provided arr with the item & write to
the provided tee if provided.
"""
if not item:
return
buf.write(item)
if tee is not None and tee is not utils.TEE_TO_LOGS:
tee.write(item)