mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
146 lines
5.4 KiB
Python
146 lines
5.4 KiB
Python
|
#!/usr/bin/python
|
||
|
|
||
|
'''CONFIG_JSON is a json encoded string base64 environment variable. It is used
|
||
|
to clone docker-ci database, generate docker-ci report and submit it by email.
|
||
|
CONFIG_JSON data comes from the file /report/credentials.json inserted in this
|
||
|
container by deployment.py:
|
||
|
|
||
|
{ "DOCKER_CI_PUB": "$(cat docker-ci_ssh_public_key.pub)",
|
||
|
"DOCKER_CI_KEY": "$(cat docker-ci_ssh_private_key.key)",
|
||
|
"DOCKER_CI_ADDRESS": "user@docker-ci_fqdn_server",
|
||
|
"SMTP_USER": "SMTP_server_user",
|
||
|
"SMTP_PWD": "SMTP_server_password",
|
||
|
"EMAIL_SENDER": "Buildbot_mailing_sender",
|
||
|
"EMAIL_RCP": "Buildbot_mailing_receipient" } '''
|
||
|
|
||
|
import os, re, json, sqlite3, datetime, base64
|
||
|
import smtplib
|
||
|
from datetime import timedelta
|
||
|
from subprocess import call
|
||
|
from os import environ as env
|
||
|
|
||
|
TODAY = datetime.date.today()
|
||
|
|
||
|
# Load credentials to the environment
|
||
|
env['CONFIG_JSON'] = base64.b64decode(open('/report/credentials.json').read())
|
||
|
|
||
|
# Remove SSH private key as it needs more processing
|
||
|
CONFIG = json.loads(re.sub(r'("DOCKER_CI_KEY".+?"(.+?)",)','',
|
||
|
env['CONFIG_JSON'], flags=re.DOTALL))
|
||
|
|
||
|
# Populate environment variables
|
||
|
for key in CONFIG:
|
||
|
env[key] = CONFIG[key]
|
||
|
|
||
|
# Load SSH private key
|
||
|
env['DOCKER_CI_KEY'] = re.sub('^.+"DOCKER_CI_KEY".+?"(.+?)".+','\\1',
|
||
|
env['CONFIG_JSON'],flags=re.DOTALL)
|
||
|
|
||
|
# Prevent rsync to validate host on first connection to docker-ci
|
||
|
os.makedirs('/root/.ssh')
|
||
|
open('/root/.ssh/id_rsa','w').write(env['DOCKER_CI_KEY'])
|
||
|
os.chmod('/root/.ssh/id_rsa',0600)
|
||
|
open('/root/.ssh/config','w').write('StrictHostKeyChecking no\n')
|
||
|
|
||
|
|
||
|
# Sync buildbot database from docker-ci
|
||
|
call('rsync {}:/data/buildbot/master/state.sqlite .'.format(
|
||
|
env['DOCKER_CI_ADDRESS']), shell=True)
|
||
|
|
||
|
class SQL:
|
||
|
def __init__(self, database_name):
|
||
|
sql = sqlite3.connect(database_name)
|
||
|
# Use column names as keys for fetchall rows
|
||
|
sql.row_factory = sqlite3.Row
|
||
|
sql = sql.cursor()
|
||
|
self.sql = sql
|
||
|
|
||
|
def query(self,query_statement):
|
||
|
return self.sql.execute(query_statement).fetchall()
|
||
|
|
||
|
sql = SQL("state.sqlite")
|
||
|
|
||
|
|
||
|
class Report():
|
||
|
|
||
|
def __init__(self,period='',date=''):
|
||
|
self.data = []
|
||
|
self.period = 'date' if not period else period
|
||
|
self.date = str(TODAY) if not date else date
|
||
|
self.compute()
|
||
|
|
||
|
def compute(self):
|
||
|
'''Compute report'''
|
||
|
if self.period == 'week':
|
||
|
self.week_report(self.date)
|
||
|
else:
|
||
|
self.date_report(self.date)
|
||
|
|
||
|
|
||
|
def date_report(self,date):
|
||
|
'''Create a date test report'''
|
||
|
builds = []
|
||
|
# Get a queryset with all builds from date
|
||
|
rows = sql.query('SELECT * FROM builds JOIN buildrequests'
|
||
|
' WHERE builds.brid=buildrequests.id and'
|
||
|
' date(start_time, "unixepoch", "localtime") = "{0}"'
|
||
|
' GROUP BY number'.format(date))
|
||
|
build_names = sorted(set([row['buildername'] for row in rows]))
|
||
|
# Create a report build line for a given build
|
||
|
for build_name in build_names:
|
||
|
tried = len([row['buildername']
|
||
|
for row in rows if row['buildername'] == build_name])
|
||
|
fail_tests = [row['buildername'] for row in rows if (
|
||
|
row['buildername'] == build_name and row['results'] != 0)]
|
||
|
fail = len(fail_tests)
|
||
|
fail_details = ''
|
||
|
fail_pct = int(100.0*fail/tried) if tried != 0 else 100
|
||
|
builds.append({'name': build_name, 'tried': tried, 'fail': fail,
|
||
|
'fail_pct': fail_pct, 'fail_details':fail_details})
|
||
|
if builds:
|
||
|
self.data.append({'date': date, 'builds': builds})
|
||
|
|
||
|
|
||
|
def week_report(self,date):
|
||
|
'''Add the week's date test reports to report.data'''
|
||
|
date = datetime.datetime.strptime(date,'%Y-%m-%d').date()
|
||
|
last_monday = date - datetime.timedelta(days=date.weekday())
|
||
|
week_dates = [last_monday + timedelta(days=x) for x in range(7,-1,-1)]
|
||
|
for date in week_dates:
|
||
|
self.date_report(str(date))
|
||
|
|
||
|
def render_text(self):
|
||
|
'''Return rendered report in text format'''
|
||
|
retval = ''
|
||
|
fail_tests = {}
|
||
|
for builds in self.data:
|
||
|
retval += 'Test date: {0}\n'.format(builds['date'],retval)
|
||
|
table = ''
|
||
|
for build in builds['builds']:
|
||
|
table += ('Build {name:15} Tried: {tried:4} '
|
||
|
' Failures: {fail:4} ({fail_pct}%)\n'.format(**build))
|
||
|
if build['name'] in fail_tests:
|
||
|
fail_tests[build['name']] += build['fail_details']
|
||
|
else:
|
||
|
fail_tests[build['name']] = build['fail_details']
|
||
|
retval += '{0}\n'.format(table)
|
||
|
retval += '\n Builds failing'
|
||
|
for fail_name in fail_tests:
|
||
|
retval += '\n' + fail_name + '\n'
|
||
|
for (fail_id,fail_url,rn_tests,nr_errors,log_errors,
|
||
|
tracelog_errors) in fail_tests[fail_name]:
|
||
|
retval += fail_url + '\n'
|
||
|
retval += '\n\n'
|
||
|
return retval
|
||
|
|
||
|
|
||
|
# Send email
|
||
|
smtp_from = env['EMAIL_SENDER']
|
||
|
subject = '[docker-ci] Daily report for {}'.format(str(TODAY))
|
||
|
msg = "From: {}\r\nTo: {}\r\nSubject: {}\r\n\r\n".format(
|
||
|
smtp_from, env['EMAIL_RCP'], subject)
|
||
|
msg = msg + Report('week').render_text()
|
||
|
server = smtplib.SMTP_SSL('smtp.mailgun.org')
|
||
|
server.login(env['SMTP_USER'], env['SMTP_PWD'])
|
||
|
server.sendmail(smtp_from, env['EMAIL_RCP'], msg)
|