summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/utils/sshcontrol.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oeqa/utils/sshcontrol.py')
-rw-r--r--meta/lib/oeqa/utils/sshcontrol.py127
1 files changed, 127 insertions, 0 deletions
diff --git a/meta/lib/oeqa/utils/sshcontrol.py b/meta/lib/oeqa/utils/sshcontrol.py
new file mode 100644
index 0000000..d355d5e
--- /dev/null
+++ b/meta/lib/oeqa/utils/sshcontrol.py
@@ -0,0 +1,127 @@
1# Copyright (C) 2013 Intel Corporation
2#
3# Released under the MIT license (see COPYING.MIT)
4
5# Provides a class for setting up ssh connections,
6# running commands and copying files to/from a target.
7# It's used by testimage.bbclass and tests in lib/oeqa/runtime.
8
9import subprocess
10import time
11import os
12import select
13
14
15class SSHProcess(object):
16 def __init__(self, **options):
17
18 self.defaultopts = {
19 "stdout": subprocess.PIPE,
20 "stderr": subprocess.STDOUT,
21 "stdin": None,
22 "shell": False,
23 "bufsize": -1,
24 "preexec_fn": os.setsid,
25 }
26 self.options = dict(self.defaultopts)
27 self.options.update(options)
28 self.status = None
29 self.output = None
30 self.process = None
31 self.starttime = None
32
33 def run(self, command, timeout=None):
34 self.starttime = time.time()
35 output = ''
36 self.process = subprocess.Popen(command, **self.options)
37 if timeout:
38 endtime = self.starttime + timeout
39 eof = False
40 while time.time() < endtime and not eof:
41 if select.select([self.process.stdout], [], [], 5)[0] != []:
42 data = os.read(self.process.stdout.fileno(), 1024)
43 if not data:
44 self.process.stdout.close()
45 eof = True
46 else:
47 output += data
48 endtime = time.time() + timeout
49
50 # process hasn't returned yet
51 if not eof:
52 self.process.terminate()
53 time.sleep(5)
54 try:
55 self.process.kill()
56 except OSError:
57 pass
58 output += "\nProcess killed - no output for %d seconds. Total running time: %d seconds." % (timeout, time.time() - self.starttime)
59 else:
60 output = self.process.communicate()[0]
61
62 self.status = self.process.wait()
63 self.output = output.rstrip()
64 return (self.status, self.output)
65
66
67class SSHControl(object):
68 def __init__(self, ip, logfile=None, timeout=300, user='root', port=None):
69 self.ip = ip
70 self.defaulttimeout = timeout
71 self.ignore_status = True
72 self.logfile = logfile
73 self.user = user
74 self.ssh_options = [
75 '-o', 'UserKnownHostsFile=/dev/null',
76 '-o', 'StrictHostKeyChecking=no',
77 '-o', 'LogLevel=ERROR'
78 ]
79 self.ssh = ['ssh', '-l', self.user ] + self.ssh_options
80 self.scp = ['scp'] + self.ssh_options
81 if port:
82 self.ssh = self.ssh + [ '-p', port ]
83 self.scp = self.scp + [ '-P', port ]
84
85 def log(self, msg):
86 if self.logfile:
87 with open(self.logfile, "a") as f:
88 f.write("%s\n" % msg)
89
90 def _internal_run(self, command, timeout=None, ignore_status = True):
91 self.log("[Running]$ %s" % " ".join(command))
92
93 proc = SSHProcess()
94 status, output = proc.run(command, timeout)
95
96 self.log("%s" % output)
97 self.log("[Command returned '%d' after %.2f seconds]" % (status, time.time() - proc.starttime))
98
99 if status and not ignore_status:
100 raise AssertionError("Command '%s' returned non-zero exit status %d:\n%s" % (command, status, output))
101
102 return (status, output)
103
104 def run(self, command, timeout=None):
105 """
106 command - ssh command to run
107 timeout=<val> - kill command if there is no output after <val> seconds
108 timeout=None - kill command if there is no output after a default value seconds
109 timeout=0 - no timeout, let command run until it returns
110 """
111
112 # We need to source /etc/profile for a proper PATH on the target
113 command = self.ssh + [self.ip, ' . /etc/profile; ' + command]
114
115 if timeout is None:
116 return self._internal_run(command, self.defaulttimeout, self.ignore_status)
117 if timeout == 0:
118 return self._internal_run(command, None, self.ignore_status)
119 return self._internal_run(command, timeout, self.ignore_status)
120
121 def copy_to(self, localpath, remotepath):
122 command = self.scp + [localpath, '%s@%s:%s' % (self.user, self.ip, remotepath)]
123 return self._internal_run(command, ignore_status=False)
124
125 def copy_from(self, remotepath, localpath):
126 command = self.scp + ['%s@%s:%s' % (self.user, self.ip, remotepath), localpath]
127 return self._internal_run(command, ignore_status=False)