Add lockfile support to artiq_devtool.

pull/875/head
whitequark 2017-11-26 15:17:35 +00:00
parent b89929565c
commit b5d098c6db
2 changed files with 46 additions and 13 deletions

View File

@ -6,6 +6,7 @@
import sys
import argparse
import logging
import subprocess
import socket
import select
@ -22,20 +23,23 @@ def get_argparser():
verbosity_args(parser)
parser.add_argument("-H", "--host", metavar="HOST",
parser.add_argument("-H", "--host", metavar="HOSTNAME",
type=str, default="lab.m-labs.hk",
help="SSH host where the development board is located")
parser.add_argument("-D", "--device", metavar="DEVICE",
parser.add_argument("-D", "--device", metavar="HOSTNAME",
type=str, default="kc705.lab.m-labs.hk",
help="address or domain corresponding to the development board")
parser.add_argument("-s", "--serial", metavar="SERIAL",
parser.add_argument("-s", "--serial", metavar="PATH",
type=str, default="/dev/ttyUSB_kc705",
help="TTY device corresponding to the development board")
parser.add_argument("-l", "--lockfile", metavar="PATH",
type=str, default="/run/boards/kc705",
help="The lockfile to be acquired for the duration of the script")
parser.add_argument("-t", "--target", metavar="TARGET",
type=str, default="kc705_dds",
help="Target to build, one of: "
"kc705_dds kc705_drtio_master kc705_drtio_satellite")
parser.add_argument("-c", "--config", metavar="TARGET_CFG",
parser.add_argument("-c", "--config", metavar="PATH",
type=str, default="openocd-kc705.cfg",
help="OpenOCD configuration file corresponding to the development board")
@ -50,6 +54,8 @@ def get_argparser():
def main():
args = get_argparser().parse_args()
init_logger(args)
if args.verbose == args.quiet == 0:
logging.getLogger().setLevel(logging.INFO)
if args.target == "kc705_dds" or args.target == "kc705_drtio_master":
firmware = "runtime"
@ -65,6 +71,27 @@ def main():
"firmware": firmware,
}
lock_acquired = False
def lock():
nonlocal lock_acquired
if not lock_acquired:
logger.info("Acquiring device lock")
flock = client.spawn_command("flock --verbose --nonblock {} /bin/sleep 86400"
.format(args.lockfile),
get_pty=True)
flock_file = flock.makefile('r')
while not lock_acquired:
line = flock_file.readline()
if not line:
break
logger.debug(line.rstrip())
if line.startswith("flock: executing"):
lock_acquired = True
elif line.startswith("flock: failed"):
logger.error("Failed to get lock")
sys.exit(1)
for action in args.actions:
if action == "build":
logger.info("Building firmware")
@ -85,6 +112,8 @@ def main():
shutil.rmtree(target_dir)
elif action == "reset":
lock()
logger.info("Resetting device")
client.run_command(
"{env} artiq_flash start" +
@ -92,6 +121,8 @@ def main():
**substs)
elif action == "boot" or action == "boot+log":
lock()
logger.info("Uploading firmware")
client.get_sftp().put("/tmp/{target}/software/{firmware}/{firmware}.bin"
.format(target=args.target, firmware=firmware),
@ -111,6 +142,8 @@ def main():
client.drain(flterm)
elif action == "connect":
lock()
transport = client.get_transport()
def forwarder(local_stream, remote_stream):
@ -141,10 +174,6 @@ def main():
local_stream, peer_addr = listener.accept()
logger.info("Accepting %s:%s and opening SSH channel to %s:%s",
*peer_addr, args.device, port)
if client.get_transport() is None:
logger.error("Trying to open a channel before the transport is ready!")
continue
try:
remote_stream = \
transport.open_channel('direct-tcpip', (args.device, port), peer_addr)
@ -156,12 +185,14 @@ def main():
name="forward-{}".format(port), daemon=True)
thread.start()
for port in (1380, 1381, 1382, 1383):
ports = [1380, 1381, 1382, 1383]
for port in ports:
thread = threading.Thread(target=listener, args=(port,),
name="listen-{}".format(port), daemon=True)
thread.start()
logger.info("Connecting to device")
logger.info("Forwarding ports {} to core device and logs from core device"
.format(", ".join(map(str, ports))))
client.run_command(
"{env} python3 flterm.py {serial} --output-only",
**substs)

View File

@ -269,10 +269,12 @@ class SSHClient:
def get_ssh(self):
if self.ssh is None:
import paramiko
logging.getLogger("paramiko").setLevel(logging.WARNING)
self.ssh = paramiko.SSHClient()
self.ssh.load_system_host_keys()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(self.host)
logger.debug("Connecting to {}".format(self.host))
return self.ssh
def get_transport(self):
@ -286,11 +288,11 @@ class SSHClient:
return self.sftp
def spawn_command(self, cmd, get_pty=False, **kws):
logger.info("Executing {}".format(cmd))
chan = self.get_ssh().get_transport().open_session()
chan = self.get_transport().open_session()
chan.set_combine_stderr(True)
if get_pty:
chan.get_pty()
chan.set_combine_stderr(True)
logger.debug("Executing {}".format(cmd))
chan.exec_command(cmd.format(tmp=self.tmp, **kws))
return chan