Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructured testbed folder. Enhanced runDentCi #421

Merged
merged 1 commit into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions CI_Automation/DentCiArgParse.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import argparse
import Utilities
import globalSettings
from re import search

timestamp = Utilities.getTimestamp(includeMillisecond=True).replace(':', '-')

Expand Down Expand Up @@ -47,6 +48,7 @@ def parse(self):
else:
self.ciVars.testId = timestamp

self.ciVars.cmdLine: str = ' '.join(sys.argv)
self.ciVars.timestamp: str = timestamp
self.ciVars.testSessionFolder: str = f'{globalSettings.dentTestResultsFolder}/{self.ciVars.testId}'
self.ciVars.testSessionLogsFolder: str = f'{self.ciVars.testSessionFolder}/CI_Logs'
Expand All @@ -58,14 +60,17 @@ def parse(self):
self.ciVars.reportFile: str = f'{self.ciVars.testSessionFolder}/ciTestReport'

if args.testSuites is None:
sys.exit(1, '-testSuites parameter is required with test suites to use for testing')
sys.exit('-testSuites parameter is required with test suites to use for testing')
else:
# Verify for user defined testSuites existence
for eachTestSuite in args.testSuites:
testSuite = eachTestSuite.replace('.yml', '')
testSuiteFile = f'{self.ciVars.testSuiteFolder}/{testSuite}.yml'
if os.path.exists(testSuiteFile) is False:
Utilities.sysExit(self.ciVars, f'No such test suite name found: {eachTestSuite}')
regexMatch = search('.*((hw|vm)/.*)', testSuite)
if regexMatch:
testSuite = regexMatch.group(1)
testSuiteFile = f'{self.ciVars.testSuiteFolder}/{testSuite}.yml'
else:
testSuiteFile = f'{self.ciVars.testSuiteFolder}/{testSuite}.yml'

self.ciVars.testSuites.append(testSuiteFile)

Expand Down
99 changes: 72 additions & 27 deletions CI_Automation/runDentCi.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/python3

"""
version = v10

Dent CI Automation Framework

Automating the following stages:
Expand Down Expand Up @@ -75,6 +77,8 @@ class CiVars:
# Stage 3
runTest: bool = True # requires cloneTestRepo for testbed configs

cmdLine: str = ''

# The test ID timestamp (without the appended testName)
timestamp: str = ''
# The follows are set in DentCiArgParse.py
Expand Down Expand Up @@ -155,6 +159,9 @@ class CiVars:
class DentCI:
def __init__(self, ciVars):
self.ciVars = ciVars
self.stage1Result = None
self.stage2Result = None
self.stage3Result = None

self.ciVars.testIdTestingBranch = f'{self.ciVars.testBranchFolder}/{self.ciVars.testId}'

Expand All @@ -176,6 +183,7 @@ def __init__(self, ciVars):
self.removeDockerStaleImages()

self.testMgmtData = {'pid': self.ciVars.pid,
'cmdLine': self.ciVars.cmdLine,
'testId': self.ciVars.testId,
'testName': self.ciVars.testName,
'startTime': datetime.now().strftime('%m-%d-%Y %H:%M:%S:%f'),
Expand Down Expand Up @@ -229,6 +237,8 @@ def __init__(self, ciVars):
self.ciVars.sessionLog.info(f'Testing repo: {self.ciVars.repo}')
self.ciVars.sessionLog.info(f'Install branchName: {self.ciVars.branchName}')

self.verifyTestSuites()

# Wait at this point until the CI system is enabled
self.isCiSystemEnabled()

Expand Down Expand Up @@ -270,6 +280,13 @@ def __init__(self, ciVars):
self.createDockerImageTag()
self.lockTestbeds()

def verifyTestSuites(self):
# Verify for user defined testSuite
for eachTestSuiteFile in self.ciVars.testSuites:
if os.path.exists(eachTestSuiteFile) is False:
self.ciVars.sessionLog.error(f'No such test suite: {eachTestSuiteFile}')
sys.exit(1)

def createDockerImageTag(self):
"""
Create a docker image tag for each test
Expand Down Expand Up @@ -359,6 +376,12 @@ def isTestIdTestBranchExists(self, stage=None):
"""
Verify if the testing branch successfully got cloned
"""
# Show the cloned test branch in the testIdTestingBranch directory for visibility and confirmation
self.ciVars.sessionLog.info(f'isTestIdTestBranchExists: Looking for testID: {self.ciVars.testId}')
output = Utilities.runLinuxCmd('ls -l', cwd=self.ciVars.testBranchFolder)
for line in output:
self.ciVars.sessionLog.info(line.strip())

if os.path.exists(self.ciVars.testIdTestingBranch) is False:
errorMsg = f'Stage={stage}: Is cloneTestBranch == True? The testID test branch does not exists: {self.ciVars.testIdTestingBranch}.'
self.ciVars.sessionLog.error(errorMsg)
Expand Down Expand Up @@ -415,7 +438,7 @@ def parseForTestbeds(self, configFullPath):
Get all testbeds from test suites "config" parameter
"""
if os.path.exists(configFullPath) is False:
print(f'Test Suite config does not exists: {configFullPath}')
self.ciVars.sessionLog.error(f'Test Suite config does not exists: {configFullPath}')
Utilities.runDentCiTearDown(ciVars, f'Test Suite file has an incorrect "config" path: {configFullPath}')

testbedContents = Utilities.readJson(configFullPath)
Expand Down Expand Up @@ -514,6 +537,7 @@ def cloneTestRepo(self):
and name it the testId
"""
if self.ciVars.cloneTestRepo is False:
self.stage1Result = 'failed'
return

self.isGitCloneSafeToRun()
Expand All @@ -530,9 +554,10 @@ def cloneTestRepo(self):
self.testbedMgmtObj.unlockTestbeds()
Utilities.closeTestMgmtStatus(overallSummaryFile=self.ciVars.overallSummaryFile,
status='aborted', result='failed', threadLock=self.ciVars.lock)
Utilities.runDentCiTearDown(self.ciVars, 'Clone Dent test repo failed')
Utilities.runDentCiTearDown(self.ciVars, 'Cloning Dent test repo failed')
self.stage1Result = 'failed'

if result:
if self.stage1Result != 'failed' and result:
# Parse out all testbeds from test suite files and from the cloned repo
for testSuite in self.ciVars.testSuites:
contents = Utilities.readYaml(testSuite)
Expand All @@ -556,30 +581,35 @@ def cloneTestRepo(self):
status='aborted', result='failed', threadLock=self.ciVars.lock)
# This will unlocktestbed, remove testId test branch, create jenkinsCI result path
Utilities.runDentCiTearDown(self.ciVars, 'Clone Dent test repo failed on clone verification')
self.stage1Result = 'failed'

self.verifyIxNetworkVMFunctionality()
self.stage1Result = 'passed'

def downloadBuilds(self):
"""
STAGE 1: Download Dent build image to tftp server /srv/tftp
"""
if self.ciVars.downloadNewBuilds is False:
self.stage1Result = 'failed'
return

downloadBuildsResults = downloadBuilds(self.ciVars)
if downloadBuildsResults is False:
self.stage1Result = 'failed'
self.testbedMgmtObj.unlockTestbeds()
Utilities.runDentCiTearDown(self.ciVars, 'Download builds failed')
else:
if self.stage1Result != 'failed':
self.stage1Result = 'passed'

def installDentOS(self):
def installDentOS(self, stage='installDentOS'):
"""
STAGE 2: Install build on Dent
"""
if self.ciVars.installDentOS is False:
if self.stage1Result == 'failed' or self.ciVars.installDentOS is False:
return

stage = 'installDentOS'

# Requires pulling the branch for testbed configs
self.isTestIdTestBranchExists(stage=stage)
updateDentResult = updateDent(self.ciVars)
Expand All @@ -589,24 +619,31 @@ def installDentOS(self):
Utilities.runLinuxCmd(f'rm -rf {self.ciVars.downloadToServerFolder}')

if updateDentResult is False:
self.stage2Result = 'failed'
Utilities.closeTestMgmtStatus(overallSummaryFile=self.ciVars.overallSummaryFile,
status='aborted', result='failed', threadLock=self.ciVars.lock)
Utilities.runDentCiTearDown(self.ciVars, 'failed')

self.ciVars.sessionLog.info(f'{stage}: passed')
else:
if self.stage2Result != 'failed':
self.stage2Result = 'passed'
self.ciVars.sessionLog.info(f'{stage}: passed')

def deployIxNetwork(self, forceBringUp=False):
"""
STAGE 2: Deploy IxNetwork
"""
if self.ciVars.deployIxNetwork is False and forceBringUp is False:
if self.stage1Result != 'failed' and self.ciVars.deployIxNetwork is False and forceBringUp is False:
return

deployIxNetworkResult = deployIxNetworkInit(ciVars=self.ciVars)
if deployIxNetworkResult is False:
self.stage2Result = 'failed'
Utilities.closeTestMgmtStatus(overallSummaryFile=self.ciVars.overallSummaryFile,
status='aborted', result='failed', threadLock=self.ciVars.lock)
Utilities.runDentCiTearDown(self.ciVars, 'failed')
else:
if self.stage2Result != 'failed':
self.stage2Result = 'passed'

# Enable back the CI system for other test to run
if os.path.exists(f'{globalSettings.dentCiMgmtPath}/{globalSettings.disableSystemFilename}'):
Expand All @@ -618,26 +655,28 @@ def deployDentTestContainers(self):
"""
STAGE 2: Deploy test containers
"""
if self.ciVars.deployDentTestContainers is False:
if self.stage2Result != 'failed' or self.ciVars.deployDentTestContainers is False:
return

dentContainerObj = DeployTestContainers(self.ciVars.testContainersLogFile, self.ciVars)
result = dentContainerObj.removeAndBuild()

if result is False:
self.stage2Result = 'failed'
Utilities.closeTestMgmtStatus(overallSummaryFile=self.ciVars.overallSummaryFile,
status='aborted', result='failed', threadLock=self.ciVars.lock)
Utilities.runDentCiTearDown(self.ciVars, 'failed')
else:
if self.stage2Result != 'failed':
self.stage2Result = 'passed'

def runTest(self):
def runTest(self, stage='runTest'):
"""
STAGE 3: Run test
"""
if self.ciVars.runTest is False:
if self.stage2Result != 'failed' or self.ciVars.runTest is False:
return

stage = 'runTest'

# Verify if test branch exists
self.isTestIdTestBranchExists(stage=stage)

Expand Down Expand Up @@ -684,23 +723,29 @@ def runTest(self):
Utilities.runThreads(ciVars, threads)

# Stage 2
threads = []
if ciVars.installDentOS:
ci.installDentOS()
# threads.append(Thread(target=ci.installDentOS, name='installDentOS'))
if ci.stage1Result == 'passed':
threads = []
if ciVars.installDentOS:
ci.installDentOS()
# threads.append(Thread(target=ci.installDentOS, name='installDentOS'))

if ciVars.deployIxNetwork:
threads.append(Thread(target=ci.deployIxNetwork, name='deployIxNetwork'))
if ciVars.deployIxNetwork:
threads.append(Thread(target=ci.deployIxNetwork, name='deployIxNetwork'))

if ciVars.deployDentTestContainers:
threads.append(Thread(target=ci.deployDentTestContainers, name='deployDentTestContainers'))
if ciVars.deployDentTestContainers:
threads.append(Thread(target=ci.deployDentTestContainers, name='deployDentTestContainers'))

if threads:
Utilities.runThreads(ciVars, threads)
if threads:
Utilities.runThreads(ciVars, threads)
else:
raise Exception('Stage 1 failed. Aborting test.')

# Stage 3
if ciVars.runTest:
ci.runTest()
if ci.stage2Result == 'passed':
if ciVars.runTest:
ci.runTest()
else:
raise Exception('Stage 2 failed. Aborting test.')

# If in dev mode, it might not call runDentCiTearDown.
# So call it to unlocktestbed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# ISC dhcpd configuration
#


option domain-name "dentlab-agg1";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dentlab-agg1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.1.1 dentlab-agg1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#
# ONL format of dent interfaces
#
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*.intf

# The loopback network interface
auto lo
iface lo inet loopback
address 20.20.0.1/32

# The management interface
auto ma1
iface ma1 inet dhcp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help


driftfile /var/lib/ntp/ntp.drift


# Enable this if you want statistics to be logged.
#statsdir /var/log/ntpstats/

statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable


# You do need to talk to an NTP server or two (or three).
#server ntp.your-provider.example


# pool.ntp.org maps to about 1000 low-stratum NTP servers. Your server will
# pick a different set every time it starts up. Please consider joining the
# pool: <http://www.pool.ntp.org/join.html>
#

# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for
# details. The web page <http://support.ntp.org/bin/view/Support/AccessRestrictions>
# might also be helpful.
#
# Note that "restrict" applies to both servers and clients, so a configuration
# that might be intended to block requests from certain clients could also end
# up blocking replies from your own upstream servers.

# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer noquery
restrict -6 default kod notrap nomodify nopeer noquery

# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1

# Clients from this (example!) subnet have unlimited access, but only if
# cryptographically authenticated.
#restrict 192.168.123.0 mask 255.255.255.0 notrust


# If you want to provide time to your local subnet, change the next line.
# (Again, the address is an example only.)
#broadcast 192.168.123.255

# If you want to listen to time broadcasts on your local subnet, de-comment the
# next lines. Please do this only if you trust everybody on the network!
#disable auth
#broadcastclient

# Specify interfaces, don't listen on switch ports
#interface listen ma1
interface listen lo
interface listen lo:0
interface listen dummy0
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
username cumulus nopassword
!
service integrated-vtysh-config
!
log timestamp precision 6
!
no zebra nexthop kernel enable
!
line vty
!
end
Loading
Loading