Commit 5201a5c3 authored by Robert Schmidt's avatar Robert Schmidt

Reimplement DeployObject()/UndeployObject()

This reimplements the CI deployment functions, and makes them a bit more
robust.  Concretely:

- Introduce a generic "deployment tag" option that can be used to
  override the tag to use for specific images. By default, it is the
  current "branch-commitID[0:8]" tag name (requires the change from
  function ImageTagToUse() to CreateTag(), impacting also pull/push
  image functions)
- Avoid sed for image names, and use an .env file that docker-compose
  picks up automatically; the deployment analyzes a potentially existing
  .env file and updates instead of simply overriding. For instance, some
  pipelines might use -asan images for the gNB and "normal" (non-asan)
  images for UE, and a simple overwriting might make the -asan image
  name tag disappear for the gNB, resulting in deployment failures).
  Finally, undeployment removes the .env file, so that there are no
  modifications in the repository after undeployment.
- Redo the previous behavior of autodetecting asan, and use that (the
  current function always uses asan, no matter what)
- Remove deployKind/displayedNewTags globals, as they are not necessary
- Make the usedImage output in HTML slimmer
- On undeployment, print service names next to undeploy analysis, and
  return success/failure.
- Make the functions generally less verbose and easier to read

Note that as of and only in this commit, deployment does not work, as
all the YAML files have not been updated to work with this updated
version.  The next commit adds tests for the new deployment, and updates
one YAML file (also being used in the tests). The follow-up commit then
modifies all YAML files.
parent d81abdaf
...@@ -263,7 +263,8 @@ class Cluster: ...@@ -263,7 +263,8 @@ class Cluster:
return False return False
for image in self.imageToPull: for image in self.imageToPull:
imagePrefix = f'{self.OCRegistry}/{CI_OC_RAN_NAMESPACE}' imagePrefix = f'{self.OCRegistry}/{CI_OC_RAN_NAMESPACE}'
imageTag = cls_containerize.ImageTagToUse(image, self.ranCommitID, self.ranBranch, self.ranAllowMerge) tag = cls_containerize.CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge)
imageTag = f"{image}:{tag}"
ret = cmd.run(f'docker pull {imagePrefix}/{imageTag}') ret = cmd.run(f'docker pull {imagePrefix}/{imageTag}')
if ret.returncode != 0: if ret.returncode != 0:
logging.error(f'Could not pull {image} from local registry : {self.OCRegistry}') logging.error(f'Could not pull {image} from local registry : {self.OCRegistry}')
......
...@@ -96,7 +96,7 @@ def CreateWorkspace(sshSession, sourcePath, ranRepository, ranCommitID, ranTarge ...@@ -96,7 +96,7 @@ def CreateWorkspace(sshSession, sourcePath, ranRepository, ranCommitID, ranTarge
sshSession.command(f'git merge --ff origin/{ranTargetBranch} -m "Temporary merge for CI"', '\$', 30) sshSession.command(f'git merge --ff origin/{ranTargetBranch} -m "Temporary merge for CI"', '\$', 30)
return True return True
def ImageTagToUse(imageName, ranCommitID, ranBranch, ranAllowMerge): def CreateTag(ranCommitID, ranBranch, ranAllowMerge):
shortCommit = ranCommitID[0:8] shortCommit = ranCommitID[0:8]
if ranAllowMerge: if ranAllowMerge:
# Allowing contributor to have a name/branchName format # Allowing contributor to have a name/branchName format
...@@ -104,8 +104,7 @@ def ImageTagToUse(imageName, ranCommitID, ranBranch, ranAllowMerge): ...@@ -104,8 +104,7 @@ def ImageTagToUse(imageName, ranCommitID, ranBranch, ranAllowMerge):
tagToUse = f'{branchName}-{shortCommit}' tagToUse = f'{branchName}-{shortCommit}'
else: else:
tagToUse = f'develop-{shortCommit}' tagToUse = f'develop-{shortCommit}'
fullTag = f'{imageName}:{tagToUse}' return tagToUse
return fullTag
def CopyLogsToExecutor(cmd, sourcePath, log_name): def CopyLogsToExecutor(cmd, sourcePath, log_name):
cmd.cd(f'{sourcePath}/cmake_targets') cmd.cd(f'{sourcePath}/cmake_targets')
...@@ -182,108 +181,142 @@ def GetCredentials(instance): ...@@ -182,108 +181,142 @@ def GetCredentials(instance):
else: else:
raise Exception ("Only supports maximum of 3 servers") raise Exception ("Only supports maximum of 3 servers")
def GetContainerName(mySSH, svcName): def GetContainerName(ssh, svcName, file):
ret = mySSH.run(f"docker compose -f docker-compose.y*ml config --format json {svcName} | jq -r '.services.\"{svcName}\".container_name'") ret = ssh.run(f"docker compose -f {file} config --format json {svcName} | jq -r '.services.\"{svcName}\".container_name'", silent=True)
containerName = ret.stdout return ret.stdout
return containerName
def GetImageName(ssh, svcName, file):
def GetImageInfo(mySSH, containerName): ret = ssh.run(f"docker compose -f {file} config --format json {svcName} | jq -r '.services.\"{svcName}\".image'", silent=True)
usedImage = '' if ret.returncode != 0:
ret = mySSH.run('docker inspect --format="{{.Config.Image}}" ' + containerName) return f"cannot retrieve image info for {containerName}: {ret.stdout}"
usedImage = ret.stdout.strip()
logging.debug('Used image is: ' + usedImage)
if usedImage:
ret = mySSH.run('docker image inspect --format "* Size = {{.Size}} bytes\n* Creation = {{.Created}}\n* Id = {{.Id}}" ' + usedImage)
imageInfo = f"Used image is {usedImage}\n{ret.stdout}\n"
return imageInfo
else: else:
return f"Could not retrieve used image info for {containerName}!\n" return ret.stdout.strip()
def GetContainerHealth(mySSH, containerName): def GetContainerHealth(ssh, containerName):
if containerName is None: if containerName is None:
return False return False
time.sleep(5) if 'db_init' in containerName or 'db-init' in containerName: # exits with 0, there cannot be healthy
for _ in range(3): return True
if containerName != 'db_init': time.sleep(5)
result = mySSH.run(f'docker inspect --format="{{{{.State.Health.Status}}}}" {containerName}') for _ in range(3):
if result.stdout == 'healthy': result = ssh.run(f'docker inspect --format="{{{{.State.Health.Status}}}}" {containerName}', silent=True)
return True if result.stdout == 'healthy':
else: return True
time.sleep(10) time.sleep(10)
return False
def ExistEnvFilePrint(ssh, wd, prompt='env vars in existing'):
ret = ssh.run(f'cat {wd}/.env', silent=True)
if ret.returncode != 0:
return False
env_vars = ret.stdout.strip().splitlines()
logging.info(f'{prompt} {wd}/.env: {env_vars}')
return True
def WriteEnvFile(ssh, services, wd, tag):
ret = ssh.run(f'cat {wd}/.env', silent=True)
registry = "oai-ci" # pull_images() gives us this registry path
envs = {"REGISTRY":registry, "TAG": tag}
if ret.returncode == 0: # it exists, we have to update
# transforms env file to dictionary
old_envs = {}
for l in ret.stdout.strip().splitlines():
var, val = l.split('=', 1)
old_envs[var] = val.strip('"')
# will retain the old environment variables
envs = {**envs, **old_envs}
for svc in services.split():
# In some scenarios we have the choice of either pulling normal images
# or -asan images. We need to detect which kind we did pull.
fullImageName = GetImageName(ssh, svc, f"{wd}/docker-compose.y*ml")
image = fullImageName.split("/")[-1].split(":")[0]
checkimg = f"{registry}/{image}-asan:{tag}"
ret = ssh.run(f'docker image inspect {checkimg}', reportNonZero=False)
if ret.returncode == 0:
logging.info(f"detected pulled image {checkimg}")
if "oai-gnb" in image: envs["GNB_IMG"] = "oai-gnb-asan"
elif "oai-nr-ue" in image: envs["NRUE_IMG"] = "oai-nr-ue-asan"
elif "oai-nr-cuup" in image: envs["NRCUUP_IMG"] = "oai-nr-cuup-asan"
else: logging.warning("undetected image format {image}, cannot use asan")
env_string = "\n".join([f"{var}=\"{val}\"" for var,val in envs.items()])
ssh.run(f'echo -e \'{env_string}\' > {wd}/.env', silent=True)
ExistEnvFilePrint(ssh, wd, prompt='New env vars in file')
def GetServices(ssh, requested, file):
if requested == [] or requested is None or requested == "":
logging.warning('No service name given: starting all services in docker-compose.yml!')
ret = ssh.run(f'docker compose -f {file} config --services')
if ret.returncode != 0:
return ""
else: else:
return True return ' '.join(ret.stdout.splitlines())
return False else:
return requested
def ReTagImages(mySSH,IMAGES,ranCommitID,ranBranch,ranAllowMerge,displayedNewTags):
mySSH.run('cp docker-compose.y*ml ci-docker-compose.yml', 5) def CopyinContainerLog(ssh, lSourcePath, yaml, containerName, filename):
for image in IMAGES: remote_filename = f"{lSourcePath}/cmake_targets/log/{filename}"
imageTag = ImageTagToUse(image, ranCommitID, ranBranch, ranAllowMerge) ssh.run(f'docker logs {containerName} &> {remote_filename}')
if image == 'oai-gnb' or image == 'oai-nr-ue' or image == 'oai-nr-cuup': local_dir = f"{os.getcwd()}/../cmake_targets/log/{yaml}"
ret = mySSH.run(f'docker image inspect oai-ci/{imageTag}', reportNonZero=False, silent=False) os.system(f'mkdir -p {local_dir}')
if ret.returncode != 0: local_filename = f"{local_dir}/{filename}"
imageTag = imageTag.replace('oai-gnb', 'oai-gnb-asan') return ssh.copyin(remote_filename, local_filename)
imageTag = imageTag.replace('oai-nr-ue', 'oai-nr-ue-asan')
imageTag = imageTag.replace('oai-nr-cuup', 'oai-nr-cuup-asan') def GetRunningServices(ssh, file):
if not displayedNewTags: ret = ssh.run(f'docker compose -f {file} config --services')
logging.debug(f'\u001B[1m Using sanitized version of {image} with {imageTag}\u001B[0m') if ret.returncode != 0:
mySSH.run(f'sed -i -e "s@oaisoftwarealliance/{image}:develop@oai-ci/{imageTag}@" ci-docker-compose.yml',silent=True) return None
def DeployServices(mySSH,svcName):
allServices = []
if svcName == '':
logging.warning('No service name given: starting all services in ci-docker-compose.yml!')
ret = mySSH.run(f'docker compose -f ci-docker-compose.yml config --services')
allServices = ret.stdout.splitlines()
deployStatus = mySSH.run(f'docker compose --file ci-docker-compose.yml up -d -- {svcName}', 50)
return deployStatus.returncode,allServices
def CopyinContainerLog(mySSH,lSourcePath,ymlPath,containerName,filename):
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[2]}'
os.system(f'mkdir -p {logPath}')
mySSH.run(f'docker logs {containerName} > {lSourcePath}/cmake_targets/log/{filename} 2>&1')
copyin_res = mySSH.copyin(f'{lSourcePath}/cmake_targets/log/{filename}', os.path.join(logPath, filename))
return copyin_res
def GetRunningServices(mySSH,yamlDir):
ret = mySSH.run(f'docker compose -f {yamlDir}/ci-docker-compose.yml config --services')
allServices = ret.stdout.splitlines() allServices = ret.stdout.splitlines()
services = [] running_services = []
for s in allServices: for s in allServices:
# outputs the hash if the container is running # outputs the hash if the container is running
ret = mySSH.run(f'docker compose -f {yamlDir}/ci-docker-compose.yml ps --all --quiet -- {s}') ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}')
c = ret.stdout if ret.returncode != 0:
logging.debug(f'running service {s} with container id {c}') logging.info(f"service {s}: {ret.stdout}")
if ret.stdout != "" and ret.returncode == 0: # something is running for that service elif ret.stdout == "":
services.append((s, c)) logging.warning(f"could not retrieve information for service {s}")
logging.info(f'stopping services {[s for s, _ in services]}') else:
return services c = ret.stdout
logging.debug(f'running service {s} with container id {c}')
def CheckLogs(self,mySSH,ymlPath,service_name,HTML,RAN): running_services.append((s, c))
logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[2]}' logging.info(f'stopping services: {running_services}')
return running_services
def CheckLogs(self, yaml, service_name, HTML, RAN):
logPath = f'{os.getcwd()}/../cmake_targets/log/{yaml}'
filename = f'{logPath}/{service_name}-{HTML.testCase_id}.log' filename = f'{logPath}/{service_name}-{HTML.testCase_id}.log'
isFailed = 0 success = True
if (any(sub in service_name for sub in ['oai_ue','oai-nr-ue','lte_ue'])): if (any(sub in service_name for sub in ['oai_ue','oai-nr-ue','lte_ue'])):
logging.debug(f'\u001B[1m Analyzing UE logfile {filename} \u001B[0m') logging.debug(f'\u001B[1m Analyzing UE logfile {filename} \u001B[0m')
logStatus = cls_oaicitest.OaiCiTest().AnalyzeLogFile_UE(filename, HTML, RAN) logStatus = cls_oaicitest.OaiCiTest().AnalyzeLogFile_UE(filename, HTML, RAN)
opt = f"UE log analysis for service {service_name}"
# usage of htmlUEFailureMsg/htmleNBFailureMsg is because Analyze log files
# abuse HTML to store their reports, and we here want to put custom options,
# which is not possible with CreateHtmlTestRow
# solution: use HTML templates, where we don't need different HTML write funcs
if (logStatus < 0): if (logStatus < 0):
HTML.CreateHtmlTestRow('UE log Analysis', 'KO', logStatus) HTML.CreateHtmlTestRowQueue(opt, 'KO', [HTML.htmlUEFailureMsg])
isFailed = 1 success = False
else: else:
HTML.CreateHtmlTestRow('UE log Analysis', 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmlUEFailureMsg])
HTML.htmlUEFailureMsg = ""
elif service_name == 'nv-cubb': elif service_name == 'nv-cubb':
msg = 'Undeploy PNF/Nvidia CUBB' msg = 'Undeploy PNF/Nvidia CUBB'
HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK)
elif (any(sub in service_name for sub in ['enb','rru','rcc','cu','du','gnb'])): elif (any(sub in service_name for sub in ['enb','rru','rcc','cu','du','gnb'])):
logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m') logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m')
logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers) logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
opt = f"xNB log analysis for service {service_name}"
if (logStatus < 0): if (logStatus < 0):
HTML.CreateHtmlTestRow(RAN.runtime_stats, 'KO', logStatus) HTML.CreateHtmlTestRowQueue(opt, 'KO', [HTML.htmleNBFailureMsg])
isFailed = 1 success = False
else: else:
HTML.CreateHtmlTestRow(RAN.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmleNBFailureMsg])
HTML.htmlUEFailureMsg = ""
else: else:
logging.info(f'Skipping to analyze log for service name {service_name}') logging.info(f'Skipping to analyze log for service name {service_name}')
return isFailed HTML.CreateHtmlTestRowQueue(f"service {service_name}", 'OK', ["no analysis function"])
logging.debug(f"log check: service {service_name} passed analysis {success}")
return success
#----------------------------------------------------------- #-----------------------------------------------------------
# Class Declaration # Class Declaration
...@@ -314,10 +347,9 @@ class Containerize(): ...@@ -314,10 +347,9 @@ class Containerize():
self.proxyCommit = None self.proxyCommit = None
self.eNB_instance = 0 self.eNB_instance = 0
self.eNB_serverId = ['', '', ''] self.eNB_serverId = ['', '', '']
self.deployKind = [True, True, True]
self.yamlPath = ['', '', ''] self.yamlPath = ['', '', '']
self.services = ['', '', ''] self.services = ['', '', '']
self.nb_healthy = [0, 0, 0] self.deploymentTag = ''
self.eNB_logFile = ['', '', ''] self.eNB_logFile = ['', '', '']
self.testCase_id = '' self.testCase_id = ''
...@@ -329,7 +361,6 @@ class Containerize(): ...@@ -329,7 +361,6 @@ class Containerize():
self.deployedContainers = [] self.deployedContainers = []
self.tsharkStarted = False self.tsharkStarted = False
self.displayedNewTags = False
self.pingContName = '' self.pingContName = ''
self.pingOptions = '' self.pingOptions = ''
self.pingLossThreshold = '' self.pingLossThreshold = ''
...@@ -828,19 +859,20 @@ class Containerize(): ...@@ -828,19 +859,20 @@ class Containerize():
if self.ranAllowMerge: if self.ranAllowMerge:
orgTag = 'ci-temp' orgTag = 'ci-temp'
for image in IMAGES: for image in IMAGES:
tagToUse = ImageTagToUse(image, self.ranCommitID, self.ranBranch, self.ranAllowMerge) tagToUse = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge)
mySSH.command(f'docker image tag {image}:{orgTag} {imagePrefix}/{tagToUse}', '\$', 5) imageTag = f"{image}:{tagToUse}"
mySSH.command(f'docker image tag {image}:{orgTag} {imagePrefix}/{imageTag}', '\$', 5)
if re.search('Error response from daemon: No such image:', mySSH.getBefore()) is not None: if re.search('Error response from daemon: No such image:', mySSH.getBefore()) is not None:
continue continue
mySSH.command(f'docker push {imagePrefix}/{tagToUse}', '\$', 120) mySSH.command(f'docker push {imagePrefix}/{imageTag}', '\$', 120)
if re.search(': digest:', mySSH.getBefore()) is None: if re.search(': digest:', mySSH.getBefore()) is None:
logging.debug(mySSH.getBefore()) logging.debug(mySSH.getBefore())
msg = f'Could not push {image} to local registry : {tagToUse}' msg = f'Could not push {image} to local registry : {imageTag}'
logging.error(msg) logging.error(msg)
mySSH.close() mySSH.close()
HTML.CreateHtmlTestRow(msg, 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(msg, 'KO', CONST.ALL_PROCESSES_OK)
return False return False
mySSH.command(f'docker rmi {imagePrefix}/{tagToUse} {image}:{orgTag}', '\$', 30) mySSH.command(f'docker rmi {imagePrefix}/{imageTag} {image}:{orgTag}', '\$', 30)
mySSH.command(f'docker logout {imagePrefix}', '\$', 5) mySSH.command(f'docker logout {imagePrefix}', '\$', 5)
if re.search('Removing login credentials', mySSH.getBefore()) is None: if re.search('Removing login credentials', mySSH.getBefore()) is None:
...@@ -886,18 +918,19 @@ class Containerize(): ...@@ -886,18 +918,19 @@ class Containerize():
HTML.CreateHtmlTestRow(msg, 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(msg, 'KO', CONST.ALL_PROCESSES_OK)
return False return False
for image in self.imageToPull: for image in self.imageToPull:
tagToUse = ImageTagToUse(image, self.ranCommitID, self.ranBranch, self.ranAllowMerge) tagToUse = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge)
cmd = f'docker pull {imagePrefix}/{tagToUse}' imageTag = f"{image}:{tagToUse}"
cmd = f'docker pull {imagePrefix}/{imageTag}'
response = myCmd.run(cmd, timeout=120) response = myCmd.run(cmd, timeout=120)
if response.returncode != 0: if response.returncode != 0:
logging.debug(response) logging.debug(response)
msg = f'Could not pull {image} from local registry : {tagToUse}' msg = f'Could not pull {image} from local registry : {imageTag}'
logging.error(msg) logging.error(msg)
myCmd.close() myCmd.close()
HTML.CreateHtmlTestRow('msg', 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow('msg', 'KO', CONST.ALL_PROCESSES_OK)
return False return False
myCmd.run(f'docker tag {imagePrefix}/{tagToUse} oai-ci/{tagToUse}') myCmd.run(f'docker tag {imagePrefix}/{imageTag} oai-ci/{imageTag}')
myCmd.run(f'docker rmi {imagePrefix}/{tagToUse}') myCmd.run(f'docker rmi {imagePrefix}/{imageTag}')
response = myCmd.run(f'docker logout {imagePrefix}') response = myCmd.run(f'docker logout {imagePrefix}')
if response.returncode != 0: if response.returncode != 0:
msg = 'Could not log off from local registry' msg = 'Could not log off from local registry'
...@@ -938,7 +971,8 @@ class Containerize(): ...@@ -938,7 +971,8 @@ class Containerize():
myCmd = cls_cmd.LocalCmd() myCmd = cls_cmd.LocalCmd()
for image in IMAGES: for image in IMAGES:
imageTag = ImageTagToUse(image, self.ranCommitID, self.ranBranch, self.ranAllowMerge) tag = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge)
imageTag = f"{image}:{tag}"
cmd = f'docker rmi oai-ci/{imageTag}' cmd = f'docker rmi oai-ci/{imageTag}'
myCmd.run(cmd, reportNonZero=False) myCmd.run(cmd, reportNonZero=False)
...@@ -982,38 +1016,49 @@ class Containerize(): ...@@ -982,38 +1016,49 @@ class Containerize():
HELP.GenericHelp(CONST.Version) HELP.GenericHelp(CONST.Version)
sys.exit('Insufficient Parameter') sys.exit('Insufficient Parameter')
logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m') logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m')
self.deployKind[self.eNB_instance] = True yaml = self.yamlPath[self.eNB_instance].strip('/')
mySSH = cls_cmd.getConnection(lIpAddr, f'{lSourcePath}/{self.yamlPath[self.eNB_instance]}') wd = f'{lSourcePath}/{yaml}'
logging.info(f'Current working directory: {lSourcePath}/{self.yamlPath[self.eNB_instance]}')
ReTagImages(mySSH,IMAGES,self.ranCommitID, self.ranBranch, self.ranAllowMerge, self.displayedNewTags) with cls_cmd.getConnection(lIpAddr) as ssh:
deployStatus,allServices = DeployServices(mySSH,self.services[self.eNB_instance]) services = GetServices(ssh, self.services[self.eNB_instance], f"{wd}/docker-compose.y*ml")
if deployStatus != 0: if services == [] or services == ' ' or services == None:
mySSH.close() msg = "Cannot determine services to start"
logging.error('Could not deploy') logging.error(msg)
HTML.CreateHtmlTestRow('Could not deploy', 'KO', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg])
return False return False
services_list = allServices if self.services[self.eNB_instance].split() == [] else self.services[self.eNB_instance].split()
status = True ExistEnvFilePrint(ssh, wd)
imagesInfo="" WriteEnvFile(ssh, services, wd, self.deploymentTag)
for svcName in services_list:
containerName = GetContainerName(mySSH, svcName) logging.info(f"will start services {services}")
healthy = GetContainerHealth(mySSH,containerName) status = ssh.run(f'docker compose -f {wd}/docker-compose.y*ml up -d -- {services}')
self.testCase_id = HTML.testCase_id if status.returncode != 0:
self.eNB_logFile[self.eNB_instance] = f'{svcName}-{self.testCase_id}.log' msg = f"cannot deploy services {services}: {status.stdout}"
if not healthy: logging.error(msg)
logging.warning(f"Deployment Failed: Trying to copy container logs {self.eNB_logFile[self.eNB_instance]}") HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg])
CopyinContainerLog(mySSH,lSourcePath,self.yamlPath[0].split('/'),containerName,self.eNB_logFile[self.eNB_instance]) return False
status = False
imagesInfo += (GetImageInfo(mySSH, containerName)) imagesInfo = []
mySSH.close() fstatus = True
imagesInfo += ("\n") for svc in services.split():
if status: containerName = GetContainerName(ssh, svc, f"{wd}/docker-compose.y*ml")
imagesInfo += ("Healthy deployment!") healthy = GetContainerHealth(ssh, containerName)
HTML.CreateHtmlTestRowQueue('N/A', 'OK', [(imagesInfo)]) if not healthy:
tgtlogfile = f'{svc}-{HTML.testCase_id}.log'
logging.warning(f"Deployment Failed: Trying to copy container logs to {tgtlogfile}")
yaml_dir = yaml.split('/')[-1]
CopyinContainerLog(ssh, lSourcePath, yaml_dir, containerName, tgtlogfile)
imagesInfo += [f"Failed to deploy: service {svc}"]
fstatus = False
else:
image = GetImageName(ssh, svc, f"{wd}/docker-compose.y*ml")
logging.info(f"service {svc} healthy, container {containerName}, image {image}")
imagesInfo += [f"service {svc} healthy, image {image}"]
if fstatus:
HTML.CreateHtmlTestRowQueue('N/A', 'OK', ['\n'.join(imagesInfo)])
else: else:
imagesInfo += ("Unhealthy deployment! -- Check logs for reason!") HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)])
HTML.CreateHtmlTestRowQueue('N/A', 'KO', [(imagesInfo)]) return fstatus
return status
def UndeployObject(self, HTML, RAN): def UndeployObject(self, HTML, RAN):
lIpAddr, lUserName, lPassWord, lSourcePath = GetCredentials(self) lIpAddr, lUserName, lPassWord, lSourcePath = GetCredentials(self)
...@@ -1021,21 +1066,27 @@ class Containerize(): ...@@ -1021,21 +1066,27 @@ class Containerize():
HELP.GenericHelp(CONST.Version) HELP.GenericHelp(CONST.Version)
sys.exit('Insufficient Parameter') sys.exit('Insufficient Parameter')
logging.debug(f'\u001B[1m Undeploying OAI Object from server: {lIpAddr}\u001B[0m') logging.debug(f'\u001B[1m Undeploying OAI Object from server: {lIpAddr}\u001B[0m')
mySSH = cls_cmd.getConnection(lIpAddr) yaml = self.yamlPath[self.eNB_instance].strip('/')
yamlDir = f'{lSourcePath}/{self.yamlPath[self.eNB_instance]}' wd = f'{lSourcePath}/{yaml}'
services = GetRunningServices(mySSH, yamlDir) yaml_dir = yaml.split('/')[-1]
mySSH.run(f'docker compose -f {yamlDir}/ci-docker-compose.yml stop -t3') with cls_cmd.getConnection(lIpAddr) as ssh:
copyin_res = True ExistEnvFilePrint(ssh, wd)
copyin_res = all(CopyinContainerLog(mySSH, lSourcePath, self.yamlPath[0].split('/'), container_id, f'{service_name}-{HTML.testCase_id}.log') for service_name, container_id in services) services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml")
mySSH.run(f'docker compose -f {yamlDir}/ci-docker-compose.yml down -v') copyin_res = None
if services is not None:
all_serv = " ".join([s for s, _ in services])
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}')
copyin_res = all(CopyinContainerLog(ssh, lSourcePath, yaml_dir, c, f'{s}-{HTML.testCase_id}.log') for s, c in services)
else:
logging.warning('could not identify services to stop => no log file')
ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v')
ssh.run(f'rm {wd}/.env')
if not copyin_res: if not copyin_res:
HTML.htmleNBFailureMsg='Could not copy logfile(s) to analyze it!' HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)'])
HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
return False return False
else: else:
log_results = [CheckLogs(self, mySSH, self.yamlPath[0].split('/'), service_name, HTML, RAN) for service_name, _ in services] log_results = [CheckLogs(self, yaml_dir, s, HTML, RAN) for s, _ in services]
success = any(log_results) success = all(log_results)
mySSH.close()
if success: if success:
logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m') logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
else: else:
......
...@@ -375,6 +375,7 @@ def ExecuteActionWithParam(action): ...@@ -375,6 +375,7 @@ def ExecuteActionWithParam(action):
string_field = test.findtext('services') string_field = test.findtext('services')
if string_field is not None: if string_field is not None:
CONTAINERS.services[CONTAINERS.eNB_instance] = string_field CONTAINERS.services[CONTAINERS.eNB_instance] = string_field
CONTAINERS.deploymentTag = cls_containerize.CreateTag(CONTAINERS.ranCommitID, CONTAINERS.ranBranch, CONTAINERS.ranAllowMerge)
if action == 'Deploy_Object': if action == 'Deploy_Object':
success = CONTAINERS.DeployObject(HTML) success = CONTAINERS.DeployObject(HTML)
elif action == 'Undeploy_Object': elif action == 'Undeploy_Object':
......
...@@ -24,6 +24,9 @@ class TestDeploymentMethods(unittest.TestCase): ...@@ -24,6 +24,9 @@ class TestDeploymentMethods(unittest.TestCase):
self.cont = cls_containerize.Containerize() self.cont = cls_containerize.Containerize()
self.ran = ran.RANManagement() self.ran = ran.RANManagement()
self.cont.yamlPath[0] = 'tests/simple-dep/' self.cont.yamlPath[0] = 'tests/simple-dep/'
self.cont.ranAllowMerge = True
self.cont.ranBranch = 'develop'
self.cont.ranCommitID = '1234567890'
self.cont.eNB_serverId[0] = '0' self.cont.eNB_serverId[0] = '0'
self.cont.eNBIPAddress = 'localhost' self.cont.eNBIPAddress = 'localhost'
self.cont.eNBUserName = None self.cont.eNBUserName = None
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment