Merge remote-tracking branch 'origin/develop' into bler_txoptim
This commit is contained in:
@@ -246,17 +246,12 @@ pipeline {
|
||||
script {
|
||||
triggerSlaveJob ('RAN-DockerHub-Push', 'Push-to-Docker-Hub')
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
echo "Push to Docker-Hub OK"
|
||||
}
|
||||
}
|
||||
failure {
|
||||
script {
|
||||
echo "Push to Docker-Hub KO"
|
||||
currentBuild.result = 'FAILURE'
|
||||
}
|
||||
}
|
||||
post {
|
||||
failure {
|
||||
script {
|
||||
echo "Push to Docker-Hub KO"
|
||||
currentBuild.result = 'FAILURE'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,12 @@ pipeline {
|
||||
stages {
|
||||
stage ("gDashboard") {
|
||||
steps {
|
||||
script {
|
||||
//retrieve MR data from gitlab and export to gSheet
|
||||
sh returnStdout: true, script: 'python3 ci-scripts/ran_dashboard.py'
|
||||
script {
|
||||
dir ("ci-scripts/ran_dashboard") {
|
||||
//retrieve MR data from gitlab / mySQL db, build HTML pages and load them to AWS S3 bucket (configured as static web page hosting)
|
||||
//deprecated method : sh returnStdout: true, script: 'python3 ran_dashboard.py'
|
||||
sh returnStdout: true, script: 'python3 Hdashboard.py'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +227,8 @@ class Containerize():
|
||||
if result is not None:
|
||||
forceSharedImageBuild = True
|
||||
sharedTag = 'ci-temp'
|
||||
else:
|
||||
forceSharedImageBuild = True
|
||||
|
||||
# Let's remove any previous run artifacts if still there
|
||||
mySSH.command(self.cli + ' image prune --force', '\$', 30)
|
||||
@@ -578,6 +580,8 @@ class Containerize():
|
||||
# Currently support only one
|
||||
mySSH.command('docker-compose --file ci-docker-compose.yml config', '\$', 5)
|
||||
result = re.search('container_name: (?P<container_name>[a-zA-Z0-9\-\_]+)', mySSH.getBefore())
|
||||
if self.eNB_logFile[self.eNB_instance] == '':
|
||||
self.eNB_logFile[self.eNB_instance] = 'enb_' + HTML.testCase_id + '.log'
|
||||
if result is not None:
|
||||
containerName = result.group('container_name')
|
||||
mySSH.command('docker kill --signal INT ' + containerName, '\$', 30)
|
||||
@@ -718,7 +722,7 @@ class Containerize():
|
||||
cmd = 'mkdir -p ../cmake_targets/log'
|
||||
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||
|
||||
cmd = 'docker exec ' + self.pingContName + ' /bin/bash -c "ping ' + self.pingOptions + '" 2>&1 | tee ../cmake_targets/log/ping_' + HTML.testCase_id + '.log'
|
||||
cmd = 'docker exec ' + self.pingContName + ' /bin/bash -c "ping ' + self.pingOptions + '" 2>&1 | tee ../cmake_targets/log/ping_' + HTML.testCase_id + '.log || true'
|
||||
logging.debug(cmd)
|
||||
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
|
||||
|
||||
@@ -784,18 +788,18 @@ class Containerize():
|
||||
logStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||
|
||||
# Start the server process
|
||||
cmd = 'docker exec -d ' + self.svrContName + ' /bin/bash -c "nohup iperf ' + self.svrOptions + ' > /tmp/iperf_server.log 2>&1"'
|
||||
cmd = 'docker exec -d ' + self.svrContName + ' /bin/bash -c "nohup iperf ' + self.svrOptions + ' > /tmp/iperf_server.log 2>&1" || true'
|
||||
logging.debug(cmd)
|
||||
serverStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||
time.sleep(5)
|
||||
|
||||
# Start the client process
|
||||
cmd = 'docker exec ' + self.cliContName + ' /bin/bash -c "iperf ' + self.cliOptions + '" 2>&1 | tee ../cmake_targets/log/iperf_client_' + HTML.testCase_id + '.log'
|
||||
cmd = 'docker exec ' + self.cliContName + ' /bin/bash -c "iperf ' + self.cliOptions + '" 2>&1 | tee ../cmake_targets/log/iperf_client_' + HTML.testCase_id + '.log || true'
|
||||
logging.debug(cmd)
|
||||
clientStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
|
||||
|
||||
# Stop the server process
|
||||
cmd = 'docker exec ' + self.svrContName + ' /bin/bash -c "pkill iperf"'
|
||||
cmd = 'docker exec ' + self.svrContName + ' /bin/bash -c "pkill iperf" || true'
|
||||
logging.debug(cmd)
|
||||
serverStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||
time.sleep(5)
|
||||
@@ -812,6 +816,7 @@ class Containerize():
|
||||
else:
|
||||
message = 'Server Report and Connection refused Not Found!'
|
||||
self.IperfExit(HTML, False, message)
|
||||
logging.error('\u001B[1;37;41m Iperf Test FAIL\u001B[0m')
|
||||
return
|
||||
|
||||
# Computing the requested bandwidth in float
|
||||
@@ -884,6 +889,8 @@ class Containerize():
|
||||
self.IperfExit(HTML, iperfStatus, 'problem?')
|
||||
if iperfStatus:
|
||||
logging.info('\u001B[1m Iperf Test PASS\u001B[0m')
|
||||
else:
|
||||
logging.error('\u001B[1;37;41m Iperf Test FAIL\u001B[0m')
|
||||
|
||||
def IperfExit(self, HTML, status, message):
|
||||
html_queue = SimpleQueue()
|
||||
@@ -921,7 +928,7 @@ class Containerize():
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
|
||||
# Check if iptables forwarding is accepted
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L FORWARD', '\$', 10)
|
||||
result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
|
||||
@@ -949,7 +956,7 @@ class Containerize():
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
|
||||
# Check if iptables forwarding is accepted
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L FORWARD', '\$', 10)
|
||||
result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
|
||||
@@ -977,7 +984,7 @@ class Containerize():
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
|
||||
# Check if iptables forwarding is accepted
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L FORWARD', '\$', 10)
|
||||
result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
|
||||
@@ -1000,7 +1007,7 @@ class Containerize():
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S sysctl net.ipv4.conf.all.forwarding=1', '\$', 10)
|
||||
# Check if iptables forwarding is accepted
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L', '\$', 10)
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -L FORWARD', '\$', 10)
|
||||
result = re.search('Chain FORWARD .*policy ACCEPT', mySSH.getBefore())
|
||||
if result is None:
|
||||
mySSH.command('echo ' + password + ' | sudo -S iptables -P FORWARD ACCEPT', '\$', 10)
|
||||
|
||||
+59
-49
@@ -368,7 +368,7 @@ class OaiCiTest():
|
||||
except:
|
||||
os.kill(os.getppid(),signal.SIGUSR1)
|
||||
|
||||
def InitializeUE(self,HTML,RAN,EPC, COTS_UE, InfraUE,ue_trace):
|
||||
def InitializeUE(self,HTML,RAN,EPC, COTS_UE, InfraUE,ue_trace,CONTAINERS):
|
||||
if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB
|
||||
if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
@@ -424,12 +424,12 @@ class OaiCiTest():
|
||||
Module_UE.CheckModuleMTU()
|
||||
else: #status==-1 failed to retrieve IP address
|
||||
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.UE_IP_ADDRESS_ISSUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
|
||||
|
||||
|
||||
def InitializeOAIUE(self,HTML,RAN,EPC,COTS_UE,InfraUE):
|
||||
def InitializeOAIUE(self,HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS):
|
||||
if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
sys.exit('Insufficient Parameter')
|
||||
@@ -653,7 +653,7 @@ class OaiCiTest():
|
||||
HTML.htmlUEFailureMsg='nr-uesoftmodem did NOT synced'
|
||||
HTML.CreateHtmlTestRow(self.air_interface + ' ' + self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE')
|
||||
logging.error('\033[91mInitialize OAI UE Failed! \033[0m')
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
|
||||
def checkDevTTYisUnlocked(self):
|
||||
SSH = sshconnection.SSHConnection()
|
||||
@@ -731,7 +731,7 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
|
||||
self.checkDevTTYisUnlocked()
|
||||
|
||||
def AttachCatM(self,HTML,RAN,COTS_UE,EPC,InfraUE):
|
||||
def AttachCatM(self,HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS):
|
||||
if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
sys.exit('Insufficient Parameter')
|
||||
@@ -804,9 +804,9 @@ class OaiCiTest():
|
||||
html_cell = '<pre style="background-color:white">CAT-M module Attachment Failed</pre>'
|
||||
html_queue.put(html_cell)
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
|
||||
def PingCatM(self,HTML,RAN,EPC,COTS_UE,InfraUE):
|
||||
def PingCatM(self,HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS):
|
||||
if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.SourceCodePath == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
sys.exit('Insufficient Parameter')
|
||||
@@ -815,7 +815,7 @@ class OaiCiTest():
|
||||
pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
|
||||
if (pStatus < 0):
|
||||
HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
try:
|
||||
statusQueue = SimpleQueue()
|
||||
@@ -836,7 +836,7 @@ class OaiCiTest():
|
||||
moduleIPAddr = result.group('ipaddr')
|
||||
else:
|
||||
HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
ping_time = re.findall("-c (\d+)",str(self.ping_args))
|
||||
device_id = 'catm'
|
||||
@@ -900,7 +900,7 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue)
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
except:
|
||||
os.kill(os.getppid(),signal.SIGUSR1)
|
||||
|
||||
@@ -992,7 +992,7 @@ class OaiCiTest():
|
||||
except:
|
||||
os.kill(os.getppid(),signal.SIGUSR1)
|
||||
|
||||
def AttachUE(self,HTML,RAN,EPC,COTS_UE,InfraUE):
|
||||
def AttachUE(self,HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS):
|
||||
if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB
|
||||
if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
@@ -1002,7 +1002,7 @@ class OaiCiTest():
|
||||
pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
|
||||
if (pStatus < 0):
|
||||
HTML.CreateHtmlTestRow('N/A', 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
multi_jobs = []
|
||||
status_queue = SimpleQueue()
|
||||
@@ -1021,7 +1021,7 @@ class OaiCiTest():
|
||||
|
||||
if (status_queue.empty()):
|
||||
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
else:
|
||||
attach_status = True
|
||||
@@ -1050,7 +1050,7 @@ class OaiCiTest():
|
||||
time.sleep(5)
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
|
||||
else: #if an ID is specified, it is a module from the yaml infrastructure file
|
||||
#Attention, as opposed to InitializeUE, the connect manager process is not checked as it is supposed to be active already
|
||||
@@ -1086,7 +1086,7 @@ class OaiCiTest():
|
||||
Module_UE.CheckModuleMTU()
|
||||
else: #status==-1 failed to retrieve IP address
|
||||
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.UE_IP_ADDRESS_ISSUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
|
||||
def DetachUE_common(self, device_id, idx,COTS_UE):
|
||||
@@ -1111,7 +1111,7 @@ class OaiCiTest():
|
||||
except:
|
||||
os.kill(os.getppid(),signal.SIGUSR1)
|
||||
|
||||
def DetachUE(self,HTML,RAN,EPC,COTS_UE,InfraUE):
|
||||
def DetachUE(self,HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS):
|
||||
if self.ue_id=='':#no ID specified, then it is a COTS controlled by ADB
|
||||
if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
@@ -1121,7 +1121,7 @@ class OaiCiTest():
|
||||
pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
|
||||
if (pStatus < 0):
|
||||
HTML.CreateHtmlTestRow('N/A', 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
multi_jobs = []
|
||||
cnt = 0
|
||||
@@ -1396,7 +1396,7 @@ class OaiCiTest():
|
||||
except:
|
||||
os.kill(os.getppid(),signal.SIGUSR1)
|
||||
|
||||
def CheckStatusUE(self,HTML,RAN,EPC,COTS_UE,InfraUE):
|
||||
def CheckStatusUE(self,HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS):
|
||||
if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
sys.exit('Insufficient Parameter')
|
||||
@@ -1443,7 +1443,7 @@ class OaiCiTest():
|
||||
|
||||
if (status_queue.empty()):
|
||||
HTML.CreateHtmlTestRow(htmlOptions, 'KO', CONST.ALL_PROCESSES_OK)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
else:
|
||||
check_status = True
|
||||
html_queue = SimpleQueue()
|
||||
@@ -1459,7 +1459,7 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue)
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
|
||||
def GetAllUEIPAddresses(self):
|
||||
SSH = sshconnection.SSHConnection()
|
||||
@@ -1686,14 +1686,14 @@ class OaiCiTest():
|
||||
html_queue.put(html_cell)
|
||||
HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue)
|
||||
|
||||
def PingNoS1(self,HTML,RAN,EPC,COTS_UE,InfraUE):
|
||||
def PingNoS1(self,HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS):
|
||||
SSH=sshconnection.SSHConnection()
|
||||
check_eNB = True
|
||||
check_OAI_UE = True
|
||||
pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
|
||||
if (pStatus < 0):
|
||||
HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args))
|
||||
if ping_from_eNB is not None:
|
||||
@@ -1779,10 +1779,10 @@ class OaiCiTest():
|
||||
except:
|
||||
os.kill(os.getppid(),signal.SIGUSR1)
|
||||
|
||||
def Ping(self,HTML,RAN,EPC,COTS_UE, InfraUE):
|
||||
def Ping(self,HTML,RAN,EPC,COTS_UE, InfraUE, CONTAINERS):
|
||||
result = re.search('noS1', str(RAN.Initialize_eNB_args))
|
||||
if result is not None:
|
||||
self.PingNoS1(HTML,RAN,EPC,COTS_UE,InfraUE)
|
||||
self.PingNoS1(HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS)
|
||||
return
|
||||
if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.SourceCodePath == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
@@ -1795,7 +1795,7 @@ class OaiCiTest():
|
||||
pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
|
||||
if (pStatus < 0):
|
||||
HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
|
||||
if self.ue_id=="":
|
||||
@@ -1803,7 +1803,7 @@ class OaiCiTest():
|
||||
ueIpStatus = self.GetAllUEIPAddresses()
|
||||
if (ueIpStatus < 0):
|
||||
HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
else:
|
||||
self.UEIPAddresses=[]
|
||||
@@ -1830,7 +1830,7 @@ class OaiCiTest():
|
||||
|
||||
if (status_queue.empty()):
|
||||
HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.ALL_PROCESSES_OK)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
else:
|
||||
ping_status = True
|
||||
html_queue = SimpleQueue()
|
||||
@@ -1847,7 +1847,7 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue)
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
|
||||
def Iperf_ComputeTime(self):
|
||||
result = re.search('-t (?P<iperf_time>\d+)', str(self.iperf_args))
|
||||
@@ -2647,7 +2647,7 @@ class OaiCiTest():
|
||||
except:
|
||||
os.kill(os.getppid(),signal.SIGUSR1)
|
||||
|
||||
def IperfNoS1(self,HTML,RAN,EPC,COTS_UE,InfraUE):
|
||||
def IperfNoS1(self,HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS):
|
||||
SSH = sshconnection.SSHConnection()
|
||||
if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
@@ -2657,7 +2657,7 @@ class OaiCiTest():
|
||||
pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
|
||||
if (pStatus < 0):
|
||||
HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
server_on_enb = re.search('-R', str(self.iperf_args))
|
||||
if server_on_enb is not None:
|
||||
@@ -2756,12 +2756,12 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue)
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
|
||||
def Iperf(self,HTML,RAN,EPC,COTS_UE, InfraUE):
|
||||
def Iperf(self,HTML,RAN,EPC,COTS_UE, InfraUE,CONTAINERS):
|
||||
result = re.search('noS1', str(RAN.Initialize_eNB_args))
|
||||
if result is not None:
|
||||
self.IperfNoS1(HTML,RAN,EPC,COTS_UE,InfraUE)
|
||||
self.IperfNoS1(HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS)
|
||||
return
|
||||
if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.SourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
@@ -2774,14 +2774,14 @@ class OaiCiTest():
|
||||
pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
|
||||
if (pStatus < 0):
|
||||
HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
|
||||
if self.ue_id=="":#is not a module, follow legacy code
|
||||
ueIpStatus = self.GetAllUEIPAddresses()
|
||||
if (ueIpStatus < 0):
|
||||
HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
return
|
||||
else: #is a module
|
||||
self.UEIPAddresses=[]
|
||||
@@ -2826,7 +2826,7 @@ class OaiCiTest():
|
||||
|
||||
if (status_queue.empty()):
|
||||
HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.ALL_PROCESSES_OK)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
else:
|
||||
iperf_status = True
|
||||
iperf_noperf = False
|
||||
@@ -2848,7 +2848,7 @@ class OaiCiTest():
|
||||
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue)
|
||||
else:
|
||||
HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
|
||||
def CheckProcessExist(self, check_eNB, check_OAI_UE,RAN,EPC):
|
||||
multi_jobs = []
|
||||
@@ -3280,7 +3280,7 @@ class OaiCiTest():
|
||||
else:
|
||||
HTML.CreateHtmlTestRow('QLog trace is disabled', 'OK', CONST.ALL_PROCESSES_OK)
|
||||
|
||||
def TerminateOAIUE(self,HTML,RAN,COTS_UE,EPC, InfraUE):
|
||||
def TerminateOAIUE(self,HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS):
|
||||
SSH = sshconnection.SSHConnection()
|
||||
SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword)
|
||||
SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5)
|
||||
@@ -3321,11 +3321,11 @@ class OaiCiTest():
|
||||
# Not an error then
|
||||
if (logStatus != CONST.OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'):
|
||||
self.Initialize_OAI_UE_args = ''
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
else:
|
||||
if (logStatus == CONST.OAI_UE_PROCESS_COULD_NOT_SYNC):
|
||||
self.Initialize_OAI_UE_args = ''
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
else:
|
||||
logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m')
|
||||
HTML.htmlUEFailureMsg='<b>' + ueAction + ' Completed</b>\n' + HTML.htmlUEFailureMsg
|
||||
@@ -3334,26 +3334,26 @@ class OaiCiTest():
|
||||
else:
|
||||
HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
|
||||
|
||||
def AutoTerminateUEandeNB(self,HTML,RAN,COTS_UE,EPC,InfraUE):
|
||||
def AutoTerminateUEandeNB(self,HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS):
|
||||
if (self.ADBIPAddress != 'none'):
|
||||
self.testCase_id = 'AUTO-KILL-UE'
|
||||
HTML.testCase_id=self.testCase_id
|
||||
HTML.testCase_id = self.testCase_id
|
||||
self.desc = 'Automatic Termination of UE'
|
||||
HTML.desc='Automatic Termination of UE'
|
||||
HTML.desc = self.desc
|
||||
self.ShowTestID()
|
||||
self.TerminateUE(HTML,COTS_UE,InfraUE,self.ue_trace)
|
||||
if (self.Initialize_OAI_UE_args != ''):
|
||||
self.testCase_id = 'AUTO-KILL-OAI-UE'
|
||||
HTML.testCase_id=self.testCase_id
|
||||
HTML.testCase_id = self.testCase_id
|
||||
self.desc = 'Automatic Termination of OAI-UE'
|
||||
HTML.desc='Automatic Termination of OAI-UE'
|
||||
HTML.desc = self.desc
|
||||
self.ShowTestID()
|
||||
self.TerminateOAIUE(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
if (RAN.Initialize_eNB_args != ''):
|
||||
self.testCase_id = 'AUTO-KILL-RAN'
|
||||
HTML.testCase_id=self.testCase_id
|
||||
HTML.testCase_id = self.testCase_id
|
||||
self.desc = 'Automatic Termination of all RAN nodes'
|
||||
HTML.desc='Automatic Termination of RAN nodes'
|
||||
HTML.desc = self.desc
|
||||
self.ShowTestID()
|
||||
#terminate all RAN nodes eNB/gNB/OCP
|
||||
for instance in range(0, len(RAN.air_interface)):
|
||||
@@ -3363,11 +3363,21 @@ class OaiCiTest():
|
||||
RAN.TerminateeNB(HTML,EPC)
|
||||
if RAN.flexranCtrlInstalled and RAN.flexranCtrlStarted:
|
||||
self.testCase_id = 'AUTO-KILL-flexran-ctl'
|
||||
HTML.testCase_id=self.testCase_id
|
||||
HTML.testCase_id = self.testCase_id
|
||||
self.desc = 'Automatic Termination of FlexRan CTL'
|
||||
HTML.desc='Automatic Termination of FlexRan CTL'
|
||||
HTML.desc = self.desc
|
||||
self.ShowTestID()
|
||||
self.TerminateFlexranCtrl(HTML,RAN,EPC)
|
||||
if CONTAINERS.yamlPath[0] != '':
|
||||
self.testCase_id = 'AUTO-KILL-CONTAINERS'
|
||||
HTML.testCase_id = self.testCase_id
|
||||
self.desc = 'Automatic Termination of all RAN containers'
|
||||
HTML.desc = self.desc
|
||||
self.ShowTestID()
|
||||
for instance in range(0, len(CONTAINERS.yamlPath)):
|
||||
if CONTAINERS.yamlPath[instance]!='':
|
||||
CONTAINERS.eNB_instance=instance
|
||||
CONTAINERS.UndeployObject(HTML,RAN)
|
||||
RAN.prematureExit=True
|
||||
|
||||
def IdleSleep(self,HTML):
|
||||
|
||||
@@ -245,7 +245,7 @@ THREAD_STRUCT =
|
||||
(
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
|
||||
parallel_config = "PARALLEL_SINGLE_THREAD";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_ENABLE";
|
||||
}
|
||||
|
||||
@@ -226,6 +226,7 @@ MACRLCs = (
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
ulsch_max_frame_inactivity = 1;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -226,6 +226,7 @@ MACRLCs = (
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
ulsch_max_frame_inactivity = 1;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
+11
-11
@@ -544,7 +544,7 @@ elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE):
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
sys.exit('Insufficient Parameter')
|
||||
signal.signal(signal.SIGUSR1, receive_signal)
|
||||
CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
elif re.match('^TerminateHSS$', mode, re.IGNORECASE):
|
||||
if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '':
|
||||
HELP.GenericHelp(CONST.Version)
|
||||
@@ -809,39 +809,39 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
|
||||
elif action == 'Terminate_eNB':
|
||||
RAN.TerminateeNB(HTML, EPC)
|
||||
elif action == 'Initialize_UE':
|
||||
CiTestObj.InitializeUE(HTML,RAN, EPC, COTS_UE, InfraUE, CiTestObj.ue_trace)
|
||||
CiTestObj.InitializeUE(HTML,RAN, EPC, COTS_UE, InfraUE, CiTestObj.ue_trace, CONTAINERS)
|
||||
elif action == 'Terminate_UE':
|
||||
CiTestObj.TerminateUE(HTML,COTS_UE, InfraUE, CiTestObj.ue_trace)
|
||||
elif action == 'Attach_UE':
|
||||
CiTestObj.AttachUE(HTML,RAN,EPC,COTS_UE,InfraUE)
|
||||
CiTestObj.AttachUE(HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS)
|
||||
elif action == 'Detach_UE':
|
||||
CiTestObj.DetachUE(HTML,RAN,EPC,COTS_UE,InfraUE)
|
||||
CiTestObj.DetachUE(HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS)
|
||||
elif action == 'DataDisable_UE':
|
||||
CiTestObj.DataDisableUE(HTML)
|
||||
elif action == 'DataEnable_UE':
|
||||
CiTestObj.DataEnableUE(HTML)
|
||||
elif action == 'CheckStatusUE':
|
||||
CiTestObj.CheckStatusUE(HTML,RAN,EPC,COTS_UE,InfraUE)
|
||||
CiTestObj.CheckStatusUE(HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS)
|
||||
elif action == 'Build_OAI_UE':
|
||||
CiTestObj.BuildOAIUE(HTML)
|
||||
elif action == 'Initialize_OAI_UE':
|
||||
CiTestObj.InitializeOAIUE(HTML,RAN,EPC,COTS_UE,InfraUE)
|
||||
CiTestObj.InitializeOAIUE(HTML,RAN,EPC,COTS_UE,InfraUE,CONTAINERS)
|
||||
elif action == 'Terminate_OAI_UE':
|
||||
CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
elif action == 'Initialize_CatM_module':
|
||||
CiTestObj.InitializeCatM(HTML)
|
||||
elif action == 'Terminate_CatM_module':
|
||||
CiTestObj.TerminateCatM(HTML)
|
||||
elif action == 'Attach_CatM_module':
|
||||
CiTestObj.AttachCatM(HTML,RAN,COTS_UE,EPC,InfraUE)
|
||||
CiTestObj.AttachCatM(HTML,RAN,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
elif action == 'Detach_CatM_module':
|
||||
CiTestObj.TerminateCatM(HTML)
|
||||
elif action == 'Ping_CatM_module':
|
||||
CiTestObj.PingCatM(HTML,RAN,EPC,COTS_UE,EPC,InfraUE)
|
||||
CiTestObj.PingCatM(HTML,RAN,EPC,COTS_UE,EPC,InfraUE,CONTAINERS)
|
||||
elif action == 'Ping':
|
||||
CiTestObj.Ping(HTML,RAN,EPC,COTS_UE, InfraUE)
|
||||
CiTestObj.Ping(HTML,RAN,EPC,COTS_UE, InfraUE, CONTAINERS)
|
||||
elif action == 'Iperf':
|
||||
CiTestObj.Iperf(HTML,RAN,EPC,COTS_UE, InfraUE)
|
||||
CiTestObj.Iperf(HTML,RAN,EPC,COTS_UE, InfraUE, CONTAINERS)
|
||||
elif action == 'Reboot_UE':
|
||||
CiTestObj.RebootUE(HTML,RAN,EPC)
|
||||
elif action == 'Initialize_HSS':
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
version: '2'
|
||||
services:
|
||||
mysql:
|
||||
container_name: oaicicd_mysql
|
||||
restart: always
|
||||
image: mysql:latest
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: 'ucZBc2XRYdvEm59F'
|
||||
ports:
|
||||
- "3307:3306"
|
||||
volumes:
|
||||
- /home/oaicicd/mysql/data:/var/lib/mysql
|
||||
@@ -0,0 +1,33 @@
|
||||
import pymysql
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
#This is the script used to write the test results to the mysql DB
|
||||
#Called by Jenkins pipeline (jenkinsfile)
|
||||
#Must be located in /home/oaicicid/mysql on the database host
|
||||
#Usage from Jenkinsfile :
|
||||
#python3 /home/oaicicd/mysql/sql_connect.py ${JOB_NAME} ${params.eNB_MR} ${params.eNB_Branch} ${env.BUILD_ID} ${env.BUILD_URL} ${StatusForDb} ''
|
||||
|
||||
class SQLConnect:
|
||||
def __init__(self):
|
||||
self.connection = pymysql.connect(
|
||||
host='172.22.0.2',
|
||||
user='root',
|
||||
password = 'ucZBc2XRYdvEm59F',
|
||||
db='oaicicd_tests',
|
||||
port=3306
|
||||
)
|
||||
|
||||
def put(self,TEST,MR,BRANCH,BUILD,BUILD_LINK,STATUS):
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
cur=self.connection.cursor()
|
||||
cur.execute ('INSERT INTO test_results (TEST,MR,BRANCH,BUILD,BUILD_LINK,STATUS,DATE) VALUES (%s,%s,%s,%s,%s,%s,%s);' , (TEST, MR, BRANCH, BUILD, BUILD_LINK, STATUS, now))
|
||||
self.connection.commit()
|
||||
self.connection.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mydb=SQLConnect()
|
||||
mydb.put(sys.argv[1],sys.argv[2],sys.argv[3],sys.argv[4],sys.argv[5],sys.argv[6])
|
||||
|
||||
|
||||
+18
-6
@@ -738,8 +738,8 @@ class RANManagement():
|
||||
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/enb_*.pcap .','\$',20)
|
||||
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/gnb_*.pcap .','\$',20)
|
||||
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5)
|
||||
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png', '\$', 60)
|
||||
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png', '\$', 5)
|
||||
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png log/*/*.log log/*/*.pcap', '\$', 60)
|
||||
mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png log/*/*.log log/*/*.pcap', '\$', 15)
|
||||
mySSH.close()
|
||||
|
||||
def AnalyzeLogFile_eNB(self, eNBlogFile, HTML):
|
||||
@@ -800,10 +800,21 @@ class RANManagement():
|
||||
x2ap_pdu = 0
|
||||
#NSA specific log markers
|
||||
nsa_markers ={'SgNBReleaseRequestAcknowledge': [],'FAILURE': [], 'scgFailureInformationNR-r15': [], 'SgNBReleaseRequest': []}
|
||||
nodeB_prefix_found = False
|
||||
|
||||
line_cnt=0 #log file line counter
|
||||
for line in enb_log_file.readlines():
|
||||
line_cnt+=1
|
||||
# Detection of eNB/gNB from a container log
|
||||
result = re.search('Starting eNB soft modem', str(line))
|
||||
if result is not None:
|
||||
nodeB_prefix_found = True
|
||||
nodeB_prefix = 'e'
|
||||
result = re.search('Starting gNB soft modem', str(line))
|
||||
if result is not None:
|
||||
nodeB_prefix_found = True
|
||||
nodeB_prefix = 'g'
|
||||
result = re.search('Run time:' ,str(line))
|
||||
# Runtime statistics
|
||||
result = re.search('Run time:' ,str(line))
|
||||
if result is not None:
|
||||
@@ -1037,10 +1048,11 @@ class RANManagement():
|
||||
logging.debug(' File analysis (stdout, stats) completed')
|
||||
|
||||
#post processing depending on the node type
|
||||
if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
|
||||
nodeB_prefix = 'e'
|
||||
else:
|
||||
nodeB_prefix = 'g'
|
||||
if not nodeB_prefix_found:
|
||||
if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
|
||||
nodeB_prefix = 'e'
|
||||
else:
|
||||
nodeB_prefix = 'g'
|
||||
|
||||
if nodeB_prefix == 'g':
|
||||
if ulschReceiveOK > 0:
|
||||
|
||||
@@ -0,0 +1,401 @@
|
||||
#/*
|
||||
# * 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
|
||||
# */
|
||||
#---------------------------------------------------------------------
|
||||
# Merge Requests Dashboard for RAN on googleSheet
|
||||
#
|
||||
# Required Python Version
|
||||
# Python 3.x
|
||||
#
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Import
|
||||
#-----------------------------------------------------------
|
||||
|
||||
|
||||
#Author Remi
|
||||
import boto3
|
||||
import shlex
|
||||
import subprocess
|
||||
import json #json structures
|
||||
import datetime #now() and date formating
|
||||
from datetime import datetime
|
||||
import re
|
||||
import gitlab
|
||||
import yaml
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
from sqlconnect import SQLConnect
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Class Declaration
|
||||
#-----------------------------------------------------------
|
||||
|
||||
class Dashboard:
|
||||
def __init__(self):
|
||||
|
||||
|
||||
#init with data sources : git, yaml config file, test results databases
|
||||
print("Collecting Data")
|
||||
cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """
|
||||
self.git = self.__getGitData(cmd) #git data from Gitlab
|
||||
self.tests = self.__loadCfg('ran_dashboard_cfg.yaml') #tests table setup from yaml
|
||||
self.db = self.__loadFromDB() #test results from database
|
||||
|
||||
|
||||
def __loadCfg(self,yaml_file):
|
||||
with open(yaml_file,'r') as f:
|
||||
tests = yaml.load(f)
|
||||
return tests
|
||||
|
||||
def __getGitData(self,cmd):
|
||||
#cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """
|
||||
process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
|
||||
output = process.stdout.readline()
|
||||
tmp=output.decode("utf-8")
|
||||
d = json.loads(tmp)
|
||||
return d
|
||||
|
||||
def __loadFromDB(self):
|
||||
mr_list=[]
|
||||
for x in range(len(self.git)):
|
||||
mr_list.append(str(self.git[x]['iid']))
|
||||
mydb=SQLConnect()
|
||||
for MR in mr_list:
|
||||
mydb.get(MR)
|
||||
mydb.close_connection()
|
||||
return mydb.data
|
||||
|
||||
def Test_initHTML(self, date):
|
||||
self.f_html.write('<!DOCTYPE html>\n')
|
||||
self.f_html.write('<head>\n')
|
||||
self.f_html.write('<link rel="stylesheet" href="test_styles.css">\n')
|
||||
self.f_html.write('<title>Test Dashboard</title>\n')
|
||||
self.f_html.write('</head>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
self.f_html.write('<table>\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td class="Main">OAI RAN TEST Status Dashboard</td>\n')
|
||||
self.f_html.write('</td>\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td class="DashLink"> <a href="https://oairandashboard.s3.eu-west-1.amazonaws.com/index.html">Merge Requests Dashboard</a></td>\n')
|
||||
self.f_html.write('</td>\n')
|
||||
self.f_html.write('<tr></tr>\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td class="Date">Update : '+date+'</td>\n')
|
||||
self.f_html.write('</td>\n')
|
||||
self.f_html.write('</tr>\n')
|
||||
self.f_html.write('</table>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
|
||||
def Test_terminateHTML(self):
|
||||
self.f_html.write('</body>\n')
|
||||
self.f_html.write('</html>\n')
|
||||
self.f_html.close()
|
||||
|
||||
|
||||
def MR_initHTML(self,date):
|
||||
self.f_html.write('<!DOCTYPE html>\n')
|
||||
self.f_html.write('<head>\n')
|
||||
self.f_html.write('<link rel="stylesheet" href="mr_styles.css">\n')
|
||||
self.f_html.write('<title>MR Dashboard</title>\n')
|
||||
self.f_html.write('</head>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
self.f_html.write('<table>\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td class="Main">OAI RAN MR Status Dashboard</td>\n')
|
||||
self.f_html.write('</td>\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td class="DashLink"> <a href="https://oaitestdashboard.s3.eu-west-1.amazonaws.com/index.html">Tests Dashboard</a></td>\n')
|
||||
self.f_html.write('</td>\n')
|
||||
self.f_html.write('<tr></tr>\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td class="Date">Update : '+date+'</td>\n')
|
||||
self.f_html.write('</td>\n')
|
||||
self.f_html.write('</tr>\n')
|
||||
self.f_html.write('</table>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
self.f_html.write('<br>\n')
|
||||
self.f_html.write('<table class="MR_Table">\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<th class="MR">MR</th>\n')
|
||||
self.f_html.write('<th class="CREATED_AT">Created_At</th>\n')
|
||||
self.f_html.write('<th class="AUTHOR">Author</th>\n')
|
||||
self.f_html.write('<th class="TITLE">Title</th>\n')
|
||||
self.f_html.write('<th class="ASSIGNEE">Assignee</th>\n')
|
||||
self.f_html.write('<th class="REVIEWER">Reviewer</th>\n')
|
||||
self.f_html.write('<th class="CAN_START">CAN START</th>\n')
|
||||
self.f_html.write('<th class="IN_PROGRESS">IN PROGRESS</th>\n')
|
||||
self.f_html.write('<th class="COMPLETED">COMPLETED</th>\n')
|
||||
self.f_html.write('<th class="REVIEW_FORM">Review Form</th>\n')
|
||||
self.f_html.write('<th class="OK_MERGE">OK Merge</th>\n')
|
||||
self.f_html.write('<th class="MERGE_CONFLICTS">Merge Conflicts</th>\n')
|
||||
self.f_html.write('</tr>\n')
|
||||
|
||||
def MR_terminateHTML(self):
|
||||
self.f_html.write('</table> \n')
|
||||
self.f_html.write('</body>\n')
|
||||
self.f_html.write('</html>\n')
|
||||
self.f_html.close()
|
||||
|
||||
|
||||
def MR_rowHTML(self,row):
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td><a href=\"'+row[0]+'\">'+row[1]+'</a></td>\n')
|
||||
self.f_html.write('<td>'+row[2]+'</td>\n')
|
||||
self.f_html.write('<td>'+row[3]+'</td>\n')
|
||||
self.f_html.write('<td class="title_cell">'+row[4]+'</td>\n')
|
||||
self.f_html.write('<td>'+row[5]+'</td>\n')
|
||||
self.f_html.write('<td>'+row[6]+'</td>\n')
|
||||
if row[7]=='X':
|
||||
self.f_html.write('<td style="background-color: orange;">'+row[7]+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
if row[8]=='X':
|
||||
self.f_html.write('<td style="background-color: yellow;">'+row[8]+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
if row[9]=='X':
|
||||
self.f_html.write('<td style="background-color: rgb(144, 221, 231);">'+row[9]+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
if row[10]=='X':
|
||||
self.f_html.write('<td style="background-color: rgb(58, 236, 58);">'+row[10]+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
if row[11]=='X':
|
||||
self.f_html.write('<td style="background-color: rgb(58, 236, 58);">'+row[11]+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
if row[12]=='YES':
|
||||
self.f_html.write('<td style="background-color: red;">'+row[12]+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
self.f_html.write('</tr>\n')
|
||||
|
||||
|
||||
def Build(self, type, htmlfilename):
|
||||
if type=='MR':
|
||||
self.Build_MR_Table(htmlfilename)
|
||||
elif type=='Tests':
|
||||
self.Build_Test_Table(htmlfilename)
|
||||
else :
|
||||
print("Undefined Dashboard Type, options : MR or Tests")
|
||||
|
||||
|
||||
def Build_Test_Table(self,htmlfilename):
|
||||
print("Building Tests Dashboard...")
|
||||
|
||||
self.f_html=open(htmlfilename,'w')
|
||||
|
||||
###update date/time, format dd/mm/YY H:M:S
|
||||
now = datetime.now()
|
||||
dt_string = now.strftime("%d/%m/%Y %H:%M")
|
||||
#HTML table header
|
||||
self.Test_initHTML(dt_string)
|
||||
|
||||
|
||||
#1 table per MR if test results exist
|
||||
for x in range(len(self.git)):
|
||||
mr=str(self.git[x]['iid'])
|
||||
if 'PASS' not in self.db[mr]:
|
||||
self.f_html.write('<h3><a href="https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/'+mr+'">'+mr+'</a>'+' '+self.git[x]['title'] + '</h3>\n')
|
||||
self.f_html.write('<table class="Test_Table">\n')
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<th class="Test_Name">Test Name</th>\n')
|
||||
self.f_html.write('<th class="Test_Descr">Bench</th> \n')
|
||||
self.f_html.write('<th class="Test_Descr">Test</th> \n')
|
||||
self.f_html.write('<th class="Pass"># Pass</th>\n')
|
||||
self.f_html.write('<th class="Fail"># Fail</th>\n')
|
||||
self.f_html.write('<th class="Last_Pass">Last Pass</th>\n')
|
||||
self.f_html.write('<th class="Last_Fail">Last Fail</th>\n')
|
||||
self.f_html.write('</tr>\n')
|
||||
|
||||
#parsing the tests
|
||||
for t in self.tests:
|
||||
|
||||
row=[]
|
||||
short_name= t
|
||||
hyperlink= self.tests[t]['link']
|
||||
job=self.tests[t]['job']
|
||||
|
||||
|
||||
if job in self.db[mr]:
|
||||
if 'PASS' in self.db[mr][job]:
|
||||
row.append(self.db[mr][job]['PASS'])
|
||||
else:
|
||||
row.append('')
|
||||
if 'FAIL' in self.db[mr][job]:
|
||||
row.append(self.db[mr][job]['FAIL'])
|
||||
else:
|
||||
row.append('')
|
||||
#2 columns for last_pass and last_fail links
|
||||
if 'last_pass' in self.db[mr][job]:
|
||||
lastpasshyperlink= self.db[mr][job]['last_pass'][1]
|
||||
lastpasstext= self.db[mr][job]['last_pass'][0]
|
||||
else:
|
||||
lastpasshyperlink=''
|
||||
lastpasstext=''
|
||||
|
||||
if 'last_fail' in self.db[mr][job]:
|
||||
lastfailhyperlink= self.db[mr][job]['last_fail'][1]
|
||||
lastfailtext= self.db[mr][job]['last_fail'][0]
|
||||
else:
|
||||
lastfailhyperlink=''
|
||||
lastfailtext=''
|
||||
|
||||
|
||||
|
||||
self.f_html.write('<tr>\n')
|
||||
self.f_html.write('<td><a href='+hyperlink+'>'+short_name+'</a></td>\n')
|
||||
self.f_html.write('<td>'+self.tests[t]['bench']+'</td>\n')
|
||||
self.f_html.write('<td>'+self.tests[t]['test']+'</td>\n')
|
||||
if row[0]!='':
|
||||
self.f_html.write('<td style="background-color: rgb(58, 236, 58);">'+str(row[0])+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
if row[1]!='':
|
||||
self.f_html.write('<td style="background-color: red;">'+str(row[1])+'</td>\n')
|
||||
else:
|
||||
self.f_html.write('<td></td>\n')
|
||||
self.f_html.write('<td><a href='+lastpasshyperlink+'>'+lastpasstext+'</a></td>\n')
|
||||
self.f_html.write('<td><a href='+lastfailhyperlink+'>'+lastfailtext+'</a></td>\n')
|
||||
self.f_html.write('</tr>\n')
|
||||
|
||||
self.f_html.write('</table>\n')
|
||||
|
||||
#terminate HTML table and close file
|
||||
self.Test_terminateHTML()
|
||||
|
||||
|
||||
def Build_MR_Table(self,htmlfilename):
|
||||
|
||||
print("Building Merge Requests Dashboard...")
|
||||
|
||||
self.f_html=open(htmlfilename,'w')
|
||||
|
||||
###update date/time, format dd/mm/YY H:M:S
|
||||
now = datetime.now()
|
||||
dt_string = now.strftime("%d/%m/%Y %H:%M")
|
||||
|
||||
#HTML table header
|
||||
self.MR_initHTML(dt_string)
|
||||
|
||||
|
||||
###MR data lines
|
||||
for x in range(len(self.git)):
|
||||
|
||||
|
||||
hyperlink= 'https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/'+ str(self.git[x]['iid'])
|
||||
text= str(self.git[x]['iid'])
|
||||
|
||||
|
||||
date_time_str = self.git[x]['created_at']
|
||||
date_time_obj = datetime.strptime(date_time_str, '%Y-%m-%dT%H:%M:%S.%fZ')
|
||||
|
||||
milestone1=milestone2=milestone3=milestone4=""
|
||||
if self.git[x]['milestone']!=None:
|
||||
if self.git[x]['milestone']['title']=="REVIEW_CAN_START":
|
||||
milestone1="X"
|
||||
elif self.git[x]['milestone']['title']=="REVIEW_IN_PROGRESS":
|
||||
milestone2="X"
|
||||
elif self.git[x]['milestone']['title']=="REVIEW_COMPLETED_AND_APPROVED":
|
||||
milestone3="X"
|
||||
elif self.git[x]['milestone']['title']=="OK_TO_BE_MERGED":
|
||||
milestone4="X"
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
#check if empty or not
|
||||
if self.git[x]['assignee']!=None:
|
||||
assignee = str(self.git[x]['assignee']['name'])
|
||||
else:
|
||||
assignee = ""
|
||||
|
||||
#check if empty or not
|
||||
if len(self.git[x]['reviewers'])!=0:
|
||||
reviewer = str(self.git[x]['reviewers'][0]['name'])
|
||||
else:
|
||||
reviewer = ""
|
||||
|
||||
if self.git[x]['has_conflicts']==True:
|
||||
conflicts = "YES"
|
||||
else:
|
||||
conflicts = ""
|
||||
|
||||
|
||||
#add a column flagging that the review form is present
|
||||
#we use gitlab API to parse the MR notes
|
||||
gl = gitlab.Gitlab.from_config('OAI')
|
||||
project_id = 223
|
||||
project = gl.projects.get(project_id)
|
||||
#get the opened MR in the project
|
||||
mrs = project.mergerequests.list(state='opened',per_page=100)
|
||||
review_form=''
|
||||
for m in range (0,len(mrs)):
|
||||
if mrs[m].iid==self.git[x]['iid']:#check the iid is the one we are on
|
||||
mr_notes = mrs[m].notes.list(all=True)
|
||||
n=0
|
||||
found=False
|
||||
while found==False and n<len(mr_notes):
|
||||
res=re.search('Code Review by',mr_notes[n].body)#this is the marker we are looking for in all notes
|
||||
if res!=None:
|
||||
review_form = "X"
|
||||
found=True
|
||||
n+=1
|
||||
|
||||
#build final row to be inserted
|
||||
row =[hyperlink, text, str(date_time_obj.date()),str(self.git[x]['author']['name']), str(self.git[x]['title']),\
|
||||
assignee, reviewer,\
|
||||
milestone1,milestone2,milestone3,review_form,milestone4,conflicts]
|
||||
|
||||
self.MR_rowHTML(row)
|
||||
|
||||
#terminate HTML table and close file
|
||||
self.MR_terminateHTML()
|
||||
|
||||
def CopyToS3(self,htmlfilename,bucket,key):
|
||||
print("Uploading to S3 bucket")
|
||||
#Creating Session With Boto3.
|
||||
s3 = boto3.client('s3')
|
||||
|
||||
#Creating S3 Resource From the Session.
|
||||
result = s3.upload_file(htmlfilename, bucket,key, ExtraArgs={'ACL':'public-read','ContentType': 'text/html'})
|
||||
|
||||
def main():
|
||||
|
||||
htmlDash=Dashboard()
|
||||
htmlDash.Build('MR','/tmp/MR_index.html')
|
||||
htmlDash.CopyToS3('/tmp/MR_index.html','oairandashboard','index.html')
|
||||
htmlDash.Build('Tests','/tmp/Tests_index.html')
|
||||
htmlDash.CopyToS3('/tmp/Tests_index.html','oaitestdashboard','index.html')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# execute only if run as a script
|
||||
main()
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
body {
|
||||
font-family: 'lato', sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.Main {
|
||||
text-align:left;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.DashLink {
|
||||
text-align:left;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.DashLink:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.Date {
|
||||
text-align:left;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:visited { text-decoration: none; color:blue}
|
||||
a:hover { text-decoration: none; font-weight: bold; color:blue}
|
||||
|
||||
|
||||
.MR_Table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.MR_Table tr {
|
||||
font-size: 12px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
|
||||
.MR_Table tr:hover {
|
||||
background-color:lightgray;
|
||||
}
|
||||
|
||||
.MR_Table td {
|
||||
border: 1px solid black;
|
||||
padding : 5px;
|
||||
}
|
||||
.MR_Table td:hover {
|
||||
font-weight : bold;
|
||||
}
|
||||
|
||||
.MR_Table th {
|
||||
font-size: 14px;
|
||||
text-align:center;
|
||||
padding : 5px;
|
||||
}
|
||||
|
||||
|
||||
.title_cell {
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
.MR {
|
||||
table-layout: fixed;
|
||||
width: 50px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.CREATED_AT {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.AUTHOR {
|
||||
table-layout: fixed;
|
||||
width: 150px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.TITLE {
|
||||
table-layout: fixed;
|
||||
width: 500px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.ASSIGNEE {
|
||||
table-layout: fixed;
|
||||
width: 150px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.REVIEWER {
|
||||
table-layout: fixed;
|
||||
width: 150px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.CAN_START {
|
||||
background-color: orange;
|
||||
table-layout: fixed;
|
||||
width: 150px;
|
||||
}
|
||||
.IN_PROGRESS {
|
||||
background-color: yellow;
|
||||
table-layout: fixed;
|
||||
width: 150px;
|
||||
}
|
||||
.COMPLETED {
|
||||
background-color: rgb(144, 221, 231);
|
||||
table-layout: fixed;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.REVIEW_FORM {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.OK_MERGE {
|
||||
background-color: rgb(58, 236, 58);
|
||||
table-layout: fixed;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.MERGE_CONFLICTS {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
# Import
|
||||
#-----------------------------------------------------------
|
||||
|
||||
#author Remi
|
||||
|
||||
#import google spreadsheet API
|
||||
import gspread
|
||||
from oauth2client.service_account import ServiceAccountCredentials
|
||||
@@ -42,6 +44,13 @@ import datetime #now() and date formating
|
||||
from datetime import datetime
|
||||
import re
|
||||
import gitlab
|
||||
import yaml
|
||||
import os
|
||||
import pickle
|
||||
import time
|
||||
|
||||
|
||||
from sqlconnect import SQLConnect
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Class Declaration
|
||||
@@ -57,48 +66,78 @@ class gDashboard:
|
||||
#worksheet
|
||||
self.sheet = self.ss.worksheet(worksheet)
|
||||
self.ss.del_worksheet(self.sheet) #start by deleting the old sheet
|
||||
self.sheet = self.ss.add_worksheet(title=worksheet, rows="100", cols="20") #create a new one
|
||||
|
||||
self.d = {} #data dictionary
|
||||
self.sheet = self.ss.add_worksheet(title=worksheet, rows="100", cols="30") #create a new one
|
||||
|
||||
#init with data sources : git, yaml config file, test results databases
|
||||
cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """
|
||||
self.git = self.__getGitData(cmd) #git data from Gitlab
|
||||
self.tests = self.__loadCfg('ran_dashboard_cfg.yaml') #tests table setup from yaml
|
||||
self.db = self.__loadFromDB() #test results from database
|
||||
|
||||
|
||||
def fetchData(self,cmd):
|
||||
def __loadCfg(self,yaml_file):
|
||||
with open(yaml_file,'r') as f:
|
||||
tests = yaml.load(f)
|
||||
return tests
|
||||
|
||||
def __getGitData(self,cmd):
|
||||
#cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """
|
||||
process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
|
||||
output = process.stdout.readline()
|
||||
tmp=output.decode("utf-8")
|
||||
self.d = json.loads(tmp)
|
||||
d = json.loads(tmp)
|
||||
return d
|
||||
|
||||
def __loadFromDB(self):
|
||||
mr_list=[]
|
||||
for x in range(len(self.git)):
|
||||
mr_list.append(str(self.git[x]['iid']))
|
||||
mydb=SQLConnect()
|
||||
for MR in mr_list:
|
||||
mydb.get(MR)
|
||||
mydb.close_connection()
|
||||
return mydb.data
|
||||
|
||||
|
||||
|
||||
def gBuild(self, destinationSheetName):
|
||||
|
||||
#line 1 : update date/time, format dd/mm/YY H:M:S
|
||||
###line 1 : update date/time, format dd/mm/YY H:M:S
|
||||
now = datetime.now()
|
||||
dt_string = "Update : " + now.strftime("%d/%m/%Y %H:%M")
|
||||
row =[dt_string]
|
||||
self.sheet.insert_row(row, index=1, value_input_option='RAW')
|
||||
|
||||
#line 2 empty
|
||||
#line 3 is for the column names
|
||||
###line 2 is for the test short names (links to jenkins pipeline), updated at the end
|
||||
|
||||
###line 3 is for the column names
|
||||
i=3
|
||||
row =["MR","Created_at","Author","Title","Assignee", "Reviewer", "CAN START","IN PROGRESS","COMPLETED","Review Form","OK MERGE","Merge conflicts"]
|
||||
row =["MR","Created_at","Author","Title","Assignee", "Reviewer", "CAN START","IN PROGRESS","COMPLETED","Review Form","OK MERGE","Merge conflicts",""]
|
||||
|
||||
#tests
|
||||
for t in range(0,len(self.tests)):
|
||||
row.append("# PASS")
|
||||
row.append("# FAIL")
|
||||
row.append("Last Pass")
|
||||
row.append("Last Fail")
|
||||
|
||||
self.sheet.insert_row(row, index=i, value_input_option='RAW')
|
||||
|
||||
#line 4 onward, MR data lines
|
||||
for x in range(len(self.d)):
|
||||
###line 4 onward, MR data lines
|
||||
for x in range(len(self.git)):
|
||||
i=i+1
|
||||
date_time_str = self.d[x]['created_at']
|
||||
date_time_str = self.git[x]['created_at']
|
||||
date_time_obj = datetime.strptime(date_time_str, '%Y-%m-%dT%H:%M:%S.%fZ')
|
||||
|
||||
milestone1=milestone2=milestone3=milestone4=""
|
||||
if self.d[x]['milestone']!=None:
|
||||
if self.d[x]['milestone']['title']=="REVIEW_CAN_START":
|
||||
if self.git[x]['milestone']!=None:
|
||||
if self.git[x]['milestone']['title']=="REVIEW_CAN_START":
|
||||
milestone1="X"
|
||||
elif self.d[x]['milestone']['title']=="REVIEW_IN_PROGRESS":
|
||||
elif self.git[x]['milestone']['title']=="REVIEW_IN_PROGRESS":
|
||||
milestone2="X"
|
||||
elif self.d[x]['milestone']['title']=="REVIEW_COMPLETED_AND_APPROVED":
|
||||
elif self.git[x]['milestone']['title']=="REVIEW_COMPLETED_AND_APPROVED":
|
||||
milestone3="X"
|
||||
elif self.d[x]['milestone']['title']=="OK_TO_BE_MERGED":
|
||||
elif self.git[x]['milestone']['title']=="OK_TO_BE_MERGED":
|
||||
milestone4="X"
|
||||
else:
|
||||
pass
|
||||
@@ -106,18 +145,18 @@ class gDashboard:
|
||||
pass
|
||||
|
||||
#check if empty or not
|
||||
if self.d[x]['assignee']!=None:
|
||||
assignee = str(self.d[x]['assignee']['name'])
|
||||
if self.git[x]['assignee']!=None:
|
||||
assignee = str(self.git[x]['assignee']['name'])
|
||||
else:
|
||||
assignee = ""
|
||||
|
||||
#check if empty or not
|
||||
if len(self.d[x]['reviewers'])!=0:
|
||||
reviewer = str(self.d[x]['reviewers'][0]['name'])
|
||||
if len(self.git[x]['reviewers'])!=0:
|
||||
reviewer = str(self.git[x]['reviewers'][0]['name'])
|
||||
else:
|
||||
reviewer = ""
|
||||
|
||||
if self.d[x]['has_conflicts']==True:
|
||||
if self.git[x]['has_conflicts']==True:
|
||||
conflicts = "YES"
|
||||
else:
|
||||
conflicts = ""
|
||||
@@ -129,13 +168,13 @@ class gDashboard:
|
||||
project_id = 223
|
||||
project = gl.projects.get(project_id)
|
||||
#get the opened MR in the project
|
||||
mrs = project.mergerequests.list(state='opened')
|
||||
mrs = project.mergerequests.list(state='opened',per_page=100)
|
||||
review_form=''
|
||||
for m in range (0,len(mrs)):
|
||||
if mrs[m].iid==self.d[x]['iid']:#check the iid is the one we are on
|
||||
if mrs[m].iid==self.git[x]['iid']:#check the iid is the one we are on
|
||||
mr_notes = mrs[m].notes.list(all=True)
|
||||
n=0
|
||||
found=False
|
||||
review_form=""
|
||||
while found==False and n<len(mr_notes):
|
||||
res=re.search('Code Review by',mr_notes[n].body)#this is the marker we are looking for in all notes
|
||||
if res!=None:
|
||||
@@ -143,29 +182,81 @@ class gDashboard:
|
||||
found=True
|
||||
n+=1
|
||||
|
||||
|
||||
#build final row to be inserted, the first column is left empty for now, will be filled afterward with hyperlinks to gitlab MR
|
||||
row =["", str(date_time_obj.date()),str(self.d[x]['author']['name']),str(self.d[x]['title']),\
|
||||
row =["", str(date_time_obj.date()),str(self.git[x]['author']['name']), str(self.git[x]['title']),\
|
||||
assignee, reviewer,\
|
||||
milestone1,milestone2,milestone3,review_form,milestone4,conflicts]
|
||||
|
||||
#insert the row to worksheet
|
||||
milestone1,milestone2,milestone3,review_form,milestone4,conflicts,""]
|
||||
#and append the test results coming from self.db
|
||||
mr=str(self.git[x]['iid'])
|
||||
for t in self.tests:
|
||||
if mr in self.db:
|
||||
job=self.tests[t]['job']
|
||||
if job in self.db[mr]:
|
||||
if 'PASS' in self.db[mr][job]:
|
||||
row.append(self.db[mr][job]['PASS'])
|
||||
else:
|
||||
row.append('')
|
||||
if 'FAIL' in self.db[mr][job]:
|
||||
row.append(self.db[mr][job]['FAIL'])
|
||||
else:
|
||||
row.append('')
|
||||
#leave 2 columns for last_pass and last_fail links
|
||||
row.append('')
|
||||
row.append('')
|
||||
else:
|
||||
#4 columns are empty
|
||||
row.append('')
|
||||
row.append('')
|
||||
row.append('')
|
||||
row.append('')
|
||||
|
||||
#insert the final row to worksheet
|
||||
self.sheet.insert_row(row, index=i, value_input_option='RAW')
|
||||
|
||||
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
#add MR hyperlinks in a list of requests to be sent as one update batch; this to save API calls (quotas)
|
||||
i=3
|
||||
requests=[]
|
||||
for x in range(len(self.d)):
|
||||
for x in range(len(self.git)):
|
||||
rowIndex=i
|
||||
colIndex=0
|
||||
hyperlink= '\"'+"https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/"+ str(self.d[x]['iid']) +'\"'
|
||||
text= '\"'+str(self.d[x]['iid'])+'"'
|
||||
hyperlink= '\"'+"https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/"+ str(self.git[x]['iid']) +'\"'
|
||||
text= '\"'+str(self.git[x]['iid'])+'"'
|
||||
requests.append(self.addHyperlink(hyperlink, text, destinationSheetName, rowIndex, colIndex))
|
||||
i=i+1
|
||||
|
||||
mr=str(self.git[x]['iid'])
|
||||
colIndex=15
|
||||
for t in self.tests:
|
||||
job=self.tests[t]['job']
|
||||
if job in self.db[mr]:
|
||||
if 'last_pass' in self.db[mr][job]:
|
||||
hyperlink= '\"'+ self.db[mr][job]['last_pass'][1] +'\"'
|
||||
text= '\"'+self.db[mr][job]['last_pass'][0]+'"'
|
||||
requests.append(self.addHyperlink(hyperlink, text, destinationSheetName, rowIndex, colIndex))
|
||||
if 'last_fail' in self.db[mr][job]:
|
||||
hyperlink= '\"'+ self.db[mr][job]['last_fail'][1] +'\"'
|
||||
text= '\"'+self.db[mr][job]['last_fail'][0]+'"'
|
||||
requests.append(self.addHyperlink(hyperlink, text, destinationSheetName, rowIndex, colIndex+1))
|
||||
colIndex+=4 #move to next test
|
||||
i=i+1 #increment row index for next MR
|
||||
|
||||
body = {"requests": requests}
|
||||
self.ss.batch_update(body)
|
||||
|
||||
###line 2 is for the test names
|
||||
#add MR hyperlinks in a list of requests to be sent as one update batch; this to save API calls (quotas)
|
||||
requests=[]
|
||||
rowIndex=1
|
||||
colIndex=13
|
||||
for t in self.tests :
|
||||
hyperlink= '\"'+self.tests[t]['link']+'\"'
|
||||
short_name= '\"'+ t +'\"'
|
||||
requests.append(self.addHyperlink(hyperlink, short_name, destinationSheetName, rowIndex, colIndex))
|
||||
colIndex+=4
|
||||
|
||||
body = {"requests": requests}
|
||||
self.ss.batch_update(body)
|
||||
|
||||
|
||||
def addHyperlink(self, hyperlink, text, destinationSheetName, rowIndex, colIndex):
|
||||
@@ -207,17 +298,17 @@ class gDashboard:
|
||||
"copyPaste": {
|
||||
"source": {
|
||||
"sheetId": sourceSheetId,
|
||||
"startRowIndex": 0,
|
||||
"startRowIndex": 1,
|
||||
"endRowIndex": 40,
|
||||
"startColumnIndex": 0,
|
||||
"endColumnIndex": 12
|
||||
"endColumnIndex": 30
|
||||
},
|
||||
"destination": {
|
||||
"sheetId": destinationSheetId,
|
||||
"startRowIndex": 0,
|
||||
"startRowIndex": 1,
|
||||
"endRowIndex": 40,
|
||||
"startColumnIndex": 0,
|
||||
"endColumnIndex": 12
|
||||
"endColumnIndex": 30
|
||||
},
|
||||
"pasteType": "PASTE_FORMAT"
|
||||
}
|
||||
@@ -280,15 +371,30 @@ class gDashboard:
|
||||
}
|
||||
)
|
||||
|
||||
body = {"requests": requests}
|
||||
self.ss.batch_update(body)
|
||||
|
||||
#group MR related columns
|
||||
# sheetId = self.ss.worksheet(destinationSheetName)._properties['sheetId']
|
||||
# requests.append(
|
||||
# {
|
||||
# "addDimensionGroup": {
|
||||
# "range": {
|
||||
# "dimension": "COLUMNS",
|
||||
# "sheetId": sheetId,
|
||||
# "startIndex": 3,
|
||||
# "endIndex": 12
|
||||
# },
|
||||
# }
|
||||
# }
|
||||
# )
|
||||
#
|
||||
body = {"requests": requests}
|
||||
self.ss.batch_update(body)
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
my_gDashboard=gDashboard("/opt/dashboard/g_creds.json", 'OAI RAN Dashboard', 'MR Status')
|
||||
cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """
|
||||
my_gDashboard.fetchData(cmd)
|
||||
my_gDashboard.gBuild("MR Status")
|
||||
my_gDashboard.gFormat("Formating" , "MR Status")
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
LTE-2x2 : #short name used in the dashboard
|
||||
job : 'RAN-LTE-2x2-Module-OAIEPC' #job name from Jenkins, used in the database
|
||||
link : 'https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-LTE-2x2-Module-OAIEPC'
|
||||
bench : 'Obelix-N310-OAIEPC-Quectel(nrmodule2)'
|
||||
test : 'TDD, 40MHz, MCS9, 26Mb DL, 7Mb UL'
|
||||
NSA-B200 :
|
||||
job : 'RAN-NSA-B200-Module-LTEBOX'
|
||||
link : 'https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-NSA-B200-Module-LTEBOX'
|
||||
bench : 'Nepes-B200-Obelix-B200-LTEBOX-Quectel(idefix)'
|
||||
test : '20MHz, 60Mb DL, 3Mb UL'
|
||||
NSA-2x2 :
|
||||
job : 'RAN-NSA-2x2-Module-OAIEPC'
|
||||
link : 'https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-NSA-2x2-Module-OAIEPC'
|
||||
bench : 'Asterix-N310-Obelix-N310-OAIEPC-Quectel(nrmodule2)'
|
||||
test : 'TDD, 40MHz, 60Mb DL, 3Mb UL'
|
||||
SA-N310 :
|
||||
job : 'RAN-SA-Module-CN5G'
|
||||
link : 'https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-Module-CN5G'
|
||||
bench : 'Asterix-N310-OAICN5G-Quectel(nrmodule2)'
|
||||
test : 'TDD, 40MHz, 60Mb DL, 3Mb UL'
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
The code ran_dashboard.py was initially developped to bring MR status and test resuts to a google sheet, using google sheets API.
|
||||
This method is now deprecated, and replaced by Hdashboard.py that builds the results as HTML page and loads it to AWS S3.
|
||||
ran_dashboard_cfg.yaml is still used by Hdashboard.py as tests config file.
|
||||
@@ -0,0 +1,107 @@
|
||||
#/*
|
||||
# * 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
|
||||
# */
|
||||
#---------------------------------------------------------------------
|
||||
# Merge Requests Dashboard for RAN on googleSheet
|
||||
#
|
||||
# Required Python Version
|
||||
# Python 3.x
|
||||
#
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
#author Remi
|
||||
|
||||
|
||||
import pymysql
|
||||
import sys
|
||||
from datetime import datetime
|
||||
import pickle
|
||||
|
||||
#This is the script/package used by the dashboard to retrieve the MR test results from the database
|
||||
|
||||
class SQLConnect:
|
||||
def __init__(self):
|
||||
self.connection = pymysql.connect(
|
||||
host='172.22.0.2',
|
||||
user='root',
|
||||
password = 'ucZBc2XRYdvEm59F',
|
||||
db='oaicicd_tests',
|
||||
port=3306
|
||||
)
|
||||
self.data={}
|
||||
|
||||
|
||||
#retrieve data from mysql database and organize it in a dictionary (per MR passed as argument)
|
||||
def get(self,MR):
|
||||
self.data[MR]={}
|
||||
cur=self.connection.cursor()
|
||||
|
||||
#get counters per test
|
||||
sql = "select TEST,STATUS, count(*) AS COUNT from test_results where MR=(%s) group by TEST, STATUS;"
|
||||
cur.execute(sql,MR)
|
||||
response=cur.fetchall()
|
||||
if len(response)==0:#no test results yet
|
||||
self.data[MR]['PASS']=''
|
||||
self.data[MR]['FAIL']=''
|
||||
else:
|
||||
for i in range(0,len(response)):
|
||||
test=response[i][0]
|
||||
status=response[i][1]
|
||||
count=response[i][2]
|
||||
if test in self.data[MR]:
|
||||
self.data[MR][test][status]=count
|
||||
else:
|
||||
self.data[MR][test]={}
|
||||
self.data[MR][test][status]=count
|
||||
|
||||
#get last failing build and link
|
||||
sql = "select TEST,BUILD, BUILD_LINK from test_results where MR=(%s) and STATUS='FAIL' order by DATE DESC;"
|
||||
cur.execute(sql,MR)
|
||||
response=cur.fetchall()
|
||||
if len(response)!=0:
|
||||
for i in range(0,len(response)):
|
||||
test=response[i][0]
|
||||
build=response[i][1]
|
||||
link=response[i][2]
|
||||
if 'last_fail' not in self.data[MR][test]:
|
||||
self.data[MR][test]['last_fail']=[]
|
||||
self.data[MR][test]['last_fail'].append(build)
|
||||
self.data[MR][test]['last_fail'].append(link)
|
||||
|
||||
#get last passing build and link
|
||||
sql = "select TEST,BUILD, BUILD_LINK from test_results where MR=(%s) and STATUS='PASS' order by DATE DESC;"
|
||||
cur.execute(sql,MR)
|
||||
response=cur.fetchall()
|
||||
if len(response)!=0:
|
||||
for i in range(0,len(response)):
|
||||
test=response[i][0]
|
||||
build=response[i][1]
|
||||
link=response[i][2]
|
||||
if 'last_pass' not in self.data[MR][test]:
|
||||
self.data[MR][test]['last_pass']=[]
|
||||
self.data[MR][test]['last_pass'].append(build)
|
||||
self.data[MR][test]['last_pass'].append(link)
|
||||
|
||||
|
||||
#close database connection
|
||||
def close_connection(self):
|
||||
self.connection.close()
|
||||
|
||||
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
body {
|
||||
font-family: 'lato', sans-serif;
|
||||
}
|
||||
|
||||
.Main {
|
||||
text-align: left;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.DashLink {
|
||||
text-align:left;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.DashLink:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.Date {
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:visited { text-decoration: none; color:blue}
|
||||
a:hover { text-decoration: none; font-weight: bold; color:blue}
|
||||
|
||||
|
||||
.Test_Table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.Test_Table tr {
|
||||
font-size: 12px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
|
||||
.Test_Table tr:hover {
|
||||
background-color:lightgray;
|
||||
}
|
||||
|
||||
.Test_Table td {
|
||||
border: 1px solid black;
|
||||
padding : 5px;
|
||||
}
|
||||
.Test_Table td:hover {
|
||||
font-weight : bold;
|
||||
}
|
||||
|
||||
.Test_Table th {
|
||||
font-size: 14px;
|
||||
text-align:center;
|
||||
padding : 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.Test_Name {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.Test_Descr {
|
||||
table-layout: fixed;
|
||||
width: 400px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.Pass {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.Fail {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.Last_Pass {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
.Last_Fail {
|
||||
table-layout: fixed;
|
||||
width: 100px;
|
||||
background-color: rgb(143, 154, 216);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<htmlTabRef>rfsim-4glte</htmlTabRef>
|
||||
<htmlTabName>Testing 4G LTE RF sim in containers</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
<repeatCount>2</repeatCount>
|
||||
<TestCaseRequestedList>
|
||||
100011
|
||||
000011
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<htmlTabRef>rfsim-5gnr</htmlTabRef>
|
||||
<htmlTabName>Testing 5G NR RF sim in containers</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
<repeatCount>4</repeatCount>
|
||||
<TestCaseRequestedList>
|
||||
100001
|
||||
000001
|
||||
|
||||
@@ -115,8 +115,8 @@
|
||||
|
||||
<testCase id="070000">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/20Mbps/UDP)(60 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 20M -t 60</iperf_args>
|
||||
<desc>iperf (DL/40Mbps/UDP)(60 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 40M -t 60</iperf_args>
|
||||
<direction>DL</direction>
|
||||
<id>idefix</id>
|
||||
<iperf_packetloss_threshold>3</iperf_packetloss_threshold>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<!--
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<testCaseList>
|
||||
<htmlTabRef>TEST-NSA-FR1-TM1-B200-terminate</htmlTabRef>
|
||||
<htmlTabName>NSA tear-down in case of problem</htmlTabName>
|
||||
<htmlTabIcon>tasks</htmlTabIcon>
|
||||
<repeatCount>1</repeatCount>
|
||||
<TestCaseRequestedList>
|
||||
030202
|
||||
030201
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
|
||||
<testCase id="030201">
|
||||
<class>Undeploy_Object</class>
|
||||
<desc>Undeploy eNB</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/nsa_b200_enb</yaml_path>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="030202">
|
||||
<class>Undeploy_Object</class>
|
||||
<desc>Undeploy gNB</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/nsa_b200_gnb</yaml_path>
|
||||
<eNB_instance>1</eNB_instance>
|
||||
<eNB_serverId>1</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
-->
|
||||
<testCaseList>
|
||||
<htmlTabRef>TEST-SA-FR1-TM1</htmlTabRef>
|
||||
<htmlTabRef>TEST-SA-FR1-Tab1</htmlTabRef>
|
||||
<htmlTabName>SA Ping DL UL with QUECTEL</htmlTabName>
|
||||
<htmlTabIcon>tasks</htmlTabIcon>
|
||||
<repeatCount>1</repeatCount>
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
<!--
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<testCaseList>
|
||||
<htmlTabRef>TEST-SA-FR1-Tab2</htmlTabRef>
|
||||
<htmlTabName>SA Staged DL with QUECTEL</htmlTabName>
|
||||
<htmlTabIcon>tasks</htmlTabIcon>
|
||||
<repeatCount>1</repeatCount>
|
||||
<TestCaseRequestedList>
|
||||
040000
|
||||
000002
|
||||
010000
|
||||
000001
|
||||
050000
|
||||
000001
|
||||
070000
|
||||
000001
|
||||
070001
|
||||
000001
|
||||
070002
|
||||
000001
|
||||
070003
|
||||
000001
|
||||
070004
|
||||
000001
|
||||
010002
|
||||
080000
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
|
||||
<testCase id="010000">
|
||||
<class>Initialize_UE</class>
|
||||
<desc>Initialize Quectel</desc>
|
||||
<id>nrmodule2_quectel</id>
|
||||
<UE_Trace>yes</UE_Trace>
|
||||
</testCase>
|
||||
|
||||
|
||||
<testCase id="010002">
|
||||
<class>Terminate_UE</class>
|
||||
<desc>Terminate Quectel</desc>
|
||||
<id>nrmodule2_quectel</id>
|
||||
</testCase>
|
||||
|
||||
|
||||
<testCase id="040000">
|
||||
<class>Initialize_eNB</class>
|
||||
<desc>Initialize gNB</desc>
|
||||
<Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf --sa -q --usrp-tx-thread-config 1 --thread-pool 0,2,4,6</Initialize_eNB_args>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
<air_interface>nr</air_interface>
|
||||
<eNB_Trace>yes</eNB_Trace>
|
||||
<eNB_Stats>yes</eNB_Stats>
|
||||
<USRP_IPAddress>192.168.18.240</USRP_IPAddress>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000001">
|
||||
<class>IdleSleep</class>
|
||||
<desc>Sleep</desc>
|
||||
<idle_sleep_time_in_sec>5</idle_sleep_time_in_sec>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000002">
|
||||
<class>IdleSleep</class>
|
||||
<desc>Sleep</desc>
|
||||
<idle_sleep_time_in_sec>20</idle_sleep_time_in_sec>
|
||||
</testCase>
|
||||
|
||||
|
||||
<testCase id="050000">
|
||||
<class>Ping</class>
|
||||
<desc>Ping: 20pings in 20sec</desc>
|
||||
<id>nrmodule2_quectel</id>
|
||||
<ping_args>-c 20</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
|
||||
<testCase id="070000">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/10Mbps/UDP)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 10M -t 30</iperf_args>
|
||||
<direction>DL</direction>
|
||||
<id>nrmodule2_quectel</id>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_profile>single-ue</iperf_profile>
|
||||
</testCase>
|
||||
<testCase id="070001">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/20Mbps/UDP)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 20M -t 30</iperf_args>
|
||||
<direction>DL</direction>
|
||||
<id>nrmodule2_quectel</id>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_profile>single-ue</iperf_profile>
|
||||
</testCase>
|
||||
<testCase id="070002">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/40Mbps/UDP)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 40M -t 30</iperf_args>
|
||||
<direction>DL</direction>
|
||||
<id>nrmodule2_quectel</id>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_profile>single-ue</iperf_profile>
|
||||
</testCase>
|
||||
<testCase id="070003">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/60Mbps/UDP)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 60M -t 30</iperf_args>
|
||||
<direction>DL</direction>
|
||||
<id>nrmodule2_quectel</id>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_profile>single-ue</iperf_profile>
|
||||
</testCase>
|
||||
<testCase id="070004">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/90Mbps/UDP)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 90M -t 30</iperf_args>
|
||||
<direction>DL</direction>
|
||||
<id>nrmodule2_quectel</id>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_profile>single-ue</iperf_profile>
|
||||
</testCase>
|
||||
|
||||
|
||||
|
||||
<testCase id="080000">
|
||||
<class>Terminate_eNB</class>
|
||||
<desc>Terminate gNB</desc>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
<air_interface>nr</air_interface>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
|
||||
@@ -30,7 +30,7 @@ services:
|
||||
FLEXRAN_ENABLED: 'no'
|
||||
FLEXRAN_INTERFACE_NAME: eth0
|
||||
FLEXRAN_IPV4_ADDRESS: 192.168.18.210
|
||||
THREAD_PARALLEL_CONFIG: PARALLEL_RU_L1_TRX_SPLIT
|
||||
THREAD_PARALLEL_CONFIG: PARALLEL_SINGLE_THREAD
|
||||
volumes:
|
||||
- /dev:/dev
|
||||
networks:
|
||||
|
||||
Reference in New Issue
Block a user