sshconnection.py 9.91 KB
Newer Older
Raphael Defosseux's avatar
Raphael Defosseux committed
1
#/*
Gabriele Perrone's avatar
Gabriele Perrone committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements.  See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1  (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# *      http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# *      contact@openairinterface.org
# */
#---------------------------------------------------------------------
# Python for CI of OAI-eNB + COTS-UE
#
#   Required Python Version
#     Python 3.x
#
#   Required Python Package
#     pexpect
#---------------------------------------------------------------------

31 32 33 34 35
#-----------------------------------------------------------
# Import
#-----------------------------------------------------------
import pexpect          # pexpect
import logging
Gabriele Perrone's avatar
Gabriele Perrone committed
36 37
import time             # sleep
import re
38
import subprocess
Raphael Defosseux's avatar
Raphael Defosseux committed
39
import sys
Raphael Defosseux's avatar
Raphael Defosseux committed
40

41 42 43 44 45
#-----------------------------------------------------------
# Class Declaration
#-----------------------------------------------------------
class SSHConnection():
	def __init__(self):
46
		self.ssh = ''
47
		self.picocom_closure = False
48 49 50
		self.ipaddress = ''
		self.username = ''
		self.cmd2Results = ''
51 52 53 54 55 56

	def disablePicocomClosure(self):
		self.picocom_closure = False

	def enablePicocomClosure(self):
		self.picocom_closure = True
57

58
	def open(self, ipaddress, username, password):
59
		prompt = "\$"
60 61 62
		count = 0
		connect_status = False
		while count < 4:
63
			self.ssh = pexpect.spawn('ssh -o PubkeyAuthentication=yes {}@{}'.format(username,ipaddress))
64 65
			# Longer timeout at connection due to asterix slowness
			self.ssh.timeout = 25
66 67 68
			self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT])
			if self.sshresponse == 0:
				self.ssh.sendline('yes')
69 70 71
				self.sshresponse = self.ssh.expect(['password:', username + '@'])
				if self.sshresponse == 0:
					self.ssh.sendline(password)
hardy's avatar
hardy committed
72
				self.sshresponse = self.ssh.expect([prompt, 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT])
73 74 75 76
				if self.sshresponse == 0:
					count = 10
					connect_status = True
				else:
77
					logging.warning('self.sshresponse = ' + str(self.sshresponse))
78 79
			elif self.sshresponse == 1:
				self.ssh.sendline(password)
hardy's avatar
hardy committed
80
				self.sshresponse = self.ssh.expect([prompt, 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT])
81 82 83 84
				if self.sshresponse == 0:
					count = 10
					connect_status = True
				else:
85
					logging.warning('self.sshresponse = ' + str(self.sshresponse))
86
			elif self.sshresponse == 2:
87 88 89 90 91
				# We directly ended up on the remote server because of pubkey auth
				count = 10
				connect_status = True
				# this expect() seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command
				self.sshresponse = self.ssh.expect([prompt])
92 93
			else:
				# debug output
94 95
				logging.warning(str(self.ssh.before))
				logging.warning('self.sshresponse = ' + str(self.sshresponse))
96 97 98 99 100
			# adding a tempo when failure
			if not connect_status:
				time.sleep(1)
			count += 1
		if connect_status:
hardy's avatar
hardy committed
101
			self.command('unset HISTFILE', prompt, 5, silent=True)
102
		else:
Gabriele Perrone's avatar
Gabriele Perrone committed
103
			sys.exit('SSH Connection Failed')
104 105
		self.ipaddress = ipaddress
		self.username = username
106

107 108 109 110



	def cde_check_value(self, commandline, expected, timeout):
111
		logging.info(commandline)
112 113 114 115 116 117 118
		self.ssh.timeout = timeout
		self.ssh.sendline(commandline)
		expected.append(pexpect.EOF)
		expected.append(pexpect.TIMEOUT)
		self.sshresponse = self.ssh.expect(expected)
		return self.sshresponse

119 120
	def command(self, commandline, expectedline, timeout, silent=False, resync=False):
		if not silent:
121
			logging.info(commandline)
122
		self.ssh.timeout = timeout
123 124
		# Nasty patch when pexpect output is out of sync.
		# Much pronounced when running back-to-back-back oc commands
125
		if resync:
126 127 128 129 130 131 132
			self.ssh.send(commandline)
			self.ssh.expect([commandline, pexpect.TIMEOUT])
			self.ssh.send('\r\n')
			self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT])
		else:
			self.ssh.sendline(commandline)
			self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT])
133 134 135
		if self.sshresponse == 0:
			return 0
		elif self.sshresponse == 1:
136 137 138
			logging.error('\u001B[1;37;41m Unexpected EOF \u001B[0m')
			logging.error('Expected Line : ' + expectedline)
			logging.error(str(self.ssh.before))
Gabriele Perrone's avatar
Gabriele Perrone committed
139
			sys.exit(self.sshresponse)
140
		elif self.sshresponse == 2:
141 142
			logging.error('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m')
			logging.error('Expected Line : ' + expectedline)
143 144
			result = re.search('ping |iperf |picocom', str(commandline))
			if result is None:
145
				logging.warning(str(self.ssh.before))
146 147 148 149
				sys.exit(self.sshresponse)
			else:
				return -1
		else:
150 151
			logging.error('\u001B[1;37;41m Unexpected Others \u001B[0m')
			logging.error('Expected Line : ' + expectedline)
152 153
			sys.exit(self.sshresponse)

154 155
	def command2(self, commandline, timeout, silent=False):
		if not silent:
156
			logging.info(commandline)
157
		self.cmd2Results = ''
158
		noHistoryCmd = 'unset HISTFILE; ' + commandline
159 160 161 162
		myHost = self.username + '@' + self.ipaddress
		# CAUTION: THIS METHOD IMPLIES THAT THERE ARE VALID SSH KEYS
		# BETWEEN THE PYTHON EXECUTOR NODE AND THE REMOTE HOST
		# OTHERWISE IT WON'T WORK
163
		lSsh = subprocess.Popen(["ssh", "%s" % myHost, noHistoryCmd],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
164 165
		self.cmd2Results = str(lSsh.stdout.readlines())

hardy's avatar
hardy committed
166 167
	def command3(self, commandline, timeout, silent=False):
		if not silent:
168
			logging.info(commandline)
hardy's avatar
hardy committed
169
		self.cmd2Results = ''
170
		noHistoryCmd = 'unset HISTFILE; ' + commandline
hardy's avatar
hardy committed
171 172 173 174
		myHost = self.username + '@' + self.ipaddress
		# CAUTION: THIS METHOD IMPLIES THAT THERE ARE VALID SSH KEYS
		# BETWEEN THE PYTHON EXECUTOR NODE AND THE REMOTE HOST
		# OTHERWISE IT WON'T WORK
175
		lSsh = subprocess.Popen(["ssh", "%s" % myHost, noHistoryCmd],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
hardy's avatar
hardy committed
176 177 178
		return lSsh.stdout.readlines()

		
179 180 181 182
	def close(self):
		self.ssh.timeout = 5
		self.ssh.sendline('exit')
		self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT])
183 184
		self.ipaddress = ''
		self.username = ''
185 186 187 188
		if self.sshresponse == 0:
			pass
		elif self.sshresponse == 1:
			if not self.picocom_closure:
189
				logging.warning('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m')
190
		else:
191
			logging.warning('\u001B[1;37;41m Unexpected Others during closing\u001B[0m')
192 193 194 195

	def copyin(self, ipaddress, username, password, source, destination):
		count = 0
		copy_status = False
196
		logging.info('scp -r '+ username + '@' + ipaddress + ':' + source + ' ' + destination)
197
		while count < 10:
198
			scp_spawn = pexpect.spawn('scp -r '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100)
199 200 201 202 203 204 205 206 207 208
			scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT])
			if scp_response == 0:
				scp_spawn.sendline('yes')
				scp_spawn.expect('password:')
				scp_spawn.sendline(password)
				scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT])
				if scp_response == 0:
					count = 10
					copy_status = True
				else:
209
					logging.warning('1 - scp_response = ' + str(scp_response))
210 211 212 213 214 215 216
			elif scp_response == 1:
				scp_spawn.sendline(password)
				scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT])
				if scp_response == 0 or scp_response == 3:
					count = 10
					copy_status = True
				else:
217
					logging.warning('2 - scp_response = ' + str(scp_response))
218 219 220 221
			elif scp_response == 2:
				count = 10
				copy_status = True
			else:
222
				logging.warning('3 - scp_response = ' + str(scp_response))
223 224 225 226 227 228 229 230 231
			# adding a tempo when failure
			if not copy_status:
				time.sleep(1)
			count += 1
		if copy_status:
			return 0
		else:
			return -1

232
	def copyout(self, ipaddress, username, password, source, destination, silent=False):
233 234
		count = 0
		copy_status = False
235 236
		if not silent:
			logging.info('scp -r ' + source + ' ' + username + '@' + ipaddress + ':' + destination)
237
		while count < 4:
238
			scp_spawn = pexpect.spawn('scp -r ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100)
239 240 241 242 243 244 245 246 247 248
			scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT])
			if scp_response == 0:
				scp_spawn.sendline('yes')
				scp_spawn.expect('password:')
				scp_spawn.sendline(password)
				scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT])
				if scp_response == 0:
					count = 10
					copy_status = True
				else:
249
					logging.warning('1 - scp_response = ' + str(scp_response))
250 251 252 253 254 255 256
			elif scp_response == 1:
				scp_spawn.sendline(password)
				scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT])
				if scp_response == 0 or scp_response == 3:
					count = 10
					copy_status = True
				else:
257
					logging.warning('2 - scp_response = ' + str(scp_response))
258 259 260 261
			elif scp_response == 2:
				count = 10
				copy_status = True
			else:
262
				logging.warning('3 - scp_response = ' + str(scp_response))
263 264 265 266 267 268 269 270 271
			# adding a tempo when failure
			if not copy_status:
				time.sleep(1)
			count += 1
		if copy_status:
			pass
		else:
			sys.exit('SCP failed')

272
	def getBefore(self):
Robert Schmidt's avatar
Robert Schmidt committed
273
		return self.ssh.before.decode('utf-8')