83227594512853788e0bef0402b3bac3617b3d90
[bbaumbach/samba-autobuild/.git] / buildtools / examples / run_on_target.py
1 #!/usr/bin/env python
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
36 import sys
37 import os
38 import subprocess
39 from optparse import OptionParser
40
41 # those are defaults, but can be overidden using command line
42 SSH = 'ssh'
43 USER = None
44 HOST = 'localhost'
45
46
47 def 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
81 def 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
102 def 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
145 if __name__ == '__main__':
146     (rc, out) = main(sys.argv[1:])
147     sys.stdout.write(out)
148     sys.exit(rc)