1#!/usr/bin/env python3 2 3# 4# Sample run-on-target script 5# This is a script that can be used as cross-execute parameter to samba 6# configuration process, running the command on a remote target for which 7# the cross-compiled configure test was compiled. 8# 9# To use: 10# ./configure \ 11# --cross-compile \ 12# '--cross-execute=./buildtools/example/run_on_target.py --host=<host>' 13# 14# A more elaborate example: 15# ./configure \ 16# --cross-compile \ 17# '--cross-execute=./buildtools/example/run_on_target.py --host=<host> --user=<user> "--ssh=ssh -i <some key file>" --destdir=/path/to/dir' 18# 19# Typically this is to be used also with --cross-answers, so that the 20# cross answers file gets built and further builds can be made without 21# the help of a remote target. 22# 23# The following assumptions are made: 24# 1. rsync is available on build machine and target machine 25# 2. A running ssh service on target machine with password-less shell login 26# 3. A directory writable by the password-less login user 27# 4. The tests on the target can run and provide reliable results 28# from the login account's home directory. This is significant 29# for example in locking tests which 30# create files in the current directory. As a workaround to this 31# assumption, the TESTDIR environment variable can be set on the target 32# (using ssh command line or server config) and the tests shall 33# chdir to that directory. 34# 35 36import sys 37import os 38import subprocess 39from optparse import OptionParser 40 41# those are defaults, but can be overidden using command line 42SSH = 'ssh' 43USER = None 44HOST = 'localhost' 45 46 47def xfer_files(ssh, srcdir, host, user, targ_destdir): 48 """Transfer executable files to target 49 50 Use rsync to copy the directory containing program to run 51 INTO a destination directory on the target. An exact copy 52 of the source directory is created on the target machine, 53 possibly deleting files on the target machine which do not 54 exist on the source directory. 55 56 The idea is that the test may include files in addition to 57 the compiled binary, and all of those files reside alongside 58 the binary in a source directory. 59 60 For example, if the test to run is /foo/bar/test and the 61 destination directory on the target is /tbaz, then /tbaz/bar 62 on the target shall be an exact copy of /foo/bar on the source, 63 including deletion of files inside /tbaz/bar which do not exist 64 on the source. 65 """ 66 67 userhost = host 68 if user: 69 userhost = '%s@%s' % (user, host) 70 71 cmd = 'rsync --verbose -rl --ignore-times --delete -e "%s" %s %s:%s/' % \ 72 (ssh, srcdir, userhost, targ_destdir) 73 p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, 74 stderr=subprocess.PIPE) 75 (out, err) = p.communicate() 76 if p.returncode != 0: 77 raise Exception('failed syncing files\n stdout:\n%s\nstderr:%s\n' 78 % (out, err)) 79 80 81def exec_remote(ssh, host, user, destdir, targdir, prog, args): 82 """Run a test on the target 83 84 Using password-less ssh, run the compiled binary on the target. 85 86 An assumption is that there's no need to cd into the target dir, 87 same as there's no need to do it on a native build. 88 """ 89 userhost = host 90 if user: 91 userhost = '%s@%s' % (user, host) 92 93 cmd = '%s %s %s/%s/%s' % (ssh, userhost, destdir, targdir, prog) 94 if args: 95 cmd = cmd + ' ' + ' '.join(args) 96 p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, 97 stderr=subprocess.PIPE) 98 (out, err) = p.communicate() 99 return (p.returncode, out) 100 101 102def main(argv): 103 usage = "usage: %prog [options] <prog> [args]" 104 parser = OptionParser(usage) 105 106 parser.add_option('--ssh', help="SSH client and additional flags", 107 default=SSH) 108 parser.add_option('--host', help="target host name or IP address", 109 default=HOST) 110 parser.add_option('--user', help="login user on target", 111 default=USER) 112 parser.add_option('--destdir', help="work directory on target", 113 default='~') 114 115 (options, args) = parser.parse_args(argv) 116 if len(args) < 1: 117 parser.error("please supply test program to run") 118 119 progpath = args[0] 120 121 # assume that a test that was not compiled fails (e.g. getconf) 122 if progpath[0] != '/': 123 return (1, "") 124 125 progdir = os.path.dirname(progpath) 126 prog = os.path.basename(progpath) 127 targ_progdir = os.path.basename(progdir) 128 129 xfer_files( 130 options.ssh, 131 progdir, 132 options.host, 133 options.user, 134 options.destdir) 135 136 (rc, out) = exec_remote(options.ssh, 137 options.host, 138 options.user, 139 options.destdir, 140 targ_progdir, 141 prog, args[1:]) 142 return (rc, out) 143 144 145if __name__ == '__main__': 146 (rc, out) = main(sys.argv[1:]) 147 sys.stdout.write(out) 148 sys.exit(rc) 149