trigger-lava-jobs accepts the YAML pipeline lava-job config file generated by run-jinja-parser scripts. This triggers a new job at LAVA end thru RPC and parses the authentication token and user credentials to launch/start the hardware automation on LAVA Dispatcher.Script will exit on error when lava-job return a state either incomplete or canceling stage. trigger-lava-jobs uses lava_scheduler.py python module where the LAVA classes and library constructed from XML-RPC API which are define and supported by Linaro, LAVA. Signed-off-by: Aaron Chan <aaron.chun.yew.chan@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
8.2 KiB
Executable File
#!/usr/bin/env python3
=====================================================================================
XML-RPC API reference taken from
-- https://validation.linaro.org/static/docs/v2/data-export.html#xml-rpc
Developed By : Chan, Aaron aaron.chun.yew.chan@intel.com
Organization : Yocto Project Open Source Technology Center (Intel)
Date : 27-Aug-2018 (Initial release)
=====================================================================================
Triggers a job execution define by YAML template on LAVA server end from autobuilder.
This script will monitor the lava-job status until the hardware boots up successfully
and returns the IPv4 addr pre-configure over network boot (PXE) on the board.
Once the IPv4 addr has been recovered, script will update the auto.conf with
TEST_TARGET_IP, TEST_SERVER_IP to establish a client-host connection and prepare to
execute automated harware test case(s) on hardware on the next step.
Options:
$1 - Supply lava-job template in a YAML format (e.g. .yaml)
$2 - Supply autobuilder buildername (e.g. nightly-x86-64-bsp, nightly-arm64-bsp)
$3 - By default set to "None", else parse in the buildnumber to create the NFS path
$4 - Supply device/board name (same as LAVA device type)
import xmlrpc.client import sys import os import time import re import json import netifaces import time from shutil import copyfile from lava_scheduler import *
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(file))),"scripts")) import utils
Enable this section on manual run
os.environ['ABHELPER_JSON'] = "config.json /home/pokybuild/yocto-autobuilder-helper/config-intelqa-x86_64-lava.json"
def lava_jobsStatus(server, jobid, timeout, bootUp=False, ipaddr=None, iparch=None, timeInt=5): jobStatus = scheduler.lava_jobs_status(server, jobid)['job_status']
while jobStatus == "Submitted" or jobStatus == "Running" or bootUp == False:
time.sleep(timeInt)
timeout += timeInt
for logs in scheduler.lava_jobs_logs(server, jobid, 0):
ipaddr = re.search("Station\s*IP\s*address\s*is\s*(.*)\"", str(logs), re.I)
iparch = re.search("Detected\s*architecture\s*(.*)\.", str(logs), re.I)
dbmsg = re.search("Board\s*boot\s*up\s*successfully", str(logs), re.I)
if ipaddr: ipaddr = ipaddr.group(1)
if iparch: iparch = iparch.group(1)
if dbmsg:
bootUp = True
break
if bootUp:
print("INFO : Board booted up successfully. LAVA is ready to handover to Buildbot-CI [%s]" % str(bootUp))
break
if timeout > 3000:
scheduler.lava_jobs_cancel(server, jobid)
print("WARNING: Board exceeded bootup time threshold %d, Job will be %s and powered down" % (
timeout, scheduler.lava_jobs_status(server, jobid)['job_status']))
break
jobStatus = scheduler.lava_jobs_status(server, jobid)['job_status']
print("INFO : Job has current status [%s]" % jobStatus)
# Job Status #
if jobStatus == 'Incomplete':
print("ABORTED: %s test!. Rerun again if required" % jobStatus)
elif jobStatus == 'Cancel':
print("ABORTED: Job has been [%s]led by user" % jobStatus)
elif jobStatus == 'Complete':
print("SUCCESS: Current JobID [%s] has been successfully [%s] and passed" % (jobid, jobStatus))
elif jobStatus == 'Running':
print("INFO : %s in %d seconds ..." % (jobStatus, timeout))
elif jobStatus == 'Submitted':
print("INFO : Lava job has been successfully %s and running in progress..." % jobStatus)
else:
print("ERROR : Job is either %s or in an unknown state. Report to LAVA Mailing Lists" % jobStatus)
return ipaddr, iparch, jobStatus
def lava_jobsSubmit(server, hostname, cfgfile, debug=False): #if os.path.isfile(cfgfile): with open(cfgfile, 'r') as yaml: yamlCfg = yaml.read() yaml.close()
if debug: print("INFO : Current YAML Job Definition\n%s" % yamlCfg)
jobid = scheduler.lava_jobs_submit(server, yamlCfg)
if jobid is not None:
print("SUCCESS: Job submitted to http://%s/scheduler/job/%s#bottom to LAVA-CI server" % (hostname, jobid))
(boardIp, boardArch, boardStat) = lava_jobsStatus(server, jobid, 0)
#else:
# print("ERROR: YAML Config not found on the LAVA-Server")
return boardIp, boardArch, boardStat, jobid
def lava_jobsDetail(server, jobid, elements, items=[]): jobInfo = scheduler.lava_jobs_details(server, jobid)
if type(elements) is str:
return jobInfo[elements]
elif type(elements) is list:
for item in elements:
items.append(jobInfo[item])
return items
else:
return jobInfo
def lava_listmethods(server): print(server.system.listMethods())
def lava_publisher(username, token, server): return xmlrpc.client.ServerProxy("http://%s:%s@%s/RPC2/" % (username, token, server))
def check_isfile(filename): if not os.path.isfile(filename): print("ERROR: Failed to locate filename %s" % filename) sys.exit(1) return True
def check_until(filename, isfound=None): if os.path.isfile(filename): isfound=False else: isfound=True return isfound
Starts here
def main(): """ For Yocto Project Reference scripts, this tool was developed to trigger a Job in LAVA server based on URL, TCP/IP port defined on config-intelqa-x86_64-lava.json. Requirement to run this script to ensure .yaml, build/build/conf/auto.conf is present. """ yamlconf = sys.argv[1] autoconf = sys.argv[2] try : boardinfo = sys.argv[3] except: boardinfo = None
ourconfig = utils.loadconfig()
lavadefs = ourconfig["lava-defaults"]
username = lavadefs['username']
token = lavadefs['token']
server = lavadefs['server']
interface = lavadefs['interface']
timemin = timesec = 0
cwd=os.path.join(os.getcwd(), "board_info.json")
# Instantiate LAVA server connection with RPC
lavaserver = lava_publisher(username, token, server)
isfile = check_isfile(yamlconf)
if isfile:
target_ip, boardArch, boardStat, jobid = lava_jobsSubmit(lavaserver, server, yamlconf)
if boardStat == 'Canceling' and boardStat == 'Incomplete':
print("Board/hardware unresponsive or software image loaded is incompatiable. Ending session.")
sys.exit(1)
if boardinfo is not None:
boardinfo = os.path.join(boardinfo, str(jobid), 'board_info.json')
print("Search if board info exists [%s]" % boardinfo)
while(check_until(boardinfo)):
time.sleep(1)
timesec += 1
if timesec > 2500:
print("Board discovery exceeds timeout %s. Ending session." % str(timesec))
sys.exit(1)
print("Board discovery in %s secs ..." % str(timesec))
(timemin, timesec)=divmod(timesec, 60)
print("Board has been discovered in %s mins, %s secs" % (timemin, timesec))
if os.path.isfile(cwd):
os.system(" ls -al %s" % boardinfo)
print("Board info existed, file will be deleted and recopied over to %s" % cwd)
os.remove(cwd)
else:
print("Board info to be copied over to %s" % cwd)
copyfile(boardinfo, cwd)
os.environ['ABHELPER_JSON'] += (" " + boardinfo)
ourconfig = utils.loadconfig()
target_ip = ourconfig['network']['ipaddr']
lavaurl = "http://" + server + str(lava_jobsDetail(lavaserver, jobid, 'absolute_url'))
jobinfo = lava_jobsDetail(lavaserver, jobid, ['actual_device_id', 'start_time', 'end_time'])
server_ip = netifaces.ifaddresses(interface)[2][0]['addr']
# Update auto.conf with board IPv4 and server IPv4 addressing
isauto = check_isfile(autoconf)
if isauto:
with open(autoconf, "a") as autof:
autof.writelines("TEST_SERVER_IP = \"%s\"\n" % server_ip)
autof.writelines("TEST_TARGET_IP = \"%s\"\n" % target_ip)
autof.close()
print("="*50)
print("""
SUMMARY: LAVA-url : %s LAVA-job : %s LAVA-status : %s Device-IP : %s Device-ARCH : %s """ % (lavaurl, jobinfo, boardStat, target_ip, boardArch)) print("="*50)
if name == 'main': main()