2
# This file is part of Checkbox.
4
# Copyright 2013 Canonical Ltd.
6
# Checkbox is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
11
# Checkbox is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
26
from gettext import gettext as _
27
from http.client import HTTPException
28
from string import printable
30
from checkbox.lib.log import format_delta
31
from checkbox.lib.transport import HTTPTransport
32
from checkbox.plugin import Plugin
33
from checkbox.properties import Bool, Int, String
36
class HexrTransport(Plugin):
37
""" This provides means for submitting test reports to hexr.canonical.com
38
and/or certification.canonical.com
41
# URL where to send submissions.
42
transport_url = String(default="https://hexr.canonical.com/checkbox/submit/")
44
# Timeout value for each submission.
45
timeout = Int(default=360)
47
# Timeout value for each submission.
48
max_tries = Int(default=5)
50
# Header to identify the hardware ID.
51
hardware_id_header = String(default="X_HARDWARE_ID")
52
submit_to_hexr_header = String(default="X_SHARE_WITH_HEXR")
54
html_link = Bool(default=True)
56
def register(self, manager):
57
super(HexrTransport, self).register(manager)
60
self._submission_filename = ""
62
#I need to have two things in order to send the report:
63
# - Filename of xml report (I get it on launchpad-report event)
64
# - Hardware secure ID (I get it on report-hardware-id event)
66
# Fire after the report has been generated.
67
self._manager.reactor.call_on("launchpad-report",
68
self._on_get_filename)
70
#This is just to get the secure_id when the report-hardware-id event
72
self._manager.reactor.call_on("report-hardware-id",
73
self._on_report_hardware_id)
74
self._manager.reactor.call_on("report-submit-to-hexr",
75
self._on_report_submit_to_hexr)
76
self._manager.reactor.call_on("hexr-exchange",
77
self._on_hexr_exchange)
79
def _on_report_hardware_id(self, hardware_id):
80
self._headers[self.hardware_id_header] = hardware_id
82
def _on_report_submit_to_hexr(self, submitToHexr):
84
self._headers[self.submit_to_hexr_header] = 'True'
86
self._headers[self.submit_to_hexr_header] = 'False'
88
def _on_get_filename(self, filename):
89
self._submission_filename = filename
91
def _on_hexr_exchange(self, interface):
92
#Ensure I have needed data!
93
if not self._headers and not self._submission_filename:
94
logging.debug("Not ready to submit to new cert website,"
95
"information missing")
99
submission_file = open(self._submission_filename, "rb")
100
body = [("data", submission_file)]
101
except (IOError, OSError, socket.error, HTTPException) as error:
103
self._manager.reactor.fire("exchange-error", error)
106
#Pathetic attempt at slightly more robustness by retrying a few times
107
#in case transmitting the submission fails due to network transient
110
for attempt in range(self.max_tries):
111
(result, details) = self.submit_results(self.transport_url,
118
link = "<a href='%s'>%s</a>" % (details, details)
119
self._manager.reactor.fire("report-final-text", "Submission link: " + link)
122
if attempt + 1 >= self.max_tries:
123
retries_string = "I won't try again, sorry."
125
retries_string = "I will retry (try %d of %d)" % \
126
(attempt + 1, self.max_tries)
128
self._manager.reactor.fire("exchange-error",
129
" ".join([details, retries_string]))
130
#File needs to be closed :)
131
submission_file.close()
134
def submit_results(self, transport_url, body, headers, timeout):
135
transport = HTTPTransport(transport_url)
136
start_time = time.time()
137
submission_stat = os.fstat(body[0][1].fileno())
138
submission_size = submission_stat.st_size
141
response = transport.exchange(body, headers, timeout)
142
except (IOError, OSError) as error:
144
return (False, error)
146
end_time = time.time()
148
error = "Error contacting the server: %s." % transport_url
150
return (False, error)
151
elif response.status != 200:
152
error = "Server returned unexpected status: %d. " % \
155
return (False, error)
157
#This is the only success block
158
text = response.read().decode()
159
status_url = json.loads(text)['url']
160
if logging.getLogger().getEffectiveLevel() <= logging.DEBUG:
161
logging.debug("Response headers:\n%s",
162
pprint.pformat(response.getheaders()))
163
logging.debug("Response content:\n%s",
164
pprint.pformat(text))
165
logging.info("Sent %d bytes and received %d bytes in %s.",
166
submission_size, len(text),
167
format_delta(end_time - start_time))
168
return (True, status_url)
171
factory = HexrTransport