diff --git a/CMakeLists.txt b/CMakeLists.txt index 116b8a55d2..7da5bbc5e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,29 +140,6 @@ set (OPENAIR_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}) project (OpenAirInterface) -############################################## -# Base CUDA setting -############################################## -find_package(CUDA) -if (CUDA_FOUND) - message ("cuda include ${CUDA_INCLUDE_DIRS}") - message ("cuda library ${CUDA_LIBRARY_DIRS}") - - add_definitions("-L/usr/local/cuda/lib64") - - SET(CUDA_NVCC_FLAGS - "${CUDA_NVCC_FLAGS};-arch=sm_60;") - - # Disable warnings for CUDA - SET(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};-lpthread;-w;-O3;--default-stream;per-thread;-I/usr/local/cuda/inc;-L/usr/local/cuda/lib -lcutil;-rdc=true;-lcudadevrt") - SET(CUDA_VERBOSE_BUILD ON) - - SET(CUDA_SEPARABLE_COMPILATION ON) - -else (CUDA_FOUND) - message ("No CUDA tool installed") -endif () - #################################################### # compilation flags ############################################# @@ -618,26 +595,19 @@ target_link_libraries(benetel_5g PRIVATE asn1_nr_rrc asn1_lte_rrc) # LDPC offload library ########################################################## -# there is no generic way to test for T1 Offload, it simply comes with the -# shared object -if (EXISTS "/usr/local/lib64/librte_pmd_hpac_sdfec_pmd.so") - set(T1_OFFLOAD_FOUND TRUE) -else() - set(T1_OFFLOAD_FOUND FALSE) +add_boolean_option(ENABLE_LDPC_T1 OFF "Build support for LDPC Offload to T1 library") +if (ENABLE_LDPC_T1) + pkg_check_modules(LIBDPDK_T1 REQUIRED libdpdk=20.05.0) + find_library(T1 NAMES rte_pmd_hpac_sdfec_pmd REQUIRED) + if (NOT T1) + message(FATAL_ERROR "Library rte_pmd_hpac_sdfec_pmd for T1 offload not found") + endif() + add_library(ldpc_t1 MODULE ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c) + set_target_properties(ldpc_t1 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") + target_compile_options(ldpc_t1 PRIVATE ${LIBDPDK_T1_CFLAGS}) + target_link_libraries(ldpc_t1 ${LIBDPDK_T1_LDFLAGS} ${T1}) endif() -if(T1_OFFLOAD_FOUND) - message(STATUS "T1 Offload support detected") - set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib64/pkgconfig/") - pkg_search_module(LIBDPDK REQUIRED libdpdk=20.05.0) - add_library(ldpc_offload MODULE ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c) - set_target_properties(ldpc_offload PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") - target_compile_options(ldpc_offload PRIVATE ${LIBDPDK_CFLAGS}) - target_link_libraries(ldpc_offload ${LIBDPDK_LDFLAGS} rte_pmd_hpac_sdfec_pmd "-Wl,-rpath /usr/local/lib64") -else() - message(STATUS "No T1 Offload support detected") -endif () - ########################################################## include_directories ("${OPENAIR_DIR}/radio/COMMON") @@ -1033,16 +1003,26 @@ add_library(ldpc_cl MODULE ${PHY_LDPC_CL_SRC} ) target_link_libraries(ldpc_cl OpenCL) add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL) -if (CUDA_FOUND) - cuda_add_library(ldpc_cuda MODULE ${PHY_LDPC_CUDA_SRC} ) + +############################################## +# Base CUDA setting +############################################## + +add_boolean_option(BUILD_CUDA False "Build support for CUDA") +if (ENABLE_LDPC_CUDA) + find_package(CUDA REQUIRED) + SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;") + SET(CUDA_VERBOSE_BUILD ON) + cuda_add_library(ldpc_cuda MODULE ${PHY_LDPC_CUDA_SRC}) set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) -# CUDA_ADD_CUFFT_TO_TARGET(ldpc_cuda) -endif (CUDA_FOUND) + if (NOT CUDA_FOUND) + message(FATAL_ERROR "no CUDA found") + endif() +endif() add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) target_link_libraries(ldpc PRIVATE ldpc_gen_HEADERS) - add_library(coding MODULE ${PHY_TURBOSRC} ) target_link_libraries(coding PRIVATE asn1_nr_rrc asn1_lte_rrc) @@ -2384,11 +2364,11 @@ target_link_libraries(nr-softmodem PRIVATE ${LIB_LMS_LIBRARIES}) target_link_libraries(nr-softmodem PRIVATE ${T_LIB}) target_link_libraries(nr-softmodem PRIVATE asn1_nr_rrc asn1_lte_rrc) -add_dependencies( nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc) +add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc) -if(T1_OFFLOAD_FOUND) -add_dependencies( nr-softmodem ldpc_offload) -endif () +if (ENABLE_LDPC_T1) + add_dependencies(nr-softmodem ldpc_t1) +endif() # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(nr-softmodem PRIVATE @@ -2451,10 +2431,10 @@ target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB}) target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc asn1_lte_rrc) add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) -if (CUDA_FOUND) - add_dependencies( nr-uesoftmodem ldpc_cuda) - add_dependencies( nr-softmodem ldpc_cuda) -endif (CUDA_FOUND) +if (ENABLE_LDPC_CUDA) + add_dependencies(nr-uesoftmodem ldpc_cuda) + add_dependencies(nr-softmodem ldpc_cuda) +endif() # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(nr-uesoftmodem PRIVATE @@ -2523,9 +2503,9 @@ add_executable(ldpctest ) add_dependencies( ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) -if (CUDA_FOUND) - add_dependencies( ldpctest ldpc_cuda) -endif (CUDA_FOUND) +if (ENABLE_LDPC_CUDA) + add_dependencies(ldpctest ldpc_cuda) +endif() target_link_libraries(ldpctest PRIVATE -Wl,--start-group UTIL SIMU PHY_NR PHY_COMMON PHY_NR_COMMON CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} dl @@ -2634,9 +2614,9 @@ add_executable(nr_ulsim ${SHLIB_LOADER_SOURCES} ) -if(T1_OFFLOAD_FOUND) -add_dependencies( nr_ulsim ldpc_offload) -endif () +if (ENABLE_LDPC_T1) + add_dependencies(nr_ulsim ldpc_t1) +endif() target_link_libraries(nr_ulsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR MAC_NR_COMMON lte_rrc nr_rrc CONFIG_LIB L2_LTE_NR L2_NR HASHTABLE x2ap SECU_CN ngap NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -lz -Wl,--end-group diff --git a/ci-scripts/Jenkinsfile-push-registry b/ci-scripts/Jenkinsfile-push-registry index 273b3876be..d05c167f6f 100644 --- a/ci-scripts/Jenkinsfile-push-registry +++ b/ci-scripts/Jenkinsfile-push-registry @@ -77,7 +77,7 @@ pipeline { withCredentials([ [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.DH_Credentials}", usernameVariable: 'DH_Username', passwordVariable: 'DH_Password'] ]) { - def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue"] + def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue", "oai-nr-cuup"] // Logging in on both registries sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" sh "docker login -u oaicicd -p oaicicd porcepix.sboai.cs.eurecom.fr > /dev/null 2>&1" diff --git a/ci-scripts/cls_cmd.py b/ci-scripts/cls_cmd.py index 12eb75e7da..8694502fe2 100644 --- a/ci-scripts/cls_cmd.py +++ b/ci-scripts/cls_cmd.py @@ -74,23 +74,22 @@ class Cmd(metaclass=abc.ABCMeta): class LocalCmd(Cmd): def __init__(self, d = None): self.cwd = d + if self.cwd is not None: + logging.debug(f'Working dir is {self.cwd}') self.cp = sp.CompletedProcess(args='', returncode=0, stdout='') def run(self, line, timeout=300, silent=False, reportNonZero=True): - if type(line) is str: - line = [s for s in line.split(' ') if len(s) > 0] if not silent: - logging.debug(' '.join(line)) + logging.info(line) try: - ret = sp.run(line, cwd=self.cwd, stdout=sp.PIPE, stderr=sp.STDOUT, timeout=timeout) + ret = sp.run(line, shell=True, cwd=self.cwd, stdout=sp.PIPE, stderr=sp.STDOUT, timeout=timeout) except Exception as e: ret = sp.CompletedProcess(args=line, returncode=255, stdout=f'Exception: {str(e)}'.encode('utf-8')) if ret.stdout is None: ret.stdout = b'' ret.stdout = ret.stdout.decode('utf-8').strip() if reportNonZero and ret.returncode != 0: - cmd = ' '.join(ret.args) - logging.warning(f'command "{cmd}" returned non-zero returncode {ret.returncode}: output:\n{ret.stdout}') + logging.warning(f'command "{ret.args}" returned non-zero returncode {ret.returncode}: output:\n{ret.stdout}') self.cp = ret return ret diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 324e718ba1..b1b147b145 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -38,6 +38,9 @@ import os import shutil import subprocess import time +import pyshark +import threading +import cls_cmd from multiprocessing import Process, Lock, SimpleQueue from zipfile import ZipFile @@ -62,7 +65,8 @@ def CreateWorkspace(sshSession, sourcePath, ranRepository, ranCommitID, ranTarge sshSession.command('mkdir -p ' + sourcePath, '\$', 5) sshSession.command('cd ' + sourcePath, '\$', 5) # Recent version of git (>2.20?) should handle missing .git extension # without problems - sshSession.command(f'git clone --filter=blob:none -n -b develop {ranRepository} .', '\$', 60) + baseBranch = re.sub('origin/', '', ranTargetBranch) + sshSession.command(f'git clone --filter=blob:none -n -b {baseBranch} {ranRepository} .', '\$', 60) if sshSession.getBefore().count('error') > 0 or sshSession.getBefore().count('error') > 0: sys.exit('error during clone') sshSession.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) @@ -287,6 +291,7 @@ class Containerize(): self.deployedContainers = [] self.tsharkStarted = False + self.displayedNewTags = False self.pingContName = '' self.pingOptions = '' self.pingLossThreshold = '' @@ -345,7 +350,7 @@ class Containerize(): self.dockerfileprefix = '.rhel8.2' self.cliBuildOptions = '--no-cache --disable-compression' - # we always build the ran-build image with all targets + # we always build the ran-build image with all targets imageNames = [('ran-build', 'build')] result = re.search('eNB', self.imageKind) # Creating a tupple with the imageName and the DockerFile prefix pattern on obelix @@ -547,14 +552,17 @@ class Containerize(): oldRanCommidID = self.ranCommitID oldRanRepository = self.ranRepository oldRanAllowMerge = self.ranAllowMerge + oldRanTargetBranch = self.ranTargetBranch self.ranCommitID = self.proxyCommit self.ranRepository = 'https://github.com/EpiSci/oai-lte-5g-multi-ue-proxy.git' self.ranAllowMerge = False + self.ranTargetBranch = 'master' CreateWorkspace(mySSH, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge) # to prevent accidentally overwriting data that might be used later self.ranCommitID = oldRanCommidID self.ranRepository = oldRanRepository self.ranAllowMerge = oldRanAllowMerge + self.ranTargetBranch = oldRanTargetBranch # Let's remove any previous run artifacts if still there mySSH.command(self.cli + ' image prune --force', '\$', 30) @@ -571,6 +579,7 @@ class Containerize(): # Note: at this point, OAI images are flattened, but we cannot do this # here, as the flatten script is not in the proxy repo mySSH.command(self.cli + ' image inspect --format=\'Size = {{.Size}} bytes\' proxy:' + tag, '\$', 5) + mySSH.command(self.cli + ' image prune --force || true','\$', 15) if mySSH.getBefore().count('o such image') != 0: logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m') mySSH.close() @@ -730,60 +739,42 @@ class Containerize(): sys.exit('Insufficient Parameter') if lIpAddr != 'none': logging.debug('Pulling images onto server: ' + lIpAddr) - mySSH = SSH.SSHConnection() - mySSH.open(lIpAddr, lUserName, lPassWord) + myCmd = cls_cmd.RemoteCmd(lIpAddr) else: logging.debug('Pulling images locally') + myCmd = cls_cmd.LocalCmd() cmd = 'docker login -u oaicicd -p oaicicd porcepix.sboai.cs.eurecom.fr' - if lIpAddr != 'none': - mySSH.command(cmd, '\$', 5) - response = mySSH.getBefore() - else: - logging.info(cmd) - response = subprocess.check_output(cmd, shell=True, universal_newlines=True, stderr=subprocess.STDOUT) - if re.search('Login Succeeded', response) is None: + response = myCmd.run(cmd) + if response.returncode != 0: msg = 'Could not log into local registry' logging.error(msg) - if lIpAddr != 'none': - mySSH.close() + myCmd.close() HTML.CreateHtmlTestRow(msg, 'KO', CONST.ALL_PROCESSES_OK) return False for image in self.imageToPull: tagToUse = self.ImageTagToUse(image) cmd = f'docker pull {tagToUse}' - if lIpAddr != 'none': - mySSH.command(cmd, '\$', 120) - response = mySSH.getBefore() - else: - logging.info(cmd) - response = subprocess.check_output(cmd, shell=True, universal_newlines=True) - if re.search('Status: Downloaded newer image for |Status: Image is up to date for', response) is None: + response = myCmd.run(cmd, timeout=120) + if response.returncode != 0: logging.debug(response) msg = f'Could not pull {image} from local registry : {tagToUse}' logging.error(msg) - if lIpAddr != 'none': - mySSH.close() + myCmd.close() HTML.CreateHtmlTestRow('msg', 'KO', CONST.ALL_PROCESSES_OK) return False cmd = 'docker logout porcepix.sboai.cs.eurecom.fr' - if lIpAddr != 'none': - mySSH.command(cmd, '\$', 5) - response = mySSH.getBefore() - else: - logging.info(cmd) - response = subprocess.check_output(cmd, shell=True, universal_newlines=True) - if re.search('Removing login credentials', response) is None: + response = myCmd.run(cmd) + if response.returncode != 0: msg = 'Could not log off from local registry' logging.error(msg) - mySSH.close() + myCmd.close() HTML.CreateHtmlTestRow(msg, 'KO', CONST.ALL_PROCESSES_OK) return False - if lIpAddr != 'none': - mySSH.close() + myCmd.close() HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) return True @@ -810,22 +801,17 @@ class Containerize(): sys.exit('Insufficient Parameter') if lIpAddr != 'none': logging.debug('Removing test images from server: ' + lIpAddr) - mySSH = SSH.SSHConnection() - mySSH.open(lIpAddr, lUserName, lPassWord) + myCmd = cls_cmd.RemoteCmd(lIpAddr) else: logging.debug('Removing test images locally') + myCmd = cls_cmd.LocalCmd() imageNames = ['oai-enb', 'oai-gnb', 'oai-lte-ue', 'oai-nr-ue', 'oai-lte-ru', 'oai-nr-cuup'] for image in imageNames: - cmd = f'docker rmi {self.ImageTagToUse(image)} || true' - if lIpAddr != 'none': - mySSH.command(cmd, '\$', 5) - else: - logging.info(cmd) - subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + cmd = f'docker rmi {self.ImageTagToUse(image)}' + myCmd.run(cmd, reportNonZero=False) - if lIpAddr != 'none': - mySSH.close() + myCmd.close() HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) return True @@ -865,7 +851,6 @@ class Containerize(): mySSH.command('sed -i -e "s/CI_MME_IP_ADDR/' + localMmeIpAddr + '/" ci-docker-compose.yml', '\$', 2) # Currently support only one - mySSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 15) svcName = self.services[self.eNB_instance] if svcName == '': logging.warning('no service name given: starting all services in ci-docker-compose.yml!') @@ -922,7 +907,7 @@ class Containerize(): if healthyNb == 1: cnt = 0 while (cnt < 20): - mySSH.command('docker logs ' + containerName + ' | egrep --text --color=never -i "wait|sync|Starting"', '\$', 30) + mySSH.command('docker logs ' + containerName + ' | egrep --text --color=never -i "wait|sync|Starting"', '\$', 30) result = re.search('got sync|Starting F1AP at CU', mySSH.getBefore()) if result is None: time.sleep(6) @@ -1048,54 +1033,58 @@ class Containerize(): def DeployGenObject(self, HTML, RAN, UE): self.exitStatus = 0 logging.debug('\u001B[1m Checking Services to deploy\u001B[0m') - cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose config --services' - logging.info(cmd) - try: - listServices = subprocess.check_output(cmd, shell=True, universal_newlines=True) - except Exception as e: + # Implicitly we are running locally + myCmd = cls_cmd.LocalCmd(d = self.yamlPath[0]) + cmd = 'docker-compose config --services' + listServices = myCmd.run(cmd) + if listServices.returncode != 0: + myCmd.close() self.exitStatus = 1 HTML.CreateHtmlTestRow('SVC not Found', 'KO', CONST.ALL_PROCESSES_OK) return for reqSvc in self.services[0].split(' '): - res = re.search(reqSvc, listServices) + res = re.search(reqSvc, listServices.stdout) if res is None: logging.error(reqSvc + ' not found in specified docker-compose') self.exitStatus = 1 if (self.exitStatus == 1): + myCmd.close() HTML.CreateHtmlTestRow('SVC not Found', 'KO', CONST.ALL_PROCESSES_OK) return - cmd = 'cd ' + self.yamlPath[0] + ' && cp docker-compose.y*ml docker-compose-ci.yml' - subprocess.run(cmd, shell=True) + cmd = 'cp docker-compose.y*ml docker-compose-ci.yml' + myCmd.run(cmd, silent=self.displayedNewTags) imageNames = ['oai-enb', 'oai-gnb', 'oai-lte-ue', 'oai-nr-ue', 'oai-lte-ru', 'oai-nr-cuup'] for image in imageNames: tagToUse = self.ImageTagToUse(image) - cmd = f'cd {self.yamlPath[0]} && sed -i -e "s@{image}:develop@{tagToUse}@" docker-compose-ci.yml' - logging.debug(cmd) - subprocess.run(cmd, shell=True) + cmd = f'sed -i -e "s@oaisoftwarealliance/{image}:develop@{tagToUse}@" docker-compose-ci.yml' + myCmd.run(cmd, silent=self.displayedNewTags) + self.displayedNewTags = True - cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml up -d ' + self.services[0] - logging.info(cmd) - try: - deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100) - except Exception as e: + cmd = f'docker-compose -f docker-compose-ci.yml up -d {self.services[0]}' + deployStatus = myCmd.run(cmd, timeout=100) + if deployStatus.returncode != 0: + myCmd.close() self.exitStatus = 1 logging.error('Could not deploy') HTML.CreateHtmlTestRow('Could not deploy', 'KO', CONST.ALL_PROCESSES_OK) return logging.debug('\u001B[1m Checking if all deployed healthy\u001B[0m') - cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml ps -a' + cmd = 'docker-compose -f docker-compose-ci.yml ps -a' count = 0 healthy = 0 + restarting = 0 newContainers = [] while (count < 10): count += 1 containerStatus = [] - deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30) + deployStatus = myCmd.run(cmd, 30, silent=True) healthy = 0 - for state in deployStatus.split('\n'): - res = re.search('Name|----------', state) + restarting = 0 + for state in deployStatus.stdout.split('\n'): + state = state.strip() + res = re.search('Name|NAME|----------', state) if res is not None: continue if len(state) == 0: @@ -1110,23 +1099,32 @@ class Containerize(): if not found: newContainers.append(cName) self.deployedContainers.append(cName) - if re.search('Up \(healthy\)', state) is not None: + if re.search('\(healthy\)', state) is not None: healthy += 1 - if re.search('rfsim4g-db-init.*Exit 0', state) is not None: - subprocess.check_output('docker rm -f rfsim4g-db-init || true', shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30) - containerStatus.append(state) - if healthy == self.nb_healthy[0]: + if re.search('rfsim4g-db-init.*Exit 0', state) is not None or re.search('rfsim4g-db-init.*Exited \(0\)', state) is not None: + myCmd.run('docker rm -f rfsim4g-db-init', timeout=30, silent=True, reportNonZero=False) + if re.search('l2sim4g-db-init.*Exit 0', state) is not None or re.search('l2sim4g-db-init.*Exited \(0\)', state) is not None: + myCmd.run('docker rm -f l2sim4g-db-init', timeout=30, silent=True, reportNonZero=False) + if re.search('Restarting', state) is None: + containerStatus.append(state) + else: + restarting += 1 + if healthy == self.nb_healthy[0] and restarting == 0: count = 100 else: time.sleep(10) imagesInfo = '' for newCont in newContainers: + if newCont == 'rfsim4g-db-init': + continue cmd = 'docker inspect -f "{{.Config.Image}}" ' + newCont - imageName = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30) - imageName = str(imageName).strip() + imageInspect = myCmd.run(cmd, timeout=30, silent=True) + imageName = str(imageInspect.stdout).strip() cmd = 'docker image inspect --format "{{.RepoTags}}\t{{.Size}} bytes\t{{.Created}}\t{{.Id}}" ' + imageName - imagesInfo += subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30) + imageInspect = myCmd.run(cmd, 30, silent=True) + imagesInfo += imageInspect.stdout.strip() + myCmd.close() html_queue = SimpleQueue() html_cell = '
\n'
@@ -1158,48 +1156,71 @@ class Containerize():
 			self.UndeployGenObject(HTML, RAN, UE)
 			self.exitStatus = 1
 
-	def CaptureOnDockerNetworks(self):
-		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml config | grep com.docker.network.bridge.name | sed -e "s@^.*name: @@"'
-		networkNames = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+	# pyshark livecapture launches 2 processes:
+	# * One using dumpcap -i lIfs -w - (ie redirecting the packets to STDOUT)
+	# * One using tshark -i - -w loFile (ie capturing from STDIN from previous process)
+	# but in fact the packets are read by the following loop before being in fact
+	# really written to loFile.
+	# So it is mandatory to keep the loop
+	def LaunchPySharkCapture(self, lIfs, lFilter, loFile):
+		capture = pyshark.LiveCapture(interface=lIfs, bpf_filter=lFilter, output_file=loFile, debug=False)
+		for packet in capture.sniff_continuously():
+			pass
 
+	def CaptureOnDockerNetworks(self):
+		myCmd = cls_cmd.LocalCmd(d = self.yamlPath[0])
+		cmd = 'docker-compose -f docker-compose-ci.yml config | grep com.docker.network.bridge.name | sed -e "s@^.*name: @@"'
+		networkNames = myCmd.run(cmd, silent=True)
+		myCmd.close()
 		# Allow only: control plane RAN (SCTP), HTTP of control in CN (port 80), PFCP traffic (port 8805), MySQL (port 3306)
-		cmd = 'sudo nohup tshark -f "sctp or port 80 or port 8805 or icmp or port 3306"'
-		for name in networkNames.split('\n'):
+		capture_filter = 'sctp or port 80 or port 8805 or icmp or port 3306'
+		interfaces = []
+		iInterfaces = ''
+		for name in networkNames.stdout.split('\n'):
 			if re.search('rfsim', name) is not None or re.search('l2sim', name) is not None:
-				cmd += ' -i ' + name
-		cmd += ' -w /tmp/capture_'
+				interfaces.append(name)
+				iInterfaces += f'-i {name} '
 		ymlPath = self.yamlPath[0].split('/')
-		cmd += ymlPath[1] + '.pcap > /tmp/tshark.log 2>&1 &'
-		logging.info(cmd)
-		networkNames = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+		output_file = f'/tmp/capture_{ymlPath[1]}.pcap'
 		self.tsharkStarted = True
+		# On old systems (ubuntu 18), pyshark live-capture is buggy.
+		# Going back to old method
+		if sys.version_info < (3, 7):
+			cmd = f'nohup tshark -f "{capture_filter}" {iInterfaces} -w {output_file} > /tmp/tshark.log 2>&1 &'
+			myCmd = cls_cmd.LocalCmd()
+			myCmd.run(cmd, timeout=5, reportNonZero=False)
+			myCmd.close()
+			return
+		x = threading.Thread(target = self.LaunchPySharkCapture, args = (interfaces,capture_filter,output_file,))
+		x.daemon = True
+		x.start()
 
 	def UndeployGenObject(self, HTML, RAN, UE):
 		self.exitStatus = 0
+		# Implicitly we are running locally
 		ymlPath = self.yamlPath[0].split('/')
 		logPath = '../cmake_targets/log/' + ymlPath[1]
+		myCmd = cls_cmd.LocalCmd(d = self.yamlPath[0])
 
-		cmd = 'cd ' + self.yamlPath[0] + ' && cp docker-compose.y*ml docker-compose-ci.yml'
-		logging.info(cmd)
-		subprocess.run(cmd, shell=True)
+		cmd = 'cp docker-compose.y*ml docker-compose-ci.yml'
+		myCmd.run(cmd, silent=self.displayedNewTags)
 		imageNames = ['oai-enb', 'oai-gnb', 'oai-lte-ue', 'oai-nr-ue', 'oai-lte-ru', 'oai-nr-cuup']
 		for image in imageNames:
 			tagToUse = self.ImageTagToUse(image)
-			cmd = f'cd {self.yamlPath[0]} && sed -i -e "s@{image}:develop@{tagToUse}@" docker-compose-ci.yml'
-			subprocess.run(cmd, shell=True)
+			cmd = f'sed -i -e "s@oaisoftwarealliance/{image}:develop@{tagToUse}@" docker-compose-ci.yml'
+			myCmd.run(cmd, silent=self.displayedNewTags)
+		self.displayedNewTags = True
 
 		# check which containers are running for log recovery later
-		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml ps --all'
-		logging.info(cmd)
-		deployStatusLogs = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
+		cmd = 'docker-compose -f docker-compose-ci.yml ps --all'
+		deployStatusLogs = myCmd.run(cmd, timeout=30)
 
 		# Stop the containers to shut down objects
 		logging.debug('\u001B[1m Stopping containers \u001B[0m')
-		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml stop -t3'
-		logging.info(cmd)
-		try:
-			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
-		except Exception as e:
+		cmd = 'docker-compose -f docker-compose-ci.yml stop -t3'
+		deployStatus = myCmd.run(cmd, timeout=100)
+		if deployStatus.returncode != 0:
+			myCmd.close()
 			self.exitStatus = 1
 			logging.error('Could not stop containers')
 			HTML.CreateHtmlTestRow('Could not stop', 'KO', CONST.ALL_PROCESSES_OK)
@@ -1207,8 +1228,12 @@ class Containerize():
 			return
 
 		anyLogs = False
-		for state in deployStatusLogs.split('\n'):
-			res = re.search('Name|----------', state)
+		logging.debug('Working dir is now . (ie ci-scripts)')
+		myCmd2 = cls_cmd.LocalCmd()
+		myCmd2.run(f'mkdir -p {logPath}')
+		myCmd2.cd(logPath)
+		for state in deployStatusLogs.stdout.split('\n'):
+			res = re.search('Name|NAME|----------', state)
 			if res is not None:
 				continue
 			if len(state) == 0:
@@ -1217,36 +1242,26 @@ class Containerize():
 			if res is not None:
 				anyLogs = True
 				cName = res.group('container_name')
-				cmd = 'cd ' + self.yamlPath[0] + ' && docker logs ' + cName + ' > ' + cName + '.log 2>&1'
-				logging.info(cmd)
-				subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
+				cmd = f'docker logs {cName} > {cName}.log 2>&1'
+				myCmd2.run(cmd, timeout=30, reportNonZero=False)
 				if re.search('magma-mme', cName) is not None:
-					cmd = 'cd ' + self.yamlPath[0] + ' && docker cp -L ' + cName + ':/var/log/mme.log ' + cName + '-full.log'
-					logging.info(cmd)
-					subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
+					cmd = f'docker cp -L {cName}:/var/log/mme.log {cName}-full.log'
+					myCmd2.run(cmd, timeout=30, reportNonZero=False)
 		fullStatus = True
 		if anyLogs:
-			cmd = 'mkdir -p '+ logPath + ' && cp ' + self.yamlPath[0] + '/*.log ' + logPath
-			logging.info(cmd)
-			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
-
 			# Analyzing log file(s)!
 			listOfPossibleRanContainers = ['enb', 'gnb', 'cu', 'du']
 			for container in listOfPossibleRanContainers:
-				filenames = self.yamlPath[0] + '/*-oai-' + container + '.log'
-				cmd = 'ls ' + filenames
-				containerStatus = True
-				try:
-					lsStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
-					filenames = str(lsStatus).strip()
-				except:
-					containerStatus = False
-				if not containerStatus:
+				filenames = './*-oai-' + container + '.log'
+				cmd = f'ls {filenames}'
+				lsStatus = myCmd2.run(cmd, silent=True, reportNonZero=False)
+				if lsStatus.returncode != 0:
 					continue
+				filenames = str(lsStatus.stdout).strip()
 
 				for filename in filenames.split('\n'):
 					logging.debug('\u001B[1m Analyzing xNB logfile ' + filename + ' \u001B[0m')
-					logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
+					logStatus = RAN.AnalyzeLogFile_eNB(f'{logPath}/{filename}', HTML, self.ran_checkers)
 					if (logStatus < 0):
 						fullStatus = False
 						self.exitStatus = 1
@@ -1256,49 +1271,42 @@ class Containerize():
 
 			listOfPossibleUeContainers = ['lte-ue*', 'nr-ue*']
 			for container in listOfPossibleUeContainers:
-				filenames = self.yamlPath[0] + '/*-oai-' + container + '.log'
-				cmd = 'ls ' + filenames
-				containerStatus = True
-				try:
-					lsStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
-					filenames = str(lsStatus).strip()
-				except:
-					containerStatus = False
-				if not containerStatus:
+				filenames = './*-oai-' + container + '.log'
+				cmd = f'ls {filenames}'
+				lsStatus = myCmd2.run(cmd, silent=True, reportNonZero=False)
+				if lsStatus.returncode != 0:
 					continue
+				filenames = str(lsStatus.stdout).strip()
 
 				for filename in filenames.split('\n'):
 					logging.debug('\u001B[1m Analyzing UE logfile ' + filename + ' \u001B[0m')
-					logStatus = UE.AnalyzeLogFile_UE(filename, HTML, RAN)
+					logStatus = UE.AnalyzeLogFile_UE(f'{logPath}/{filename}', HTML, RAN)
 					if (logStatus < 0):
 						fullStatus = False
 						HTML.CreateHtmlTestRow('UE log Analysis', 'KO', logStatus)
 					else:
 						HTML.CreateHtmlTestRow('UE log Analysis', 'OK', CONST.ALL_PROCESSES_OK)
 
-			cmd = 'rm ' + self.yamlPath[0] + '/*.log'
-			logging.info(cmd)
-			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
 			if self.tsharkStarted:
 				self.tsharkStarted = True
+				cmd = 'killall tshark'
+				myCmd2.run(cmd, reportNonZero=False)
+				cmd = 'killall dumpcap'
+				myCmd2.run(cmd, reportNonZero=False)
+				time.sleep(5)
 				ymlPath = self.yamlPath[0].split('/')
-				cmd = 'sudo chmod 666 /tmp/capture_' + ymlPath[1] + '.pcap'
-				logging.info(cmd)
-				copyStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
-				cmd = 'cp /tmp/capture_' + ymlPath[1] + '.pcap ' + logPath
-				logging.info(cmd)
-				copyStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
-				cmd = 'sudo rm /tmp/capture_' + ymlPath[1] + '.pcap'
-				logging.info(cmd)
-				copyStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
+				# The working dir is still logPath
+				cmd = f'mv /tmp/capture_{ymlPath[1]}.pcap .'
+				myCmd2.run(cmd, timeout=100, reportNonZero=False)
 				self.tsharkStarted = False
+		myCmd2.close()
 
 		logging.debug('\u001B[1m Undeploying \u001B[0m')
-		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml down'
-		logging.info(cmd)
-		try:
-			deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
-		except Exception as e:
+		logging.debug(f'Working dir is back {self.yamlPath[0]}')
+		cmd = 'docker-compose -f docker-compose-ci.yml down'
+		deployStatus = myCmd.run(cmd, timeout=100)
+		if deployStatus.returncode != 0:
+			myCmd.close()
 			self.exitStatus = 1
 			logging.error('Could not undeploy')
 			HTML.CreateHtmlTestRow('Could not undeploy', 'KO', CONST.ALL_PROCESSES_OK)
@@ -1307,9 +1315,9 @@ class Containerize():
 
 		self.deployedContainers = []
 		# Cleaning any created tmp volume
-		cmd = 'docker volume prune --force || true'
-		logging.info(cmd)
-		deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
+		cmd = 'docker volume prune --force'
+		deployStatus = myCmd.run(cmd, timeout=100, reportNonZero=False)
+		myCmd.close()
 
 		if fullStatus:
 			HTML.CreateHtmlTestRow('n/a', 'OK', CONST.ALL_PROCESSES_OK)
@@ -1324,13 +1332,13 @@ class Containerize():
 		logPath = '../cmake_targets/log/' + ymlPath[1]
 
 		# if the containers are running, recover the logs!
-		cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml ps --all'
-		logging.info(cmd)
-		deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
+		myCmd = cls_cmd.LocalCmd(d = self.yamlPath[0])
+		cmd = 'docker-compose -f docker-compose-ci.yml ps --all'
+		deployStatus = myCmd.run(cmd, timeout=30)
 		cmd = 'docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}" '
 		anyLogs = False
-		for state in deployStatus.split('\n'):
-			res = re.search('Name|----------', state)
+		for state in deployStatus.stdout.split('\n'):
+			res = re.search('Name|NAME|----------', state)
 			if res is not None:
 				continue
 			if len(state) == 0:
@@ -1341,11 +1349,11 @@ class Containerize():
 				cmd += res.group('container_name') + ' '
 		message = ''
 		if anyLogs:
-			logging.info(cmd)
-			stats = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
-			for statLine in stats.split('\n'):
+			stats = myCmd.run(cmd, timeout=30)
+			for statLine in stats.stdout.split('\n'):
 				logging.debug(statLine)
 				message += statLine + '\n'
+		myCmd.close()
 
 		html_queue = SimpleQueue()
 		html_cell = '
\n' + message + '
' @@ -1353,18 +1361,18 @@ class Containerize(): HTML.CreateHtmlTestRowQueue(self.pingOptions, 'OK', 1, html_queue) def PingFromContainer(self, HTML, RAN, UE): + myCmd = cls_cmd.LocalCmd() self.exitStatus = 0 ymlPath = self.yamlPath[0].split('/') logPath = '../cmake_targets/log/' + ymlPath[1] - cmd = 'mkdir -p ' + logPath - deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10) + cmd = f'mkdir -p {logPath}' + myCmd.run(cmd, silent=True) - cmd = 'docker exec ' + self.pingContName + ' /bin/bash -c "ping ' + self.pingOptions + '" 2>&1 | tee ' + logPath + '/ping_' + HTML.testCase_id + '.log || true' + cmd = f'docker exec {self.pingContName} /bin/bash -c "ping {self.pingOptions}" 2>&1 | tee {logPath}/ping_{HTML.testCase_id}.log' + pingStatus = myCmd.run(cmd, timeout=100, reportNonZero=False) + myCmd.close() - logging.info(cmd) - deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100) - - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', deployStatus) + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', pingStatus.stdout) if result is None: self.PingExit(HTML, RAN, UE, False, 'Packet Loss Not Found') return @@ -1374,7 +1382,7 @@ class Containerize(): self.PingExit(HTML, RAN, UE, False, 'Packet Loss is 100%') return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', deployStatus) + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', pingStatus.stdout) if result is None: self.PingExit(HTML, RAN, UE, False, 'Ping RTT_Min RTT_Avg RTT_Max Not Found!') return @@ -1427,39 +1435,37 @@ class Containerize(): self.exitStatus = 1 def IperfFromContainer(self, HTML, RAN, UE): + myCmd = cls_cmd.LocalCmd() self.exitStatus = 0 ymlPath = self.yamlPath[0].split('/') logPath = '../cmake_targets/log/' + ymlPath[1] - cmd = 'mkdir -p ' + logPath - logStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10) + cmd = f'mkdir -p {logPath}' + myCmd.run(cmd, silent=True) # Start the server process cmd = f'docker exec -d {self.svrContName} /bin/bash -c "nohup iperf {self.svrOptions} > /tmp/iperf_server.log 2>&1"' - logging.info(cmd) - subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10) + myCmd.run(cmd) time.sleep(3) # Start the client process cmd = f'docker exec {self.cliContName} /bin/bash -c "iperf {self.cliOptions}" 2>&1 | tee {logPath}/iperf_client_{HTML.testCase_id}.log' - logging.info(cmd) - clientStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100) + clientStatus = myCmd.run(cmd, timeout=100) # Stop the server process cmd = f'docker exec {self.svrContName} /bin/bash -c "pkill iperf"' - logging.info(cmd) - subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10) + myCmd.run(cmd) time.sleep(3) serverStatusFilename = f'{logPath}/iperf_server_{HTML.testCase_id}.log' cmd = f'docker cp {self.svrContName}:/tmp/iperf_server.log {serverStatusFilename}' - logging.info(cmd) - subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30) + myCmd.run(cmd, timeout=60) + myCmd.close() # clientStatus was retrieved above. The serverStatus was # written in the background, then copied to the local machine with open(serverStatusFilename, 'r') as f: serverStatus = f.read() - (iperfStatus, msg) = AnalyzeIperf(self.cliOptions, clientStatus, serverStatus) + (iperfStatus, msg) = AnalyzeIperf(self.cliOptions, clientStatus.stdout, serverStatus) if iperfStatus: logging.info('\u001B[1m Iperf Test PASS\u001B[0m') else: @@ -1595,4 +1601,3 @@ class Containerize(): if result is None: mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10) mySSH.close() - diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 328785f8d1..51e43109a0 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -453,17 +453,6 @@ class OaiCiTest(): UE_prefix = 'NR ' SSH = sshconnection.SSHConnection() SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - # b2xx_fx3_utils reset procedure - SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 180) - result = re.search('type: b200', SSH.getBefore()) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - SSH.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 180) - result = re.search('type: n3xx', str(SSH.getBefore())) - if result is not None: - logging.debug('Found a N3xx device --> resetting it') SSH.command('cd ' + self.UESourceCodePath, '\$', 5) # Initialize_OAI_UE_args usually start with -C and followed by the location in repository SSH.command('source oaienv', '\$', 5) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 8ee4a0a5e6..64074fdd6a 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -43,7 +43,7 @@ from multiprocessing import Process, Lock, SimpleQueue #----------------------------------------------------------- # OAI Testing modules #----------------------------------------------------------- -import sshconnection as SSH +import sshconnection as SSH import helpreadme as HELP import constants as CONST @@ -66,8 +66,8 @@ class EPCManagement(): self.mmeConfFile = 'mme.conf' self.yamlPath = '' self.isMagmaUsed = False - self.cfgDeploy = '--type start-mini --fqdn yes --scenario 1 --capture /tmp/oai-cn5g-v1.3.pcap' #from xml, 'mini' is default normal for docker-network.py - self.cfgUnDeploy = '--type stop-mini --fqdn yes --scenario 1' #from xml, 'mini' is default normal for docker-network.py + self.cfgDeploy = '--type start-mini --scenario 1 --capture /tmp/oai-cn5g-v1.5.pcap' #from xml, 'mini' is default normal for docker-network.py + self.cfgUnDeploy = '--type stop-mini --scenario 1' #from xml, 'mini' is default normal for docker-network.py #----------------------------------------------------------- @@ -253,18 +253,18 @@ class EPCManagement(): logging.debug('Starting OAI CN5G') mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5) mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts', '\$', 5) - mySSH.command('cd /opt/oai-cn5g-fed-v1.4/docker-compose', '\$', 5) + mySSH.command('cd /opt/oai-cn5g-fed-v1.5/docker-compose', '\$', 5) mySSH.command('python3 ./core-network.py '+self.cfgDeploy, '\$', 60) if re.search('start-mini-as-ue', self.cfgDeploy): dFile = 'docker-compose-mini-nrf-asue.yaml' else: dFile = 'docker-compose-mini-nrf.yaml' - mySSH.command('docker-compose -p 5gcn -f ' + dFile + ' ps -a', '\$', 60) + mySSH.command('docker-compose -f ' + dFile + ' ps -a', '\$', 60) if mySSH.getBefore().count('Up (healthy)') != 6: logging.error('Not all container healthy') else: logging.debug('OK --> all containers are healthy') - mySSH.command('docker-compose -p 5gcn -f ' + dFile + ' config | grep --colour=never image', '\$', 10) + mySSH.command('docker-compose -f ' + dFile + ' config | grep --colour=never image', '\$', 10) listOfImages = mySSH.getBefore() for imageLine in listOfImages.split('\\r\\n'): res1 = re.search('image: (?P[a-zA-Z0-9\-/]+):(?P[a-zA-Z0-9\-]+)', str(imageLine)) @@ -537,11 +537,11 @@ class EPCManagement(): mySSH.command('docker logs ' + c + ' > ' + self.SourceCodePath + '/logs/' + c + '.log', '\$', 5) logging.debug('Terminating OAI CN5G') - mySSH.command('cd /opt/oai-cn5g-fed-v1.4/docker-compose', '\$', 5) + mySSH.command('cd /opt/oai-cn5g-fed-v1.5/docker-compose', '\$', 5) mySSH.command('python3 ./core-network.py '+self.cfgUnDeploy, '\$', 60) mySSH.command('docker volume prune --force || true', '\$', 60) time.sleep(2) - mySSH.command('tshark -r /tmp/oai-cn5g-v1.3.pcap | egrep --colour=never "Tracking area update" ','\$', 30) + mySSH.command('tshark -r /tmp/oai-cn5g-v1.5.pcap | egrep --colour=never "Tracking area update" ','\$', 30) result = re.search('Tracking area update request', mySSH.getBefore()) if result is not None: message = 'UE requested ' + str(mySSH.getBefore().count('Tracking area update request')) + 'Tracking area update request(s)' @@ -828,7 +828,7 @@ class EPCManagement(): mySSH.command('zip mme.log.zip mme_check_run.*', '\$', 60) elif re.match('OAICN5G', self.Type, re.IGNORECASE): mySSH.command('cd ' + self.SourceCodePath + '/logs','\$', 5) - mySSH.command('cp -f /tmp/oai-cn5g-v1.3.pcap .','\$', 30) + mySSH.command('cp -f /tmp/oai-cn5g-v1.5.pcap .','\$', 30) mySSH.command('zip mme.log.zip oai-amf.log oai-nrf.log oai-cn5g*.pcap','\$', 30) mySSH.command('mv mme.log.zip ' + self.SourceCodePath + '/scripts','\$', 30) elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE): diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 322b6a5c72..fd3f1f773a 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -70,6 +70,7 @@ import subprocess from multiprocessing import Process, Lock, SimpleQueue logging.basicConfig( level=logging.DEBUG, + stream=sys.stdout, format="[%(asctime)s] %(levelname)8s: %(message)s" ) @@ -498,6 +499,9 @@ def GetParametersFromXML(action): string_field = test.findtext('test_svr_id') if (string_field is not None): CONTAINERS.testSvrId = string_field + elif action == 'Custom_Command': + RAN.node = test.findtext('node') + RAN.command = test.findtext('command') else: logging.warning(f"unknown action {action} from option-parsing point-of-view") @@ -879,6 +883,9 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re RAN.BuildeNB(HTML) elif action == 'WaitEndBuild_eNB': RAN.WaitBuildeNBisFinished(HTML) + elif action == 'Custom_Command': + logging.info(f"Executing custom command") + RAN.CustomCommand(HTML) elif action == 'Initialize_eNB': check_eNB = False check_OAI_UE = False diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index fd6a073f21..8628d5f3d8 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -38,6 +38,7 @@ import os import time from multiprocessing import Process, Lock, SimpleQueue import yaml +import cls_cmd #----------------------------------------------------------- @@ -96,6 +97,8 @@ class RANManagement(): #checkers from xml self.ran_checkers={} self.cmd_prefix = '' # prefix before {lte,nr}-softmodem + self.node = '' + self.command = '' #----------------------------------------------------------- @@ -259,6 +262,21 @@ class RANManagement(): mySSH.close() self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)], HTML) + def CustomCommand(self, HTML): + if self.node == '' or self.node == "localhost": + cmd = cls_cmd.LocalCmd() + else: + cmd = cls_cmd.RemoteCmd(self.node) + ret = cmd.run(self.command) + cmd.close() + logging.debug(f'CustomCommand: {self.command} returnCode: {ret.returncode} output: {ret.stdout}') + html_queue = SimpleQueue() + status = 'OK' + if ret.returncode != 0: + html_queue.put(ret.stdout) + status = 'Warning' + HTML.CreateHtmlTestRow(self.command, status, 1, html_queue) + def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId, HTML): HTML.testCase_id=testcaseId @@ -347,17 +365,6 @@ class RANManagement(): cwd = os.getcwd() mySSH.copyout(lIpAddr,lUserName,lPassWord, cwd + "/active_net_interfaces.awk", "/tmp") - #reboot USRP if requested in xml - if self.USRPIPAddress!='': - logging.debug('USRP '+ self.USRPIPAddress +': reboot request') - mySSH.open(lIpAddr, lUserName, lPassWord) - cmd2usrp='ssh root@'+self.USRPIPAddress+' reboot' - mySSH.command2(cmd2usrp,1) - mySSH.close() - logging.debug('Waiting for USRP to be ready') - time.sleep(120) - - if (self.pStatus < 0): HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' ' + self.Initialize_eNB_args, 'KO', self.pStatus) HTML.CreateHtmlTabFooter(False) @@ -419,16 +426,6 @@ class RANManagement(): result = re.search('^rru|^rcc|^du.band', str(config_file)) if result is not None: rruCheck = True - # do not reset board twice in IF4.5 case - result = re.search('^rru|^enb|^du.band', str(config_file)) - if result is not None: - mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 180) - result = re.search('type: b200', mySSH.getBefore()) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - mySSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 180) # Make a copy and adapt to EPC / eNB IP addresses mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) localMmeIpAddr = EPC.MmeIPAddress diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index b4dabb1654..93e3bc9fb0 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -51,3 +51,4 @@ - Push_Local_Registry - Pull_Local_Registry - Clean_Test_Server_Images + - Custom_Command diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml index ce9a19fde3..698c620329 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml @@ -27,12 +27,15 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1.xml Test-FDD-05MHz-TM1 tasks +100000 111110 +300000 040101 030101 000001 040301 000001 040501 040603 040604 040605 040606 040607 040641 040642 040643 040644 040401 040201 030201 +200000 @@ -42,7 +45,24 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1.xml 0 oai-enb - + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -E + + + Custom_Command + To reset USRP + hutch + sudo -S b2xx_fx3_utils --reset-device + Deploy_Object Deploy eNB (FDD/Band7/5MHz/B200) in a container diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml index 8ead87d703..66d0c982ec 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml @@ -27,11 +27,13 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xm Test-FDD-05MHz-TM1-RRC-Inactivity tasks +100000 111110 040101 030102 000010 040301 040502 000011 040302 000001 000012 040303 000002 000013 040503 040401 040201 030201 +200000 @@ -41,6 +43,18 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xm 0 oai-enb + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -E + Deploy_Object diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml index ce3161c94c..07f23ff2f0 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml @@ -28,12 +28,14 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Test-FDD-10MHz-TM1 tasks +100000 111110 040101 030111 000001 040301 040511 040613 040614 040615 040651 040652 040653 040654 040401 040201 030201 +200000 @@ -43,6 +45,18 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml 0 oai-enb + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -E + Deploy_Object diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml index 4d09bada08..caa888e4a8 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml @@ -27,11 +27,13 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Test-FDD-10MHz-CDRX-TM1 tasks +100000 111110 040101 030112 040301 040512 040612 040650 040401 040201 030201 +200000 @@ -41,6 +43,18 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml 0 oai-enb + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -E + Deploy_Object diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml index 092ee208d1..e57e40cb1f 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml @@ -27,12 +27,14 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Test-FDD-20MHz-TM1 tasks +100000 111110 040101 030121 000001 040301 040521 040623 040624 040625 040662 040401 040201 030201 +200000 @@ -42,6 +44,18 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml 0 oai-enb + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + hutch + sudo cpupower idle-set -E + Deploy_Object diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml index fa191cd163..9f3bedba9e 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml @@ -27,11 +27,13 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm1.xml Test-TDD-05MHz-TM1 tasks +100000 111110 040101 030104 040301 040501 040602 040601 040603 040604 040605 040642 040641 040643 040644 040645 040401 040201 030201 +200000 @@ -41,6 +43,18 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm1.xml 0 oai-enb + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -E + Deploy_Object diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm2.xml b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm2.xml index 69997c5586..d8f87b4741 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm2.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm2.xml @@ -27,11 +27,13 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm2.xml Test-TDD-05MHz-TM2 tasks +100000 111110 040101 030105 040301 040502 040606 040608 040646 040648 040401 040201 030201 +200000 @@ -41,7 +43,18 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm2.xml 0 oai-enb - + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -E + Deploy_Object Deploy eNB (TDD/Band40/5MHz/B200) in a container diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml index ada6945aad..fe47e7c958 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml @@ -27,11 +27,13 @@ Replaces xml_files/enb_usrp210_band40_test_10mhz_tm1.xml Test-TDD-10MHz-TM1 tasks +100000 111110 040101 030114 040301 040511 040612 040611 040613 040614 040615 040652 040651 040653 040654 040655 040401 040201 030201 +200000 @@ -41,7 +43,18 @@ Replaces xml_files/enb_usrp210_band40_test_10mhz_tm1.xml 0 oai-enb - + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -E + Deploy_Object Deploy eNB (TDD/Band40/10MHz/B200) in a container diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml index ec3de1a5ae..51c4f95137 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml @@ -27,11 +27,13 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1.xml Test-TDD-20MHz-TM1 tasks +100000 111110 040101 030124 040301 040521 040622 040621 040623 040662 040401 040201 030201 +200000 @@ -41,7 +43,18 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1.xml 0 oai-enb - + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -E + Deploy_Object Deploy eNB (TDD/Band40/20MHz/B200) in a container diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml index b5ff90e112..57ebb79fac 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml @@ -27,11 +27,13 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1_default_scheduler.xml Test-TDD-20MHz-TM1-Default-Scheduler tasks +100000 111110 040101 030125 040301 040522 040627 040626 040628 040629 040630 040667 040666 040668 040669 040670 040401 040201 030201 +200000 @@ -41,7 +43,18 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1_default_scheduler.xml 0 oai-enb - + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower + starsky + sudo cpupower idle-set -E + Deploy_Object Deploy eNB (TDD/Band40/20MHz/B200) in a container diff --git a/ci-scripts/xml_files/container_nsa_b200_quectel.xml b/ci-scripts/xml_files/container_nsa_b200_quectel.xml index 3734c91229..397e6aadbd 100644 --- a/ci-scripts/xml_files/container_nsa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_nsa_b200_quectel.xml @@ -26,6 +26,9 @@ tasks 1 + 200000 + 100000 + 500000 111110 111111 000001 @@ -47,6 +50,8 @@ 000001 030202 030201 + 300000 + 600000 @@ -69,7 +74,36 @@ Initialize Quectel idefix - + + Custom_Command + To reset USRP + nepes + sudo -S b2xx_fx3_utils --reset-device + + + Custom_Command + To reset cpupower - nepes + nepes + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower - nepes + nepes + sudo cpupower idle-set -E + + + Custom_Command + To reset cpupower - obelix + obelix + sudo cpupower idle-set -D 0 + + + Custom_Command + To reset cpupower - obelix + obelix + sudo cpupower idle-set -E + Terminate_UE diff --git a/ci-scripts/xml_files/container_sa_b200_quectel.xml b/ci-scripts/xml_files/container_sa_b200_quectel.xml index 53cfbf80cb..4f0e01c692 100644 --- a/ci-scripts/xml_files/container_sa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_b200_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 100000 111111 010002 030101 @@ -39,6 +40,7 @@ 010002 000001 030201 + 200000