1 # Thierry Parmentelat <thierry.parmentelat@inria.fr>
2 # Copyright (C) 2010 INRIA
4 # class for issuing commands on a box, either local or remote
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
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
13 # also, the copy operations
14 # (*) either do nothing if ran locally
15 # (*) or copy a local file into the remote 'buildname'
24 # inserts a backslash before each occurence of the following chars
25 # \ " ' < > & | ; ( ) $ * ~
27 def backslash_shell_specials (command):
30 if char in "\\\"'<>&|;()$*~":
36 # check main IP address against the provided hostname
38 def is_local_hostname (hostname):
39 if hostname == "localhost":
43 local_ip = socket.gethostbyname(socket.gethostname())
44 remote_ip = socket.gethostbyname(hostname)
45 return local_ip==remote_ip
47 utils.header("WARNING : something wrong in is_local_hostname with hostname=%s"%hostname)
50 def __init__(self,hostname,buildname=None,key=None, username=None):
51 self.hostname=hostname
52 self.buildname=buildname
54 self.username=username
57 return TestSsh.is_local_hostname(self.hostname)
59 std_options="-o BatchMode=yes -o StrictHostKeyChecking=no -o CheckHostIP=no -o ConnectTimeout=5 -o UserKnownHostsFile=/dev/null "
64 return "-i %s "%self.key
66 def hostname_part (self):
70 return "%s@%s"%(self.username,self.hostname)
72 # command gets run on the right box
73 def actual_command (self, command,keep_stdin=False):
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))
84 def run(self, command,background=False):
85 local_command = self.actual_command(command)
86 return utils.system(local_command,background)
88 def clean_dir (self,dirname):
91 return self.run("rm -rf %s"%dirname)
93 def mkdir (self,dirname=None):
96 return os.path.mkdir(dirname)
99 dirname="%s/%s"%(self.buildname,dirname)
101 dirname=self.buildname
102 return self.run("mkdir -p %s"%dirname)
104 def rmdir (self,dirname=None):
107 return shutil.rmtree(dirname)
110 dirname="%s/%s"%(self.buildname,dirname)
112 dirname=self.buildname
113 return self.run("rm -rf %s"%dirname)
115 def create_buildname_once (self):
118 # create remote buildname on demand
120 self.buildname_created
123 self.buildname_created=True
125 def run_in_buildname (self,command, background=False):
127 return utils.system(command,background)
128 self.create_buildname_once()
129 return self.run("cd %s ; %s"%(self.buildname,command),background)
131 def copy (self,local_file,recursive=False):
134 self.create_buildname_once()
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)
143 def copy_abs (self,local_file,remote_file,recursive=False):
147 dest= "%s:"%self.hostname_part()
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)
155 def copy_home (self, local_file, recursive=False):
156 return self.copy_abs(local_file,os.path.basename(local_file),recursive)
158 def fetch (self, remote_file, local_file, recursive=False):
161 if recursive: command += "-r "
162 command += "%s %s"%(remote_file,local_file)
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
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)
176 # this is only to avoid harmless message when host cannot be identified
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))