the way tests was pushing the build to the vplc box was wrong, we were getting build...
[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 import shutil
21
22 class TestSsh:
23     
24     # inserts a backslash before each occurence of the following chars
25     # \ " ' < > & | ; ( ) $ * ~ 
26     @staticmethod
27     def backslash_shell_specials (command):
28         result=''
29         for char in command:
30             if char in "\\\"'<>&|;()$*~":
31                 result +='\\'+char
32             else:
33                 result +=char
34         return result
35
36     # check main IP address against the provided hostname
37     @staticmethod
38     def is_local_hostname (hostname):
39         if hostname == "localhost":
40             return True
41         import socket
42         try:
43             local_ip = socket.gethostbyname(socket.gethostname())
44             remote_ip = socket.gethostbyname(hostname)
45             return local_ip==remote_ip
46         except:
47             utils.header("WARNING : something wrong in is_local_hostname with hostname=%s"%hostname)
48             return False
49
50     def __init__(self,hostname,buildname=None,key=None, username=None):
51         self.hostname=hostname
52         self.buildname=buildname
53         self.key=key
54         self.username=username
55
56     def is_local(self):
57         return TestSsh.is_local_hostname(self.hostname)
58      
59     std_options="-o BatchMode=yes -o StrictHostKeyChecking=no -o CheckHostIP=no -o ConnectTimeout=5 -o UserKnownHostsFile=/dev/null "
60     
61     def key_part (self):
62         if not self.key:
63             return ""
64         return "-i %s "%self.key
65
66     def hostname_part (self):
67         if not self.username:
68             return self.hostname
69         else:
70             return "%s@%s"%(self.username,self.hostname)
71     
72     # command gets run on the right box
73     def actual_command (self, command,keep_stdin=False):
74         if self.is_local():
75             return command
76         ssh_command = "ssh "
77         if not keep_stdin:
78             ssh_command += "-n "
79         ssh_command += TestSsh.std_options
80         ssh_command += self.key_part()
81         ssh_command += "%s %s" %(self.hostname_part(),TestSsh.backslash_shell_specials(command))
82         return ssh_command
83
84     def run(self, command,background=False):
85         local_command = self.actual_command(command)
86         return utils.system(local_command,background)
87
88     def clean_dir (self,dirname):
89         if self.is_local():
90             return 0
91         return self.run("rm -rf %s"%dirname)
92
93     def mkdir (self,dirname=None):
94         if self.is_local():
95             if dirname:
96                 return os.path.mkdir(dirname)
97             return 0
98         if dirname:
99             dirname="%s/%s"%(self.buildname,dirname)
100         else:
101             dirname=self.buildname
102         return self.run("mkdir -p %s"%dirname)
103
104     def rmdir (self,dirname=None):
105         if self.is_local():
106             if dirname:
107                 return shutil.rmtree(dirname)
108             return 0
109         if dirname:
110             dirname="%s/%s"%(self.buildname,dirname)
111         else:
112             dirname=self.buildname
113         return self.run("rm -rf %s"%dirname)
114
115     def create_buildname_once (self):
116         if self.is_local():
117             return
118         # create remote buildname on demand
119         try:
120             self.buildname_created
121         except:
122             self.mkdir()
123             self.buildname_created=True
124
125     def run_in_buildname (self,command, background=False):
126         if self.is_local():
127             return utils.system(command,background)
128         self.create_buildname_once()
129         return self.run("cd %s ; %s"%(self.buildname,command),background)
130
131     def copy (self,local_file,recursive=False):
132         if self.is_local():
133             return 0
134         self.create_buildname_once()
135         scp_command="scp "
136         scp_command += TestSsh.std_options
137         if recursive: scp_command += "-r "
138         scp_command += self.key_part()
139         scp_command += "%s %s:%s/%s"%(local_file,self.hostname_part(),
140                                       self.buildname,os.path.basename(local_file) or ".")
141         return utils.system(scp_command)
142
143     def copy_abs (self,local_file,remote_file,recursive=False):
144         if self.is_local():
145             dest=""
146         else:
147             dest= "%s:"%self.hostname_part()
148         scp_command="scp "
149         scp_command += TestSsh.std_options
150         if recursive: scp_command += "-r "
151         scp_command += self.key_part()
152         scp_command += "%s %s%s"%(local_file,dest,remote_file)
153         return utils.system(scp_command)
154
155     def copy_home (self, local_file, recursive=False):
156         return self.copy_abs(local_file,os.path.basename(local_file),recursive)
157
158     def fetch (self, remote_file, local_file, recursive=False):
159         if self.is_local():
160             command="cp "
161             if recursive: command += "-r "
162             command += "%s %s"%(remote_file,local_file)
163         else:
164             command="scp "
165             command += TestSsh.std_options
166             if recursive: command += "-r "
167             command += self.key_part()
168             # absolute path - do not preprend buildname
169             if remote_file.find("/")==0:
170                 remote_path=remote_file
171             else:
172                 remote_path="%s/%s"%(self.buildname,remote_file)
173             command += "%s:%s %s"%(self.hostname_part(),remote_path,local_file)
174         return utils.system(command)
175
176     # this is only to avoid harmless message when host cannot be identified
177     # convenience only
178     # the only place where this is needed is when tring to reach a slice in a node,
179     # which is done from the test master box
180     def clear_known_hosts (self):
181         known_hosts = "%s/.ssh/known_hosts"%os.getenv("HOME")
182         utils.header("Clearing entry for %s in %s"%(self.hostname,known_hosts))
183         return utils.system("sed -i -e /^%s/d %s"%(self.hostname,known_hosts))
184