Merge remote-tracking branch 'origin/ci-collect-ue-logs' into integration_2025_w32 (!3560)
CI: Refactor log collection, collect also (COTS) UE logs Refactor log handling in CI: collect according to currently used XML files. This makes it homogeneous in the pipelines, and avoids accidental overwriting (as happens in phytest-timing), as well as harmonizing the log placement (e.g., no YAML lookup in Ping/Iperf). Allow to trace and archive UE logs (e.g., Quectel via QLog, Amarisoft UE logs). By default, no logs will be collected as of this MR, as many files are big. Various cleanup in Jenkinsfiles, some bugfixes, add unit tests.
This commit is contained in:
@@ -216,24 +216,6 @@ pipeline {
|
|||||||
}
|
}
|
||||||
stage('Log Collection') {
|
stage('Log Collection') {
|
||||||
parallel {
|
parallel {
|
||||||
stage('Log Collection (eNB - Build)') {
|
|
||||||
steps {
|
|
||||||
withCredentials([
|
|
||||||
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
|
|
||||||
]) {
|
|
||||||
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
|
|
||||||
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
|
|
||||||
|
|
||||||
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
|
|
||||||
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
|
|
||||||
}
|
|
||||||
script {
|
|
||||||
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
|
|
||||||
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Log Collection (eNB - Run)') {
|
stage('Log Collection (eNB - Run)') {
|
||||||
steps {
|
steps {
|
||||||
withCredentials([
|
withCredentials([
|
||||||
|
|||||||
@@ -222,24 +222,6 @@ pipeline {
|
|||||||
}
|
}
|
||||||
stage('Log Collection') {
|
stage('Log Collection') {
|
||||||
parallel {
|
parallel {
|
||||||
stage('Log Collection (eNB - Build)') {
|
|
||||||
steps {
|
|
||||||
withCredentials([
|
|
||||||
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
|
|
||||||
]) {
|
|
||||||
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
|
|
||||||
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
|
|
||||||
|
|
||||||
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
|
|
||||||
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
|
|
||||||
}
|
|
||||||
script {
|
|
||||||
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
|
|
||||||
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Log Collection (eNB - Run)') {
|
stage('Log Collection (eNB - Run)') {
|
||||||
steps {
|
steps {
|
||||||
withCredentials([
|
withCredentials([
|
||||||
|
|||||||
@@ -210,24 +210,6 @@ pipeline {
|
|||||||
}
|
}
|
||||||
stage('Log Collection') {
|
stage('Log Collection') {
|
||||||
parallel {
|
parallel {
|
||||||
stage('Log Collection (eNB - Build)') {
|
|
||||||
steps {
|
|
||||||
withCredentials([
|
|
||||||
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
|
|
||||||
]) {
|
|
||||||
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
|
|
||||||
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
|
|
||||||
|
|
||||||
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
|
|
||||||
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
|
|
||||||
}
|
|
||||||
script {
|
|
||||||
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
|
|
||||||
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Log Collection (eNB - Run)') {
|
stage('Log Collection (eNB - Run)') {
|
||||||
steps {
|
steps {
|
||||||
withCredentials([
|
withCredentials([
|
||||||
|
|||||||
@@ -227,24 +227,6 @@ pipeline {
|
|||||||
}
|
}
|
||||||
stage('Log Collection') {
|
stage('Log Collection') {
|
||||||
parallel {
|
parallel {
|
||||||
stage('Log Collection (eNB - Build)') {
|
|
||||||
steps {
|
|
||||||
withCredentials([
|
|
||||||
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password']
|
|
||||||
]) {
|
|
||||||
echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m'
|
|
||||||
sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}"
|
|
||||||
|
|
||||||
echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m'
|
|
||||||
sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true"
|
|
||||||
}
|
|
||||||
script {
|
|
||||||
if(fileExists("build.log.${env.BUILD_ID}.zip")) {
|
|
||||||
archiveArtifacts "build.log.${env.BUILD_ID}.zip"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Log Collection (eNB - Run)') {
|
stage('Log Collection (eNB - Run)') {
|
||||||
steps {
|
steps {
|
||||||
withCredentials([
|
withCredentials([
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ idefix:
|
|||||||
AttachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 wup
|
AttachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 wup
|
||||||
DetachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 detach
|
DetachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 detach
|
||||||
NetworkScript: ip a show dev wwan0
|
NetworkScript: ip a show dev wwan0
|
||||||
|
#Tracing:
|
||||||
|
# Start: 'sudo rm -f ci_qlog/*; nohup sudo -b QLog/QLog -s ci_qlog -f NR5G.cfg &'
|
||||||
|
# Stop: 'sudo killall QLog'
|
||||||
|
# Collect: 'sudo mv ci_qlog/* %%log_dir%%/'
|
||||||
IF: wwan0
|
IF: wwan0
|
||||||
MTU: 1500
|
MTU: 1500
|
||||||
Trace: True
|
|
||||||
LogStore: /media/usb-drive/ci_qlogs
|
|
||||||
|
|
||||||
up2:
|
up2:
|
||||||
Host: up2
|
Host: up2
|
||||||
@@ -46,7 +48,6 @@ adb_ue_1:
|
|||||||
NetworkScript: adb -s R3CM40LZPHT shell "ip address show | grep rmnet_data0"
|
NetworkScript: adb -s R3CM40LZPHT shell "ip address show | grep rmnet_data0"
|
||||||
CmdPrefix: adb -s R3CM40LZPHT shell
|
CmdPrefix: adb -s R3CM40LZPHT shell
|
||||||
MTU: 1500
|
MTU: 1500
|
||||||
LogStore: /media/usb-drive/ci_adb_1-logs
|
|
||||||
adb_ue_2:
|
adb_ue_2:
|
||||||
Host: nano
|
Host: nano
|
||||||
InitScript: /home/oaicicd/ci_ctl_adb.sh initialize 5200c00db4413517
|
InitScript: /home/oaicicd/ci_ctl_adb.sh initialize 5200c00db4413517
|
||||||
@@ -59,7 +60,6 @@ adb_ue_2:
|
|||||||
NetworkScript: adb -s 5200c00db4413517 shell "ip address show | grep rmnet"
|
NetworkScript: adb -s 5200c00db4413517 shell "ip address show | grep rmnet"
|
||||||
CmdPrefix: adb -s 5200c00db4413517 shell
|
CmdPrefix: adb -s 5200c00db4413517 shell
|
||||||
MTU: 1500
|
MTU: 1500
|
||||||
LogStore: /media/usb-drive/ci_adb_2-logs
|
|
||||||
|
|
||||||
oc-cn5g:
|
oc-cn5g:
|
||||||
Host: avra
|
Host: avra
|
||||||
@@ -150,6 +150,10 @@ amarisoft_ue:
|
|||||||
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz/aw2s-multi-00102-20.cfg &
|
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz/aw2s-multi-00102-20.cfg &
|
||||||
TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2
|
TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2
|
||||||
NetworkScript: ip netns exec ue1 ip a show dev pdn0
|
NetworkScript: ip netns exec ue1 ip a show dev pdn0
|
||||||
|
#Tracing:
|
||||||
|
# Start: '' # nothing to be done
|
||||||
|
# Stop: '' # nothing to be done
|
||||||
|
# Collect: 'cp /tmp/ue.log %%log_dir%%'
|
||||||
amarisoft_ue_2x2:
|
amarisoft_ue_2x2:
|
||||||
Host: amariue
|
Host: amariue
|
||||||
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz_2x2/aw2s-multi-00102-2x2-v2.cfg &
|
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz_2x2/aw2s-multi-00102-2x2-v2.cfg &
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class Analysis():
|
|||||||
|
|
||||||
return success,msg
|
return success,msg
|
||||||
|
|
||||||
def analyze_oc_physim(result_junit, details_json):
|
def analyze_oc_physim(result_junit, details_json, logPath):
|
||||||
try:
|
try:
|
||||||
tree = ET.parse(result_junit)
|
tree = ET.parse(result_junit)
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
@@ -124,7 +124,7 @@ class Analysis():
|
|||||||
output = test.findtext("system-out")
|
output = test.findtext("system-out")
|
||||||
output_check = "exceeds the threshold" not in output
|
output_check = "exceeds the threshold" not in output
|
||||||
# collect logs
|
# collect logs
|
||||||
log_dir = f'../cmake_targets/log/{test_exec}'
|
log_dir = f'{logPath}/{test_exec}'
|
||||||
os.makedirs(log_dir, exist_ok=True)
|
os.makedirs(log_dir, exist_ok=True)
|
||||||
with open(f'{log_dir}/{test_name}.log', 'w') as f:
|
with open(f'{log_dir}/{test_name}.log', 'w') as f:
|
||||||
f.write(output)
|
f.write(output)
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#/*
|
||||||
|
# * 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
|
||||||
|
# */
|
||||||
|
|
||||||
|
import os
|
||||||
|
from typing import NamedTuple
|
||||||
|
import logging
|
||||||
|
|
||||||
|
class TestCaseCtx(NamedTuple):
|
||||||
|
count: int
|
||||||
|
test_id: int
|
||||||
|
logPath: str
|
||||||
|
|
||||||
|
def Default(logPath):
|
||||||
|
return TestCaseCtx(123, 112233, logPath)
|
||||||
|
def baseFilename(self):
|
||||||
|
# typically, the test ID is of form 001234 (6 digits)
|
||||||
|
return f"{self.logPath}/{self.count}-{self.test_id:06d}"
|
||||||
|
|
||||||
|
def archiveArtifact(cmd, ctx, remote_path):
|
||||||
|
base = os.path.basename(remote_path)
|
||||||
|
local = f"{ctx.baseFilename()}-{base}"
|
||||||
|
logging.info(f"Archive artifact '{local}'")
|
||||||
|
success = cmd.copyin(remote_path, local)
|
||||||
|
if success:
|
||||||
|
cmd.run(f'rm {remote_path}', silent=True)
|
||||||
|
return local if success else None
|
||||||
+57
-52
@@ -39,6 +39,7 @@ import constants as CONST
|
|||||||
import helpreadme as HELP
|
import helpreadme as HELP
|
||||||
import cls_containerize
|
import cls_containerize
|
||||||
import cls_cmd
|
import cls_cmd
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
IMAGE_REGISTRY_SERVICE_NAME = "image-registry.openshift-image-registry.svc"
|
IMAGE_REGISTRY_SERVICE_NAME = "image-registry.openshift-image-registry.svc"
|
||||||
NAMESPACE = "oaicicd-ran"
|
NAMESPACE = "oaicicd-ran"
|
||||||
@@ -207,7 +208,12 @@ class Cluster:
|
|||||||
HTML.CreateHtmlTestRowQueue(param, 'KO', [msg])
|
HTML.CreateHtmlTestRowQueue(param, 'KO', [msg])
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def BuildClusterImage(self, HTML):
|
def _retrieveOCLog(self, ctx, job, lSourcePath, image):
|
||||||
|
fn = f'{lSourcePath}/cmake_targets/log/{image}.log'
|
||||||
|
self.cmd.run(f'oc logs {job} &> {fn}')
|
||||||
|
return (image, archiveArtifact(self.cmd, ctx, fn))
|
||||||
|
|
||||||
|
def BuildClusterImage(self, ctx, HTML):
|
||||||
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
|
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
|
||||||
HELP.GenericHelp(CONST.Version)
|
HELP.GenericHelp(CONST.Version)
|
||||||
raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {ranBranch} ranCommitID {self.ranCommitID}')
|
raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {ranBranch} ranCommitID {self.ranCommitID}')
|
||||||
@@ -280,22 +286,27 @@ class Cluster:
|
|||||||
self._recreate_entitlements()
|
self._recreate_entitlements()
|
||||||
|
|
||||||
status = True # flag to abandon compiling if any image fails
|
status = True # flag to abandon compiling if any image fails
|
||||||
attemptedImages = []
|
log_files = []
|
||||||
|
build_metrics = f"{lSourcePath}/cmake_targets/log/build-metrics.log"
|
||||||
if forceBaseImageBuild:
|
if forceBaseImageBuild:
|
||||||
self._recreate_is_tag('ran-base', baseTag, 'openshift/ran-base-is.yaml')
|
self._recreate_is_tag('ran-base', baseTag, 'openshift/ran-base-is.yaml')
|
||||||
self._recreate_bc('ran-base', baseTag, 'openshift/ran-base-bc.yaml')
|
self._recreate_bc('ran-base', baseTag, 'openshift/ran-base-bc.yaml')
|
||||||
ranbase_job = self._start_build('ran-base')
|
ranbase_job = self._start_build('ran-base')
|
||||||
attemptedImages += ['ran-base']
|
|
||||||
status = ranbase_job is not None and self._wait_build_end([ranbase_job], 1000)
|
status = ranbase_job is not None and self._wait_build_end([ranbase_job], 1000)
|
||||||
if not status: logging.error('failure during build of ran-base')
|
if not status: logging.error('failure during build of ran-base')
|
||||||
self.cmd.run(f'oc logs {ranbase_job} &> cmake_targets/log/ran-base.log') # cannot use cmd.run because of redirect
|
log_files.append(self._retrieveOCLog(ctx, ranbase_job, lSourcePath, 'ran-base'))
|
||||||
|
|
||||||
# recover logs by mounting image
|
# recover logs by mounting image
|
||||||
self._retag_image_statement('ran-base', 'ran-base', baseTag, 'openshift/ran-base-log-retrieval.yaml')
|
self._retag_image_statement('ran-base', 'ran-base', baseTag, 'openshift/ran-base-log-retrieval.yaml')
|
||||||
pod = self._deploy_pod('openshift/ran-base-log-retrieval.yaml')
|
pod = self._deploy_pod('openshift/ran-base-log-retrieval.yaml')
|
||||||
if pod is not None:
|
if pod is not None:
|
||||||
self.cmd.run(f'mkdir -p cmake_targets/log/ran-base')
|
logdir = f'{lSourcePath}/cmake_targets/log/ran-base'
|
||||||
self.cmd.run(f'oc rsync {pod}:/oai-ran/cmake_targets/log/ cmake_targets/log/ran-base')
|
self.cmd.run(f'mkdir -p {logdir}')
|
||||||
|
self.cmd.run(f'oc rsync {pod}:/oai-ran/cmake_targets/log/ {logdir}')
|
||||||
self._undeploy_pod('openshift/ran-base-log-retrieval.yaml')
|
self._undeploy_pod('openshift/ran-base-log-retrieval.yaml')
|
||||||
|
ret = self.cmd.run(f'ls {logdir}')
|
||||||
|
for f in ret.stdout.splitlines():
|
||||||
|
archiveArtifact(self.cmd, ctx, f"{logdir}/{f}")
|
||||||
else:
|
else:
|
||||||
status = False
|
status = False
|
||||||
|
|
||||||
@@ -304,27 +315,24 @@ class Cluster:
|
|||||||
self._recreate_bc('oai-physim', imageTag, 'openshift/oai-physim-bc.yaml')
|
self._recreate_bc('oai-physim', imageTag, 'openshift/oai-physim-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.phySim.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.phySim.rhel9')
|
||||||
physim_job = self._start_build('oai-physim')
|
physim_job = self._start_build('oai-physim')
|
||||||
attemptedImages += ['oai-physim']
|
|
||||||
|
|
||||||
self._recreate_is_tag('ran-build', imageTag, 'openshift/ran-build-is.yaml')
|
self._recreate_is_tag('ran-build', imageTag, 'openshift/ran-build-is.yaml')
|
||||||
self._recreate_bc('ran-build', imageTag, 'openshift/ran-build-bc.yaml')
|
self._recreate_bc('ran-build', imageTag, 'openshift/ran-build-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.rhel9')
|
||||||
ranbuild_job = self._start_build('ran-build')
|
ranbuild_job = self._start_build('ran-build')
|
||||||
attemptedImages += ['ran-build']
|
|
||||||
|
|
||||||
self._recreate_is_tag('oai-clang', imageTag, 'openshift/oai-clang-is.yaml')
|
self._recreate_is_tag('oai-clang', imageTag, 'openshift/oai-clang-is.yaml')
|
||||||
self._recreate_bc('oai-clang', imageTag, 'openshift/oai-clang-bc.yaml')
|
self._recreate_bc('oai-clang', imageTag, 'openshift/oai-clang-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.clang.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.clang.rhel9')
|
||||||
clang_job = self._start_build('oai-clang')
|
clang_job = self._start_build('oai-clang')
|
||||||
attemptedImages += ['oai-clang']
|
|
||||||
|
|
||||||
wait = ranbuild_job is not None and physim_job is not None and clang_job is not None and self._wait_build_end([ranbuild_job, physim_job, clang_job], 1200)
|
wait = ranbuild_job is not None and physim_job is not None and clang_job is not None and self._wait_build_end([ranbuild_job, physim_job, clang_job], 1200)
|
||||||
if not wait: logging.error('error during build of ranbuild_job or physim_job or clang_job')
|
if not wait: logging.error('error during build of ranbuild_job or physim_job or clang_job')
|
||||||
status = status and wait
|
status = status and wait
|
||||||
self.cmd.run(f'oc logs {ranbuild_job} &> cmake_targets/log/ran-build.log')
|
log_files.append(self._retrieveOCLog(ctx, ranbuild_job, lSourcePath, 'ran-build'))
|
||||||
self.cmd.run(f'oc logs {physim_job} &> cmake_targets/log/oai-physim.log')
|
log_files.append(self._retrieveOCLog(ctx, physim_job, lSourcePath, 'oai-physim'))
|
||||||
self.cmd.run(f'oc logs {clang_job} &> cmake_targets/log/oai-clang.log')
|
log_files.append(self._retrieveOCLog(ctx, clang_job, lSourcePath, 'oai-clang'))
|
||||||
self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
|
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
|
||||||
|
|
||||||
if status:
|
if status:
|
||||||
self._recreate_is_tag('oai-enb', imageTag, 'openshift/oai-enb-is.yaml')
|
self._recreate_is_tag('oai-enb', imageTag, 'openshift/oai-enb-is.yaml')
|
||||||
@@ -332,72 +340,66 @@ class Cluster:
|
|||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.eNB.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.eNB.rhel9')
|
||||||
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.eNB.rhel9')
|
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.eNB.rhel9')
|
||||||
enb_job = self._start_build('oai-enb')
|
enb_job = self._start_build('oai-enb')
|
||||||
attemptedImages += ['oai-enb']
|
|
||||||
|
|
||||||
self._recreate_is_tag('oai-gnb', imageTag, 'openshift/oai-gnb-is.yaml')
|
self._recreate_is_tag('oai-gnb', imageTag, 'openshift/oai-gnb-is.yaml')
|
||||||
self._recreate_bc('oai-gnb', imageTag, 'openshift/oai-gnb-bc.yaml')
|
self._recreate_bc('oai-gnb', imageTag, 'openshift/oai-gnb-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.rhel9')
|
||||||
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.rhel9')
|
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.rhel9')
|
||||||
gnb_job = self._start_build('oai-gnb')
|
gnb_job = self._start_build('oai-gnb')
|
||||||
attemptedImages += ['oai-gnb']
|
|
||||||
|
|
||||||
self._recreate_is_tag('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-is.yaml')
|
self._recreate_is_tag('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-is.yaml')
|
||||||
self._recreate_bc('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-bc.yaml')
|
self._recreate_bc('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
|
||||||
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
|
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.aw2s.rhel9')
|
||||||
gnb_aw2s_job = self._start_build('oai-gnb-aw2s')
|
gnb_aw2s_job = self._start_build('oai-gnb-aw2s')
|
||||||
attemptedImages += ['oai-gnb-aw2s']
|
|
||||||
|
|
||||||
wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 800)
|
wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 800)
|
||||||
if not wait: logging.error('error during build of eNB/gNB')
|
if not wait: logging.error('error during build of eNB/gNB')
|
||||||
status = status and wait
|
status = status and wait
|
||||||
# recover logs
|
# recover logs
|
||||||
self.cmd.run(f'oc logs {enb_job} &> cmake_targets/log/oai-enb.log')
|
log_files.append(self._retrieveOCLog(ctx, enb_job, lSourcePath, 'oai-enb'))
|
||||||
self.cmd.run(f'oc logs {gnb_job} &> cmake_targets/log/oai-gnb.log')
|
log_files.append(self._retrieveOCLog(ctx, gnb_job, lSourcePath, 'oai-gnb'))
|
||||||
self.cmd.run(f'oc logs {gnb_aw2s_job} &> cmake_targets/log/oai-gnb-aw2s.log')
|
log_files.append(self._retrieveOCLog(ctx, gnb_aw2s_job, lSourcePath, 'oai-gnb-aw2s'))
|
||||||
|
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
|
||||||
|
|
||||||
self._recreate_is_tag('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-is.yaml')
|
self._recreate_is_tag('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-is.yaml')
|
||||||
self._recreate_bc('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-bc.yaml')
|
self._recreate_bc('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nr-cuup.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nr-cuup.rhel9')
|
||||||
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nr-cuup.rhel9')
|
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nr-cuup.rhel9')
|
||||||
nr_cuup_job = self._start_build('oai-nr-cuup')
|
nr_cuup_job = self._start_build('oai-nr-cuup')
|
||||||
attemptedImages += ['oai-nr-cuup']
|
|
||||||
|
|
||||||
self._recreate_is_tag('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-is.yaml')
|
self._recreate_is_tag('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-is.yaml')
|
||||||
self._recreate_bc('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-bc.yaml')
|
self._recreate_bc('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.lteUE.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.lteUE.rhel9')
|
||||||
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.lteUE.rhel9')
|
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.lteUE.rhel9')
|
||||||
lteue_job = self._start_build('oai-lte-ue')
|
lteue_job = self._start_build('oai-lte-ue')
|
||||||
attemptedImages += ['oai-lte-ue']
|
|
||||||
|
|
||||||
self._recreate_is_tag('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-is.yaml')
|
self._recreate_is_tag('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-is.yaml')
|
||||||
self._recreate_bc('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-bc.yaml')
|
self._recreate_bc('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nrUE.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nrUE.rhel9')
|
||||||
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nrUE.rhel9')
|
self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nrUE.rhel9')
|
||||||
nrue_job = self._start_build('oai-nr-ue')
|
nrue_job = self._start_build('oai-nr-ue')
|
||||||
attemptedImages += ['oai-nr-ue']
|
|
||||||
|
|
||||||
wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800)
|
wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800)
|
||||||
if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE')
|
if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE')
|
||||||
status = status and wait
|
status = status and wait
|
||||||
# recover logs
|
# recover logs
|
||||||
self.cmd.run(f'oc logs {nr_cuup_job} &> cmake_targets/log/oai-nr-cuup.log')
|
log_files.append(self._retrieveOCLog(ctx, nr_cuup_job, lSourcePath, 'oai-nr-cuup'))
|
||||||
self.cmd.run(f'oc logs {lteue_job} &> cmake_targets/log/oai-lte-ue.log')
|
log_files.append(self._retrieveOCLog(ctx, lteue_job, lSourcePath, 'oai-lte-ue'))
|
||||||
self.cmd.run(f'oc logs {nrue_job} &> cmake_targets/log/oai-nr-ue.log')
|
log_files.append(self._retrieveOCLog(ctx, nrue_job, lSourcePath, 'oai-nr-ue'))
|
||||||
self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
|
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
|
||||||
|
|
||||||
if status:
|
if status:
|
||||||
self._recreate_is_tag('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-is.yaml')
|
self._recreate_is_tag('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-is.yaml')
|
||||||
self._recreate_bc('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-bc.yaml')
|
self._recreate_bc('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-bc.yaml')
|
||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.fhi72.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.fhi72.rhel9')
|
||||||
ranbuildfhi72_job = self._start_build('ran-build-fhi72')
|
ranbuildfhi72_job = self._start_build('ran-build-fhi72')
|
||||||
attemptedImages += ['ran-build-fhi72']
|
|
||||||
|
|
||||||
wait = ranbuildfhi72_job is not None and self._wait_build_end([ranbuildfhi72_job], 1200)
|
wait = ranbuildfhi72_job is not None and self._wait_build_end([ranbuildfhi72_job], 1200)
|
||||||
if not wait: logging.error('error during build of ranbuildfhi72_job')
|
if not wait: logging.error('error during build of ranbuildfhi72_job')
|
||||||
status = status and wait
|
status = status and wait
|
||||||
self.cmd.run(f'oc logs {ranbuildfhi72_job} &> cmake_targets/log/ran-build-fhi72.log')
|
log_files.append(self._retrieveOCLog(ctx, ranbuildfhi72_job, lSourcePath, 'ran-build-fhi72'))
|
||||||
self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
|
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
|
||||||
|
|
||||||
if status:
|
if status:
|
||||||
self._recreate_is_tag('oai-gnb-fhi72', imageTag, 'openshift/oai-gnb-fhi72-is.yaml')
|
self._recreate_is_tag('oai-gnb-fhi72', imageTag, 'openshift/oai-gnb-fhi72-is.yaml')
|
||||||
@@ -405,19 +407,17 @@ class Cluster:
|
|||||||
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.fhi72.rhel9')
|
self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.fhi72.rhel9')
|
||||||
self._retag_image_statement('ran-build-fhi72', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build-fhi72', imageTag, 'docker/Dockerfile.gNB.fhi72.rhel9')
|
self._retag_image_statement('ran-build-fhi72', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build-fhi72', imageTag, 'docker/Dockerfile.gNB.fhi72.rhel9')
|
||||||
gnb_fhi72_job = self._start_build('oai-gnb-fhi72')
|
gnb_fhi72_job = self._start_build('oai-gnb-fhi72')
|
||||||
attemptedImages += ['oai-gnb-fhi72']
|
|
||||||
|
|
||||||
wait = gnb_fhi72_job is not None and self._wait_build_end([gnb_fhi72_job], 600)
|
wait = gnb_fhi72_job is not None and self._wait_build_end([gnb_fhi72_job], 600)
|
||||||
if not wait: logging.error('error during build of gNB-fhi72')
|
if not wait: logging.error('error during build of gNB-fhi72')
|
||||||
status = status and wait
|
status = status and wait
|
||||||
# recover logs
|
# recover logs
|
||||||
self.cmd.run(f'oc logs {gnb_fhi72_job} &> cmake_targets/log/oai-gnb-fhi72.log')
|
log_files.append(self._retrieveOCLog(ctx, gnb_fhi72_job, lSourcePath, 'oai-gnb-fhi72'))
|
||||||
self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log')
|
self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}')
|
||||||
|
|
||||||
# split and analyze logs
|
# split and analyze logs
|
||||||
imageSize = {}
|
imageSize = {}
|
||||||
for image in attemptedImages:
|
for image, _ in log_files:
|
||||||
self.cmd.run(f'mkdir -p cmake_targets/log/{image}')
|
|
||||||
tag = imageTag if image != 'ran-base' else baseTag
|
tag = imageTag if image != 'ran-base' else baseTag
|
||||||
size = self._get_image_size(image, tag)
|
size = self._get_image_size(image, tag)
|
||||||
if size <= 0:
|
if size <= 0:
|
||||||
@@ -428,12 +428,14 @@ class Cluster:
|
|||||||
imageSize[image] = f'{sizeMb:.1f} Mbytes (uncompressed: ~{sizeMb*2.5:.1f} Mbytes)'
|
imageSize[image] = f'{sizeMb:.1f} Mbytes (uncompressed: ~{sizeMb*2.5:.1f} Mbytes)'
|
||||||
logging.info(f'\u001B[1m{image} size is {imageSize[image]}\u001B[0m')
|
logging.info(f'\u001B[1m{image} size is {imageSize[image]}\u001B[0m')
|
||||||
|
|
||||||
grep_exp = r"\|".join(attemptedImages)
|
archiveArtifact(self.cmd, ctx, build_metrics)
|
||||||
self.cmd.run(f'oc get images | grep -e \'{grep_exp}\' &> cmake_targets/log/image_registry.log');
|
logfile = f'{lSourcePath}/cmake_targets/log/image_registry.log'
|
||||||
self.cmd.run(f'for pod in $(oc get pods | tail -n +2 | awk \'{{print $1}}\'); do oc get pod $pod -o json &>> cmake_targets/log/build_pod_summary.log; done')
|
grep_exp = r"\|".join([i for i,f in log_files])
|
||||||
|
self.cmd.run(f'oc get images | grep -e \'{grep_exp}\' &> {logfile}');
|
||||||
build_log_name = f'build_log_{self.testCase_id}'
|
archiveArtifact(self.cmd, ctx, logfile)
|
||||||
cls_containerize.CopyLogsToExecutor(self.cmd, lSourcePath, build_log_name)
|
logfile = f'{lSourcePath}/cmake_targets/log/build_pod_summary.log'
|
||||||
|
self.cmd.run(f'for pod in $(oc get pods | tail -n +2 | awk \'{{print $1}}\'); do oc get pod $pod -o json &>> {logfile}; done')
|
||||||
|
archiveArtifact(self.cmd, ctx, logfile)
|
||||||
|
|
||||||
self.cmd.run('for pod in $(oc get pods | tail -n +2 | awk \'{print $1}\'); do oc delete pod ${pod}; done')
|
self.cmd.run('for pod in $(oc get pods | tail -n +2 | awk \'{print $1}\'); do oc delete pod ${pod}; done')
|
||||||
|
|
||||||
@@ -442,7 +444,7 @@ class Cluster:
|
|||||||
self.cmd.close()
|
self.cmd.close()
|
||||||
|
|
||||||
# Analyze the logs
|
# Analyze the logs
|
||||||
collectInfo = cls_containerize.AnalyzeBuildLogs(build_log_name, attemptedImages, status)
|
collectInfo = cls_containerize.AnalyzeBuildLogs(log_files, status)
|
||||||
for img in collectInfo:
|
for img in collectInfo:
|
||||||
for f in collectInfo[img]:
|
for f in collectInfo[img]:
|
||||||
status = status and collectInfo[img][f]['status']
|
status = status and collectInfo[img][f]['status']
|
||||||
@@ -458,9 +460,16 @@ class Cluster:
|
|||||||
|
|
||||||
HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, imageSize)
|
HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, imageSize)
|
||||||
|
|
||||||
|
# TODO fix groovy script, remove the following.
|
||||||
|
# the groovy scripts expects all logs in
|
||||||
|
# <jenkins-workspace>/<pipeline>/ci-scripts, so copy it there
|
||||||
|
with cls_cmd.LocalCmd() as c:
|
||||||
|
c.run(f'mkdir -p {os.getcwd()}/test_log_{ctx.test_id}/')
|
||||||
|
c.run(f'cp -r {ctx.logPath} {os.getcwd()}/test_log_{ctx.test_id}/')
|
||||||
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def deploy_oc_physim(self, HTML, oc_release, svr_id):
|
def deploy_oc_physim(self, ctx, HTML, oc_release, svr_id):
|
||||||
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
|
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
|
||||||
HELP.GenericHelp(CONST.Version)
|
HELP.GenericHelp(CONST.Version)
|
||||||
raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {self.ranBranch} ranCommitID {self.ranCommitID}')
|
raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {self.ranBranch} ranCommitID {self.ranCommitID}')
|
||||||
@@ -470,17 +479,13 @@ class Cluster:
|
|||||||
options = f"oaicicd-core-for-ci-ran {oc_release} {image_tag} {self.eNBSourceCodePath}"
|
options = f"oaicicd-core-for-ci-ran {oc_release} {image_tag} {self.eNBSourceCodePath}"
|
||||||
ret = cls_cmd.runScript(svr_id, script, 600, options)
|
ret = cls_cmd.runScript(svr_id, script, 600, options)
|
||||||
logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}')
|
logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}')
|
||||||
log_dir = f'{os.getcwd()}/../cmake_targets/log'
|
|
||||||
os.makedirs(log_dir, exist_ok=True)
|
|
||||||
result_junit = f'{oc_release}-run.xml'
|
|
||||||
details_json = f'{oc_release}-tests.json'
|
|
||||||
with cls_cmd.getConnection(svr_id) as ssh:
|
with cls_cmd.getConnection(svr_id) as ssh:
|
||||||
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/{details_json}', tgt=f'{log_dir}/{details_json}')
|
details_json = archiveArtifact(ssh, ctx, f'{self.eNBSourceCodePath}/ci-scripts/{oc_release}-tests.json')
|
||||||
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/{result_junit}', tgt=f'{log_dir}/{result_junit}')
|
result_junit = archiveArtifact(ssh, ctx, f'{self.eNBSourceCodePath}/ci-scripts/{oc_release}-run.xml')
|
||||||
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/physim_log.txt', tgt=f'{log_dir}/physim_log.txt')
|
archiveArtifact(ssh, ctx, f'{self.eNBSourceCodePath}/ci-scripts/physim_log.txt')
|
||||||
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/physim_pods_summary.txt', tgt=f'{log_dir}/physim_pods_summary.txt')
|
archiveArtifact(ssh, ctx, f'{self.eNBSourceCodePath}/ci-scripts/physim_pods_summary.txt')
|
||||||
ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/LastTestsFailed.log', tgt=f'{log_dir}/LastTestsFailed.log')
|
archiveArtifact(ssh, ctx, f'{self.eNBSourceCodePath}/ci-scripts/LastTestsFailed.log')
|
||||||
test_status, test_summary, test_result = cls_analysis.Analysis.analyze_oc_physim(f'{log_dir}/{result_junit}', f'{log_dir}/{details_json}')
|
test_status, test_summary, test_result = cls_analysis.Analysis.analyze_oc_physim(result_junit, details_json, ctx.logPath)
|
||||||
if test_summary:
|
if test_summary:
|
||||||
if test_status:
|
if test_status:
|
||||||
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
|
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
|
||||||
|
|||||||
+80
-129
@@ -46,6 +46,7 @@ import cls_cmd
|
|||||||
import helpreadme as HELP
|
import helpreadme as HELP
|
||||||
import constants as CONST
|
import constants as CONST
|
||||||
import cls_oaicitest
|
import cls_oaicitest
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
# Helper functions used here and in other classes
|
# Helper functions used here and in other classes
|
||||||
@@ -81,67 +82,26 @@ def CreateTag(ranCommitID, ranBranch, ranAllowMerge):
|
|||||||
tagToUse = f'develop-{shortCommit}'
|
tagToUse = f'develop-{shortCommit}'
|
||||||
return tagToUse
|
return tagToUse
|
||||||
|
|
||||||
def CopyLogsToExecutor(cmd, sourcePath, log_name):
|
def AnalyzeBuildLogs(logfiles, globalStatus):
|
||||||
cmd.cd(f'{sourcePath}/cmake_targets')
|
|
||||||
cmd.run(f'rm -f {log_name}.zip')
|
|
||||||
cmd.run(f'mkdir -p {log_name}')
|
|
||||||
cmd.run(f'mv log/* {log_name}')
|
|
||||||
cmd.run(f'zip -r -qq {log_name}.zip {log_name}')
|
|
||||||
|
|
||||||
# copy zip to executor for analysis
|
|
||||||
if (os.path.isfile(f'./{log_name}.zip')):
|
|
||||||
os.remove(f'./{log_name}.zip')
|
|
||||||
if (os.path.isdir(f'./{log_name}')):
|
|
||||||
shutil.rmtree(f'./{log_name}')
|
|
||||||
cmd.copyin(src=f'{sourcePath}/cmake_targets/{log_name}.zip', tgt=f'{os.getcwd()}/{log_name}.zip')
|
|
||||||
cmd.run(f'rm -f {log_name}.zip')
|
|
||||||
ZipFile(f'{log_name}.zip').extractall('.')
|
|
||||||
|
|
||||||
def AnalyzeBuildLogs(buildRoot, images, globalStatus):
|
|
||||||
collectInfo = {}
|
collectInfo = {}
|
||||||
for image in images:
|
for image, lf in logfiles:
|
||||||
files = {}
|
files = {}
|
||||||
file_list = [f for f in os.listdir(f'{buildRoot}/{image}') if os.path.isfile(os.path.join(f'{buildRoot}/{image}', f)) and f.endswith('.txt')]
|
errorandwarnings = {}
|
||||||
# Analyze the "sub-logs" of every target image
|
committed = False
|
||||||
for fil in file_list:
|
tagged = False
|
||||||
errorandwarnings = {}
|
with open(lf, mode='r') as inputfile:
|
||||||
warningsNo = 0
|
for line in inputfile:
|
||||||
errorsNo = 0
|
lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None
|
||||||
with open(f'{buildRoot}/{image}/{fil}', mode='r') as inputfile:
|
lineHasTag2 = re.search(f'naming to docker.io/library/{image}:', str(line)) is not None
|
||||||
for line in inputfile:
|
tagged = tagged or lineHasTag or lineHasTag2
|
||||||
result = re.search(' ERROR ', str(line))
|
# the OpenShift Cluster builder prepends image registry URL
|
||||||
if result is not None:
|
lineHasCommit = re.search(r'COMMIT [a-zA-Z0-9\.:/\-]*' + image, str(line)) is not None
|
||||||
errorsNo += 1
|
committed = committed or lineHasCommit
|
||||||
result = re.search(' error:', str(line))
|
errorandwarnings['errors'] = 0 if committed or tagged else 1
|
||||||
if result is not None:
|
errorandwarnings['warnings'] = 0
|
||||||
errorsNo += 1
|
errorandwarnings['status'] = committed or tagged
|
||||||
result = re.search(' WARNING ', str(line))
|
logging.info(f"Analyzing {image}, file {lf}: {errorandwarnings}")
|
||||||
if result is not None:
|
files['Target Image Creation'] = errorandwarnings
|
||||||
warningsNo += 1
|
|
||||||
result = re.search(' warning:', str(line))
|
|
||||||
if result is not None:
|
|
||||||
warningsNo += 1
|
|
||||||
errorandwarnings['errors'] = errorsNo
|
|
||||||
errorandwarnings['warnings'] = warningsNo
|
|
||||||
errorandwarnings['status'] = globalStatus
|
|
||||||
files[fil] = errorandwarnings
|
|
||||||
# Analyze the target image
|
|
||||||
if os.path.isfile(f'{buildRoot}/{image}.log'):
|
|
||||||
errorandwarnings = {}
|
|
||||||
committed = False
|
|
||||||
tagged = False
|
|
||||||
with open(f'{buildRoot}/{image}.log', mode='r') as inputfile:
|
|
||||||
for line in inputfile:
|
|
||||||
lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None
|
|
||||||
lineHasTag2 = re.search(f'naming to docker.io/library/{image}:', str(line)) is not None
|
|
||||||
tagged = tagged or lineHasTag or lineHasTag2
|
|
||||||
# the OpenShift Cluster builder prepends image registry URL
|
|
||||||
lineHasCommit = re.search(f'COMMIT [a-zA-Z0-9\.:/\-]*{image}', str(line)) is not None
|
|
||||||
committed = committed or lineHasCommit
|
|
||||||
errorandwarnings['errors'] = 0 if committed or tagged else 1
|
|
||||||
errorandwarnings['warnings'] = 0
|
|
||||||
errorandwarnings['status'] = committed or tagged
|
|
||||||
files['Target Image Creation'] = errorandwarnings
|
|
||||||
collectInfo[image] = files
|
collectInfo[image] = files
|
||||||
return collectInfo
|
return collectInfo
|
||||||
|
|
||||||
@@ -202,12 +162,10 @@ def GetServices(ssh, requested, file):
|
|||||||
else:
|
else:
|
||||||
return requested
|
return requested
|
||||||
|
|
||||||
def CopyinServiceLog(ssh, lSourcePath, yaml, svcName, wd_yaml, filename):
|
def CopyinServiceLog(ssh, lSourcePath, svcName, wd_yaml, ctx):
|
||||||
remote_filename = f"{lSourcePath}/cmake_targets/log/{filename}"
|
remote_filename = f"{lSourcePath}/cmake_targets/log/{svcName}.logs"
|
||||||
ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}')
|
ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}')
|
||||||
local_dir = f"{os.getcwd()}/../cmake_targets/log/{yaml}"
|
return archiveArtifact(ssh, ctx, remote_filename)
|
||||||
local_filename = f"{local_dir}/{filename}"
|
|
||||||
return ssh.copyin(remote_filename, local_filename)
|
|
||||||
|
|
||||||
def GetRunningServices(ssh, file):
|
def GetRunningServices(ssh, file):
|
||||||
ret = ssh.run(f'docker compose -f {file} config --services')
|
ret = ssh.run(f'docker compose -f {file} config --services')
|
||||||
@@ -229,14 +187,13 @@ def GetRunningServices(ssh, file):
|
|||||||
logging.info(f'stopping services: {running_services}')
|
logging.info(f'stopping services: {running_services}')
|
||||||
return running_services
|
return running_services
|
||||||
|
|
||||||
def CheckLogs(self, yaml, service_name, HTML, RAN):
|
def CheckLogs(self, filename, HTML, RAN):
|
||||||
logPath = f'{os.getcwd()}/../cmake_targets/log/{yaml}'
|
|
||||||
filename = f'{logPath}/{service_name}-{HTML.testCase_id}.log'
|
|
||||||
success = True
|
success = True
|
||||||
if (any(sub in service_name for sub in ['oai_ue','oai-nr-ue','lte_ue'])):
|
name = os.path.basename(filename)
|
||||||
|
if (any(sub in name for sub in ['oai_ue','oai-nr-ue','lte_ue'])):
|
||||||
logging.debug(f'\u001B[1m Analyzing UE logfile {filename} \u001B[0m')
|
logging.debug(f'\u001B[1m Analyzing UE logfile {filename} \u001B[0m')
|
||||||
logStatus = cls_oaicitest.OaiCiTest().AnalyzeLogFile_UE(filename, HTML, RAN)
|
logStatus = cls_oaicitest.OaiCiTest().AnalyzeLogFile_UE(filename, HTML, RAN)
|
||||||
opt = f"UE log analysis for service {service_name}"
|
opt = f"UE log analysis ({name})"
|
||||||
# usage of htmlUEFailureMsg/htmleNBFailureMsg is because Analyze log files
|
# usage of htmlUEFailureMsg/htmleNBFailureMsg is because Analyze log files
|
||||||
# abuse HTML to store their reports, and we here want to put custom options,
|
# abuse HTML to store their reports, and we here want to put custom options,
|
||||||
# which is not possible with CreateHtmlTestRow
|
# which is not possible with CreateHtmlTestRow
|
||||||
@@ -247,13 +204,13 @@ def CheckLogs(self, yaml, service_name, HTML, RAN):
|
|||||||
else:
|
else:
|
||||||
HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmlUEFailureMsg])
|
HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmlUEFailureMsg])
|
||||||
HTML.htmlUEFailureMsg = ""
|
HTML.htmlUEFailureMsg = ""
|
||||||
elif service_name == 'nv-cubb':
|
elif 'nv-cubb' in name:
|
||||||
msg = 'Undeploy PNF/Nvidia CUBB'
|
msg = 'Undeploy PNF/Nvidia CUBB'
|
||||||
HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK)
|
HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK)
|
||||||
elif (any(sub in service_name for sub in ['enb','rru','rcc','cu','du','gnb'])):
|
elif (any(sub in name for sub in ['enb','rru','rcc','cu','du','gnb'])):
|
||||||
logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m')
|
logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m')
|
||||||
logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
|
logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
|
||||||
opt = f"xNB log analysis for service {service_name}"
|
opt = f"xNB log analysis ({name})"
|
||||||
if (logStatus < 0):
|
if (logStatus < 0):
|
||||||
HTML.CreateHtmlTestRowQueue(opt, 'KO', [HTML.htmleNBFailureMsg])
|
HTML.CreateHtmlTestRowQueue(opt, 'KO', [HTML.htmleNBFailureMsg])
|
||||||
success = False
|
success = False
|
||||||
@@ -261,9 +218,9 @@ def CheckLogs(self, yaml, service_name, HTML, RAN):
|
|||||||
HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmleNBFailureMsg])
|
HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmleNBFailureMsg])
|
||||||
HTML.htmleNBFailureMsg = ""
|
HTML.htmleNBFailureMsg = ""
|
||||||
else:
|
else:
|
||||||
logging.info(f'Skipping to analyze log for service name {service_name}')
|
logging.info(f"Skipping analysis of log '{filename}': no submatch for xNB/UE")
|
||||||
HTML.CreateHtmlTestRowQueue(f"service {service_name}", 'OK', ["no analysis function"])
|
HTML.CreateHtmlTestRowQueue(f"file {name}", 'OK', ["no analysis function"])
|
||||||
logging.debug(f"log check: service {service_name} passed analysis {success}")
|
logging.debug(f"log check: file {filename} passed analysis {success}")
|
||||||
return success
|
return success
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
@@ -299,8 +256,6 @@ class Containerize():
|
|||||||
self.services = ['', '', '']
|
self.services = ['', '', '']
|
||||||
self.deploymentTag = ''
|
self.deploymentTag = ''
|
||||||
|
|
||||||
self.testCase_id = ''
|
|
||||||
|
|
||||||
self.cli = ''
|
self.cli = ''
|
||||||
self.cliBuildOptions = ''
|
self.cliBuildOptions = ''
|
||||||
self.dockerfileprefix = ''
|
self.dockerfileprefix = ''
|
||||||
@@ -330,11 +285,12 @@ class Containerize():
|
|||||||
raise ValueError(f'Insufficient Parameter: IP/node {ip}, path {path}')
|
raise ValueError(f'Insufficient Parameter: IP/node {ip}, path {path}')
|
||||||
return (ip, path)
|
return (ip, path)
|
||||||
|
|
||||||
def BuildImage(self, HTML):
|
def BuildImage(self, ctx, HTML):
|
||||||
svr = self.eNB_serverId[self.eNB_instance]
|
svr = self.eNB_serverId[self.eNB_instance]
|
||||||
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
||||||
logging.debug('Building on server: ' + lIpAddr)
|
logging.debug('Building on server: ' + lIpAddr)
|
||||||
cmd = cls_cmd.getConnection(lIpAddr)
|
cmd = cls_cmd.getConnection(lIpAddr)
|
||||||
|
log_files = []
|
||||||
|
|
||||||
# Checking the hostname to get adapted on cli and dockerfileprefixes
|
# Checking the hostname to get adapted on cli and dockerfileprefixes
|
||||||
cmd.run('hostnamectl')
|
cmd.run('hostnamectl')
|
||||||
@@ -390,7 +346,6 @@ class Containerize():
|
|||||||
imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', ''))
|
imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', ''))
|
||||||
imageNames.append(('oai-gnb-aerial', 'gNB.aerial', 'oai-gnb-aerial', ''))
|
imageNames.append(('oai-gnb-aerial', 'gNB.aerial', 'oai-gnb-aerial', ''))
|
||||||
|
|
||||||
self.testCase_id = HTML.testCase_id
|
|
||||||
cmd.cd(lSourcePath)
|
cmd.cd(lSourcePath)
|
||||||
# if asterix, copy the entitlement and subscription manager configurations
|
# if asterix, copy the entitlement and subscription manager configurations
|
||||||
if self.host == 'Red Hat':
|
if self.host == 'Red Hat':
|
||||||
@@ -420,13 +375,24 @@ class Containerize():
|
|||||||
# Let's remove any previous run artifacts if still there
|
# Let's remove any previous run artifacts if still there
|
||||||
cmd.run(f"{self.cli} image prune --force")
|
cmd.run(f"{self.cli} image prune --force")
|
||||||
for image,pattern,name,option in imageNames:
|
for image,pattern,name,option in imageNames:
|
||||||
cmd.run(f"{self.cli} image rm {name}:{imageTag}")
|
cmd.run(f"{self.cli} image rm {name}:{imageTag}", reportNonZero=False)
|
||||||
|
|
||||||
# Build the base image only on Push Events (not on Merge Requests)
|
# Build the base image only on Push Events (not on Merge Requests)
|
||||||
# On when the base image docker file is being modified.
|
# On when the base image docker file is being modified.
|
||||||
if forceBaseImageBuild:
|
if forceBaseImageBuild:
|
||||||
cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}")
|
cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}")
|
||||||
cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} . &> cmake_targets/log/ran-base.log", timeout=1600)
|
logfile = f'{lSourcePath}/cmake_targets/log/ran-base.docker.log'
|
||||||
|
cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} . &> {logfile}", timeout=1600)
|
||||||
|
t = ("ran-base", archiveArtifact(cmd, ctx, logfile))
|
||||||
|
log_files.append(t)
|
||||||
|
|
||||||
|
# Recover build logs, for the moment only possible when build is successful
|
||||||
|
cmd.run(f"{self.cli} create --name test {baseImage}:{baseTag}")
|
||||||
|
cmd.run("mkdir -p cmake_targets/log/ran-base")
|
||||||
|
logfile = f'{lSourcePath}/cmake_targets/log/ran-base.log'
|
||||||
|
cmd.run(f"{self.cli} cp test:/oai-ran/cmake_targets/log/all.txt {logfile}")
|
||||||
|
cmd.run(f"{self.cli} rm -f test")
|
||||||
|
archiveArtifact(cmd, ctx, logfile)
|
||||||
# First verify if the base image was properly created.
|
# First verify if the base image was properly created.
|
||||||
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}")
|
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}")
|
||||||
allImagesSize = {}
|
allImagesSize = {}
|
||||||
@@ -441,7 +407,7 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTabFooter(False)
|
HTML.CreateHtmlTabFooter(False)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore())
|
result = re.search(r'Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore())
|
||||||
if result is not None:
|
if result is not None:
|
||||||
size = float(result.group("size")) / 1000000
|
size = float(result.group("size")) / 1000000
|
||||||
imageSizeStr = f'{size:.1f}'
|
imageSizeStr = f'{size:.1f}'
|
||||||
@@ -450,17 +416,9 @@ class Containerize():
|
|||||||
else:
|
else:
|
||||||
logging.debug('ran-base size is unknown')
|
logging.debug('ran-base size is unknown')
|
||||||
|
|
||||||
# Recover build logs, for the moment only possible when build is successful
|
|
||||||
cmd.run(f"{self.cli} create --name test {baseImage}:{baseTag}")
|
|
||||||
cmd.run("mkdir -p cmake_targets/log/ran-base")
|
|
||||||
cmd.run(f"{self.cli} cp test:/oai-ran/cmake_targets/log/. cmake_targets/log/ran-base")
|
|
||||||
cmd.run(f"{self.cli} rm -f test")
|
|
||||||
|
|
||||||
# Build the target image(s)
|
# Build the target image(s)
|
||||||
status = True
|
status = True
|
||||||
attemptedImages = ['ran-base']
|
|
||||||
for image,pattern,name,option in imageNames:
|
for image,pattern,name,option in imageNames:
|
||||||
attemptedImages += [name]
|
|
||||||
# the archived Dockerfiles have "ran-base:latest" as base image
|
# the archived Dockerfiles have "ran-base:latest" as base image
|
||||||
# we need to update them with proper tag
|
# we need to update them with proper tag
|
||||||
cmd.run(f'git checkout -- docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
cmd.run(f'git checkout -- docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
||||||
@@ -474,15 +432,18 @@ class Containerize():
|
|||||||
cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
||||||
if image == 'oai-gnb-aerial':
|
if image == 'oai-gnb-aerial':
|
||||||
cmd.run('cp -f /opt/nvidia-ipc/nvipc.src.2025.05.20.tar.gz .')
|
cmd.run('cp -f /opt/nvidia-ipc/nvipc.src.2025.05.20.tar.gz .')
|
||||||
ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > cmake_targets/log/{name}.log 2>&1', timeout=1200)
|
logfile = f'{lSourcePath}/cmake_targets/log/{name}.docker.log'
|
||||||
|
ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > {logfile} 2>&1', timeout=1200)
|
||||||
|
t = (name, archiveArtifact(cmd, ctx, logfile))
|
||||||
|
log_files.append(t)
|
||||||
if image == 'oai-gnb-aerial':
|
if image == 'oai-gnb-aerial':
|
||||||
cmd.run('rm -f nvipc.src.2025.05.20.tar.gz')
|
cmd.run('rm -f nvipc.src.2025.05.20.tar.gz')
|
||||||
if image == 'ran-build' and ret.returncode == 0:
|
if image == 'ran-build' or image == 'ran-build-asan' or image == 'ran-build-fhi72':
|
||||||
cmd.run(f"docker run --name test-log -d {name}:{imageTag} /bin/true")
|
cmd.run(f"docker run --name test-log -d {name}:{imageTag} /bin/true")
|
||||||
cmd.run(f"docker cp test-log:/oai-ran/cmake_targets/log/ cmake_targets/log/{name}/")
|
logfile = f'{lSourcePath}/{image}.ninja.log'
|
||||||
|
cmd.run(f"docker cp test-log:/oai-ran/cmake_targets/log/all.txt {logfile}")
|
||||||
cmd.run(f"docker rm -f test-log")
|
cmd.run(f"docker rm -f test-log")
|
||||||
else:
|
archiveArtifact(cmd, ctx, logfile)
|
||||||
cmd.run(f"mkdir -p cmake_targets/log/{name}")
|
|
||||||
# check the status of the build
|
# check the status of the build
|
||||||
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}")
|
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}")
|
||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
@@ -493,7 +454,7 @@ class Containerize():
|
|||||||
allImagesSize[name] = 'N/A -- Build Failed'
|
allImagesSize[name] = 'N/A -- Build Failed'
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore())
|
result = re.search(r'Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore())
|
||||||
if result is not None:
|
if result is not None:
|
||||||
size = float(result.group("size")) / 1000000 # convert to MB
|
size = float(result.group("size")) / 1000000 # convert to MB
|
||||||
imageSizeStr = f'{size:.1f}'
|
imageSizeStr = f'{size:.1f}'
|
||||||
@@ -516,13 +477,10 @@ class Containerize():
|
|||||||
logging.debug(cmd.run("df -h").stdout)
|
logging.debug(cmd.run("df -h").stdout)
|
||||||
logging.debug(cmd.run("docker system df").stdout)
|
logging.debug(cmd.run("docker system df").stdout)
|
||||||
|
|
||||||
# create a zip with all logs
|
|
||||||
build_log_name = f'build_log_{self.testCase_id}'
|
|
||||||
CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
|
|
||||||
cmd.close()
|
cmd.close()
|
||||||
|
|
||||||
# Analyze the logs
|
# Analyze the logs
|
||||||
collectInfo = AnalyzeBuildLogs(build_log_name, attemptedImages, status)
|
collectInfo = AnalyzeBuildLogs(log_files, status)
|
||||||
|
|
||||||
if status:
|
if status:
|
||||||
logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m')
|
logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m')
|
||||||
@@ -536,13 +494,12 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTabFooter(False)
|
HTML.CreateHtmlTabFooter(False)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def BuildProxy(self, HTML):
|
def BuildProxy(self, ctx, HTML):
|
||||||
svr = self.eNB_serverId[self.eNB_instance]
|
svr = self.eNB_serverId[self.eNB_instance]
|
||||||
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
||||||
logging.debug('Building on server: ' + lIpAddr)
|
logging.debug('Building on server: ' + lIpAddr)
|
||||||
ssh = cls_cmd.getConnection(lIpAddr)
|
ssh = cls_cmd.getConnection(lIpAddr)
|
||||||
|
|
||||||
self.testCase_id = HTML.testCase_id
|
|
||||||
oldRanCommidID = self.ranCommitID
|
oldRanCommidID = self.ranCommitID
|
||||||
oldRanRepository = self.ranRepository
|
oldRanRepository = self.ranRepository
|
||||||
oldRanAllowMerge = self.ranAllowMerge
|
oldRanAllowMerge = self.ranAllowMerge
|
||||||
@@ -568,15 +525,10 @@ class Containerize():
|
|||||||
if not success:
|
if not success:
|
||||||
raise Exception("could not clone proxy repository")
|
raise Exception("could not clone proxy repository")
|
||||||
|
|
||||||
filename = f'build_log_{self.testCase_id}'
|
fullpath = f'{lSourcePath}/proxy_build.log'
|
||||||
fullpath = f'{lSourcePath}/{filename}'
|
|
||||||
|
|
||||||
ssh.run(f'docker build --target oai-lte-multi-ue-proxy --tag proxy:{tag} --file {lSourcePath}/docker/Dockerfile.ubuntu18.04 {lSourcePath} > {fullpath} 2>&1')
|
ssh.run(f'docker build --target oai-lte-multi-ue-proxy --tag proxy:{tag} --file {lSourcePath}/docker/Dockerfile.ubuntu18.04 {lSourcePath} > {fullpath} 2>&1')
|
||||||
ssh.run(f'zip -r -qq {fullpath}.zip {fullpath}')
|
archiveArtifact(ssh, ctx, fullpath)
|
||||||
local_file = f"{os.getcwd()}/../cmake_targets/log/{filename}.zip"
|
|
||||||
ssh.copyin(f'{fullpath}.zip', local_file)
|
|
||||||
# don't delete such that we might recover the zips
|
|
||||||
#ssh.run(f'rm -f {fullpath}.zip')
|
|
||||||
|
|
||||||
ssh.run('docker image prune --force')
|
ssh.run('docker image prune --force')
|
||||||
ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}')
|
ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}')
|
||||||
@@ -616,7 +568,7 @@ class Containerize():
|
|||||||
collectInfo = {}
|
collectInfo = {}
|
||||||
collectInfo['proxy'] = files
|
collectInfo['proxy'] = files
|
||||||
ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}')
|
ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}')
|
||||||
result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', ret.stdout)
|
result = re.search(r'Size *= *(?P<size>[0-9\-]+) *bytes', ret.stdout)
|
||||||
# Cleaning any created tmp volume
|
# Cleaning any created tmp volume
|
||||||
ssh.run('docker volume prune --force')
|
ssh.run('docker volume prune --force')
|
||||||
ssh.close()
|
ssh.close()
|
||||||
@@ -638,7 +590,7 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTabFooter(False)
|
HTML.CreateHtmlTabFooter(False)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def BuildRunTests(self, HTML):
|
def BuildRunTests(self, ctx, HTML):
|
||||||
svr = self.eNB_serverId[self.eNB_instance]
|
svr = self.eNB_serverId[self.eNB_instance]
|
||||||
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
||||||
logging.debug('Building on server: ' + lIpAddr)
|
logging.debug('Building on server: ' + lIpAddr)
|
||||||
@@ -655,7 +607,6 @@ class Containerize():
|
|||||||
|
|
||||||
if self.forcedWorkspaceCleanup:
|
if self.forcedWorkspaceCleanup:
|
||||||
cmd.run(f'sudo -S rm -Rf {lSourcePath}')
|
cmd.run(f'sudo -S rm -Rf {lSourcePath}')
|
||||||
self.testCase_id = HTML.testCase_id
|
|
||||||
|
|
||||||
# check that ran-base image exists as we expect it
|
# check that ran-base image exists as we expect it
|
||||||
baseImage = 'ran-base'
|
baseImage = 'ran-base'
|
||||||
@@ -675,10 +626,10 @@ class Containerize():
|
|||||||
|
|
||||||
# build ran-unittests image
|
# build ran-unittests image
|
||||||
dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu22"
|
dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu22"
|
||||||
ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {lSourcePath}/cmake_targets/log/unittest-build.log')
|
logfile = f'{lSourcePath}/cmake_targets/log/unittest-build.log'
|
||||||
|
ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {logfile}')
|
||||||
|
archiveArtifact(cmd, ctx, logfile)
|
||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
build_log_name = f'build_log_{self.testCase_id}'
|
|
||||||
CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
|
|
||||||
logging.error(f'Cannot build unit tests')
|
logging.error(f'Cannot build unit tests')
|
||||||
HTML.CreateHtmlTestRow("Unit test build failed", 'KO', [dockerfile])
|
HTML.CreateHtmlTestRow("Unit test build failed", 'KO', [dockerfile])
|
||||||
HTML.CreateHtmlTabFooter(False)
|
HTML.CreateHtmlTabFooter(False)
|
||||||
@@ -687,10 +638,15 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTestRowQueue("Build unit tests", 'OK', [dockerfile])
|
HTML.CreateHtmlTestRowQueue("Build unit tests", 'OK', [dockerfile])
|
||||||
|
|
||||||
# it worked, build and execute tests, and close connection
|
# it worked, build and execute tests, and close connection
|
||||||
ret = cmd.run(f'docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --rm ran-unittests:{baseTag} ctest --no-label-summary -j$(nproc)')
|
# I would like to run it with --rm and mount the ctest result directory to avoid 'docker cp'
|
||||||
cmd.run(f'docker rmi ran-unittests:{baseTag}')
|
# below, but then permissions are messed up and we can't remove the directory without sudo
|
||||||
build_log_name = f'build_log_{self.testCase_id}'
|
# making the next pipeline fail
|
||||||
CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
|
ret = cmd.run(f'docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --name ran-unittests ran-unittests:{baseTag} ctest --no-label-summary -j$(nproc)')
|
||||||
|
cmd.run('docker cp ran-unittests:/oai-ran/build/Testing/Temporary/LastTest.log .')
|
||||||
|
archiveArtifact(cmd, ctx, f'{lSourcePath}/LastTest.log')
|
||||||
|
cmd.run('docker cp ran-unittests:/oai-ran/build/Testing/Temporary/LastTestsFailed.log .')
|
||||||
|
archiveArtifact(cmd, ctx, f'{lSourcePath}/LastTestsFailed.log')
|
||||||
|
cmd.run('docker rm ran-unittests')
|
||||||
cmd.close()
|
cmd.close()
|
||||||
|
|
||||||
if ret.returncode == 0:
|
if ret.returncode == 0:
|
||||||
@@ -823,18 +779,14 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["cannot create workspace"])
|
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["cannot create workspace"])
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def DeployObject(self, HTML):
|
def DeployObject(self, ctx, HTML):
|
||||||
svr = self.eNB_serverId[self.eNB_instance]
|
svr = self.eNB_serverId[self.eNB_instance]
|
||||||
num_attempts = self.num_attempts
|
num_attempts = self.num_attempts
|
||||||
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
||||||
logging.debug(f'Deploying OAI Object on server: {lIpAddr}')
|
logging.debug(f'Deploying OAI Object on server: {lIpAddr}')
|
||||||
yaml = self.yamlPath[self.eNB_instance].strip('/')
|
yaml = self.yamlPath[self.eNB_instance].strip('/')
|
||||||
# creating the log folder by default
|
|
||||||
local_dir = f"{os.getcwd()}/../cmake_targets/log/{yaml.split('/')[-1]}"
|
|
||||||
os.system(f'mkdir -p {local_dir}')
|
|
||||||
wd = f'{lSourcePath}/{yaml}'
|
wd = f'{lSourcePath}/{yaml}'
|
||||||
wd_yaml = f'{wd}/docker-compose.y*ml'
|
wd_yaml = f'{wd}/docker-compose.y*ml'
|
||||||
yaml_dir = yaml.split('/')[-1]
|
|
||||||
with cls_cmd.getConnection(lIpAddr) as ssh:
|
with cls_cmd.getConnection(lIpAddr) as ssh:
|
||||||
services = GetServices(ssh, self.services[self.eNB_instance], wd_yaml)
|
services = GetServices(ssh, self.services[self.eNB_instance], wd_yaml)
|
||||||
if services == [] or services == ' ' or services == None:
|
if services == [] or services == ' ' or services == None:
|
||||||
@@ -861,7 +813,7 @@ class Containerize():
|
|||||||
logging.warning(warning_msg)
|
logging.warning(warning_msg)
|
||||||
HTML.CreateHtmlTestRowQueue('N/A', 'NOK', [warning_msg])
|
HTML.CreateHtmlTestRowQueue('N/A', 'NOK', [warning_msg])
|
||||||
for svc in services.split():
|
for svc in services.split():
|
||||||
CopyinServiceLog(ssh, lSourcePath, yaml_dir, svc, wd_yaml, f'{svc}-{HTML.testCase_id}-attempt{attempt}.log')
|
CopyinServiceLog(ssh, lSourcePath, svc, wd_yaml, ctx)
|
||||||
ssh.run(f'docker compose -f {wd_yaml} down -- {services}')
|
ssh.run(f'docker compose -f {wd_yaml} down -- {services}')
|
||||||
imagesInfo = info.stdout.splitlines()[1:]
|
imagesInfo = info.stdout.splitlines()[1:]
|
||||||
logging.debug(f'{info.stdout.splitlines()[1:]}')
|
logging.debug(f'{info.stdout.splitlines()[1:]}')
|
||||||
@@ -871,13 +823,12 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)])
|
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)])
|
||||||
return deployed
|
return deployed
|
||||||
|
|
||||||
def UndeployObject(self, HTML, RAN):
|
def UndeployObject(self, ctx, HTML, RAN):
|
||||||
svr = self.eNB_serverId[self.eNB_instance]
|
svr = self.eNB_serverId[self.eNB_instance]
|
||||||
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
lIpAddr, lSourcePath = self.GetCredentials(svr)
|
||||||
logging.debug(f'\u001B[1m Undeploying OAI Object from server: {lIpAddr}\u001B[0m')
|
logging.debug(f'\u001B[1m Undeploying OAI Object from server: {lIpAddr}\u001B[0m')
|
||||||
yaml = self.yamlPath[self.eNB_instance].strip('/')
|
yaml = self.yamlPath[self.eNB_instance].strip('/')
|
||||||
wd = f'{lSourcePath}/{yaml}'
|
wd = f'{lSourcePath}/{yaml}'
|
||||||
yaml_dir = yaml.split('/')[-1]
|
|
||||||
with cls_cmd.getConnection(lIpAddr) as ssh:
|
with cls_cmd.getConnection(lIpAddr) as ssh:
|
||||||
ExistEnvFilePrint(ssh, wd)
|
ExistEnvFilePrint(ssh, wd)
|
||||||
services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml")
|
services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml")
|
||||||
@@ -885,7 +836,7 @@ class Containerize():
|
|||||||
if services is not None:
|
if services is not None:
|
||||||
all_serv = " ".join([s for s, _ in services])
|
all_serv = " ".join([s for s, _ in services])
|
||||||
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}')
|
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}')
|
||||||
copyin_res = all(CopyinServiceLog(ssh, lSourcePath, yaml_dir, s, f"{wd}/docker-compose.y*ml", f'{s}-{HTML.testCase_id}.log') for s, c in services)
|
copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, f"{wd}/docker-compose.y*ml", ctx) for s, _ in services]
|
||||||
else:
|
else:
|
||||||
logging.warning('could not identify services to stop => no log file')
|
logging.warning('could not identify services to stop => no log file')
|
||||||
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v')
|
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v')
|
||||||
@@ -894,7 +845,7 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)'])
|
HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)'])
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
log_results = [CheckLogs(self, yaml_dir, s, HTML, RAN) for s, _ in services]
|
log_results = [CheckLogs(self, f, HTML, RAN) for f in copyin_res]
|
||||||
success = all(log_results)
|
success = all(log_results)
|
||||||
if success:
|
if success:
|
||||||
logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
|
logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import yaml
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
import cls_cmd
|
import cls_cmd
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
def listify(s):
|
def listify(s):
|
||||||
if s is None:
|
if s is None:
|
||||||
@@ -114,8 +115,7 @@ class CoreNetwork:
|
|||||||
logging.info(f'deployed core network {self}, pingable IP address {ip}')
|
logging.info(f'deployed core network {self}, pingable IP address {ip}')
|
||||||
return True, output
|
return True, output
|
||||||
|
|
||||||
def _collect_logs(self, log_dir):
|
def _collect_logs(self, ctx):
|
||||||
logging.info(f'collecting logs into (local) {log_dir}')
|
|
||||||
remote_dir = "/tmp/cn-undeploy-logs"
|
remote_dir = "/tmp/cn-undeploy-logs"
|
||||||
with cls_cmd.getConnection(self._host) as c:
|
with cls_cmd.getConnection(self._host) as c:
|
||||||
# create a directory for log collection
|
# create a directory for log collection
|
||||||
@@ -134,18 +134,17 @@ class CoreNetwork:
|
|||||||
logging.error("cannot enumerate log files")
|
logging.error("cannot enumerate log files")
|
||||||
return []
|
return []
|
||||||
log_files = []
|
log_files = []
|
||||||
# copy them to the executor one by one, and store in log_dir
|
# copy them to the executor one by one
|
||||||
for f in ret.stdout.split("\n"):
|
for f in ret.stdout.split("\n"):
|
||||||
l = f.replace(remote_dir, log_dir)
|
name = archiveArtifact(c, ctx, f)
|
||||||
c.copyin(f, l)
|
log_files.append(name)
|
||||||
log_files.append(l)
|
|
||||||
c.run(f'rm -rf {remote_dir}')
|
c.run(f'rm -rf {remote_dir}')
|
||||||
return log_files
|
return log_files
|
||||||
|
|
||||||
def undeploy(self, log_dir=None):
|
def undeploy(self, ctx=None):
|
||||||
log_files = []
|
log_files = []
|
||||||
if log_dir is not None:
|
if ctx is not None:
|
||||||
log_files = self._collect_logs(log_dir)
|
log_files = self._collect_logs(ctx)
|
||||||
else:
|
else:
|
||||||
logging.warning("no directory for log collection specified, cannot retrieve core network logs")
|
logging.warning("no directory for log collection specified, cannot retrieve core network logs")
|
||||||
logging.info(f'undeploy core network {self}')
|
logging.info(f'undeploy core network {self}')
|
||||||
|
|||||||
+54
-26
@@ -32,6 +32,7 @@ import re
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
import cls_cmd
|
import cls_cmd
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
class Module_UE:
|
class Module_UE:
|
||||||
|
|
||||||
@@ -59,26 +60,31 @@ class Module_UE:
|
|||||||
}
|
}
|
||||||
self.interface = m.get('IF')
|
self.interface = m.get('IF')
|
||||||
self.MTU = m.get('MTU')
|
self.MTU = m.get('MTU')
|
||||||
self.trace = m.get('trace') == True
|
|
||||||
self.logStore = m.get('LogStore')
|
|
||||||
self.cmd_prefix = m.get('CmdPrefix')
|
self.cmd_prefix = m.get('CmdPrefix')
|
||||||
logging.info(f'initialized UE {self} from {filename}')
|
logging.info(f'initialized UE {self} from {filename}')
|
||||||
|
|
||||||
|
t = m.get('Tracing')
|
||||||
|
self.trace = t is not None
|
||||||
|
if self.trace:
|
||||||
|
if t.get('Start') is None or t.get('Stop') is None or t.get('Collect')is None :
|
||||||
|
raise ValueError("need to have Start/Stop/Collect for tracing")
|
||||||
|
self.cmd_dict["traceStart"] = t.get('Start')
|
||||||
|
self.cmd_dict["traceStop"] = t.get('Stop')
|
||||||
|
self._logCollect = t.get('Collect')
|
||||||
|
if "%%log_dir%%" not in self._logCollect:
|
||||||
|
raise ValueError(f"(At least one) LogCollect expression for {module_name} must contain \"%%log_dir%%\"")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.module_name}@{self.host} [IP: {self.getIP()}]"
|
return f"{self.module_name}@{self.host}"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.__str__()
|
return self.__str__()
|
||||||
|
|
||||||
def _command(self, cmd, silent = False):
|
def _command(self, cmd, silent=False, reportNonZero=True):
|
||||||
if cmd is None:
|
if cmd is None:
|
||||||
raise Exception("no command provided")
|
raise Exception("no command provided")
|
||||||
if self.host == "" or self.host == "localhost":
|
with cls_cmd.getConnection(self.host) as c:
|
||||||
c = cls_cmd.LocalCmd()
|
response = c.run(cmd, silent=silent, reportNonZero=reportNonZero)
|
||||||
else:
|
|
||||||
c = cls_cmd.RemoteCmd(self.host)
|
|
||||||
response = c.run(cmd, silent=silent)
|
|
||||||
c.close()
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
#-----------------$
|
#-----------------$
|
||||||
@@ -86,25 +92,23 @@ class Module_UE:
|
|||||||
#-----------------$
|
#-----------------$
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if self.trace:
|
|
||||||
raise Exception("UE tracing not implemented yet")
|
|
||||||
self._enableTrace()
|
|
||||||
# we first terminate to make sure the UE has been stopped
|
# we first terminate to make sure the UE has been stopped
|
||||||
if self.cmd_dict["detach"]:
|
if self.cmd_dict["detach"]:
|
||||||
self._command(self.cmd_dict["detach"], silent=True)
|
self._command(self.cmd_dict["detach"], silent=True)
|
||||||
self._command(self.cmd_dict["terminate"], silent=True)
|
self._command(self.cmd_dict["terminate"], silent=True)
|
||||||
ret = self._command(self.cmd_dict["initialize"])
|
ret = self._command(self.cmd_dict["initialize"])
|
||||||
logging.info(f'For command: {ret.args} | return output: {ret.stdout} | Code: {ret.returncode}')
|
logging.info(f'For command: {ret.args} | return output: {ret.stdout} | Code: {ret.returncode}')
|
||||||
|
if self.trace:
|
||||||
|
self._enableTrace()
|
||||||
# Here each UE returns differently for the successful initialization, requires check based on UE
|
# Here each UE returns differently for the successful initialization, requires check based on UE
|
||||||
return ret.returncode == 0
|
return ret.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
def terminate(self):
|
def terminate(self, ctx=None):
|
||||||
self._command(self.cmd_dict["terminate"])
|
self._command(self.cmd_dict["terminate"])
|
||||||
if self.trace:
|
if self.trace and ctx is not None:
|
||||||
raise Exception("UE tracing not implemented yet")
|
|
||||||
self._disableTrace()
|
self._disableTrace()
|
||||||
return self._logCollect()
|
return self._collectTrace(ctx)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def attach(self, attach_tries = 4, attach_timeout = 60):
|
def attach(self, attach_tries = 4, attach_timeout = 60):
|
||||||
@@ -113,10 +117,11 @@ class Module_UE:
|
|||||||
self._command(self.cmd_dict["attach"])
|
self._command(self.cmd_dict["attach"])
|
||||||
timeout = attach_timeout
|
timeout = attach_timeout
|
||||||
logging.debug("Waiting for IP address to be assigned")
|
logging.debug("Waiting for IP address to be assigned")
|
||||||
|
ip = self.getIP(silent=False, reportNonZero=True)
|
||||||
while timeout > 0 and not ip:
|
while timeout > 0 and not ip:
|
||||||
time.sleep(5)
|
time.sleep(1)
|
||||||
timeout -= 5
|
timeout -= 1
|
||||||
ip = self.getIP()
|
ip = self.getIP(silent=True, reportNonZero=False)
|
||||||
if ip:
|
if ip:
|
||||||
break
|
break
|
||||||
logging.warning(f"UE did not receive IP address after {attach_timeout} s, detaching")
|
logging.warning(f"UE did not receive IP address after {attach_timeout} s, detaching")
|
||||||
@@ -160,8 +165,8 @@ class Module_UE:
|
|||||||
logging.error(message)
|
logging.error(message)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getIP(self):
|
def getIP(self, silent=True, reportNonZero=True):
|
||||||
output = self._command(self.cmd_dict["getNetwork"], silent=True)
|
output = self._command(self.cmd_dict["getNetwork"], silent=silent, reportNonZero=reportNonZero)
|
||||||
result = re.search(r'inet (?P<ip>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', output.stdout)
|
result = re.search(r'inet (?P<ip>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', output.stdout)
|
||||||
if result and result.group('ip'):
|
if result and result.group('ip'):
|
||||||
ip = result.group('ip')
|
ip = result.group('ip')
|
||||||
@@ -191,10 +196,33 @@ class Module_UE:
|
|||||||
return self.cmd_prefix if self.cmd_prefix else ""
|
return self.cmd_prefix if self.cmd_prefix else ""
|
||||||
|
|
||||||
def _enableTrace(self):
|
def _enableTrace(self):
|
||||||
raise Exception("not implemented")
|
logging.info(f'UE {self}: start UE tracing')
|
||||||
|
self._command(self.cmd_dict["traceStart"])
|
||||||
|
|
||||||
def _disableTrace(self):
|
def _disableTrace(self):
|
||||||
raise Exception("not implemented")
|
logging.info(f'UE {self}: stop UE tracing')
|
||||||
|
self._command(self.cmd_dict["traceStop"])
|
||||||
|
|
||||||
def _logCollect(self):
|
def _collectTrace(self, ctx):
|
||||||
raise Exception("not implemented")
|
remote_dir = "/tmp/ue-trace-logs"
|
||||||
|
with cls_cmd.getConnection(self.host) as c:
|
||||||
|
# create a directory for log collection
|
||||||
|
c.run(f'rm -rf {remote_dir}')
|
||||||
|
ret = c.run(f'mkdir {remote_dir}')
|
||||||
|
if ret.returncode != 0:
|
||||||
|
logging.error("cannot create directory for log collection")
|
||||||
|
return []
|
||||||
|
log_cmd = self._logCollect.replace('%%log_dir%%', remote_dir)
|
||||||
|
self._command(log_cmd)
|
||||||
|
# enumerate collected files
|
||||||
|
ret = c.run(f'ls {remote_dir}/*')
|
||||||
|
if ret.returncode != 0:
|
||||||
|
logging.error("cannot enumerate log files")
|
||||||
|
return []
|
||||||
|
log_files = []
|
||||||
|
# copy them to the executor one by one, and store in log_dir
|
||||||
|
for f in ret.stdout.split("\n"):
|
||||||
|
name = archiveArtifact(c, ctx, f)
|
||||||
|
log_files.append(name)
|
||||||
|
c.run(f'rm -rf {remote_dir}')
|
||||||
|
return log_files
|
||||||
|
|||||||
+10
-14
@@ -28,27 +28,24 @@ import cls_cmd
|
|||||||
import cls_oai_html
|
import cls_oai_html
|
||||||
import cls_analysis
|
import cls_analysis
|
||||||
import constants as CONST
|
import constants as CONST
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
LOG_PATH_PHYSIM = 'phy_sim_logs'
|
|
||||||
DPDK_PATH = '/opt/dpdk-t2-22.11.0'
|
DPDK_PATH = '/opt/dpdk-t2-22.11.0'
|
||||||
|
|
||||||
class Native():
|
class Native():
|
||||||
|
|
||||||
def Build(test_case, HTML, host, directory, options):
|
def Build(ctx, test_case, HTML, host, directory, options):
|
||||||
logging.debug(f'Building on server: {host}')
|
logging.debug(f'Building on server: {host}')
|
||||||
HTML.testCase_id = test_case
|
HTML.testCase_id = test_case
|
||||||
|
|
||||||
with cls_cmd.getConnection(host) as ssh:
|
with cls_cmd.getConnection(host) as ssh:
|
||||||
base = f"{directory}/cmake_targets"
|
base = f"{directory}/cmake_targets"
|
||||||
ret = ssh.run(f"C_INCLUDE_PATH={DPDK_PATH}/include/ PKG_CONFIG_PATH={DPDK_PATH}/lib64/pkgconfig/ {base}/build_oai {options} > {base}/log/build_oai.log", timeout=900)
|
ret = ssh.run(f"C_INCLUDE_PATH={DPDK_PATH}/include/ PKG_CONFIG_PATH={DPDK_PATH}/lib64/pkgconfig/ {base}/build_oai {options} > {base}/build_oai.log", timeout=900)
|
||||||
success = ret.returncode == 0
|
success = ret.returncode == 0
|
||||||
logs = ssh.run(f"cat {base}/log/build_oai.log", silent=True)
|
logs = ssh.run(f"cat {base}/build_oai.log", silent=True)
|
||||||
logging.debug(f"build finished with code {ret.returncode}, output:\n{logs.stdout}")
|
logging.debug(f"build finished with code {ret.returncode}, output:\n{logs.stdout}")
|
||||||
|
|
||||||
# create log directory, and copy build logs
|
archiveArtifact(ssh, ctx, f'{base}/build_oai.log')
|
||||||
target = f"{base}/build_log_{test_case}/"
|
|
||||||
ssh.run(f"mkdir -p {target}")
|
|
||||||
ssh.run(f"mv {base}/log/* {target}")
|
|
||||||
|
|
||||||
# check if build artifacts are there
|
# check if build artifacts are there
|
||||||
# NOTE: build_oai should fail with exit code if it could not build, but it does not
|
# NOTE: build_oai should fail with exit code if it could not build, but it does not
|
||||||
@@ -68,15 +65,14 @@ class Native():
|
|||||||
HTML.CreateHtmlTestRow(options, 'KO', CONST.ALL_PROCESSES_OK)
|
HTML.CreateHtmlTestRow(options, 'KO', CONST.ALL_PROCESSES_OK)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def Run_Physim(HTML, host, directory, options, physim_test, threshold):
|
def Run_Physim(ctx, HTML, host, directory, options, physim_test, threshold):
|
||||||
logging.debug(f'Runnin {physim_test} on server: {host}')
|
logging.debug(f'Runnin {physim_test} on server: {host}')
|
||||||
workSpacePath = f'{directory}/cmake_targets'
|
workSpacePath = f'{directory}/cmake_targets'
|
||||||
os.system(f'mkdir -p ./{LOG_PATH_PHYSIM}')
|
runLogFile=f'{workSpacePath}/physim.log'
|
||||||
runLogFile=f'physim_{HTML.testCase_id}.log'
|
|
||||||
with cls_cmd.getConnection(host) as cmd:
|
with cls_cmd.getConnection(host) as cmd:
|
||||||
cmd.run(f'sudo LD_LIBRARY_PATH=.:{DPDK_PATH}/lib64/ {workSpacePath}/ran_build/build/{physim_test} {options} >> {workSpacePath}/{runLogFile}')
|
cmd.run(f'sudo LD_LIBRARY_PATH=.:{DPDK_PATH}/lib64/ {workSpacePath}/ran_build/build/{physim_test} {options} >> {runLogFile}')
|
||||||
cmd.copyin(src=f'{workSpacePath}/{runLogFile}', tgt=f'{LOG_PATH_PHYSIM}/{runLogFile}')
|
physim_file = archiveArtifact(cmd, ctx, runLogFile)
|
||||||
success, msg = cls_analysis.Analysis.analyze_physim(f'{LOG_PATH_PHYSIM}/{runLogFile}', physim_test, options, threshold)
|
success, msg = cls_analysis.Analysis.analyze_physim(physim_file, physim_test, options, threshold)
|
||||||
if success:
|
if success:
|
||||||
HTML.CreateHtmlTestRowQueue(options, 'OK', [msg])
|
HTML.CreateHtmlTestRowQueue(options, 'OK', [msg])
|
||||||
else:
|
else:
|
||||||
|
|||||||
+26
-78
@@ -47,6 +47,7 @@ import constants as CONST
|
|||||||
import cls_module
|
import cls_module
|
||||||
import cls_corenetwork
|
import cls_corenetwork
|
||||||
import cls_cmd
|
import cls_cmd
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
# Helper functions used here and in other classes
|
# Helper functions used here and in other classes
|
||||||
@@ -259,9 +260,7 @@ class OaiCiTest():
|
|||||||
self.ranAllowMerge = False
|
self.ranAllowMerge = False
|
||||||
self.ranTargetBranch = ''
|
self.ranTargetBranch = ''
|
||||||
|
|
||||||
self.testCase_id = ''
|
|
||||||
self.testXMLfiles = []
|
self.testXMLfiles = []
|
||||||
self.desc = ''
|
|
||||||
self.ping_args = ''
|
self.ping_args = ''
|
||||||
self.ping_packetloss_threshold = ''
|
self.ping_packetloss_threshold = ''
|
||||||
self.ping_rttavg_threshold =''
|
self.ping_rttavg_threshold =''
|
||||||
@@ -355,7 +354,7 @@ class OaiCiTest():
|
|||||||
HTML.CreateHtmlTestRowQueue('NA', 'OK', messages)
|
HTML.CreateHtmlTestRowQueue('NA', 'OK', messages)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def Ping_common(self, cn, ue, logPath):
|
def Ping_common(self, ctx, cn, ue):
|
||||||
ping_status = 0
|
ping_status = 0
|
||||||
ueIP = ue.getIP()
|
ueIP = ue.getIP()
|
||||||
if not ueIP:
|
if not ueIP:
|
||||||
@@ -363,13 +362,12 @@ class OaiCiTest():
|
|||||||
svrIP = cn.getIP()
|
svrIP = cn.getIP()
|
||||||
if not svrIP:
|
if not svrIP:
|
||||||
return (False, f"CN {cn.getName()} has no IP address")
|
return (False, f"CN {cn.getName()} has no IP address")
|
||||||
ping_log_file = f'ping_{self.testCase_id}_{ue.getName()}.log'
|
ping_log_file = f'/tmp/ping_{ue.getName()}.log'
|
||||||
ping_time = re.findall(r"-c *(\d+)",str(self.ping_args))
|
ping_time = re.findall(r"-c *(\d+)",str(self.ping_args))
|
||||||
local_ping_log_file = f'{logPath}/{ping_log_file}'
|
|
||||||
if re.search('%cn_ip%', self.ping_args) or re.search(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', self.ping_args):
|
if re.search('%cn_ip%', self.ping_args) or re.search(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', self.ping_args):
|
||||||
raise Exception(f"ping_args should not have IP address: {self.ping_args}")
|
raise Exception(f"ping_args should not have IP address: {self.ping_args}")
|
||||||
interface = f'-I {ue.getIFName()}' if ue.getIFName() else ''
|
interface = f'-I {ue.getIFName()}' if ue.getIFName() else ''
|
||||||
ping_cmd = f'{ue.getCmdPrefix()} ping {interface} {self.ping_args} {svrIP} 2>&1 | tee /tmp/{ping_log_file}'
|
ping_cmd = f'{ue.getCmdPrefix()} ping {interface} {self.ping_args} {svrIP} 2>&1 | tee {ping_log_file}'
|
||||||
cmd = cls_cmd.getConnection(ue.getHost())
|
cmd = cls_cmd.getConnection(ue.getHost())
|
||||||
response = cmd.run(ping_cmd, timeout=int(ping_time[0])*1.5)
|
response = cmd.run(ping_cmd, timeout=int(ping_time[0])*1.5)
|
||||||
ue_header = f'UE {ue.getName()} ({ueIP})'
|
ue_header = f'UE {ue.getName()} ({ueIP})'
|
||||||
@@ -377,8 +375,7 @@ class OaiCiTest():
|
|||||||
message = ue_header + ': ping crashed: TIMEOUT?'
|
message = ue_header + ': ping crashed: TIMEOUT?'
|
||||||
return (False, message)
|
return (False, message)
|
||||||
|
|
||||||
#copy the ping log file to have it locally for analysis (ping stats)
|
local_ping_log_file = archiveArtifact(cmd, ctx, ping_log_file)
|
||||||
cmd.copyin(src=f'/tmp/{ping_log_file}', tgt=local_ping_log_file)
|
|
||||||
cmd.close()
|
cmd.close()
|
||||||
|
|
||||||
with open(local_ping_log_file, 'r') as f:
|
with open(local_ping_log_file, 'r') as f:
|
||||||
@@ -418,18 +415,13 @@ class OaiCiTest():
|
|||||||
|
|
||||||
return (True, message)
|
return (True, message)
|
||||||
|
|
||||||
def Ping(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"):
|
def Ping(self, ctx, HTML, infra_file="ci_infra.yaml"):
|
||||||
if self.ue_ids == [] or self.svr_id == None:
|
if self.ue_ids == [] or self.svr_id == None:
|
||||||
raise Exception("no module names in self.ue_ids or/and self.svr_id provided")
|
raise Exception("no module names in self.ue_ids or/and self.svr_id provided")
|
||||||
# Creating destination log folder if needed on the python executor workspace
|
|
||||||
with cls_cmd.getConnection('localhost') as local:
|
|
||||||
ymlPath = CONTAINERS.yamlPath[0].split('/')
|
|
||||||
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}'
|
|
||||||
local.run(f'mkdir -p {logPath}', silent=True)
|
|
||||||
ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
||||||
cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
|
cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||||
futures = [executor.submit(self.Ping_common, cn, ue, logPath) for ue in ues]
|
futures = [executor.submit(self.Ping_common, ctx, cn, ue) for ue in ues]
|
||||||
results = [f.result() for f in futures]
|
results = [f.result() for f in futures]
|
||||||
# each result in results is a tuple, first member goes to successes, second to messages
|
# each result in results is a tuple, first member goes to successes, second to messages
|
||||||
successes, messages = map(list, zip(*results))
|
successes, messages = map(list, zip(*results))
|
||||||
@@ -450,7 +442,7 @@ class OaiCiTest():
|
|||||||
HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', messages)
|
HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', messages)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def Iperf_Module(self, cn, ue, idx, ue_num, logPath):
|
def Iperf_Module(self, ctx, cn, ue, idx, ue_num):
|
||||||
ueIP = ue.getIP()
|
ueIP = ue.getIP()
|
||||||
if not ueIP:
|
if not ueIP:
|
||||||
return (False, f"UE {ue.getName()} has no IP address")
|
return (False, f"UE {ue.getName()} has no IP address")
|
||||||
@@ -463,7 +455,7 @@ class OaiCiTest():
|
|||||||
serverReport = ""
|
serverReport = ""
|
||||||
udpIperf = re.search('-u', iperf_opt) is not None
|
udpIperf = re.search('-u', iperf_opt) is not None
|
||||||
bidirIperf = re.search('--bidir', iperf_opt) is not None
|
bidirIperf = re.search('--bidir', iperf_opt) is not None
|
||||||
client_filename = f'iperf_client_{self.testCase_id}_{ue.getName()}.log'
|
client_filename = f'/tmp/iperf_client_{ue.getName()}.log'
|
||||||
if udpIperf:
|
if udpIperf:
|
||||||
target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(idx, ue_num, self.iperf_profile, self.iperf_args)
|
target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(idx, ue_num, self.iperf_profile, self.iperf_args)
|
||||||
# note: for UDP testing we don't want to use json report - reports 0 Mbps received bitrate
|
# note: for UDP testing we don't want to use json report - reports 0 Mbps received bitrate
|
||||||
@@ -478,14 +470,11 @@ class OaiCiTest():
|
|||||||
port = 5002 + idx
|
port = 5002 + idx
|
||||||
# note: some core setups start an iperf3 server automatically, indicated in ci_infra by runIperf3Server: False`
|
# note: some core setups start an iperf3 server automatically, indicated in ci_infra by runIperf3Server: False`
|
||||||
t = iperf_time * 2.5
|
t = iperf_time * 2.5
|
||||||
cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False, silent=True)
|
cmd_ue.run(f'rm {client_filename}', reportNonZero=False, silent=True)
|
||||||
if cn.runIperf3Server():
|
if cn.runIperf3Server():
|
||||||
cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf3 -s -B {svrIP} -p {port} -1 {jsonReport} >> /dev/null &', timeout=t)
|
cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf3 -s -B {svrIP} -p {port} -1 {jsonReport} >> /dev/null &', timeout=t)
|
||||||
cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} {iperf_ue} -B {ueIP} -c {svrIP} -p {port} {iperf_opt} {jsonReport} {serverReport} -O 5 >> /tmp/{client_filename}', timeout=t)
|
cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} {iperf_ue} -B {ueIP} -c {svrIP} -p {port} {iperf_opt} {jsonReport} {serverReport} -O 5 >> {client_filename}', timeout=t)
|
||||||
# note: copy iperf3 log to the current directory for log analysis and log collection
|
dest_filename = archiveArtifact(cmd_ue, ctx, client_filename)
|
||||||
dest_filename = f'{logPath}/{client_filename}'
|
|
||||||
cmd_ue.copyin(f'/tmp/{client_filename}', dest_filename)
|
|
||||||
cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False, silent=True)
|
|
||||||
if udpIperf:
|
if udpIperf:
|
||||||
status, msg = Iperf_analyzeV3UDP(dest_filename, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate)
|
status, msg = Iperf_analyzeV3UDP(dest_filename, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate)
|
||||||
elif bidirIperf:
|
elif bidirIperf:
|
||||||
@@ -495,20 +484,15 @@ class OaiCiTest():
|
|||||||
|
|
||||||
return (status, f'{ue_header}\n{msg}')
|
return (status, f'{ue_header}\n{msg}')
|
||||||
|
|
||||||
def Iperf(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"):
|
def Iperf(self, ctx, HTML, infra_file="ci_infra.yaml"):
|
||||||
logging.debug(f'Iperf: iperf_args "{self.iperf_args}" iperf_packetloss_threshold "{self.iperf_packetloss_threshold}" iperf_bitrate_threshold "{self.iperf_bitrate_threshold}" iperf_profile "{self.iperf_profile}" iperf_options "{self.iperf_options}"')
|
logging.debug(f'Iperf: iperf_args "{self.iperf_args}" iperf_packetloss_threshold "{self.iperf_packetloss_threshold}" iperf_bitrate_threshold "{self.iperf_bitrate_threshold}" iperf_profile "{self.iperf_profile}" iperf_options "{self.iperf_options}"')
|
||||||
|
|
||||||
if self.ue_ids == [] or self.svr_id == None:
|
if self.ue_ids == [] or self.svr_id == None:
|
||||||
raise Exception("no module names in self.ue_ids or/and self.svr_id provided")
|
raise Exception("no module names in self.ue_ids or/and self.svr_id provided")
|
||||||
# create log directory on executor node
|
|
||||||
with cls_cmd.getConnection('localhost') as local:
|
|
||||||
ymlPath = CONTAINERS.yamlPath[0].split('/')
|
|
||||||
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}'
|
|
||||||
local.run(f'mkdir -p {logPath}', silent=True)
|
|
||||||
ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)]
|
||||||
cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
|
cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file)
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||||
futures = [executor.submit(self.Iperf_Module, cn, ue, i, len(ues), logPath) for i, ue in enumerate(ues)]
|
futures = [executor.submit(self.Iperf_Module, ctx, cn, ue, i, len(ues)) for i, ue in enumerate(ues)]
|
||||||
results = [f.result() for f in futures]
|
results = [f.result() for f in futures]
|
||||||
# each result in results is a tuple, first member goes to successes, second to messages
|
# each result in results is a tuple, first member goes to successes, second to messages
|
||||||
successes, messages = map(list, zip(*results))
|
successes, messages = map(list, zip(*results))
|
||||||
@@ -529,7 +513,7 @@ class OaiCiTest():
|
|||||||
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', messages)
|
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', messages)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def Iperf2_Unidir(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"):
|
def Iperf2_Unidir(self, ctx, HTML, infra_file="ci_infra.yaml"):
|
||||||
if self.ue_ids == [] or self.svr_id == None or len(self.ue_ids) != 1:
|
if self.ue_ids == [] or self.svr_id == None or len(self.ue_ids) != 1:
|
||||||
raise Exception("no module names in self.ue_ids or/and self.svr_id provided, multi UE scenario not supported")
|
raise Exception("no module names in self.ue_ids or/and self.svr_id provided, multi UE scenario not supported")
|
||||||
ue = cls_module.Module_UE(self.ue_ids[0].strip(),self.nodes[0].strip(), infra_file)
|
ue = cls_module.Module_UE(self.ue_ids[0].strip(),self.nodes[0].strip(), infra_file)
|
||||||
@@ -540,23 +524,17 @@ class OaiCiTest():
|
|||||||
svrIP = cn.getIP()
|
svrIP = cn.getIP()
|
||||||
if not svrIP:
|
if not svrIP:
|
||||||
return False
|
return False
|
||||||
server_filename = f'iperf_server_{self.testCase_id}_{ue.getName()}.log'
|
server_filename = f'/tmp/iperf_server_{ue.getName()}.log'
|
||||||
ymlPath = CONTAINERS.yamlPath[0].split('/')
|
|
||||||
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}'
|
|
||||||
iperf_time = Iperf_ComputeTime(self.iperf_args)
|
iperf_time = Iperf_ComputeTime(self.iperf_args)
|
||||||
target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(0, 1, self.iperf_profile, self.iperf_args)
|
target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(0, 1, self.iperf_profile, self.iperf_args)
|
||||||
t = iperf_time*2.5
|
t = iperf_time*2.5
|
||||||
with cls_cmd.getConnection('localhost') as local:
|
|
||||||
local.run(f'mkdir -p {logPath}')
|
|
||||||
with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(cn.getHost()) as cmd_svr:
|
with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(cn.getHost()) as cmd_svr:
|
||||||
cmd_ue.run(f'rm /tmp/{server_filename}', reportNonZero=False)
|
cmd_ue.run(f'rm {server_filename}', reportNonZero=False)
|
||||||
cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} iperf -B {ueIP} -s -u -i1 >> /tmp/{server_filename} &', timeout=t)
|
cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} iperf -B {ueIP} -s -u -i1 >> {server_filename} &', timeout=t)
|
||||||
cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 >> /dev/null', timeout=t)
|
cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 >> /dev/null', timeout=t)
|
||||||
localPath = f'{os.getcwd()}'
|
localPath = f'{os.getcwd()}'
|
||||||
# note: copy iperf2 log to the directory for log collection
|
local = archiveArtifact(cmd_ue, ctx, server_filename)
|
||||||
cmd_ue.copyin(f'/tmp/{server_filename}', f'{logPath}/{server_filename}')
|
success, msg = Iperf_analyzeV2UDP(local, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate)
|
||||||
cmd_ue.run(f'rm /tmp/{server_filename}', reportNonZero=False)
|
|
||||||
success, msg = Iperf_analyzeV2UDP(f'{logPath}/{server_filename}', self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate)
|
|
||||||
ue_header = f'UE {ue.getName()} ({ueIP})'
|
ue_header = f'UE {ue.getName()} ({ueIP})'
|
||||||
logging.info(f'\u001B[1;37;45m iperf result for {ue_header}\u001B[0m')
|
logging.info(f'\u001B[1;37;45m iperf result for {ue_header}\u001B[0m')
|
||||||
for l in msg.split('\n'):
|
for l in msg.split('\n'):
|
||||||
@@ -838,17 +816,17 @@ class OaiCiTest():
|
|||||||
global_status = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC
|
global_status = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC
|
||||||
return global_status
|
return global_status
|
||||||
|
|
||||||
def TerminateUE(self, HTML):
|
def TerminateUE(self, ctx, HTML):
|
||||||
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
|
ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids]
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor:
|
||||||
futures = [executor.submit(ue.terminate) for ue in ues]
|
futures = [executor.submit(ue.terminate, ctx) for ue in ues]
|
||||||
archives = [f.result() for f in futures]
|
archives = [f.result() for f in futures]
|
||||||
archive_info = [f'Log at: {a}' if a else 'No log available' for a in archives]
|
archive_info = [f'Log at: {a}' if a else 'No log available' for a in archives]
|
||||||
messages = [f"UE {ue.getName()}: {log}" for (ue, log) in zip(ues, archive_info)]
|
messages = [f"UE {ue.getName()}: {log}" for (ue, log) in zip(ues, archive_info)]
|
||||||
HTML.CreateHtmlTestRowQueue(f'N/A', 'OK', messages)
|
HTML.CreateHtmlTestRowQueue(f'N/A', 'OK', messages)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def DeployCoreNetwork(cn_id, HTML):
|
def DeployCoreNetwork(cn_id, ctx, HTML):
|
||||||
core_name = cn_id.strip()
|
core_name = cn_id.strip()
|
||||||
cn = cls_corenetwork.CoreNetwork(core_name)
|
cn = cls_corenetwork.CoreNetwork(core_name)
|
||||||
success, output = cn.deploy()
|
success, output = cn.deploy()
|
||||||
@@ -862,41 +840,11 @@ class OaiCiTest():
|
|||||||
HTML.CreateHtmlTestRowQueue(core_name, 'KO', [msg])
|
HTML.CreateHtmlTestRowQueue(core_name, 'KO', [msg])
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def UndeployCoreNetwork(cn_id, HTML):
|
def UndeployCoreNetwork(cn_id, ctx, HTML):
|
||||||
# Ping, Iperf, DeployObject put logs into a path based on YAML. We
|
|
||||||
# can't do this here (because there is no yaml), so hardcode a path for
|
|
||||||
# "cn_logs" for the moment
|
|
||||||
logPath = f'{os.getcwd()}/../cmake_targets/log/cn_logs'
|
|
||||||
with cls_cmd.getConnection('localhost') as local:
|
|
||||||
local.run(f'mkdir -p {logPath}', silent=True)
|
|
||||||
core_name = cn_id.strip()
|
core_name = cn_id.strip()
|
||||||
cn = cls_corenetwork.CoreNetwork(core_name)
|
cn = cls_corenetwork.CoreNetwork(core_name)
|
||||||
logs, output = cn.undeploy(log_dir=logPath)
|
logs, output = cn.undeploy(ctx=ctx)
|
||||||
logging.info(f"undeployed core network {core_name}, logs {logs}, output:\n{output}")
|
logging.info(f"undeployed core network {core_name}, logs {logs}, output:\n{output}")
|
||||||
message = "Log files: " + ", ".join([os.path.basename(l) for l in logs])
|
message = "Log files:\n" + "\n".join([os.path.basename(l) for l in logs])
|
||||||
HTML.CreateHtmlTestRowQueue(core_name, 'OK', [message])
|
HTML.CreateHtmlTestRowQueue(core_name, 'OK', [message])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def LogCollectBuild(self,RAN):
|
|
||||||
# Some pipelines are using "none" IP / Credentials
|
|
||||||
# In that case, just forget about it
|
|
||||||
if RAN.eNBIPAddress == 'none':
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if (RAN.eNBIPAddress != '' and RAN.eNBUserName != '' and RAN.eNBPassword != ''):
|
|
||||||
IPAddress = RAN.eNBIPAddress
|
|
||||||
UserName = RAN.eNBUserName
|
|
||||||
Password = RAN.eNBPassword
|
|
||||||
SourceCodePath = RAN.eNBSourceCodePath
|
|
||||||
else:
|
|
||||||
sys.exit('Insufficient Parameter')
|
|
||||||
with cls_cmd.getConnection(IPAddress) as cmd:
|
|
||||||
d = f'{SourceCodePath}/cmake_targets'
|
|
||||||
cmd.run(f'rm -f {d}/build.log.zip')
|
|
||||||
cmd.run(f'cd {d} && zip -r build.log.zip build_log_*/*')
|
|
||||||
|
|
||||||
def ShowTestID(self):
|
|
||||||
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')
|
|
||||||
logging.info(f'\u001B[1m Test ID: {self.testCase_id} \u001B[0m')
|
|
||||||
logging.info(f'\u001B[1m {self.desc} \u001B[0m')
|
|
||||||
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ from pathlib import Path
|
|||||||
import helpreadme as HELP
|
import helpreadme as HELP
|
||||||
import constants as CONST
|
import constants as CONST
|
||||||
import cls_cmd
|
import cls_cmd
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
# Class Declaration
|
# Class Declaration
|
||||||
@@ -80,7 +81,7 @@ class StaticCodeAnalysis():
|
|||||||
self.eNBPassword = ''
|
self.eNBPassword = ''
|
||||||
self.eNBSourceCodePath = ''
|
self.eNBSourceCodePath = ''
|
||||||
|
|
||||||
def CppCheckAnalysis(self, HTML):
|
def CppCheckAnalysis(self, ctx, HTML):
|
||||||
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
|
if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
|
||||||
HELP.GenericHelp(CONST.Version)
|
HELP.GenericHelp(CONST.Version)
|
||||||
sys.exit('Insufficient Parameter')
|
sys.exit('Insufficient Parameter')
|
||||||
@@ -103,7 +104,7 @@ class StaticCodeAnalysis():
|
|||||||
full_ran_repo_name = self.ranRepository + '.git'
|
full_ran_repo_name = self.ranRepository + '.git'
|
||||||
|
|
||||||
cmd.cd(lSourcePath)
|
cmd.cd(lSourcePath)
|
||||||
logDir = f'{lSourcePath}/cmake_targets/build_log_{self.testCase_id}'
|
logDir = f'{lSourcePath}/cmake_targets/log'
|
||||||
cmd.run(f'mkdir -p {logDir}')
|
cmd.run(f'mkdir -p {logDir}')
|
||||||
cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal')
|
cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal')
|
||||||
cmd.run(f'sed -e "s@xenial@bionic@" {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.xenial > {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.bionic')
|
cmd.run(f'sed -e "s@xenial@bionic@" {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.xenial > {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.bionic')
|
||||||
@@ -112,31 +113,21 @@ class StaticCodeAnalysis():
|
|||||||
cmd.run(f'docker build --tag oai-cppcheck:focal --file {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.focal . > {logDir}/cppcheck-focal.txt 2>&1')
|
cmd.run(f'docker build --tag oai-cppcheck:focal --file {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.focal . > {logDir}/cppcheck-focal.txt 2>&1')
|
||||||
cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal')
|
cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal')
|
||||||
|
|
||||||
# Analyzing the logs
|
bionic = archiveArtifact(cmd, ctx, f'{logDir}/cppcheck-bionic.txt')
|
||||||
cmd.copyin(f'{logDir}/cppcheck-bionic.txt', 'cppcheck-bionic.txt')
|
focal = archiveArtifact(cmd, ctx, f'{logDir}/cppcheck-focal.txt')
|
||||||
cmd.copyin(f'{logDir}/cppcheck-focal.txt', 'cppcheck-focal.txt')
|
|
||||||
cmd.close()
|
cmd.close()
|
||||||
|
|
||||||
CCR = CppCheckResults()
|
CCR = CppCheckResults()
|
||||||
CCR_ref = CppCheckResults()
|
CCR_ref = CppCheckResults()
|
||||||
vId = 0
|
vId = 0
|
||||||
for variant in CCR.variants:
|
for variant in CCR.variants:
|
||||||
refAvailable = False
|
filename = ctx.baseFilename() + '-cppcheck-'+ variant + '.txt'
|
||||||
if self.ranAllowMerge:
|
logging.info(f"will check file '{filename}'")
|
||||||
refFolder = str(Path.home()) + '/cppcheck-references'
|
if not os.path.isfile(filename):
|
||||||
if (os.path.isfile(refFolder + '/cppcheck-'+ variant + '.txt')):
|
raise FileNotFoundError(f"{filename} is not a file")
|
||||||
refAvailable = True
|
else:
|
||||||
with open(refFolder + '/cppcheck-'+ variant + '.txt', 'r') as refFile:
|
|
||||||
for line in refFile:
|
|
||||||
ret = re.search(' (?P<nb_errors>[0-9\.]+) errors', str(line))
|
|
||||||
if ret is not None:
|
|
||||||
CCR_ref.nbErrors[vId] = int(ret.group('nb_errors'))
|
|
||||||
ret = re.search(' (?P<nb_warnings>[0-9\.]+) warnings', str(line))
|
|
||||||
if ret is not None:
|
|
||||||
CCR_ref.nbWarnings[vId] = int(ret.group('nb_warnings'))
|
|
||||||
if (os.path.isfile('./cppcheck-'+ variant + '.txt')):
|
|
||||||
xmlStart = False
|
xmlStart = False
|
||||||
with open('./cppcheck-'+ variant + '.txt', 'r') as logfile:
|
with open(filename, 'r') as logfile:
|
||||||
for line in logfile:
|
for line in logfile:
|
||||||
ret = re.search('cppcheck version="(?P<version>[0-9\.]+)"', str(line))
|
ret = re.search('cppcheck version="(?P<version>[0-9\.]+)"', str(line))
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
@@ -185,26 +176,6 @@ class StaticCodeAnalysis():
|
|||||||
vMsg += ' Wrong Scanf Nb Args: ' + str(CCR.nbWrongScanfArg[vId]) + '\n'
|
vMsg += ' Wrong Scanf Nb Args: ' + str(CCR.nbWrongScanfArg[vId]) + '\n'
|
||||||
for vLine in vMsg.split('\n'):
|
for vLine in vMsg.split('\n'):
|
||||||
logging.debug(vLine)
|
logging.debug(vLine)
|
||||||
if self.ranAllowMerge and refAvailable:
|
|
||||||
if CCR_ref.nbErrors[vId] == CCR.nbErrors[vId]:
|
|
||||||
logging.debug(' No change in number of errors')
|
|
||||||
elif CCR_ref.nbErrors[vId] > CCR.nbErrors[vId]:
|
|
||||||
logging.debug(' Good! Decrease in number of errors')
|
|
||||||
else:
|
|
||||||
logging.debug(' Bad! increase in number of errors')
|
|
||||||
if CCR_ref.nbWarnings[vId] == CCR.nbWarnings[vId]:
|
|
||||||
logging.debug(' No change in number of warnings')
|
|
||||||
elif CCR_ref.nbWarnings[vId] > CCR.nbWarnings[vId]:
|
|
||||||
logging.debug(' Good! Decrease in number of warnings')
|
|
||||||
else:
|
|
||||||
logging.debug(' Bad! increase in number of warnings')
|
|
||||||
# Create new reference file
|
|
||||||
if not self.ranAllowMerge:
|
|
||||||
refFolder = str(Path.home()) + '/cppcheck-references'
|
|
||||||
if not os.path.isdir(refFolder):
|
|
||||||
os.mkdir(refFolder)
|
|
||||||
with open(refFolder + '/cppcheck-'+ variant + '.txt', 'w') as refFile:
|
|
||||||
refFile.write(vMsg)
|
|
||||||
vId += 1
|
vId += 1
|
||||||
|
|
||||||
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
|
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
|
||||||
@@ -213,7 +184,7 @@ class StaticCodeAnalysis():
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def LicenceAndFormattingCheck(self, HTML):
|
def LicenceAndFormattingCheck(self, ctx, HTML):
|
||||||
# Workspace is no longer recreated from scratch.
|
# Workspace is no longer recreated from scratch.
|
||||||
# It implies that this method shall be called last within a build pipeline
|
# It implies that this method shall be called last within a build pipeline
|
||||||
# where workspace is already created
|
# where workspace is already created
|
||||||
@@ -238,7 +209,7 @@ class StaticCodeAnalysis():
|
|||||||
else:
|
else:
|
||||||
check_options += f' --build-arg TARGET_BRANCH={self.ranTargetBranch}'
|
check_options += f' --build-arg TARGET_BRANCH={self.ranTargetBranch}'
|
||||||
|
|
||||||
logDir = f'{lSourcePath}/cmake_targets/build_log_{self.testCase_id}'
|
logDir = f'{lSourcePath}/cmake_targets/log/'
|
||||||
cmd.run(f'mkdir -p {logDir}')
|
cmd.run(f'mkdir -p {logDir}')
|
||||||
cmd.run('docker image rm oai-formatting-check:latest')
|
cmd.run('docker image rm oai-formatting-check:latest')
|
||||||
cmd.run(f'docker build --target oai-formatting-check --tag oai-formatting-check:latest {check_options} --file {lSourcePath}/ci-scripts/docker/Dockerfile.formatting.bionic {lSourcePath} > {logDir}/oai-formatting-check.txt 2>&1')
|
cmd.run(f'docker build --target oai-formatting-check --tag oai-formatting-check:latest {check_options} --file {lSourcePath}/ci-scripts/docker/Dockerfile.formatting.bionic {lSourcePath} > {logDir}/oai-formatting-check.txt 2>&1')
|
||||||
@@ -247,12 +218,11 @@ class StaticCodeAnalysis():
|
|||||||
cmd.run('docker image prune --force')
|
cmd.run('docker image prune --force')
|
||||||
cmd.run('docker volume prune --force')
|
cmd.run('docker volume prune --force')
|
||||||
|
|
||||||
# Analyzing the logs
|
file = archiveArtifact(cmd, ctx, f'{logDir}/oai-formatting-check.txt')
|
||||||
cmd.copyin(f'{logDir}/oai-formatting-check.txt', 'oai-formatting-check.txt')
|
|
||||||
cmd.close()
|
cmd.close()
|
||||||
|
|
||||||
finalStatus = 0
|
finalStatus = 0
|
||||||
if (os.path.isfile('./oai-formatting-check.txt')):
|
if (os.path.isfile(file)):
|
||||||
analyzed = False
|
analyzed = False
|
||||||
nbFilesNotFormatted = 0
|
nbFilesNotFormatted = 0
|
||||||
listFiles = False
|
listFiles = False
|
||||||
@@ -263,7 +233,7 @@ class StaticCodeAnalysis():
|
|||||||
gnuGplLicenceFiles = []
|
gnuGplLicenceFiles = []
|
||||||
suspectLicence = False
|
suspectLicence = False
|
||||||
suspectLicenceFiles = []
|
suspectLicenceFiles = []
|
||||||
with open('./oai-formatting-check.txt', 'r') as logfile:
|
with open(file, 'r') as logfile:
|
||||||
for line in logfile:
|
for line in logfile:
|
||||||
ret = re.search('./ci-scripts/checkCodingFormattingRules.sh', str(line))
|
ret = re.search('./ci-scripts/checkCodingFormattingRules.sh', str(line))
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
|
|||||||
+44
-41
@@ -43,8 +43,10 @@ import cls_containerize #class Containerize for all container-based operations
|
|||||||
import cls_static_code_analysis #class for static code analysis
|
import cls_static_code_analysis #class for static code analysis
|
||||||
import cls_cluster # class for building/deploying on cluster
|
import cls_cluster # class for building/deploying on cluster
|
||||||
import cls_native # class for all native/source-based operations
|
import cls_native # class for all native/source-based operations
|
||||||
|
from cls_ci_helper import TestCaseCtx
|
||||||
|
|
||||||
import ran
|
import ran
|
||||||
|
import cls_cmd
|
||||||
import cls_oai_html
|
import cls_oai_html
|
||||||
|
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ def AssignParams(params_dict):
|
|||||||
setattr(RAN, key, value)
|
setattr(RAN, key, value)
|
||||||
setattr(HTML, key, value)
|
setattr(HTML, key, value)
|
||||||
|
|
||||||
def ExecuteActionWithParam(action):
|
def ExecuteActionWithParam(action, ctx):
|
||||||
global RAN
|
global RAN
|
||||||
global HTML
|
global HTML
|
||||||
global CONTAINERS
|
global CONTAINERS
|
||||||
@@ -134,15 +136,15 @@ def ExecuteActionWithParam(action):
|
|||||||
if proxy_commit is not None:
|
if proxy_commit is not None:
|
||||||
CONTAINERS.proxyCommit = proxy_commit
|
CONTAINERS.proxyCommit = proxy_commit
|
||||||
if action == 'Build_eNB':
|
if action == 'Build_eNB':
|
||||||
success = cls_native.Native.Build(HTML.testCase_id, HTML, RAN.eNBIPAddress, RAN.eNBSourceCodePath, RAN.Build_eNB_args)
|
success = cls_native.Native.Build(ctx, HTML.testCase_id, HTML, RAN.eNBIPAddress, RAN.eNBSourceCodePath, RAN.Build_eNB_args)
|
||||||
elif action == 'Build_Image':
|
elif action == 'Build_Image':
|
||||||
success = CONTAINERS.BuildImage(HTML)
|
success = CONTAINERS.BuildImage(ctx, HTML)
|
||||||
elif action == 'Build_Proxy':
|
elif action == 'Build_Proxy':
|
||||||
success = CONTAINERS.BuildProxy(HTML)
|
success = CONTAINERS.BuildProxy(ctx, HTML)
|
||||||
elif action == 'Build_Cluster_Image':
|
elif action == 'Build_Cluster_Image':
|
||||||
success = CLUSTER.BuildClusterImage(HTML)
|
success = CLUSTER.BuildClusterImage(ctx, HTML)
|
||||||
elif action == 'Build_Run_Tests':
|
elif action == 'Build_Run_Tests':
|
||||||
success = CONTAINERS.BuildRunTests(HTML)
|
success = CONTAINERS.BuildRunTests(ctx, HTML)
|
||||||
|
|
||||||
elif action == 'Initialize_eNB':
|
elif action == 'Initialize_eNB':
|
||||||
datalog_rt_stats_file=test.findtext('rt_stats_cfg')
|
datalog_rt_stats_file=test.findtext('rt_stats_cfg')
|
||||||
@@ -204,7 +206,7 @@ def ExecuteActionWithParam(action):
|
|||||||
RAN.air_interface[RAN.eNB_instance] = 'lte-softmodem'
|
RAN.air_interface[RAN.eNB_instance] = 'lte-softmodem'
|
||||||
else:
|
else:
|
||||||
RAN.air_interface[RAN.eNB_instance] = air_interface.lower() +'-softmodem'
|
RAN.air_interface[RAN.eNB_instance] = air_interface.lower() +'-softmodem'
|
||||||
success = RAN.TerminateeNB(HTML)
|
success = RAN.TerminateeNB(ctx, HTML)
|
||||||
|
|
||||||
elif action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Terminate_UE' or action == 'CheckStatusUE' or action == 'DataEnable_UE' or action == 'DataDisable_UE':
|
elif action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Terminate_UE' or action == 'CheckStatusUE' or action == 'DataEnable_UE' or action == 'DataDisable_UE':
|
||||||
CiTestObj.ue_ids = test.findtext('id').split(' ')
|
CiTestObj.ue_ids = test.findtext('id').split(' ')
|
||||||
@@ -226,7 +228,7 @@ def ExecuteActionWithParam(action):
|
|||||||
elif action == 'Detach_UE':
|
elif action == 'Detach_UE':
|
||||||
success = CiTestObj.DetachUE(HTML)
|
success = CiTestObj.DetachUE(HTML)
|
||||||
elif action == 'Terminate_UE':
|
elif action == 'Terminate_UE':
|
||||||
success = CiTestObj.TerminateUE(HTML)
|
success = CiTestObj.TerminateUE(ctx, HTML)
|
||||||
elif action == 'CheckStatusUE':
|
elif action == 'CheckStatusUE':
|
||||||
success = CiTestObj.CheckStatusUE(HTML)
|
success = CiTestObj.CheckStatusUE(HTML)
|
||||||
elif action == 'DataEnable_UE':
|
elif action == 'DataEnable_UE':
|
||||||
@@ -253,7 +255,7 @@ def ExecuteActionWithParam(action):
|
|||||||
else:
|
else:
|
||||||
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
|
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
|
||||||
ping_rttavg_threshold = test.findtext('ping_rttavg_threshold') or ''
|
ping_rttavg_threshold = test.findtext('ping_rttavg_threshold') or ''
|
||||||
success = CiTestObj.Ping(HTML, CONTAINERS)
|
success = CiTestObj.Ping(ctx, HTML)
|
||||||
|
|
||||||
elif action == 'Iperf' or action == 'Iperf2_Unidir':
|
elif action == 'Iperf' or action == 'Iperf2_Unidir':
|
||||||
CiTestObj.iperf_args = test.findtext('iperf_args')
|
CiTestObj.iperf_args = test.findtext('iperf_args')
|
||||||
@@ -284,9 +286,9 @@ def ExecuteActionWithParam(action):
|
|||||||
logging.error('test-case has wrong option ' + CiTestObj.iperf_options)
|
logging.error('test-case has wrong option ' + CiTestObj.iperf_options)
|
||||||
CiTestObj.iperf_options = 'check'
|
CiTestObj.iperf_options = 'check'
|
||||||
if action == 'Iperf':
|
if action == 'Iperf':
|
||||||
success = CiTestObj.Iperf(HTML, CONTAINERS)
|
success = CiTestObj.Iperf(ctx, HTML)
|
||||||
elif action == 'Iperf2_Unidir':
|
elif action == 'Iperf2_Unidir':
|
||||||
success = CiTestObj.Iperf2_Unidir(HTML, CONTAINERS)
|
success = CiTestObj.Iperf2_Unidir(ctx, HTML)
|
||||||
|
|
||||||
elif action == 'IdleSleep':
|
elif action == 'IdleSleep':
|
||||||
st = test.findtext('idle_sleep_time_in_sec') or "5"
|
st = test.findtext('idle_sleep_time_in_sec') or "5"
|
||||||
@@ -295,12 +297,12 @@ def ExecuteActionWithParam(action):
|
|||||||
elif action == 'Deploy_Run_PhySim':
|
elif action == 'Deploy_Run_PhySim':
|
||||||
oc_release = test.findtext('oc_release')
|
oc_release = test.findtext('oc_release')
|
||||||
svr_id = test.findtext('svr_id') or None
|
svr_id = test.findtext('svr_id') or None
|
||||||
success = CLUSTER.deploy_oc_physim(HTML, oc_release, svr_id)
|
success = CLUSTER.deploy_oc_physim(ctx, HTML, oc_release, svr_id)
|
||||||
|
|
||||||
elif action == 'DeployCoreNetwork' or action == 'UndeployCoreNetwork':
|
elif action == 'DeployCoreNetwork' or action == 'UndeployCoreNetwork':
|
||||||
cn_id = test.findtext('cn_id')
|
cn_id = test.findtext('cn_id')
|
||||||
core_op = getattr(cls_oaicitest.OaiCiTest, action)
|
core_op = getattr(cls_oaicitest.OaiCiTest, action)
|
||||||
success = core_op(cn_id, HTML)
|
success = core_op(cn_id, ctx, HTML)
|
||||||
|
|
||||||
elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace":
|
elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace":
|
||||||
eNB_instance=test.findtext('eNB_instance')
|
eNB_instance=test.findtext('eNB_instance')
|
||||||
@@ -328,9 +330,9 @@ def ExecuteActionWithParam(action):
|
|||||||
CONTAINERS.num_attempts = int(test.findtext('num_attempts') or 1)
|
CONTAINERS.num_attempts = int(test.findtext('num_attempts') or 1)
|
||||||
CONTAINERS.deploymentTag = cls_containerize.CreateTag(CONTAINERS.ranCommitID, CONTAINERS.ranBranch, CONTAINERS.ranAllowMerge)
|
CONTAINERS.deploymentTag = cls_containerize.CreateTag(CONTAINERS.ranCommitID, CONTAINERS.ranBranch, CONTAINERS.ranAllowMerge)
|
||||||
if action == 'Deploy_Object':
|
if action == 'Deploy_Object':
|
||||||
success = CONTAINERS.DeployObject(HTML)
|
success = CONTAINERS.DeployObject(ctx, HTML)
|
||||||
elif action == 'Undeploy_Object':
|
elif action == 'Undeploy_Object':
|
||||||
success = CONTAINERS.UndeployObject(HTML, RAN)
|
success = CONTAINERS.UndeployObject(ctx, HTML, RAN)
|
||||||
elif action == 'Create_Workspace':
|
elif action == 'Create_Workspace':
|
||||||
if force_local:
|
if force_local:
|
||||||
# Do not create a working directory when running locally. Current repo directory will be used
|
# Do not create a working directory when running locally. Current repo directory will be used
|
||||||
@@ -341,13 +343,13 @@ def ExecuteActionWithParam(action):
|
|||||||
physim_options = test.findtext('physim_run_args')
|
physim_options = test.findtext('physim_run_args')
|
||||||
physim_test = test.findtext('physim_test')
|
physim_test = test.findtext('physim_test')
|
||||||
physim_threshold = test.findtext('physim_time_threshold') or 'inf'
|
physim_threshold = test.findtext('physim_time_threshold') or 'inf'
|
||||||
success = cls_native.Native.Run_Physim(HTML, RAN.eNBIPAddress, RAN.eNBSourceCodePath, physim_options, physim_test, physim_threshold)
|
success = cls_native.Native.Run_Physim(ctx, HTML, RAN.eNBIPAddress, RAN.eNBSourceCodePath, physim_options, physim_test, physim_threshold)
|
||||||
|
|
||||||
elif action == 'LicenceAndFormattingCheck':
|
elif action == 'LicenceAndFormattingCheck':
|
||||||
success = SCA.LicenceAndFormattingCheck(HTML)
|
success = SCA.LicenceAndFormattingCheck(ctx, HTML)
|
||||||
|
|
||||||
elif action == 'Cppcheck_Analysis':
|
elif action == 'Cppcheck_Analysis':
|
||||||
success = SCA.CppCheckAnalysis(HTML)
|
success = SCA.CppCheckAnalysis(ctx, HTML)
|
||||||
|
|
||||||
elif action == 'Push_Local_Registry':
|
elif action == 'Push_Local_Registry':
|
||||||
svr_id = test.findtext('svr_id')
|
svr_id = test.findtext('svr_id')
|
||||||
@@ -407,10 +409,11 @@ def test_in_list(test, list):
|
|||||||
def receive_signal(signum, frame):
|
def receive_signal(signum, frame):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def ShowTestID(ctx, desc):
|
||||||
|
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')
|
||||||
|
logging.info(f'\u001B[1m Test ID: {ctx.test_id} (#{ctx.count}) \u001B[0m')
|
||||||
|
logging.info(f'\u001B[1m {desc} \u001B[0m')
|
||||||
|
logging.info(f'\u001B[1m----------------------------------------\u001B[0m')
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
# MAIN PART
|
# MAIN PART
|
||||||
@@ -466,15 +469,7 @@ if py_param_file_present == True:
|
|||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
|
|
||||||
if re.match('^TerminateeNB$', mode, re.IGNORECASE):
|
if re.match('^TerminateeNB$', mode, re.IGNORECASE):
|
||||||
if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '':
|
logging.warning("Option TerminateeNB ignored")
|
||||||
HELP.GenericHelp(CONST.Version)
|
|
||||||
sys.exit('Insufficient Parameter')
|
|
||||||
if RAN.eNBIPAddress == 'none':
|
|
||||||
sys.exit(0)
|
|
||||||
RAN.eNB_instance=0
|
|
||||||
RAN.eNB_serverId[0]='0'
|
|
||||||
RAN.eNBSourceCodePath='/tmp/'
|
|
||||||
RAN.TerminateeNB(HTML)
|
|
||||||
elif re.match('^TerminateHSS$', mode, re.IGNORECASE):
|
elif re.match('^TerminateHSS$', mode, re.IGNORECASE):
|
||||||
logging.warning("Option TerminateHSS ignored")
|
logging.warning("Option TerminateHSS ignored")
|
||||||
elif re.match('^TerminateMME$', mode, re.IGNORECASE):
|
elif re.match('^TerminateMME$', mode, re.IGNORECASE):
|
||||||
@@ -482,12 +477,7 @@ elif re.match('^TerminateMME$', mode, re.IGNORECASE):
|
|||||||
elif re.match('^TerminateSPGW$', mode, re.IGNORECASE):
|
elif re.match('^TerminateSPGW$', mode, re.IGNORECASE):
|
||||||
logging.warning("Option TerminateSPGW ignored")
|
logging.warning("Option TerminateSPGW ignored")
|
||||||
elif re.match('^LogCollectBuild$', mode, re.IGNORECASE):
|
elif re.match('^LogCollectBuild$', mode, re.IGNORECASE):
|
||||||
if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '':
|
logging.warning("Option LogCollectBuild ignored")
|
||||||
logging.warning("nothing to collect (eNBIPAddress/eNBUserName/eNBPassword/eNBSourceCodePath is '')")
|
|
||||||
sys.exit(0)
|
|
||||||
if RAN.eNBIPAddress == 'none':
|
|
||||||
sys.exit(0)
|
|
||||||
CiTestObj.LogCollectBuild(RAN)
|
|
||||||
elif re.match('^LogCollecteNB$', mode, re.IGNORECASE):
|
elif re.match('^LogCollecteNB$', mode, re.IGNORECASE):
|
||||||
if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '':
|
if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '':
|
||||||
HELP.GenericHelp(CONST.Version)
|
HELP.GenericHelp(CONST.Version)
|
||||||
@@ -565,6 +555,16 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
|
|||||||
else:
|
else:
|
||||||
xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[0]
|
xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[0]
|
||||||
|
|
||||||
|
# directory where all log artifacts will be placed
|
||||||
|
logPath = f"{cwd}/../cmake_targets/log/{CiTestObj.testXMLfiles[0].split('/')[-1]}.d"
|
||||||
|
# we run from within ci-scripts, but the logPath is absolute, so replace
|
||||||
|
# the ci-scripts/..; if it does not exist, nothing will happen
|
||||||
|
logPath = logPath.replace(r'/ci-scripts/..', '')
|
||||||
|
logging.info(f"placing all artifacts for this run in {logPath}/")
|
||||||
|
with cls_cmd.LocalCmd() as c:
|
||||||
|
c.run(f"rm -rf {logPath}")
|
||||||
|
c.run(f"mkdir -p {logPath}")
|
||||||
|
|
||||||
xmlTree = ET.parse(xml_test_file)
|
xmlTree = ET.parse(xml_test_file)
|
||||||
xmlRoot = xmlTree.getroot()
|
xmlRoot = xmlTree.getroot()
|
||||||
|
|
||||||
@@ -615,29 +615,32 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
|
|||||||
task_set_succeeded = True
|
task_set_succeeded = True
|
||||||
HTML.startTime=int(round(time.time() * 1000))
|
HTML.startTime=int(round(time.time() * 1000))
|
||||||
|
|
||||||
|
i = 0
|
||||||
for test_case_id in todo_tests:
|
for test_case_id in todo_tests:
|
||||||
for test in all_tests:
|
for test in all_tests:
|
||||||
id = test.get('id')
|
id = test.get('id')
|
||||||
if test_case_id != id:
|
if test_case_id != id:
|
||||||
continue
|
continue
|
||||||
|
i += 1
|
||||||
CiTestObj.testCase_id = id
|
CiTestObj.testCase_id = id
|
||||||
|
ctx = TestCaseCtx(i, int(id), logPath)
|
||||||
HTML.testCase_id=CiTestObj.testCase_id
|
HTML.testCase_id=CiTestObj.testCase_id
|
||||||
CiTestObj.desc = test.findtext('desc')
|
desc = test.findtext('desc')
|
||||||
always_exec = test.findtext('always_exec') in ['True', 'true', 'Yes', 'yes']
|
always_exec = test.findtext('always_exec') in ['True', 'true', 'Yes', 'yes']
|
||||||
may_fail = test.findtext('may_fail') in ['True', 'true', 'Yes', 'yes']
|
may_fail = test.findtext('may_fail') in ['True', 'true', 'Yes', 'yes']
|
||||||
HTML.desc=CiTestObj.desc
|
HTML.desc = desc
|
||||||
action = test.findtext('class')
|
action = test.findtext('class')
|
||||||
if (CheckClassValidity(xml_class_list, action, id) == False):
|
if (CheckClassValidity(xml_class_list, action, id) == False):
|
||||||
task_set_succeeded = False
|
task_set_succeeded = False
|
||||||
continue
|
continue
|
||||||
CiTestObj.ShowTestID()
|
ShowTestID(ctx, desc)
|
||||||
if not task_set_succeeded and not always_exec:
|
if not task_set_succeeded and not always_exec:
|
||||||
msg = f"skipping test due to prior error"
|
msg = f"skipping test due to prior error"
|
||||||
logging.warning(msg)
|
logging.warning(msg)
|
||||||
HTML.CreateHtmlTestRowQueue(msg, "SKIP", [])
|
HTML.CreateHtmlTestRowQueue(msg, "SKIP", [])
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
test_succeeded = ExecuteActionWithParam(action)
|
test_succeeded = ExecuteActionWithParam(action, ctx)
|
||||||
if not test_succeeded and may_fail:
|
if not test_succeeded and may_fail:
|
||||||
logging.warning(f"test ID {test_case_id} action {action} may or may not fail, proceeding despite error")
|
logging.warning(f"test ID {test_case_id} action {action} may or may not fail, proceeding despite error")
|
||||||
elif not test_succeeded:
|
elif not test_succeeded:
|
||||||
|
|||||||
+18
-50
@@ -46,6 +46,7 @@ import cls_cmd
|
|||||||
import sshconnection as SSH
|
import sshconnection as SSH
|
||||||
import helpreadme as HELP
|
import helpreadme as HELP
|
||||||
import constants as CONST
|
import constants as CONST
|
||||||
|
from cls_ci_helper import archiveArtifact
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
# Class Declaration
|
# Class Declaration
|
||||||
@@ -124,7 +125,6 @@ class RANManagement():
|
|||||||
|
|
||||||
self.testCase_id = HTML.testCase_id
|
self.testCase_id = HTML.testCase_id
|
||||||
mySSH = SSH.SSHConnection()
|
mySSH = SSH.SSHConnection()
|
||||||
cwd = os.getcwd()
|
|
||||||
|
|
||||||
mySSH.open(lIpAddr, lUserName, lPassWord)
|
mySSH.open(lIpAddr, lUserName, lPassWord)
|
||||||
mySSH.command('cd ' + lSourcePath, '\$', 5)
|
mySSH.command('cd ' + lSourcePath, '\$', 5)
|
||||||
@@ -249,42 +249,7 @@ class RANManagement():
|
|||||||
logging.debug('\u001B[1m Initialize eNB/gNB Completed\u001B[0m')
|
logging.debug('\u001B[1m Initialize eNB/gNB Completed\u001B[0m')
|
||||||
return enbDidSync
|
return enbDidSync
|
||||||
|
|
||||||
def CheckeNBProcess(self, status_queue):
|
def TerminateeNB(self, ctx, HTML):
|
||||||
# At least the instance 0 SHALL be on!
|
|
||||||
if self.eNBstatuses[0] == 0:
|
|
||||||
lIpAddr = self.eNBIPAddress
|
|
||||||
lUserName = self.eNBUserName
|
|
||||||
lPassWord = self.eNBPassword
|
|
||||||
elif self.eNBstatuses[0] == 1:
|
|
||||||
lIpAddr = self.eNB1IPAddress
|
|
||||||
lUserName = self.eNB1UserName
|
|
||||||
lPassWord = self.eNB1Password
|
|
||||||
elif self.eNBstatuses[0] == 2:
|
|
||||||
lIpAddr = self.eNB2IPAddress
|
|
||||||
lUserName = self.eNB2UserName
|
|
||||||
lPassWord = self.eNB2Password
|
|
||||||
else:
|
|
||||||
lIpAddr = self.eNBIPAddress
|
|
||||||
lUserName = self.eNBUserName
|
|
||||||
lPassWord = self.eNBPassword
|
|
||||||
mySSH = SSH.SSHConnection()
|
|
||||||
mySSH.open(lIpAddr, lUserName, lPassWord)
|
|
||||||
if self.air_interface[self.eNB_instance] == '':
|
|
||||||
pattern = 'softmodem'
|
|
||||||
else:
|
|
||||||
pattern = self.air_interface[self.eNB_instance]
|
|
||||||
mySSH.command('stdbuf -o0 ps -aux | grep --color=never ' + pattern + ' | grep -v grep', '\$', 5)
|
|
||||||
result = re.search(pattern, mySSH.getBefore())
|
|
||||||
success = result is not None
|
|
||||||
if not success:
|
|
||||||
logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m')
|
|
||||||
status_queue.put(CONST.ENB_PROCESS_FAILED)
|
|
||||||
else:
|
|
||||||
status_queue.put(CONST.ENB_PROCESS_OK)
|
|
||||||
mySSH.close()
|
|
||||||
return success
|
|
||||||
|
|
||||||
def TerminateeNB(self, HTML):
|
|
||||||
if self.eNB_serverId[self.eNB_instance] == '0':
|
if self.eNB_serverId[self.eNB_instance] == '0':
|
||||||
lIpAddr = self.eNBIPAddress
|
lIpAddr = self.eNBIPAddress
|
||||||
lUserName = self.eNBUserName
|
lUserName = self.eNBUserName
|
||||||
@@ -356,13 +321,11 @@ class RANManagement():
|
|||||||
fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)]
|
fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)]
|
||||||
self.eNBLogFiles[int(self.eNB_instance)] = ''
|
self.eNBLogFiles[int(self.eNB_instance)] = ''
|
||||||
if analyzeFile:
|
if analyzeFile:
|
||||||
#*stats.log files + pickle + png
|
with cls_cmd.getConnection(lIpAddr) as cmd:
|
||||||
mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*stats.log', '.')
|
file = archiveArtifact(cmd, ctx, lSourcePath + '/cmake_targets/' + fileToAnalyze)
|
||||||
mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*.pickle', '.')
|
archiveArtifact(cmd, ctx, lSourcePath + '/cmake_targets/nrL1_stats.log')
|
||||||
mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*.png', '.')
|
archiveArtifact(cmd, ctx, lSourcePath + '/cmake_targets/nrMAC_stats.log')
|
||||||
#
|
if file is None:
|
||||||
copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.')
|
|
||||||
if (copyin_res == -1):
|
|
||||||
logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m')
|
logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m')
|
||||||
HTML.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
|
HTML.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
|
||||||
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
|
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
|
||||||
@@ -375,8 +338,8 @@ class RANManagement():
|
|||||||
mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrL1_stats.log', self.eNBSourceCodePath + '/cmake_targets/')
|
mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrL1_stats.log', self.eNBSourceCodePath + '/cmake_targets/')
|
||||||
mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrMAC_stats.log', self.eNBSourceCodePath + '/cmake_targets/')
|
mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrMAC_stats.log', self.eNBSourceCodePath + '/cmake_targets/')
|
||||||
mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/')
|
mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/')
|
||||||
logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze)
|
logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + file)
|
||||||
logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze, HTML, self.ran_checkers)
|
logStatus = self.AnalyzeLogFile_eNB(file, HTML, self.ran_checkers)
|
||||||
if (logStatus < 0):
|
if (logStatus < 0):
|
||||||
HTML.CreateHtmlTestRow('N/A', 'KO', logStatus)
|
HTML.CreateHtmlTestRow('N/A', 'KO', logStatus)
|
||||||
#display rt stats for gNB only
|
#display rt stats for gNB only
|
||||||
@@ -734,11 +697,16 @@ class RANManagement():
|
|||||||
datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
|
datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
|
||||||
rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field
|
rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field
|
||||||
|
|
||||||
if os.path.isfile('./nrL1_stats.log') and os.path.isfile('./nrMAC_stats.log'):
|
# nrL1_stats.log/nrMAC_stats.log should be in the same directory as main log file
|
||||||
|
# currently the link is only implicit as below based on pattern matching
|
||||||
|
# I will rework this to give the file explicitly
|
||||||
|
l1_stats_fn = re.sub(r'enb_[0-9]+', 'nrL1_stats', eNBlogFile)
|
||||||
|
mac_stats_fn = re.sub(r'enb_[0-9]+', 'nrMAC_stats', eNBlogFile)
|
||||||
|
if os.path.isfile(l1_stats_fn) and os.path.isfile(mac_stats_fn):
|
||||||
# don't use CI-nrL1_stats.log, as this will increase the processing time for
|
# don't use CI-nrL1_stats.log, as this will increase the processing time for
|
||||||
# no reason, we just need the last occurence
|
# no reason, we just need the last occurence
|
||||||
nrL1_stats = open('./nrL1_stats.log', 'r')
|
nrL1_stats = open(l1_stats_fn, 'r')
|
||||||
nrMAC_stats = open('./nrMAC_stats.log', 'r')
|
nrMAC_stats = open(mac_stats_fn, 'r')
|
||||||
for line in nrL1_stats.readlines():
|
for line in nrL1_stats.readlines():
|
||||||
for k in rt_keys:
|
for k in rt_keys:
|
||||||
result = re.search(k, line)
|
result = re.search(k, line)
|
||||||
@@ -758,7 +726,7 @@ class RANManagement():
|
|||||||
nrL1_stats.close()
|
nrL1_stats.close()
|
||||||
nrMAC_stats.close()
|
nrMAC_stats.close()
|
||||||
else:
|
else:
|
||||||
logging.debug("NR Stats files for RT analysis not found")
|
logging.debug(f"NR Stats files for RT analysis not found: {l1_stats_fn}, {mac_stats_fn}")
|
||||||
|
|
||||||
#stdout log file and stat log files analysis completed
|
#stdout log file and stat log files analysis completed
|
||||||
logging.debug(' File analysis (stdout, stats) completed')
|
logging.debug(' File analysis (stdout, stats) completed')
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
test:
|
||||||
|
Host: localhost
|
||||||
|
InitScript: ""
|
||||||
|
TermScript: ""
|
||||||
|
AttachScript: "true"
|
||||||
|
DetachScript: "true"
|
||||||
|
NetworkScript: ip a show dev lo
|
||||||
|
IF: lo
|
||||||
|
MTU: 65536
|
||||||
|
|
||||||
|
test-fail:
|
||||||
|
Host: localhost
|
||||||
|
InitScript: ""
|
||||||
|
TermScript: ""
|
||||||
|
AttachScript: "false"
|
||||||
|
DetachScript: "true"
|
||||||
|
NetworkScript: ip a show dev TESTDEVICEDOESNOTEXIST
|
||||||
|
IF: TESTDEVICEDOESNOTEXIST
|
||||||
|
MTU: 123
|
||||||
|
|
||||||
|
test-trace:
|
||||||
|
Host: localhost
|
||||||
|
InitScript: ""
|
||||||
|
TermScript: ""
|
||||||
|
AttachScript: "true"
|
||||||
|
DetachScript: "true"
|
||||||
|
Tracing:
|
||||||
|
# tttf: temp-trace-test-file
|
||||||
|
Start: "rm -f /tmp/tttf; for i in {1..8}; do echo $i >> /tmp/tttf; sleep 1; done &"
|
||||||
|
Stop: "while [[ $(wc -l /tmp/tttf) < 4 ]]; do sleep 1; done"
|
||||||
|
Collect: "cp /tmp/tttf %%log_dir%%"
|
||||||
|
NetworkScript: ip a show dev lo
|
||||||
|
IF: lo
|
||||||
|
MTU: 65536
|
||||||
@@ -6,14 +6,22 @@ logging.basicConfig(
|
|||||||
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
||||||
)
|
)
|
||||||
import os
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
sys.path.append('./') # to find OAI imports below
|
sys.path.append('./') # to find OAI imports below
|
||||||
import cls_corenetwork
|
import cls_corenetwork
|
||||||
|
from cls_ci_helper import TestCaseCtx
|
||||||
import cls_cmd
|
import cls_cmd
|
||||||
|
|
||||||
class TestCoreNetwork(unittest.TestCase):
|
class TestCoreNetwork(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.ctx = TestCaseCtx.Default(tempfile.mkdtemp())
|
||||||
|
def tearDown(self):
|
||||||
|
with cls_cmd.LocalCmd() as c:
|
||||||
|
c.run(f'rm -rf {self.ctx.logPath}')
|
||||||
|
|
||||||
def test_simple_core(self):
|
def test_simple_core(self):
|
||||||
c = cls_corenetwork.CoreNetwork("test", filename="tests/config/test_core_infra.yaml")
|
c = cls_corenetwork.CoreNetwork("test", filename="tests/config/test_core_infra.yaml")
|
||||||
success, output = c.deploy()
|
success, output = c.deploy()
|
||||||
@@ -22,14 +30,14 @@ class TestCoreNetwork(unittest.TestCase):
|
|||||||
# should not have it set in config
|
# should not have it set in config
|
||||||
self.assertTrue(c.runIperf3Server())
|
self.assertTrue(c.runIperf3Server())
|
||||||
self.assertEqual(c.getIP(), "127.0.0.1")
|
self.assertEqual(c.getIP(), "127.0.0.1")
|
||||||
log_files, output = c.undeploy(log_dir="/tmp")
|
log_files, output = c.undeploy(self.ctx)
|
||||||
self.assertEqual(output, "undeploy")
|
self.assertEqual(output, "undeploy")
|
||||||
with cls_cmd.LocalCmd() as cmd:
|
with cls_cmd.LocalCmd() as cmd:
|
||||||
# there must be one log file for this (test) core
|
# there must be one log file for this (test) core
|
||||||
self.assertEqual(len(log_files), 1)
|
self.assertEqual(len(log_files), 1)
|
||||||
# test core writes to %%log_dir%%/logs, which expands to /tmp/logs
|
# undeploy uses archiveArtifact(), which writes to {prefix}-logs
|
||||||
l = log_files[0]
|
l = log_files[0]
|
||||||
self.assertEqual(l, "/tmp/logs")
|
self.assertEqual(l, f"{self.ctx.baseFilename()}-logs")
|
||||||
ret = cmd.run(f"cat {l}")
|
ret = cmd.run(f"cat {l}")
|
||||||
self.assertEqual(ret.returncode, 0) # command must succeed
|
self.assertEqual(ret.returncode, 0) # command must succeed
|
||||||
self.assertEqual(ret.stdout, "logs") # output should be "logs"
|
self.assertEqual(ret.stdout, "logs") # output should be "logs"
|
||||||
@@ -39,14 +47,14 @@ class TestCoreNetwork(unittest.TestCase):
|
|||||||
success, _ = c.deploy()
|
success, _ = c.deploy()
|
||||||
self.assertTrue(success)
|
self.assertTrue(success)
|
||||||
self.assertFalse(c.runIperf3Server())
|
self.assertFalse(c.runIperf3Server())
|
||||||
c.undeploy(log_dir="/tmp")
|
c.undeploy(None)
|
||||||
|
|
||||||
def test_core_fail(self):
|
def test_core_fail(self):
|
||||||
c = cls_corenetwork.CoreNetwork("test_fail", filename="tests/config/test_core_infra.yaml")
|
c = cls_corenetwork.CoreNetwork("test_fail", filename="tests/config/test_core_infra.yaml")
|
||||||
success, _ = c.deploy()
|
success, _ = c.deploy()
|
||||||
self.assertFalse(success)
|
self.assertFalse(success)
|
||||||
# undeployment should still work
|
# undeployment should still work
|
||||||
c.undeploy(log_dir="/tmp")
|
c.undeploy(None)
|
||||||
|
|
||||||
def test_core_script(self):
|
def test_core_script(self):
|
||||||
c = cls_corenetwork.CoreNetwork("test_script", filename="tests/config/test_core_infra.yaml")
|
c = cls_corenetwork.CoreNetwork("test_script", filename="tests/config/test_core_infra.yaml")
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ logging.basicConfig(
|
|||||||
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
||||||
)
|
)
|
||||||
import os
|
import os
|
||||||
|
import tempfile
|
||||||
os.system(f'rm -rf cmake_targets')
|
os.system(f'rm -rf cmake_targets')
|
||||||
os.system(f'mkdir -p cmake_targets/log')
|
os.system(f'mkdir -p cmake_targets/log')
|
||||||
import unittest
|
import unittest
|
||||||
@@ -14,6 +15,7 @@ sys.path.append('./') # to find OAI imports below
|
|||||||
import cls_oai_html
|
import cls_oai_html
|
||||||
import cls_oaicitest
|
import cls_oaicitest
|
||||||
import cls_containerize
|
import cls_containerize
|
||||||
|
from cls_ci_helper import TestCaseCtx
|
||||||
import ran
|
import ran
|
||||||
import cls_cmd
|
import cls_cmd
|
||||||
|
|
||||||
@@ -48,12 +50,16 @@ class TestDeploymentMethods(unittest.TestCase):
|
|||||||
self.cont.eNBPassword = None
|
self.cont.eNBPassword = None
|
||||||
self.cont.eNBSourceCodePath = os.getcwd()
|
self.cont.eNBSourceCodePath = os.getcwd()
|
||||||
self.cont.num_attempts = 3
|
self.cont.num_attempts = 3
|
||||||
|
self.ctx = TestCaseCtx.Default(tempfile.mkdtemp())
|
||||||
|
def tearDown(self):
|
||||||
|
with cls_cmd.LocalCmd() as c:
|
||||||
|
c.run(f'rm -rf {self.ctx.logPath}')
|
||||||
|
|
||||||
def test_deploy(self):
|
def test_deploy(self):
|
||||||
self.cont.yamlPath[0] = 'tests/simple-dep/'
|
self.cont.yamlPath[0] = 'tests/simple-dep/'
|
||||||
self.cont.deploymentTag = "noble"
|
self.cont.deploymentTag = "noble"
|
||||||
deploy = self.cont.DeployObject(self.html)
|
deploy = self.cont.DeployObject(self.ctx, self.html)
|
||||||
undeploy = self.cont.UndeployObject(self.html, self.ran)
|
undeploy = self.cont.UndeployObject(self.ctx, self.html, self.ran)
|
||||||
self.assertTrue(deploy)
|
self.assertTrue(deploy)
|
||||||
self.assertTrue(undeploy)
|
self.assertTrue(undeploy)
|
||||||
|
|
||||||
@@ -61,8 +67,8 @@ class TestDeploymentMethods(unittest.TestCase):
|
|||||||
# fails reliably
|
# fails reliably
|
||||||
old = self.cont.yamlPath
|
old = self.cont.yamlPath
|
||||||
self.cont.yamlPath[0] = 'tests/simple-fail/'
|
self.cont.yamlPath[0] = 'tests/simple-fail/'
|
||||||
deploy = self.cont.DeployObject(self.html)
|
deploy = self.cont.DeployObject(self.ctx, self.html)
|
||||||
self.cont.UndeployObject(self.html, self.ran)
|
self.cont.UndeployObject(self.ctx, self.html, self.ran)
|
||||||
self.assertFalse(deploy)
|
self.assertFalse(deploy)
|
||||||
self.cont.yamlPath = old
|
self.cont.yamlPath = old
|
||||||
|
|
||||||
@@ -70,8 +76,8 @@ class TestDeploymentMethods(unittest.TestCase):
|
|||||||
# fails reliably
|
# fails reliably
|
||||||
old = self.cont.yamlPath
|
old = self.cont.yamlPath
|
||||||
self.cont.yamlPath[0] = 'tests/simple-fail-2svc/'
|
self.cont.yamlPath[0] = 'tests/simple-fail-2svc/'
|
||||||
deploy = self.cont.DeployObject(self.html)
|
deploy = self.cont.DeployObject(self.ctx, self.html)
|
||||||
self.cont.UndeployObject(self.html, self.ran)
|
self.cont.UndeployObject(self.ctx, self.html, self.ran)
|
||||||
self.assertFalse(deploy)
|
self.assertFalse(deploy)
|
||||||
self.cont.yamlPath = old
|
self.cont.yamlPath = old
|
||||||
|
|
||||||
@@ -79,8 +85,8 @@ class TestDeploymentMethods(unittest.TestCase):
|
|||||||
self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora'
|
self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora'
|
||||||
self.cont.services[0] = "oai-gnb"
|
self.cont.services[0] = "oai-gnb"
|
||||||
self.cont.deploymentTag = 'develop-12345678'
|
self.cont.deploymentTag = 'develop-12345678'
|
||||||
deploy = self.cont.DeployObject(self.html)
|
deploy = self.cont.DeployObject(self.ctx, self.html)
|
||||||
undeploy = self.cont.UndeployObject(self.html, self.ran)
|
undeploy = self.cont.UndeployObject(self.ctx, self.html, self.ran)
|
||||||
self.assertTrue(deploy)
|
self.assertTrue(deploy)
|
||||||
self.assertTrue(undeploy)
|
self.assertTrue(undeploy)
|
||||||
|
|
||||||
@@ -88,8 +94,8 @@ class TestDeploymentMethods(unittest.TestCase):
|
|||||||
self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora'
|
self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora'
|
||||||
self.cont.services[0] = "oai-gnb oai-nr-ue"
|
self.cont.services[0] = "oai-gnb oai-nr-ue"
|
||||||
self.cont.deploymentTag = 'develop-12345678'
|
self.cont.deploymentTag = 'develop-12345678'
|
||||||
deploy = self.cont.DeployObject(self.html)
|
deploy = self.cont.DeployObject(self.ctx, self.html)
|
||||||
undeploy = self.cont.UndeployObject(self.html, self.ran)
|
undeploy = self.cont.UndeployObject(self.ctx, self.html, self.ran)
|
||||||
self.assertTrue(deploy)
|
self.assertTrue(deploy)
|
||||||
self.assertTrue(undeploy)
|
self.assertTrue(undeploy)
|
||||||
|
|
||||||
@@ -97,10 +103,10 @@ class TestDeploymentMethods(unittest.TestCase):
|
|||||||
self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora'
|
self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora'
|
||||||
self.cont.services[0] = "oai-gnb"
|
self.cont.services[0] = "oai-gnb"
|
||||||
self.cont.deploymentTag = 'develop-12345678'
|
self.cont.deploymentTag = 'develop-12345678'
|
||||||
deploy1 = self.cont.DeployObject(self.html)
|
deploy1 = self.cont.DeployObject(self.ctx, self.html)
|
||||||
self.cont.services[0] = "oai-nr-ue"
|
self.cont.services[0] = "oai-nr-ue"
|
||||||
deploy2 = self.cont.DeployObject(self.html)
|
deploy2 = self.cont.DeployObject(self.ctx, self.html)
|
||||||
undeploy = self.cont.UndeployObject(self.html, self.ran)
|
undeploy = self.cont.UndeployObject(self.ctx, self.html, self.ran)
|
||||||
self.assertTrue(deploy1)
|
self.assertTrue(deploy1)
|
||||||
self.assertTrue(deploy2)
|
self.assertTrue(deploy2)
|
||||||
self.assertTrue(undeploy)
|
self.assertTrue(undeploy)
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import tempfile
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
stream=sys.stdout,
|
||||||
|
format="[%(asctime)s] %(levelname)8s: %(message)s"
|
||||||
|
)
|
||||||
|
import os
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.path.append('./') # to find OAI imports below
|
||||||
|
import cls_module
|
||||||
|
from cls_ci_helper import TestCaseCtx
|
||||||
|
import cls_cmd
|
||||||
|
|
||||||
|
class TestModule(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.ctx = TestCaseCtx.Default(tempfile.mkdtemp())
|
||||||
|
def tearDown(self):
|
||||||
|
with cls_cmd.LocalCmd() as c:
|
||||||
|
c.run(f'rm -rf {self.ctx.logPath}')
|
||||||
|
|
||||||
|
def test_simple_module(self):
|
||||||
|
c = cls_module.Module_UE("test", filename="tests/config/test_module_infra.yaml")
|
||||||
|
self.assertFalse(c.trace)
|
||||||
|
success = c.initialize()
|
||||||
|
self.assertTrue(success)
|
||||||
|
ip = c.attach()
|
||||||
|
self.assertEqual(ip, "127.0.0.1")
|
||||||
|
self.assertTrue(c.checkMTU())
|
||||||
|
c.detach()
|
||||||
|
logs = c.terminate()
|
||||||
|
self.assertEqual(logs, None) # no tracing
|
||||||
|
|
||||||
|
@unittest.skip("this test takes long: it verifies the UE cannot attach")
|
||||||
|
def test_simple_fail(self):
|
||||||
|
c = cls_module.Module_UE("test-fail", filename="tests/config/test_module_infra.yaml")
|
||||||
|
success = c.initialize()
|
||||||
|
self.assertTrue(success)
|
||||||
|
ip = c.attach()
|
||||||
|
self.assertEqual(ip, None)
|
||||||
|
self.assertFalse(c.checkMTU())
|
||||||
|
c.detach()
|
||||||
|
logs = c.terminate()
|
||||||
|
self.assertEqual(logs, None) # no tracing
|
||||||
|
|
||||||
|
def test_simple_trace(self):
|
||||||
|
c = cls_module.Module_UE("test-trace", filename="tests/config/test_module_infra.yaml")
|
||||||
|
self.assertTrue(c.trace)
|
||||||
|
success = c.initialize()
|
||||||
|
self.assertTrue(success)
|
||||||
|
ip = c.attach()
|
||||||
|
self.assertEqual(ip, "127.0.0.1")
|
||||||
|
self.assertTrue(c.checkMTU())
|
||||||
|
c.detach()
|
||||||
|
tmp = tempfile.mkdtemp()
|
||||||
|
log_file = c.terminate(self.ctx)
|
||||||
|
# undeploy uses archiveArtifact(), which writes to {prefix}-logs
|
||||||
|
self.assertEqual(log_file, [f"{self.ctx.baseFilename()}-tttf"]) # matches test-trace UE collection file
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -9,11 +9,13 @@ import os
|
|||||||
os.system(f'rm -rf cmake_targets')
|
os.system(f'rm -rf cmake_targets')
|
||||||
os.system(f'mkdir -p cmake_targets/log')
|
os.system(f'mkdir -p cmake_targets/log')
|
||||||
import unittest
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
|
||||||
sys.path.append('./') # to find OAI imports below
|
sys.path.append('./') # to find OAI imports below
|
||||||
import cls_oai_html
|
import cls_oai_html
|
||||||
|
from cls_ci_helper import TestCaseCtx
|
||||||
import cls_oaicitest
|
import cls_oaicitest
|
||||||
import cls_containerize
|
import cls_cmd
|
||||||
|
|
||||||
class TestPingIperf(unittest.TestCase):
|
class TestPingIperf(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -22,7 +24,10 @@ class TestPingIperf(unittest.TestCase):
|
|||||||
self.ci = cls_oaicitest.OaiCiTest()
|
self.ci = cls_oaicitest.OaiCiTest()
|
||||||
self.ci.ue_ids = ["test"]
|
self.ci.ue_ids = ["test"]
|
||||||
self.ci.nodes = ["localhost"]
|
self.ci.nodes = ["localhost"]
|
||||||
self.cont = cls_containerize.Containerize()
|
self.ctx = TestCaseCtx.Default(tempfile.mkdtemp())
|
||||||
|
def tearDown(self):
|
||||||
|
with cls_cmd.LocalCmd() as c:
|
||||||
|
c.run(f'rm -rf {self.ctx.logPath}')
|
||||||
|
|
||||||
def test_ping(self):
|
def test_ping(self):
|
||||||
self.ci.ping_args = "-c3"
|
self.ci.ping_args = "-c3"
|
||||||
@@ -30,7 +35,7 @@ class TestPingIperf(unittest.TestCase):
|
|||||||
self.ci.svr_id = "test"
|
self.ci.svr_id = "test"
|
||||||
infra_file = "tests/config/infra_ping_iperf.yaml"
|
infra_file = "tests/config/infra_ping_iperf.yaml"
|
||||||
# TODO Should need nothing but options and UE(s) to use
|
# TODO Should need nothing but options and UE(s) to use
|
||||||
success = self.ci.Ping(self.html, self.cont, infra_file=infra_file)
|
success = self.ci.Ping(self.ctx, self.html, infra_file=infra_file)
|
||||||
self.assertTrue(success)
|
self.assertTrue(success)
|
||||||
|
|
||||||
def test_iperf(self):
|
def test_iperf(self):
|
||||||
@@ -45,7 +50,7 @@ class TestPingIperf(unittest.TestCase):
|
|||||||
self.ci.iperf_profile = "balanced"
|
self.ci.iperf_profile = "balanced"
|
||||||
infra_file = "tests/config/infra_ping_iperf.yaml"
|
infra_file = "tests/config/infra_ping_iperf.yaml"
|
||||||
# TODO Should need nothing but options and UE(s) to use
|
# TODO Should need nothing but options and UE(s) to use
|
||||||
success = self.ci.Iperf(self.html, self.cont, infra_file=infra_file)
|
success = self.ci.Iperf(self.ctx, self.html, infra_file=infra_file)
|
||||||
self.assertTrue(success)
|
self.assertTrue(success)
|
||||||
|
|
||||||
def test_iperf2_unidir(self):
|
def test_iperf2_unidir(self):
|
||||||
@@ -57,7 +62,7 @@ class TestPingIperf(unittest.TestCase):
|
|||||||
self.ci.iperf_profile = "balanced"
|
self.ci.iperf_profile = "balanced"
|
||||||
infra_file = "tests/config/infra_ping_iperf.yaml"
|
infra_file = "tests/config/infra_ping_iperf.yaml"
|
||||||
# TODO Should need nothing but options and UE(s) to use
|
# TODO Should need nothing but options and UE(s) to use
|
||||||
success = self.ci.Iperf2_Unidir(self.html, self.cont, infra_file=infra_file)
|
success = self.ci.Iperf2_Unidir(self.ctx, self.html, infra_file=infra_file)
|
||||||
self.assertTrue(success)
|
self.assertTrue(success)
|
||||||
|
|
||||||
def test_iperf_highrate(self):
|
def test_iperf_highrate(self):
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
<htmlTabIcon>wrench</htmlTabIcon>
|
<htmlTabIcon>wrench</htmlTabIcon>
|
||||||
<TestCaseRequestedList>
|
<TestCaseRequestedList>
|
||||||
111111
|
111111
|
||||||
100001
|
|
||||||
800813
|
800813
|
||||||
000001
|
000001
|
||||||
000002
|
000002
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
<htmlTabIcon>wrench</htmlTabIcon>
|
<htmlTabIcon>wrench</htmlTabIcon>
|
||||||
<TestCaseRequestedList>
|
<TestCaseRequestedList>
|
||||||
111111
|
111111
|
||||||
100001
|
|
||||||
800813
|
800813
|
||||||
000001
|
000001
|
||||||
000002
|
000002
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
<testCase id="100000">
|
<testCase id="100000">
|
||||||
<class>Custom_Command</class>
|
<class>Custom_Command</class>
|
||||||
<desc>Reboot USRP</desc>
|
<desc>Reboot USRP</desc>
|
||||||
|
<may_fail>true</may_fail>
|
||||||
<node>caracal</node>
|
<node>caracal</node>
|
||||||
<command>ssh root@192.168.20.2 reboot</command>
|
<command>ssh root@192.168.20.2 reboot</command>
|
||||||
</testCase>
|
</testCase>
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ RUN /bin/sh oaienv && \
|
|||||||
cd cmake_targets && \
|
cd cmake_targets && \
|
||||||
mkdir -p log && \
|
mkdir -p log && \
|
||||||
./build_oai \
|
./build_oai \
|
||||||
--gNB \
|
--ninja --gNB \
|
||||||
--build-lib "telnetsrv enbscope uescope nrscope" \
|
--build-lib "telnetsrv enbscope uescope nrscope" \
|
||||||
-t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \
|
-t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \
|
||||||
--build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \
|
--build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ RUN /bin/sh oaienv && \
|
|||||||
mkdir -p log && \
|
mkdir -p log && \
|
||||||
scl enable gcc-toolset-13 "\
|
scl enable gcc-toolset-13 "\
|
||||||
./build_oai \
|
./build_oai \
|
||||||
--gNB \
|
--ninja --gNB \
|
||||||
--build-lib 'telnetsrv enbscope uescope nrscope' \
|
--build-lib 'telnetsrv enbscope uescope nrscope' \
|
||||||
-t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \
|
-t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \
|
||||||
--build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION" &&\
|
--build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION" &&\
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ RUN /bin/sh oaienv && \
|
|||||||
cd cmake_targets && \
|
cd cmake_targets && \
|
||||||
mkdir -p log && \
|
mkdir -p log && \
|
||||||
./build_oai \
|
./build_oai \
|
||||||
--gNB \
|
--ninja --gNB \
|
||||||
--build-lib "telnetsrv enbscope uescope nrscope" \
|
--build-lib "telnetsrv enbscope uescope nrscope" \
|
||||||
-t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \
|
-t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \
|
||||||
--build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \
|
--build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \
|
||||||
|
|||||||
Reference in New Issue
Block a user