feat(ci): Q&D adding of 5G RF sim on container/docker-compose
Signed-off-by: Raphael Defosseux <raphael.defosseux@eurecom.fr>
This commit is contained in:
@@ -36,6 +36,7 @@ import re # reg
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
import time
|
import time
|
||||||
from multiprocessing import Process, Lock, SimpleQueue
|
from multiprocessing import Process, Lock, SimpleQueue
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
@@ -76,6 +77,9 @@ class Containerize():
|
|||||||
self.eNB_instance = 0
|
self.eNB_instance = 0
|
||||||
self.eNB_serverId = ['', '', '']
|
self.eNB_serverId = ['', '', '']
|
||||||
self.yamlPath = ['', '', '']
|
self.yamlPath = ['', '', '']
|
||||||
|
self.services = ['', '', '']
|
||||||
|
self.nb_healthy = [0, 0, 0]
|
||||||
|
self.exitStatus = 0
|
||||||
self.eNB_logFile = ['', '', '']
|
self.eNB_logFile = ['', '', '']
|
||||||
|
|
||||||
self.testCase_id = ''
|
self.testCase_id = ''
|
||||||
@@ -89,6 +93,14 @@ class Containerize():
|
|||||||
self.allImagesSize = {}
|
self.allImagesSize = {}
|
||||||
self.collectInfo = {}
|
self.collectInfo = {}
|
||||||
|
|
||||||
|
self.pingContName = ''
|
||||||
|
self.pingOptions = ''
|
||||||
|
self.pingLossThreshold = ''
|
||||||
|
self.svrContName = ''
|
||||||
|
self.svrOptions = ''
|
||||||
|
self.cliContName = ''
|
||||||
|
self.cliOptions = ''
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
# Container management functions
|
# Container management functions
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
@@ -476,7 +488,6 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
|
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
|
||||||
|
|
||||||
def UndeployObject(self, HTML, RAN):
|
def UndeployObject(self, HTML, RAN):
|
||||||
logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
|
|
||||||
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
|
||||||
@@ -529,4 +540,307 @@ class Containerize():
|
|||||||
HTML.CreateHtmlTestRow(RAN.runtime_stats, 'KO', logStatus)
|
HTML.CreateHtmlTestRow(RAN.runtime_stats, 'KO', logStatus)
|
||||||
else:
|
else:
|
||||||
HTML.CreateHtmlTestRow(RAN.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
|
HTML.CreateHtmlTestRow(RAN.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
|
||||||
|
logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
|
||||||
|
|
||||||
|
def DeployGenObject(self, HTML):
|
||||||
|
self.exitStatus = 0
|
||||||
|
logging.info('\u001B[1m Checking Services to deploy\u001B[0m')
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose config --services'
|
||||||
|
logging.debug(cmd)
|
||||||
|
try:
|
||||||
|
listServices = subprocess.check_output(cmd, shell=True, universal_newlines=True)
|
||||||
|
except Exception as e:
|
||||||
|
self.exitStatus = 1
|
||||||
|
HTML.CreateHtmlTestRow('SVC not Found', 'KO', CONST.ALL_PROCESSES_OK)
|
||||||
|
return
|
||||||
|
for reqSvc in self.services[0].split(' '):
|
||||||
|
res = re.search(reqSvc, listServices)
|
||||||
|
if res is None:
|
||||||
|
logging.error(reqSvc + ' not found in specified docker-compose')
|
||||||
|
self.exitStatus = 1
|
||||||
|
if (self.exitStatus == 1):
|
||||||
|
HTML.CreateHtmlTestRow('SVC not Found', 'KO', CONST.ALL_PROCESSES_OK)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (self.ranAllowMerge):
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@ci-temp@" docker-compose.y*ml > docker-compose-ci.yml'
|
||||||
|
else:
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@develop@" docker-compose.y*ml > docker-compose-ci.yml'
|
||||||
|
logging.debug(cmd)
|
||||||
|
subprocess.run(cmd, shell=True)
|
||||||
|
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml up -d ' + self.services[0]
|
||||||
|
logging.debug(cmd)
|
||||||
|
try:
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
|
||||||
|
except Exception as e:
|
||||||
|
self.exitStatus = 1
|
||||||
|
logging.error('Could not deploy')
|
||||||
|
HTML.CreateHtmlTestRow('Could not deploy', 'KO', CONST.ALL_PROCESSES_OK)
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.info('\u001B[1m Checking if all deployed healthy\u001B[0m')
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml ps -a'
|
||||||
|
count = 0
|
||||||
|
healthy = 0
|
||||||
|
while (count < 10):
|
||||||
|
count += 1
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
healthy = 0
|
||||||
|
for state in deployStatus.split('\n'):
|
||||||
|
res = re.search('Up \(healthy\)', state)
|
||||||
|
if res is not None:
|
||||||
|
healthy += 1
|
||||||
|
if healthy == self.nb_healthy[0]:
|
||||||
|
count = 100
|
||||||
|
else:
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
# HACK TO REMOVE LATER WHEN FIX
|
||||||
|
res = re.search('oai-nr-ue', self.services[0])
|
||||||
|
if res is not None:
|
||||||
|
cmd = 'docker exec rfsim5g-oai-nr-ue /bin/bash -c "ip route del default"'
|
||||||
|
logging.debug(cmd)
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
cmd = 'docker exec rfsim5g-oai-nr-ue /bin/bash -c "ip route del 12.1.1.0/24"'
|
||||||
|
logging.debug(cmd)
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
cmd = 'docker exec rfsim5g-oai-nr-ue /bin/bash -c "ip route add default via 12.1.1.2 dev oaitun_ue1"'
|
||||||
|
logging.debug(cmd)
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
# END OF HACK TO REMOVE LATER WHEN FIX
|
||||||
|
|
||||||
|
if count == 100 and healthy == self.nb_healthy[0]:
|
||||||
|
HTML.CreateHtmlTestRow('n/a', 'OK', CONST.ALL_PROCESSES_OK)
|
||||||
|
logging.info('\u001B[1m Deploying OAI Object(s) PASS\u001B[0m')
|
||||||
|
else:
|
||||||
|
self.exitStatus = 1
|
||||||
|
HTML.CreateHtmlTestRow('Could not deploy in time', 'KO', CONST.ALL_PROCESSES_OK)
|
||||||
|
logging.error('\u001B[1m Deploying OAI Object(s) FAILED\u001B[0m')
|
||||||
|
|
||||||
|
def UndeployGenObject(self, HTML):
|
||||||
|
self.exitStatus = 0
|
||||||
|
|
||||||
|
if (self.ranAllowMerge):
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@ci-temp@" docker-compose.y*ml > docker-compose-ci.yml'
|
||||||
|
else:
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && sed -e "s@develop@develop@" docker-compose.y*ml > docker-compose-ci.yml'
|
||||||
|
logging.debug(cmd)
|
||||||
|
subprocess.run(cmd, shell=True)
|
||||||
|
|
||||||
|
# if the containers are running, recover the logs!
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml ps --all'
|
||||||
|
logging.debug(cmd)
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
anyLogs = False
|
||||||
|
for state in deployStatus.split('\n'):
|
||||||
|
res = re.search('Name|----------', state)
|
||||||
|
if res is not None:
|
||||||
|
continue
|
||||||
|
if len(state) == 0:
|
||||||
|
continue
|
||||||
|
res = re.search('^(?P<container_name>[a-zA-Z0-9\-\_]+) ', state)
|
||||||
|
if res is not None:
|
||||||
|
anyLogs = True
|
||||||
|
cName = res.group('container_name')
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && docker logs ' + cName + ' > ' + cName + '.log 2>&1'
|
||||||
|
logging.debug(cmd)
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
if anyLogs:
|
||||||
|
cmd = 'mkdir -p ../cmake_targets/log && mv ' + self.yamlPath[0] + '/*.log ../cmake_targets/log'
|
||||||
|
logging.debug(cmd)
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
|
||||||
|
cmd = 'cd ' + self.yamlPath[0] + ' && docker-compose -f docker-compose-ci.yml down'
|
||||||
|
logging.debug(cmd)
|
||||||
|
try:
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
|
||||||
|
except Exception as e:
|
||||||
|
self.exitStatus = 1
|
||||||
|
logging.error('Could not undeploy')
|
||||||
|
HTML.CreateHtmlTestRow('Could not undeploy', 'KO', CONST.ALL_PROCESSES_OK)
|
||||||
|
logging.error('\u001B[1m Undeploying OAI Object(s) FAILED\u001B[0m')
|
||||||
|
return
|
||||||
|
|
||||||
|
HTML.CreateHtmlTestRow('n/a', 'OK', CONST.ALL_PROCESSES_OK)
|
||||||
|
logging.info('\u001B[1m Undeploying OAI Object(s) PASS\u001B[0m')
|
||||||
|
|
||||||
|
def PingFromContainer(self, HTML):
|
||||||
|
self.exitStatus = 0
|
||||||
|
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'
|
||||||
|
logging.debug(cmd)
|
||||||
|
deployStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=100)
|
||||||
|
|
||||||
|
result = re.search(', (?P<packetloss>[0-9\.]+)% packet loss, time [0-9\.]+ms', deployStatus)
|
||||||
|
if result is None:
|
||||||
|
self.PingExit(HTML, False, 'Packet Loss Not Found')
|
||||||
|
return
|
||||||
|
|
||||||
|
packetloss = result.group('packetloss')
|
||||||
|
if float(packetloss) == 100:
|
||||||
|
self.PingExit(HTML, False, 'Packet Loss is 100%')
|
||||||
|
return
|
||||||
|
|
||||||
|
result = re.search('rtt min\/avg\/max\/mdev = (?P<rtt_min>[0-9\.]+)\/(?P<rtt_avg>[0-9\.]+)\/(?P<rtt_max>[0-9\.]+)\/[0-9\.]+ ms', deployStatus)
|
||||||
|
if result is None:
|
||||||
|
self.PingExit(HTML, False, 'Ping RTT_Min RTT_Avg RTT_Max Not Found!')
|
||||||
|
return
|
||||||
|
|
||||||
|
rtt_min = result.group('rtt_min')
|
||||||
|
rtt_avg = result.group('rtt_avg')
|
||||||
|
rtt_max = result.group('rtt_max')
|
||||||
|
pal_msg = 'Packet Loss : ' + packetloss + '%'
|
||||||
|
min_msg = 'RTT(Min) : ' + rtt_min + ' ms'
|
||||||
|
avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms'
|
||||||
|
max_msg = 'RTT(Max) : ' + rtt_max + ' ms'
|
||||||
|
|
||||||
|
message = 'ping result\n'
|
||||||
|
message += ' ' + pal_msg + '\n'
|
||||||
|
message += ' ' + min_msg + '\n'
|
||||||
|
message += ' ' + avg_msg + '\n'
|
||||||
|
message += ' ' + max_msg + '\n'
|
||||||
|
packetLossOK = True
|
||||||
|
if float(packetloss) > float(self.pingLossThreshold):
|
||||||
|
message += '\nPacket Loss too high'
|
||||||
|
packetLossOK = False
|
||||||
|
elif float(packetloss) > 0:
|
||||||
|
message += '\nPacket Loss is not 0%'
|
||||||
|
self.PingExit(HTML, packetLossOK, message)
|
||||||
|
|
||||||
|
if packetLossOK:
|
||||||
|
logging.debug('\u001B[1;37;44m ping result \u001B[0m')
|
||||||
|
logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m')
|
||||||
|
logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m')
|
||||||
|
logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m')
|
||||||
|
logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m')
|
||||||
|
logging.info('\u001B[1m Ping Test PASS\u001B[0m')
|
||||||
|
|
||||||
|
def PingExit(self, HTML, status, message):
|
||||||
|
html_queue = SimpleQueue()
|
||||||
|
html_cell = '<pre style="background-color:white">UE\n' + message + '</pre>'
|
||||||
|
html_queue.put(html_cell)
|
||||||
|
if status:
|
||||||
|
HTML.CreateHtmlTestRowQueue(self.pingOptions, 'OK', 1, html_queue)
|
||||||
|
else:
|
||||||
|
self.exitStatus = 1
|
||||||
|
logging.error('\u001B[1;37;41m ' + message + ' \u001B[0m')
|
||||||
|
HTML.CreateHtmlTestRowQueue(self.pingOptions, 'KO', 1, html_queue)
|
||||||
|
|
||||||
|
def IperfFromContainer(self, HTML):
|
||||||
|
self.exitStatus = 0
|
||||||
|
|
||||||
|
cmd = 'mkdir -p ../cmake_targets/log'
|
||||||
|
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"'
|
||||||
|
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'
|
||||||
|
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"'
|
||||||
|
logging.debug(cmd)
|
||||||
|
serverStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
time.sleep(5)
|
||||||
|
cmd = 'docker cp ' + self.svrContName + ':/tmp/iperf_server.log ../cmake_targets/log/iperf_server_' + HTML.testCase_id + '.log'
|
||||||
|
logging.debug(cmd)
|
||||||
|
serverStatus = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True, timeout=10)
|
||||||
|
|
||||||
|
# Analyze client output
|
||||||
|
result = re.search('Server Report:', clientStatus)
|
||||||
|
if result is None:
|
||||||
|
result = re.search('read failed: Connection refused', clientStatus)
|
||||||
|
if result is not None:
|
||||||
|
message = 'Could not connect to iperf server!'
|
||||||
|
else:
|
||||||
|
message = 'Server Report and Connection refused Not Found!'
|
||||||
|
self.IperfExit(HTML, False, message)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Computing the requested bandwidth in float
|
||||||
|
result = re.search('-b (?P<iperf_bandwidth>[0-9\.]+)[KMG]', self.cliOptions)
|
||||||
|
if result is not None:
|
||||||
|
req_bandwidth = result.group('iperf_bandwidth')
|
||||||
|
req_bw = float(req_bandwidth)
|
||||||
|
result = re.search('-b [0-9\.]+K', self.cliOptions)
|
||||||
|
if result is not None:
|
||||||
|
req_bandwidth = '%.1f Kbits/sec' % req_bw
|
||||||
|
req_bw = req_bw * 1000
|
||||||
|
result = re.search('-b [0-9\.]+M', self.cliOptions)
|
||||||
|
if result is not None:
|
||||||
|
req_bandwidth = '%.1f Mbits/sec' % req_bw
|
||||||
|
req_bw = req_bw * 1000000
|
||||||
|
|
||||||
|
reportLine = None
|
||||||
|
reportLineFound = False
|
||||||
|
for iLine in clientStatus.split('\n'):
|
||||||
|
if reportLineFound:
|
||||||
|
reportLine = iLine
|
||||||
|
reportLineFound = False
|
||||||
|
res = re.search('Server Report:', iLine)
|
||||||
|
if res is not None:
|
||||||
|
reportLineFound = True
|
||||||
|
result = None
|
||||||
|
if reportLine is not None:
|
||||||
|
result = re.search('(?:|\[ *\d+\].*) (?P<bitrate>[0-9\.]+ [KMG]bits\/sec) +(?P<jitter>[0-9\.]+ ms) +(\d+\/ ..\d+) +(\((?P<packetloss>[0-9\.]+)%\))', reportLine)
|
||||||
|
iperfStatus = True
|
||||||
|
if result is not None:
|
||||||
|
bitrate = result.group('bitrate')
|
||||||
|
packetloss = result.group('packetloss')
|
||||||
|
jitter = result.group('jitter')
|
||||||
|
logging.debug('\u001B[1;37;44m iperf result \u001B[0m')
|
||||||
|
iperfStatus = True
|
||||||
|
msg = 'Req Bitrate : ' + req_bandwidth + '\n'
|
||||||
|
logging.debug('\u001B[1;34m Req Bitrate : ' + req_bandwidth + '\u001B[0m')
|
||||||
|
if bitrate is not None:
|
||||||
|
msg += 'Bitrate : ' + bitrate + '\n'
|
||||||
|
logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m')
|
||||||
|
result = re.search('(?P<real_bw>[0-9\.]+) [KMG]bits/sec', str(bitrate))
|
||||||
|
if result is not None:
|
||||||
|
actual_bw = float(str(result.group('real_bw')))
|
||||||
|
result = re.search('[0-9\.]+ K', bitrate)
|
||||||
|
if result is not None:
|
||||||
|
actual_bw = actual_bw * 1000
|
||||||
|
result = re.search('[0-9\.]+ M', bitrate)
|
||||||
|
if result is not None:
|
||||||
|
actual_bw = actual_bw * 1000000
|
||||||
|
br_loss = 100 * actual_bw / req_bw
|
||||||
|
if br_loss < 90:
|
||||||
|
iperfStatus = False
|
||||||
|
bitperf = '%.2f ' % br_loss
|
||||||
|
msg += 'Bitrate Perf: ' + bitperf + '%\n'
|
||||||
|
logging.debug('\u001B[1;34m Bitrate Perf: ' + bitperf + '%\u001B[0m')
|
||||||
|
if packetloss is not None:
|
||||||
|
msg += 'Packet Loss : ' + packetloss + '%\n'
|
||||||
|
logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m')
|
||||||
|
if float(packetloss) > float(5):
|
||||||
|
msg += 'Packet Loss too high!\n'
|
||||||
|
logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m')
|
||||||
|
iperfStatus = False
|
||||||
|
if jitter is not None:
|
||||||
|
msg += 'Jitter : ' + jitter + '\n'
|
||||||
|
logging.debug('\u001B[1;34m Jitter : ' + jitter + '\u001B[0m')
|
||||||
|
self.IperfExit(HTML, iperfStatus, msg)
|
||||||
|
else:
|
||||||
|
logging.error('problem?')
|
||||||
|
if iperfStatus:
|
||||||
|
logging.info('\u001B[1m Iperf Test PASS\u001B[0m')
|
||||||
|
|
||||||
|
def IperfExit(self, HTML, status, message):
|
||||||
|
html_queue = SimpleQueue()
|
||||||
|
html_cell = '<pre style="background-color:white">UE\n' + message + '</pre>'
|
||||||
|
html_queue.put(html_cell)
|
||||||
|
if status:
|
||||||
|
HTML.CreateHtmlTestRowQueue(self.cliOptions, 'OK', 1, html_queue)
|
||||||
|
else:
|
||||||
|
self.exitStatus = 1
|
||||||
|
HTML.CreateHtmlTestRowQueue(self.cliOptions, 'KO', 1, html_queue)
|
||||||
|
|||||||
+59
-2
@@ -372,6 +372,41 @@ def GetParametersFromXML(action):
|
|||||||
if (string_field is not None):
|
if (string_field is not None):
|
||||||
CONTAINERS.yamlPath[CONTAINERS.eNB_instance] = string_field
|
CONTAINERS.yamlPath[CONTAINERS.eNB_instance] = string_field
|
||||||
|
|
||||||
|
elif action == 'DeployGenObject' or action == 'UndeployGenObject':
|
||||||
|
string_field=test.findtext('yaml_path')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.yamlPath[0] = string_field
|
||||||
|
string_field=test.findtext('services')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.services[0] = string_field
|
||||||
|
string_field=test.findtext('nb_healthy')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.nb_healthy[0] = int(string_field)
|
||||||
|
|
||||||
|
elif action == 'PingFromContainer':
|
||||||
|
string_field = test.findtext('container_name')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.pingContName = string_field
|
||||||
|
string_field = test.findtext('options')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.pingOptions = string_field
|
||||||
|
string_field = test.findtext('loss_threshold')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.pingLossThreshold = string_field
|
||||||
|
|
||||||
|
elif action == 'IperfFromContainer':
|
||||||
|
string_field = test.findtext('server_container_name')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.svrContName = string_field
|
||||||
|
string_field = test.findtext('server_options')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.svrOptions = string_field
|
||||||
|
string_field = test.findtext('client_container_name')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.cliContName = string_field
|
||||||
|
string_field = test.findtext('client_options')
|
||||||
|
if (string_field is not None):
|
||||||
|
CONTAINERS.cliOptions = string_field
|
||||||
|
|
||||||
else: # ie action == 'Run_PhySim':
|
else: # ie action == 'Run_PhySim':
|
||||||
ldpc.runargs = test.findtext('physim_run_args')
|
ldpc.runargs = test.findtext('physim_run_args')
|
||||||
@@ -479,6 +514,8 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE):
|
|||||||
if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '':
|
if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '':
|
||||||
HELP.GenericHelp(CONST.Version)
|
HELP.GenericHelp(CONST.Version)
|
||||||
sys.exit('Insufficient Parameter')
|
sys.exit('Insufficient Parameter')
|
||||||
|
if RAN.eNBIPAddress == 'none':
|
||||||
|
sys.exit(0)
|
||||||
RAN.eNB_instance=0
|
RAN.eNB_instance=0
|
||||||
RAN.eNB_serverId[0]='0'
|
RAN.eNB_serverId[0]='0'
|
||||||
RAN.eNBSourceCodePath='/tmp/'
|
RAN.eNBSourceCodePath='/tmp/'
|
||||||
@@ -514,11 +551,15 @@ elif re.match('^LogCollectBuild$', mode, re.IGNORECASE):
|
|||||||
if (RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''):
|
if (RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''):
|
||||||
HELP.GenericHelp(CONST.Version)
|
HELP.GenericHelp(CONST.Version)
|
||||||
sys.exit('Insufficient Parameter')
|
sys.exit('Insufficient Parameter')
|
||||||
|
if RAN.eNBIPAddress == 'none':
|
||||||
|
sys.exit(0)
|
||||||
CiTestObj.LogCollectBuild(RAN)
|
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)
|
||||||
sys.exit('Insufficient Parameter')
|
sys.exit('Insufficient Parameter')
|
||||||
|
if RAN.eNBIPAddress == 'none':
|
||||||
|
sys.exit(0)
|
||||||
RAN.LogCollecteNB()
|
RAN.LogCollecteNB()
|
||||||
elif re.match('^LogCollectHSS$', mode, re.IGNORECASE):
|
elif re.match('^LogCollectHSS$', mode, re.IGNORECASE):
|
||||||
if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '':
|
if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '':
|
||||||
@@ -802,7 +843,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
|
|||||||
elif action == 'Build_PhySim':
|
elif action == 'Build_PhySim':
|
||||||
HTML=ldpc.Build_PhySim(HTML,CONST)
|
HTML=ldpc.Build_PhySim(HTML,CONST)
|
||||||
if ldpc.exitStatus==1:
|
if ldpc.exitStatus==1:
|
||||||
RAN.prematureExit = False
|
RAN.prematureExit = True
|
||||||
elif action == 'Run_PhySim':
|
elif action == 'Run_PhySim':
|
||||||
HTML=ldpc.Run_PhySim(HTML,CONST,id)
|
HTML=ldpc.Run_PhySim(HTML,CONST,id)
|
||||||
elif action == 'Build_Image':
|
elif action == 'Build_Image':
|
||||||
@@ -815,9 +856,25 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
|
|||||||
SCA.CppCheckAnalysis(HTML)
|
SCA.CppCheckAnalysis(HTML)
|
||||||
elif action == 'Deploy_Run_PhySim':
|
elif action == 'Deploy_Run_PhySim':
|
||||||
PHYSIM.Deploy_PhySim(HTML, RAN)
|
PHYSIM.Deploy_PhySim(HTML, RAN)
|
||||||
|
elif action == 'DeployGenObject':
|
||||||
|
CONTAINERS.DeployGenObject(HTML)
|
||||||
|
if CONTAINERS.exitStatus==1:
|
||||||
|
RAN.prematureExit = True
|
||||||
|
elif action == 'UndeployGenObject':
|
||||||
|
CONTAINERS.UndeployGenObject(HTML)
|
||||||
|
if CONTAINERS.exitStatus==1:
|
||||||
|
RAN.prematureExit = True
|
||||||
|
elif action == 'PingFromContainer':
|
||||||
|
CONTAINERS.PingFromContainer(HTML)
|
||||||
|
if CONTAINERS.exitStatus==1:
|
||||||
|
RAN.prematureExit = True
|
||||||
|
elif action == 'IperfFromContainer':
|
||||||
|
CONTAINERS.IperfFromContainer(HTML)
|
||||||
|
if CONTAINERS.exitStatus==1:
|
||||||
|
RAN.prematureExit = True
|
||||||
else:
|
else:
|
||||||
sys.exit('Invalid class (action) from xml')
|
sys.exit('Invalid class (action) from xml')
|
||||||
if not RAN.prematureExit:
|
if RAN.prematureExit:
|
||||||
if CiTestObj.testCase_id == CiTestObj.testMinStableId:
|
if CiTestObj.testCase_id == CiTestObj.testMinStableId:
|
||||||
logging.debug('Scenario has reached minimal stability point')
|
logging.debug('Scenario has reached minimal stability point')
|
||||||
CiTestObj.testStabilityPointReached = True
|
CiTestObj.testStabilityPointReached = True
|
||||||
|
|||||||
@@ -41,3 +41,7 @@
|
|||||||
- Undeploy_Object
|
- Undeploy_Object
|
||||||
- Cppcheck_Analysis
|
- Cppcheck_Analysis
|
||||||
- Deploy_Run_PhySim
|
- Deploy_Run_PhySim
|
||||||
|
- DeployGenObject
|
||||||
|
- UndeployGenObject
|
||||||
|
- PingFromContainer
|
||||||
|
- IperfFromContainer
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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>rfsim-5gnr</htmlTabRef>
|
||||||
|
<htmlTabName>Testing 5G NR RF sim in containers</htmlTabName>
|
||||||
|
<htmlTabIcon>wrench</htmlTabIcon>
|
||||||
|
<TestCaseRequestedList>
|
||||||
|
000001
|
||||||
|
000002
|
||||||
|
000003
|
||||||
|
020001
|
||||||
|
020002
|
||||||
|
030001
|
||||||
|
030002
|
||||||
|
100001
|
||||||
|
</TestCaseRequestedList>
|
||||||
|
<TestCaseExclusionList></TestCaseExclusionList>
|
||||||
|
|
||||||
|
<testCase id="000001">
|
||||||
|
<class>DeployGenObject</class>
|
||||||
|
<desc>Deploy OAI 5G CoreNetwork</desc>
|
||||||
|
<yaml_path>yaml_files/5g_rfsimulator</yaml_path>
|
||||||
|
<services>mysql oai-nrf oai-amf oai-smf oai-spgwu oai-ext-dn</services>
|
||||||
|
<nb_healthy>6</nb_healthy>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
<testCase id="000002">
|
||||||
|
<class>DeployGenObject</class>
|
||||||
|
<desc>Deploy OAI 5G gNB RF sim SA</desc>
|
||||||
|
<yaml_path>yaml_files/5g_rfsimulator</yaml_path>
|
||||||
|
<services>oai-gnb</services>
|
||||||
|
<nb_healthy>7</nb_healthy>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
<testCase id="000003">
|
||||||
|
<class>DeployGenObject</class>
|
||||||
|
<desc>Deploy OAI 5G NR-UE RF sim SA</desc>
|
||||||
|
<yaml_path>yaml_files/5g_rfsimulator</yaml_path>
|
||||||
|
<services>oai-nr-ue</services>
|
||||||
|
<nb_healthy>8</nb_healthy>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
<testCase id="020001">
|
||||||
|
<class>PingFromContainer</class>
|
||||||
|
<desc>Ping ext-dn from NR-UE</desc>
|
||||||
|
<container_name>rfsim5g-oai-nr-ue</container_name>
|
||||||
|
<options>-I oaitun_ue1 -c 20 192.168.72.135</options>
|
||||||
|
<loss_threshold>5</loss_threshold>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
<testCase id="020002">
|
||||||
|
<class>PingFromContainer</class>
|
||||||
|
<desc>Ping NR-UE from ext-dn</desc>
|
||||||
|
<container_name>rfsim5g-oai-ext-dn</container_name>
|
||||||
|
<options>-c 20 12.1.1.2</options>
|
||||||
|
<loss_threshold>5</loss_threshold>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
<testCase id="030001">
|
||||||
|
<class>IperfFromContainer</class>
|
||||||
|
<desc>Iperf UDP Downlink</desc>
|
||||||
|
<server_container_name>rfsim5g-oai-nr-ue</server_container_name>
|
||||||
|
<client_container_name>rfsim5g-oai-ext-dn</client_container_name>
|
||||||
|
<server_options>-B 12.1.1.2 -u -i 1 -s</server_options>
|
||||||
|
<client_options>-c 12.1.1.2 -u -i 1 -t 30 -b 400K</client_options>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
<testCase id="030002">
|
||||||
|
<class>IperfFromContainer</class>
|
||||||
|
<desc>Iperf UDP Uplink</desc>
|
||||||
|
<server_container_name>rfsim5g-oai-ext-dn</server_container_name>
|
||||||
|
<client_container_name>rfsim5g-oai-nr-ue</client_container_name>
|
||||||
|
<server_options>-u -i 1 -s</server_options>
|
||||||
|
<client_options>-B 12.1.1.2 -c 192.168.72.135 -u -i 1 -t 30 -b 20K</client_options>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
<testCase id="100001">
|
||||||
|
<class>UndeployGenObject</class>
|
||||||
|
<desc>Undeploy all OAI 5G stack</desc>
|
||||||
|
<yaml_path>yaml_files/5g_rfsimulator</yaml_path>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
</testCaseList>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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>rfsim-5gnr-down</htmlTabRef>
|
||||||
|
<htmlTabName>CleanUp 5G RF</htmlTabName>
|
||||||
|
<htmlTabIcon>trash</htmlTabIcon>
|
||||||
|
<TestCaseRequestedList>
|
||||||
|
100002
|
||||||
|
</TestCaseRequestedList>
|
||||||
|
<TestCaseExclusionList></TestCaseExclusionList>
|
||||||
|
|
||||||
|
<testCase id="100002">
|
||||||
|
<class>UndeployGenObject</class>
|
||||||
|
<desc>Undeploy all OAI 5G stack</desc>
|
||||||
|
<yaml_path>yaml_files/5g_rfsimulator</yaml_path>
|
||||||
|
</testCase>
|
||||||
|
|
||||||
|
</testCaseList>
|
||||||
@@ -206,7 +206,7 @@ services:
|
|||||||
privileged: true
|
privileged: true
|
||||||
container_name: rfsim5g-oai-ext-dn
|
container_name: rfsim5g-oai-ext-dn
|
||||||
entrypoint: /bin/bash -c \
|
entrypoint: /bin/bash -c \
|
||||||
"apt update; apt install -y iptables iproute2 iperf iputils-ping;"\
|
"apt update; apt install -y procps iptables iproute2 iperf iputils-ping;"\
|
||||||
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
||||||
"ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
|
"ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
Reference in New Issue
Block a user