open up traffic to qemu nodes + miscell
[tests.git] / system / TestSsh.py
1 #
2 # Thierry Parmentelat - INRIA
3 #
4 # class for issuing commands on a box, either local or remote
5 #
6 # the notion of 'buildname' is for providing each test run with a dir of its own
7 # buildname is generally the name of the build being tested, and can be considered unique
8 #
9 # thus 'run_in_buildname' mostly :
10 # (*) either runs locally in . - as on a local node we are already in a dedicated directory
11 # (*) or makes sure that there's a remote dir called 'buildname' and runs in it
12 #
13 # also, the copy operations
14 # (*) either do nothing if ran locally
15 # (*) or copy a local file into the remote 'buildname' 
16
17
18 import os.path
19 import utils
20
21 class TestSsh:
22     
23     # inserts a backslash before each occurence of the following chars
24     # \ " ' < > & | ; ( ) $ * ~ 
25     @staticmethod
26     def backslash_shell_specials (command):
27         result=''
28         for char in command:
29             if char in "\\\"'<>&|;()$*~":
30                 result +='\\'+char
31             else:
32                 result +=char
33         return result
34
35     # check main IP address against the provided hostname
36     @staticmethod
37     def is_local_hostname (hostname):
38         if hostname == "localhost":
39             return True
40         import socket
41         try:
42             local_ip = socket.gethostbyname(socket.gethostname())
43             remote_ip = socket.gethostbyname(hostname)
44             return local_ip==remote_ip
45         except:
46             utils.header("WARNING : something wrong in is_local_hostname with hostname=%s"%hostname)
47             return False
48
49     def __init__(self,hostname,buildname=None,key=None, username=None):
50         self.hostname=hostname
51         self.buildname=buildname
52         self.key=key
53         self.username=username
54
55     def is_local(self):
56         return TestSsh.is_local_hostname(self.hostname)
57      
58     std_options="-o StrictHostKeyChecking=no -o BatchMode=yes "
59     
60     def key_part (self):
61         if not self.key:
62             return ""
63         return "-i %s "%self.key
64
65     def hostname_part (self):
66         if not self.username:
67             return self.hostname
68         else:
69             return "%s@%s"%(self.username,self.hostname)
70     
71     # command gets run on the right box
72     def actual_command (self, command):
73         if self.is_local():
74             return command
75         ssh_command = "ssh "
76         ssh_command += TestSsh.std_options
77         ssh_command += self.key_part()
78         ssh_command += "%s %s" %(self.hostname_part(),TestSsh.backslash_shell_specials(command))
79         return ssh_command
80
81     def run(self, command,background=False):
82         local_command = self.actual_command(command)
83         return utils.system(local_command,background)
84
85     def clean_dir (self,dirname):
86         if self.is_local():
87             return 0
88         return self.run("rm -rf %s"%dirname)
89
90     def mkdir (self,dirname=None):
91         if self.is_local():
92             if dirname:
93                 return os.path.mkdir(dirname)
94             return 0
95         if dirname:
96             dirname="%s/%s"%(self.buildname,dirname)
97         else:
98             dirname=self.buildname
99         return self.run("mkdir -p %s"%dirname)
100
101     def create_buildname_once (self):
102         if self.is_local():
103             return
104         # create remote buildname on demand
105         try:
106             self.buildname_created
107         except:
108             self.mkdir()
109             self.buildname_created=True
110
111     def run_in_buildname (self,command, background=False):
112         if self.is_local():
113             return utils.system(command,background)
114         self.create_buildname_once()
115         return self.run("cd %s ; %s"%(self.buildname,command),background)
116
117     def copy (self,local_file,recursive=False):
118         if self.is_local():
119             return 0
120         self.create_buildname_once()
121         scp_command="scp "
122         scp_command += TestSsh.std_options
123         if recursive: scp_command += "-r "
124         scp_command += self.key_part()
125         scp_command += "%s %s:%s/%s"%(local_file,self.hostname_part(),
126                                       self.buildname,os.path.basename(local_file) or ".")
127         return utils.system(scp_command)
128
129     def fetch (self, remote_file, local_file, recursive=False):
130         if self.is_local():
131             command="cp "
132             if recursive: command += "-r "
133             command += "%s %s"%(remote_file,local_file)
134         else:
135             command="scp "
136             command += TestSsh.std_options
137             if recursive: command += "-r "
138             command += self.key_part()
139             command += "%s:%s/%s %s"%(self.hostname_part(),self.buildname,remote_file,local_file)
140         utils.system(command)
141
142     # this is only to avoid harmless message when host cannot be identified
143     # convenience only
144     # the only place where this is needed is when tring to reach a slice in a node,
145     # which is done from the test master box
146     def clear_known_hosts (self):
147         known_hosts = "%s/.ssh/known_hosts"%os.getenv("HOME")
148         utils.header("Clearing entry for %s in %s"%(self.hostname,known_hosts))
149         utils.system("sed -i -e /^%s/d %s"%(self.hostname,known_hosts))
150