From 04adce6b15cf2eb0349cf0ebfdee3031388a89d0 Mon Sep 17 00:00:00 2001
From: Raphael Defosseux <raphael.defosseux@eurecom.fr>
Date: Mon, 10 May 2021 14:04:51 +0200
Subject: [PATCH] CI: some cosmetics changes and better handling physim cluster
 deployment errors

Signed-off-by: Raphael Defosseux <raphael.defosseux@eurecom.fr>
---
 ci-scripts/cls_containerize.py                |   4 +-
 ci-scripts/cls_oaicitest.py                   |   4 +-
 ci-scripts/cls_physim.py                      | 382 +++++++++---------
 ci-scripts/cls_physim1.py                     |  76 +++-
 ci-scripts/cls_static_code_analysis.py        |   4 +-
 ci-scripts/constants.py                       |   5 +
 ci-scripts/html.py                            |  10 +
 ci-scripts/main.py                            |   2 +-
 ci-scripts/ran.py                             |   4 +-
 .../xml_files/container_image_build.xml       |   1 +
 10 files changed, 275 insertions(+), 217 deletions(-)

diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py
index 2c8a2cd339..dff0838d49 100644
--- a/ci-scripts/cls_containerize.py
+++ b/ci-scripts/cls_containerize.py
@@ -162,7 +162,7 @@ class Containerize():
 		# on RedHat/CentOS .git extension is mandatory
 		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
 		if result is not None:
-			full_ran_repo_name = self.ranRepository
+			full_ran_repo_name = self.ranRepository.replace('git/', 'git')
 		else:
 			full_ran_repo_name = self.ranRepository + '.git'
 		mySSH.command('mkdir -p ' + lSourcePath, '\$', 5)
@@ -176,7 +176,7 @@ class Containerize():
 		mySSH.command('mkdir -p cmake_targets/log', '\$', 5)
 		# if the commit ID is provided use it to point to it
 		if self.ranCommitID != '':
-			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
+			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 30)
 		# if the branch is not develop, then it is a merge request and we need to do 
 		# the potential merge. Note that merge conflicts should already been checked earlier
 		imageTag = 'develop'
diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py
index 7b75cf82c5..5c882618e4 100644
--- a/ci-scripts/cls_oaicitest.py
+++ b/ci-scripts/cls_oaicitest.py
@@ -177,7 +177,7 @@ class OaiCiTest():
 			ue_prefix = ''
 		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
 		if result is not None:
-			full_ran_repo_name = self.ranRepository
+			full_ran_repo_name = self.ranRepository.replace('git/', 'git')
 		else:
 			full_ran_repo_name = self.ranRepository + '.git'
 		SSH.command('mkdir -p ' + self.UESourceCodePath, '\$', 5)
@@ -220,7 +220,7 @@ class OaiCiTest():
 
 		# if the commit ID is provided use it to point to it
 		if self.ranCommitID != '':
-			SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
+			SSH.command('git checkout -f ' + self.ranCommitID, '\$', 30)
 		# if the branch is not develop, then it is a merge request and we need to do 
 		# the potential merge. Note that merge conflicts should already been checked earlier
 		if self.ranAllowMerge:
diff --git a/ci-scripts/cls_physim.py b/ci-scripts/cls_physim.py
index 4ca36b8cf0..e825b2f7bd 100644
--- a/ci-scripts/cls_physim.py
+++ b/ci-scripts/cls_physim.py
@@ -1,191 +1,191 @@
-# * 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
-#---------------------------------------------------------------------
-
-#to use logging.info()
-import logging
-#to create a SSH object locally in the methods
-import sshconnection
-#to update the HTML object
-import html
-from multiprocessing import SimpleQueue
-#for log folder maintenance
-import os
-
-class PhySim:
-	def __init__(self):
-		self.buildargs = ""
-		self.runargs = ""
-		self.eNBIpAddr = ""
-		self.eNBUserName = ""
-		self.eNBPassWord = ""
-		self.eNBSourceCodePath = ""
-		self.ranRepository = ""
-		self.ranBranch = ""
-		self.ranCommitID= ""
-		self.ranAllowMerge= ""
-		self.ranTargetBranch= ""
-		self.exitStatus=0
-		self.forced_workspace_cleanup=False
-		#private attributes
-		self.__workSpacePath=''
-		self.__buildLogFile='compile_phy_sim.log'
-		self.__runLogFile=''
-		self.__runResults=[]
-		self.__runLogPath='phy_sim_logs'
-
-
-#-----------------
-#PRIVATE Methods
-#-----------------
-
-	def __CheckResults_PhySim(self,HTML,CONST,testcase_id):
-		mySSH = sshconnection.SSHConnection()
-		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
-		#retrieve run log file and store it locally$
-		mySSH.copyin(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord, self.__workSpacePath+self.__runLogFile, '.')
-		mySSH.close()
-		#parse results looking for Encoding and Decoding mean values
-		self.__runResults=[]
-		with open(self.__runLogFile) as f:
-			for line in f:
-				if 'mean' in line:
-					self.__runResults.append(line)
-		#the values are appended for each mean value (2), so we take these 2 values from the list
-		info=self.__runResults[0]+self.__runResults[1]
-
-		#once parsed move the local logfile to its folder for tidiness
-		os.system('mv '+self.__runLogFile+' '+ self.__runLogPath+'/.')
-
-		#updating the HTML with results
-		html_cell = '<pre style="background-color:white">' + info  + '</pre>'
-		html_queue=SimpleQueue()
-		html_queue.put(html_cell)
-		HTML.CreateHtmlTestRowQueue(self.runargs, 'OK', 1, html_queue)
-		return HTML
-
-
-	def __CheckBuild_PhySim(self, HTML, CONST):
-		self.__workSpacePath=self.eNBSourceCodePath+'/cmake_targets/'
-		mySSH = sshconnection.SSHConnection()
-		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
-		#retrieve compile log file and store it locally
-		mySSH.copyin(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord, self.__workSpacePath+self.__buildLogFile, '.')
-		#delete older run log file
-		mySSH.command('rm ' + self.__workSpacePath+self.__runLogFile, '\$', 5)
-		mySSH.close()
-		#check build result from local compile log file
-		buildStatus=False
-		with open(self.__buildLogFile) as f:
-		#nr_prachsim is the last compile step
-			if 'nr_prachsim compiled' in f.read():
-				buildStatus=True
-		#update HTML based on build status
-		if buildStatus:
-			HTML.CreateHtmlTestRow(self.buildargs, 'OK', CONST.ALL_PROCESSES_OK, 'LDPC')
-			self.exitStatus=0
-		else:
-			logging.error('\u001B[1m Building Physical Simulators Failed\u001B[0m')
-			HTML.CreateHtmlTestRow(self.buildargs, 'KO', CONST.ALL_PROCESSES_OK, 'LDPC')
-			HTML.CreateHtmlTabFooter(False)
-			#exitStatus=1 will do a sys.exit in main
-			self.exitStatus=1
-		return HTML
-
-
-#-----------------$
-#PUBLIC Methods$
-#-----------------$
-
-	def Build_PhySim(self,htmlObj,constObj):
-		mySSH = sshconnection.SSHConnection()    
-		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
-
-		#create working dir    
-		mySSH.command('mkdir -p ' + self.eNBSourceCodePath, '\$', 5)
-		mySSH.command('cd ' + self.eNBSourceCodePath, '\$', 5)
-
-		if not self.ranRepository.lower().endswith('.git'):
-			self.ranRepository+='.git'
-
-		#git clone
-		mySSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone '  + self.ranRepository + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600)
-		#git config 
-		mySSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5)
-		mySSH.command('git config user.name "OAI Jenkins"', '\$', 5) 
-
-		#git clean depending on self.forced_workspace_cleanup captured in xml
-		if self.forced_workspace_cleanup==True:
-			logging.info('Cleaning workspace ...')
-			mySSH.command('echo ' + self.eNBPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30)
-		else:
-			logging.info('Workspace cleaning was disabled')
-
-		# if the commit ID is provided, use it to point to it
-		if self.ranCommitID != '':
-			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
-		# if the branch is not develop, then it is a merge request and we need to do 
-		# the potential merge. Note that merge conflicts should have already been checked earlier
-		if (self.ranAllowMerge):
-			if self.ranTargetBranch == '':
-				if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'):
-					mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5)
-			else:
-				logging.info('Merging with the target branch: ' + self.ranTargetBranch)
-				mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5)
-
-		#build
-		mySSH.command('source oaienv', '\$', 5)
-		mySSH.command('cd cmake_targets', '\$', 5)
-		mySSH.command('mkdir -p log', '\$', 5)
-		mySSH.command('chmod 777 log', '\$', 5)
-		mySSH.command('stdbuf -o0 ./build_oai ' + self.buildargs + ' 2>&1 | stdbuf -o0 tee ' + self.__buildLogFile, 'Bypassing the Tests|build have failed', 1500) 
-
-		mySSH.close()
-		#check build status and update HTML object
-		lHTML = html.HTMLManagement()
-		lHTML=self.__CheckBuild_PhySim(htmlObj,constObj)
-		return lHTML
-
-
-	def Run_PhySim(self,htmlObj,constObj,testcase_id):
-		#create run logs folder locally
-		os.system('mkdir -p ./'+self.__runLogPath)
-		#log file is tc_<testcase_id>.log remotely
-		self.__runLogFile='physim_'+str(testcase_id)+'.log'
-		#open a session for test run
-		mySSH = sshconnection.SSHConnection()
-		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
-		mySSH.command('cd '+self.__workSpacePath,'\$',5)
-		#run and redirect the results to a log file
-		mySSH.command(self.__workSpacePath+'phy_simulators/build/ldpctest ' + self.runargs + ' >> '+self.__runLogFile, '\$', 30)   
-		mySSH.close()
-		#return updated HTML to main
-		lHTML = html.HTMLManagement()
-		lHTML=self.__CheckResults_PhySim(htmlObj,constObj,testcase_id)
-		return lHTML
+# * 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
+#---------------------------------------------------------------------
+
+#to use logging.info()
+import logging
+#to create a SSH object locally in the methods
+import sshconnection
+#to update the HTML object
+import html
+from multiprocessing import SimpleQueue
+#for log folder maintenance
+import os
+
+class PhySim:
+	def __init__(self):
+		self.buildargs = ""
+		self.runargs = ""
+		self.eNBIpAddr = ""
+		self.eNBUserName = ""
+		self.eNBPassWord = ""
+		self.eNBSourceCodePath = ""
+		self.ranRepository = ""
+		self.ranBranch = ""
+		self.ranCommitID= ""
+		self.ranAllowMerge= ""
+		self.ranTargetBranch= ""
+		self.exitStatus=0
+		self.forced_workspace_cleanup=False
+		#private attributes
+		self.__workSpacePath=''
+		self.__buildLogFile='compile_phy_sim.log'
+		self.__runLogFile=''
+		self.__runResults=[]
+		self.__runLogPath='phy_sim_logs'
+
+
+#-----------------
+#PRIVATE Methods
+#-----------------
+
+	def __CheckResults_PhySim(self,HTML,CONST,testcase_id):
+		mySSH = sshconnection.SSHConnection()
+		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
+		#retrieve run log file and store it locally$
+		mySSH.copyin(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord, self.__workSpacePath+self.__runLogFile, '.')
+		mySSH.close()
+		#parse results looking for Encoding and Decoding mean values
+		self.__runResults=[]
+		with open(self.__runLogFile) as f:
+			for line in f:
+				if 'mean' in line:
+					self.__runResults.append(line)
+		#the values are appended for each mean value (2), so we take these 2 values from the list
+		info=self.__runResults[0]+self.__runResults[1]
+
+		#once parsed move the local logfile to its folder for tidiness
+		os.system('mv '+self.__runLogFile+' '+ self.__runLogPath+'/.')
+
+		#updating the HTML with results
+		html_cell = '<pre style="background-color:white">' + info  + '</pre>'
+		html_queue=SimpleQueue()
+		html_queue.put(html_cell)
+		HTML.CreateHtmlTestRowQueue(self.runargs, 'OK', 1, html_queue)
+		return HTML
+
+
+	def __CheckBuild_PhySim(self, HTML, CONST):
+		self.__workSpacePath=self.eNBSourceCodePath+'/cmake_targets/'
+		mySSH = sshconnection.SSHConnection()
+		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
+		#retrieve compile log file and store it locally
+		mySSH.copyin(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord, self.__workSpacePath+self.__buildLogFile, '.')
+		#delete older run log file
+		mySSH.command('rm ' + self.__workSpacePath+self.__runLogFile, '\$', 5)
+		mySSH.close()
+		#check build result from local compile log file
+		buildStatus=False
+		with open(self.__buildLogFile) as f:
+		#nr_prachsim is the last compile step
+			if 'nr_prachsim compiled' in f.read():
+				buildStatus=True
+		#update HTML based on build status
+		if buildStatus:
+			HTML.CreateHtmlTestRow(self.buildargs, 'OK', CONST.ALL_PROCESSES_OK, 'LDPC')
+			self.exitStatus=0
+		else:
+			logging.error('\u001B[1m Building Physical Simulators Failed\u001B[0m')
+			HTML.CreateHtmlTestRow(self.buildargs, 'KO', CONST.ALL_PROCESSES_OK, 'LDPC')
+			HTML.CreateHtmlTabFooter(False)
+			#exitStatus=1 will do a sys.exit in main
+			self.exitStatus=1
+		return HTML
+
+
+#-----------------$
+#PUBLIC Methods$
+#-----------------$
+
+	def Build_PhySim(self,htmlObj,constObj):
+		mySSH = sshconnection.SSHConnection()
+		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
+
+		#create working dir
+		mySSH.command('mkdir -p ' + self.eNBSourceCodePath, '\$', 5)
+		mySSH.command('cd ' + self.eNBSourceCodePath, '\$', 5)
+
+		if not self.ranRepository.lower().endswith('.git'):
+			self.ranRepository+='.git'
+
+		#git clone
+		mySSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone '  + self.ranRepository + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600)
+		#git config
+		mySSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5)
+		mySSH.command('git config user.name "OAI Jenkins"', '\$', 5)
+
+		#git clean depending on self.forced_workspace_cleanup captured in xml
+		if self.forced_workspace_cleanup==True:
+			logging.info('Cleaning workspace ...')
+			mySSH.command('echo ' + self.eNBPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30)
+		else:
+			logging.info('Workspace cleaning was disabled')
+
+		# if the commit ID is provided, use it to point to it
+		if self.ranCommitID != '':
+			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 30)
+		# if the branch is not develop, then it is a merge request and we need to do
+		# the potential merge. Note that merge conflicts should have already been checked earlier
+		if (self.ranAllowMerge):
+			if self.ranTargetBranch == '':
+				if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'):
+					mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5)
+			else:
+				logging.info('Merging with the target branch: ' + self.ranTargetBranch)
+				mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5)
+
+		#build
+		mySSH.command('source oaienv', '\$', 5)
+		mySSH.command('cd cmake_targets', '\$', 5)
+		mySSH.command('mkdir -p log', '\$', 5)
+		mySSH.command('chmod 777 log', '\$', 5)
+		mySSH.command('stdbuf -o0 ./build_oai ' + self.buildargs + ' 2>&1 | stdbuf -o0 tee ' + self.__buildLogFile, 'Bypassing the Tests|build have failed', 1500)
+
+		mySSH.close()
+		#check build status and update HTML object
+		lHTML = html.HTMLManagement()
+		lHTML=self.__CheckBuild_PhySim(htmlObj,constObj)
+		return lHTML
+
+
+	def Run_PhySim(self,htmlObj,constObj,testcase_id):
+		#create run logs folder locally
+		os.system('mkdir -p ./'+self.__runLogPath)
+		#log file is tc_<testcase_id>.log remotely
+		self.__runLogFile='physim_'+str(testcase_id)+'.log'
+		#open a session for test run
+		mySSH = sshconnection.SSHConnection()
+		mySSH.open(self.eNBIpAddr, self.eNBUserName, self.eNBPassWord)
+		mySSH.command('cd '+self.__workSpacePath,'\$',5)
+		#run and redirect the results to a log file
+		mySSH.command(self.__workSpacePath+'phy_simulators/build/ldpctest ' + self.runargs + ' >> '+self.__runLogFile, '\$', 30)
+		mySSH.close()
+		#return updated HTML to main
+		lHTML = html.HTMLManagement()
+		lHTML=self.__CheckResults_PhySim(htmlObj,constObj,testcase_id)
+		return lHTML
diff --git a/ci-scripts/cls_physim1.py b/ci-scripts/cls_physim1.py
index 86150a1470..1c82526831 100644
--- a/ci-scripts/cls_physim1.py
+++ b/ci-scripts/cls_physim1.py
@@ -64,7 +64,7 @@ class PhySim:
 #PUBLIC Methods$
 #-----------------$
 
-	def Deploy_PhySim(self, HTML):
+	def Deploy_PhySim(self, HTML, RAN):
 		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
@@ -88,9 +88,10 @@ class PhySim:
 		# on RedHat/CentOS .git extension is mandatory
 		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
 		if result is not None:
-			full_ran_repo_name = self.ranRepository
+			full_ran_repo_name = self.ranRepository.replace('git/', 'git')
 		else:
 			full_ran_repo_name = self.ranRepository + '.git'
+		mySSH.command('echo ' + lPassWord + ' | sudo rm -Rf ' + lSourcePath, '\$', 30)
 		mySSH.command('mkdir -p ' + lSourcePath, '\$', 5)
 		mySSH.command('cd ' + lSourcePath, '\$', 5)
 		mySSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600)
@@ -102,9 +103,15 @@ class PhySim:
 		mySSH.command('mkdir -p cmake_targets/log', '\$', 5)
 		# if the commit ID is provided use it to point to it
 		if self.ranCommitID != '':
-			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
+			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 30)
 		if self.ranAllowMerge:
 			imageTag = "ci-temp"
+			if self.ranTargetBranch == '':
+				if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'):
+					mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5)
+			else:
+				logging.debug('Merging with the target branch: ' + self.ranTargetBranch)
+				mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5)
 		else:
 			imageTag = "develop"
 		# Check if image is exist on the Red Hat server, before pushing it to OC cluster
@@ -112,7 +119,9 @@ class PhySim:
 		if mySSH.getBefore().count('no such image') != 0:
 			logging.error('\u001B[1m No such image oai-physim\u001B[0m')
 			mySSH.close()
-			sys.exit(-1)
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.PHYSIM_IMAGE_ABSENT)
+			RAN.prematureExit = True
+			return
 		else:
 			result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', mySSH.getBefore())
 			if result is not None:
@@ -135,14 +144,18 @@ class PhySim:
 		if mySSH.getBefore().count('Login successful.') == 0:
 			logging.error('\u001B[1m OC Cluster Login Failed\u001B[0m')
 			mySSH.close()
-			sys.exit(-1)
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_LOGIN_FAIL)
+			RAN.prematureExit = True
+			return
 		else:
 			logging.debug('\u001B[1m   Login to OC Cluster Successfully\u001B[0m')
 		mySSH.command(f'oc project {ocProjectName}', '\$', 6)
 		if mySSH.getBefore().count(f'Already on project "{ocProjectName}"') == 0 and mySSH.getBefore().count(f'Now using project "{self.OCProjectName}"') == 0:
 			logging.error(f'\u001B[1m Unable to access OC project {ocProjectName}\u001B[0m')
 			mySSH.close()
-			sys.exit(-1)
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_PROJECT_FAIL)
+			RAN.prematureExit = True
+			return
 		else:
 			logging.debug(f'\u001B[1m   Now using project {ocProjectName}\u001B[0m')
 
@@ -151,7 +164,9 @@ class PhySim:
 		if mySSH.getBefore().count('Login Succeeded!') == 0:
 			logging.error('\u001B[1m Podman Login to OC Cluster Registry Failed\u001B[0m')
 			mySSH.close()
-			sys.exit(-1)
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_LOGIN_FAIL)
+			RAN.prematureExit = True
+			return
 		else:
 			logging.debug('\u001B[1m Podman Login to OC Cluster Registry Successfully\u001B[0m')
 		time.sleep(2)
@@ -159,7 +174,9 @@ class PhySim:
 		if mySSH.getBefore().count('(AlreadyExists):') == 0 and mySSH.getBefore().count('created') == 0:
 			logging.error(f'\u001B[1m Image Stream "oai-physim" Creation Failed on OC Cluster {ocProjectName}\u001B[0m')
 			mySSH.close()
-			sys.exit(-1)
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_IS_FAIL)
+			RAN.prematureExit = True
+			return
 		else:
 			logging.debug(f'\u001B[1m   Image Stream "oai-physim" created on OC project {ocProjectName}\u001B[0m')
 		time.sleep(2)
@@ -169,7 +186,9 @@ class PhySim:
 		if mySSH.getBefore().count('Storing signatures') == 0:
 			logging.error('\u001B[1m Image "oai-physim" push to OC Cluster Registry Failed\u001B[0m')
 			mySSH.close()
-			sys.exit(-1)
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_IS_FAIL)
+			RAN.prematureExit = True
+			return
 		else:
 			logging.debug('\u001B[1m Image "oai-physim" push to OC Cluster Registry Successfully\u001B[0m')
 
@@ -180,9 +199,18 @@ class PhySim:
 		if mySSH.getBefore().count('STATUS: deployed') == 0:
 			logging.error('\u001B[1m Deploying PhySim Failed using helm chart on OC Cluster\u001B[0m')
 			mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
+			isFinished1 = False
+			while(isFinished1 == False):
+				time.sleep(20)
+				mySSH.command('oc get pods -l app.kubernetes.io/instance=physim', '\$', 6, resync=True)
+				if re.search('No resources found', mySSH.getBefore()):
+					isFinished1 = True
+			mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6)
+			mySSH.command('oc delete is oai-physim', '\$', 6)
 			mySSH.close()
 			self.AnalyzeLogFile_phySim(HTML)
-			sys.exit(-1)
+			RAN.prematureExit = True
+			return
 		else:
 			logging.debug('\u001B[1m   Deployed PhySim Successfully using helm chart\u001B[0m')
 		isRunning = False
@@ -200,7 +228,18 @@ class PhySim:
 			mySSH.command('oc get pods -l app.kubernetes.io/instance=physim 2>&1 | tee -a cmake_targets/log/physim_pods_summary.txt', '\$', 6)
 			mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
 			self.AnalyzeLogFile_phySim(HTML)
-			sys.exit(-1)
+			isFinished1 = False
+			while(isFinished1 == False):
+				time.sleep(20)
+				mySSH.command('oc get pods -l app.kubernetes.io/instance=physim', '\$', 6, resync=True)
+				if re.search('No resources found', mySSH.getBefore()):
+					isFinished1 = True
+			mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6)
+			mySSH.command('oc delete is oai-physim', '\$', 6)
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OC_PHYSIM_DEPLOY_FAIL)
+			HTML.CreateHtmlTestRowPhySimTestResult(self.testSummary,self.testResult)
+			RAN.prematureExit = True
+			return
 		# Waiting to complete the running test
 		count = 0
 		isFinished = False
@@ -240,8 +279,15 @@ class PhySim:
 		mySSH.command('oc logout', '\$', 6)
 		mySSH.close()
 		self.AnalyzeLogFile_phySim(HTML)
-		if self.testStatus == False:
-			sys.exit(-1)
+		if self.testStatus:
+			HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTestRowPhySimTestResult(self.testSummary,self.testResult)
+			logging.info('\u001B[1m Physical Simulator Pass\u001B[0m')
+		else:
+			RAN.prematureExit = True
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTestRowPhySimTestResult(self.testSummary,self.testResult)
+			logging.info('\u001B[1m Physical Simulator Fail\u001B[0m')
 
 	def AnalyzeLogFile_phySim(self, HTML):
 		lIpAddr = self.eNBIPAddress
@@ -258,7 +304,6 @@ class PhySim:
 			os.mkdir(f'./physim_test_logs_{self.testCase_id}')
 		mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/physim_test_log_' + self.testCase_id + '/*', './physim_test_logs_' + self.testCase_id)
 		mySSH.command('rm -rf ./physim_test_log_'+ self.testCase_id, '\$', 5)
-		mySSH.command('oc logout', '\$', 6)
 		mySSH.close()
 		# physim test log analysis
 		nextt = 0
@@ -289,7 +334,4 @@ class PhySim:
 		self.testSummary['Nbfail'] =  self.testCount[2]
 		if self.testSummary['Nbfail'] == 0:
 			self.testStatus = True
-		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
-		HTML.CreateHtmlTestRowPhySimTestResult(self.testSummary,self.testResult)
-		logging.info('\u001B[1m Physical Simulator Pass\u001B[0m')
 		return 0
diff --git a/ci-scripts/cls_static_code_analysis.py b/ci-scripts/cls_static_code_analysis.py
index 980efb4f8a..1680f3e560 100644
--- a/ci-scripts/cls_static_code_analysis.py
+++ b/ci-scripts/cls_static_code_analysis.py
@@ -101,7 +101,7 @@ class StaticCodeAnalysis():
 		# on RedHat/CentOS .git extension is mandatory
 		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
 		if result is not None:
-			full_ran_repo_name = self.ranRepository
+			full_ran_repo_name = self.ranRepository.replace('git/', 'git')
 		else:
 			full_ran_repo_name = self.ranRepository + '.git'
 		mySSH.command('mkdir -p ' + lSourcePath, '\$', 5)
@@ -115,7 +115,7 @@ class StaticCodeAnalysis():
 		mySSH.command('mkdir -p cmake_targets/log', '\$', 5)
 		# if the commit ID is provided use it to point to it
 		if self.ranCommitID != '':
-			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
+			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 30)
 
 		mySSH.command('docker image rm oai-cppcheck:bionic oai-cppcheck:xenial || true', '\$', 60)
 		mySSH.command('docker build --tag oai-cppcheck:xenial --file ci-scripts/docker/Dockerfile.cppcheck.xenial . > cmake_targets/log/cppcheck-xenial.txt 2>&1', '\$', 600)
diff --git a/ci-scripts/constants.py b/ci-scripts/constants.py
index a0e1ac5c45..bb110bc0e8 100644
--- a/ci-scripts/constants.py
+++ b/ci-scripts/constants.py
@@ -60,6 +60,11 @@ OAI_UE_PROCESS_SEG_FAULT = -25
 OAI_UE_PROCESS_NO_MBMS_MSGS = -26
 OAI_UE_PROCESS_OK = +6
 INVALID_PARAMETER = -50
+PHYSIM_IMAGE_ABSENT = -60
+OC_LOGIN_FAIL = -61
+OC_PROJECT_FAIL = -62
+OC_IS_FAIL = -63
+OC_PHYSIM_DEPLOY_FAIL = -64
 
 UE_STATUS_DETACHED = 0
 UE_STATUS_DETACHING = 1
diff --git a/ci-scripts/html.py b/ci-scripts/html.py
index de4e049adb..9eadf30279 100644
--- a/ci-scripts/html.py
+++ b/ci-scripts/html.py
@@ -365,6 +365,16 @@ class HTMLManagement():
 				self.htmlFile.write('        <td bgcolor = "lightcoral" >KO - SPGW process not found</td>\n')
 			elif (processesStatus == CONST.UE_IP_ADDRESS_ISSUE):
 				self.htmlFile.write('        <td bgcolor = "lightcoral" >KO - Could not retrieve UE IP address</td>\n')
+			elif (processesStatus == CONST.PHYSIM_IMAGE_ABSENT):
+				self.htmlFile.write('        <td bgcolor = "lightcoral" >KO - No such image oai-physim</td>\n')
+			elif (processesStatus == CONST.OC_LOGIN_FAIL):
+				self.htmlFile.write('        <td bgcolor = "lightcoral" >KO - Could not log onto cluster</td>\n')
+			elif (processesStatus == CONST.OC_PROJECT_FAIL):
+				self.htmlFile.write('        <td bgcolor = "lightcoral" >KO - Could not register into cluster project</td>\n')
+			elif (processesStatus == CONST.OC_IS_FAIL):
+				self.htmlFile.write('        <td bgcolor = "lightcoral" >KO - Could not create Image Stream</td>\n')
+			elif (processesStatus == CONST.OC_PHYSIM_DEPLOY_FAIL):
+				self.htmlFile.write('        <td bgcolor = "lightcoral" >KO - Could not properly deploy physim on cluster</td>\n')
 			else:
 				self.htmlFile.write('        <td bgcolor = "lightcoral" >' + str(status)  + '</td>\n')
 		else:
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 389e7f8614..3f5b57e016 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -786,7 +786,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 				elif action == 'Cppcheck_Analysis':
 					SCA.CppCheckAnalysis(HTML)
 				elif action == 'Deploy_Run_PhySim':
-					PHYSIM.Deploy_PhySim(HTML)
+					PHYSIM.Deploy_PhySim(HTML, RAN)
 				else:
 					sys.exit('Invalid class (action) from xml')
 				if not RAN.prematureExit:
diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py
index 7079773a34..49601d9cc9 100644
--- a/ci-scripts/ran.py
+++ b/ci-scripts/ran.py
@@ -144,7 +144,7 @@ class RANManagement():
 		# on RedHat/CentOS .git extension is mandatory
 		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
 		if result is not None:
-			full_ran_repo_name = self.ranRepository
+			full_ran_repo_name = self.ranRepository.replace('git/', 'git')
 		else:
 			full_ran_repo_name = self.ranRepository + '.git'
 		mySSH.command('mkdir -p ' + lSourcePath, '\$', 5)
@@ -187,7 +187,7 @@ class RANManagement():
 		mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30)
 		# if the commit ID is provided use it to point to it
 		if self.ranCommitID != '':
-			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
+			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 30)
 		# if the branch is not develop, then it is a merge request and we need to do 
 		# the potential merge. Note that merge conflicts should already been checked earlier
 		if (self.ranAllowMerge):
diff --git a/ci-scripts/xml_files/container_image_build.xml b/ci-scripts/xml_files/container_image_build.xml
index 430729c49c..e7eabc0794 100644
--- a/ci-scripts/xml_files/container_image_build.xml
+++ b/ci-scripts/xml_files/container_image_build.xml
@@ -35,6 +35,7 @@
 		<kind>all</kind>
 		<eNB_instance>0</eNB_instance>
 		<eNB_serverId>0</eNB_serverId>
+		<forced_workspace_cleanup>True</forced_workspace_cleanup>
 	</testCase>
 
 </testCaseList>
-- 
2.26.2