Merge lp:~joetalbott/utah/dashboard_integration into lp:utah

Proposed by Joe Talbott
Status: Rejected
Rejected by: Joe Talbott
Proposed branch: lp:~joetalbott/utah/dashboard_integration
Merge into: lp:utah
Diff against target: 186 lines (+155/-2)
2 files modified
utah/client/common.py (+4/-2)
utah/publish.py (+151/-0)
To merge this branch: bzr merge lp:~joetalbott/utah/dashboard_integration
Reviewer Review Type Date Requested Status
Max Brustkern (community) Needs Information
Review via email: mp+133365@code.launchpad.net

Description of the change

Add publish capabilities.

This includes the ability to manually process a results file from the utah client.

To post a comment you must log in.
Revision history for this message
Joe Talbott (joetalbott) wrote :

Bump

Revision history for this message
Max Brustkern (nuclearbob) wrote :

The only thing I'm not sure about is the import from client. Most of the other places in the code that reference things in utah refer to them as utah.whatever, but if the current setup works, then it looks good to me.

review: Needs Information
Revision history for this message
Joe Talbott (joetalbott) wrote :

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'utah/client/common.py'
2--- utah/client/common.py 2012-11-07 18:00:47 +0000
3+++ utah/client/common.py 2012-11-07 22:17:22 +0000
4@@ -54,6 +54,8 @@
5 CMD_TS_SETUP = 'testsuite_setup'
6 CMD_TS_CLEANUP = 'testsuite_cleanup'
7
8+DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
9+
10
11 def do_nothing(_obj=None):
12 """
13@@ -114,7 +116,7 @@
14
15 return make_result(command=command,
16 retcode=ERROR_TIMEOUT,
17- start_time=str(start_time),
18+ start_time=start_time.strftime(DATE_FORMAT),
19 time_delta=str(time_delta),
20 cmd_type=cmd_type,
21 user=run_as,
22@@ -126,7 +128,7 @@
23 retcode=p.returncode,
24 stdout=stdout,
25 stderr=stderr,
26- start_time=str(start_time),
27+ start_time=start_time.strftime(DATE_FORMAT),
28 time_delta=str(time_delta),
29 cmd_type=cmd_type,
30 user=run_as,
31
32=== added file 'utah/publish.py'
33--- utah/publish.py 1970-01-01 00:00:00 +0000
34+++ utah/publish.py 2012-11-07 22:17:22 +0000
35@@ -0,0 +1,151 @@
36+import argparse
37+import datetime
38+import jsonschema
39+import os
40+import urllib
41+import urllib2
42+import yaml
43+from client import exceptions
44+
45+
46+DATE_FORMAT = "%Y-%m-%d %H:%M"
47+
48+COMMAND_SCHEMA = {
49+ 'type': 'object',
50+ 'properties': {
51+ 'cmd_type': {'type': 'string'},
52+ 'command': {'type': 'string'},
53+ 'returncode': {'type': 'integer'},
54+ 'start_time': {'type': 'string'},
55+ 'stderr': {'type': 'string'},
56+ 'stdout': {'type': 'string'},
57+ 'testcase': {'type': 'string'},
58+ 'testsuite': {'type': 'string'},
59+ 'time_delta': {'type': 'string'},
60+ 'user': {'type': 'string'},
61+ },
62+}
63+
64+CLIENT_OUTPUT_SCHEMA = {
65+ 'type': 'object',
66+ 'properties': {
67+ 'runlist': {
68+ 'type': 'string',
69+ 'required': True,
70+ },
71+ 'commands': {
72+ 'type': 'array',
73+ 'items': {'type': COMMAND_SCHEMA},
74+ 'required': True,
75+ },
76+ 'fetch_errors': {
77+ 'type': 'integer',
78+ 'required': True,
79+ },
80+ 'errors': {
81+ 'type': 'integer',
82+ 'required': True,
83+ },
84+ 'failures': {
85+ 'type': 'integer',
86+ 'required': True,
87+ },
88+ 'passes': {
89+ 'type': 'integer',
90+ 'required': True,
91+ },
92+ 'uname': {
93+ 'type': 'array',
94+ 'items': {'type': 'string'},
95+ 'required': True,
96+ },
97+ 'media-info': {
98+ 'type': 'string',
99+ 'required': True,
100+ },
101+ 'install_type': {
102+ 'type': 'string',
103+ 'required': True,
104+ },
105+ },
106+}
107+
108+
109+def _parse_logfile(logfile):
110+ """ Parse client output log for publishing. """
111+
112+ data = None
113+
114+ if not os.access(logfile, os.R_OK):
115+ return data
116+
117+ with open(logfile, 'r') as fp:
118+ data = yaml.load(fp)
119+
120+ try:
121+ jsonschema.validate(data, CLIENT_OUTPUT_SCHEMA)
122+ except jsonschema.ValidationError as exception:
123+ raise exceptions.ValidationError(
124+ 'Client results failed to validate: {!r}\n'
125+ 'Detailed information: {}'
126+ .format(logfile, exception))
127+
128+ return data
129+
130+
131+def _publish_results(url, data=None):
132+ """ Publish results to the QA Dashboard. """
133+
134+ if data is None:
135+ return "Not publishing null data"
136+
137+ try:
138+ u = urllib2.urlopen(url, urllib.urlencode(data))
139+
140+ return u.read()
141+ except urllib2.URLError as exception:
142+ return "ERROR: bad url {}: {}".format(url, exception)
143+
144+
145+def publish(logfile, url, token):
146+ """ Publish result from logfile to url using token. """
147+
148+ data = {}
149+
150+ # Defaults
151+ data['flavor'] = 'ubuntu'
152+ data['skip_count'] = 0
153+
154+ log_data = _parse_logfile(logfile)
155+
156+ if log_data is None:
157+ return "Failed to parse logfile: {}".format(logfile)
158+
159+ data['token'] = token
160+ data['fail_count'] = log_data['failures']
161+ data['pass_count'] = log_data['passes']
162+ data['error_count'] = log_data['errors']
163+ data['build_no'] = log_data['build_number']
164+ data['build_name'] = "{}-{}-{}_{}".format(
165+ log_data['release'], log_data['install_type'],
166+ log_data['arch'], log_data['name'])
167+ data['ran_at'] = log_data['ran_at']
168+
169+ return _publish_results(url, data)
170+
171+if __name__ == "__main__":
172+ parser = argparse.ArgumentParser(
173+ description='utah results publisher'
174+ )
175+ parser.add_argument('logfile', metavar='LOGFILE', type=str,
176+ help="utah client results log")
177+ parser.add_argument('url', metavar='URL', type=str,
178+ help="QA Dashboard API URL")
179+ parser.add_argument('token', metavar='API_TOKEN', type=str,
180+ help="QA Dashboard API token")
181+
182+ args = parser.parse_args()
183+
184+ print publish(args.logfile,
185+ url=args.url,
186+ token=args.token)

Subscribers

People subscribed via source and target branches