d4f0a0e2bc
Note that all files were moved to a new directory. The diffs won't be 100% friendly because of this. Extracted common handling for OAuth on both sides of the connection in order to add a new build status data handler. This data handler will be used to report build status data. Don't look too closely at the details of what data is transferred as this will change in the next patch. We will also extract data from a different page in a slightly different way, but there won't be huge differences. In particular, we won't look at the /one_box_per_builder page on the master but rather at the transposed grid (/tgrid) on the build master since we also need the revision number. The regular expressions to extract the data will be slightly more complex. BUG= TEST= Review URL: https://webrtc-codereview.appspot.com/367023 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1586 4adac7df-926f-26a2-2b94-8c16560cd09d
138 lines
5.1 KiB
Python
138 lines
5.1 KiB
Python
#!/usr/bin/env python
|
|
#-*- coding: utf-8 -*-
|
|
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
#
|
|
# Use of this source code is governed by a BSD-style license
|
|
# that can be found in the LICENSE file in the root of the source
|
|
# tree. An additional intellectual property rights grant can be found
|
|
# in the file PATENTS. All contributing project authors may
|
|
# be found in the AUTHORS file in the root of the source tree.
|
|
|
|
"""Contains utilities for communicating with the dashboard."""
|
|
|
|
__author__ = 'phoglund@webrtc.org (Patrik Höglund)'
|
|
|
|
import httplib
|
|
import shelve
|
|
import oauth.oauth as oauth
|
|
|
|
import constants
|
|
|
|
|
|
class FailedToReadRequiredInputFile(Exception):
|
|
pass
|
|
|
|
|
|
class FailedToReportToDashboard(Exception):
|
|
pass
|
|
|
|
|
|
class DashboardConnection:
|
|
"""Helper class for pushing data to the dashboard.
|
|
|
|
This class deals with most of details for accessing protected resources
|
|
(i.e. data-writing operations) on the dashboard. Such operations are
|
|
authenticated using OAuth. This class requires a consumer secret and a
|
|
access token.
|
|
|
|
The consumer secret is created manually on the machine running the script
|
|
(only authorized users should be able to log into the machine and see the
|
|
secret though). The access token is generated by the
|
|
request_oauth_permission.py script. Both these values are stored as files
|
|
on disk, in the scripts' working directory, according to the formats
|
|
prescribed in the read_required_files method.
|
|
"""
|
|
|
|
def __init__(self, consumer_key):
|
|
self.consumer_key_ = consumer_key
|
|
|
|
def read_required_files(self, consumer_secret_file, access_token_file):
|
|
"""Reads required data for making OAuth requests.
|
|
|
|
Args:
|
|
consumer_secret_file: A plain text file with a single line containing
|
|
the consumer secret string.
|
|
access_token_file: A shelve file with an entry access_token
|
|
containing the access token in string form.
|
|
"""
|
|
self.access_token_ = self._read_access_token(access_token_file)
|
|
self.consumer_secret_ = self._read_consumer_secret(consumer_secret_file)
|
|
|
|
def send_post_request(self, sub_url, parameters):
|
|
"""Sends an OAuth request for a protected resource in the dashboard.
|
|
|
|
Use this when you want to report new data to the dashboard. You must have
|
|
called the read_required_files method prior to calling this method, since
|
|
that method will read in the consumer secret and access token we need to
|
|
make the OAuth request. These concepts are described in the class
|
|
description.
|
|
|
|
Args:
|
|
sub_url: A relative url within the dashboard domain, for example
|
|
/add_coverage_data.
|
|
parameters: A dict which maps from POST parameter names to values.
|
|
|
|
Returns:
|
|
A httplib response object.
|
|
|
|
Raises:
|
|
FailedToReportToDashboard: If the dashboard didn't respond
|
|
with HTTP 200 to our request.
|
|
"""
|
|
consumer = oauth.OAuthConsumer(self.consumer_key_, self.consumer_secret_)
|
|
create_oauth_request = oauth.OAuthRequest.from_consumer_and_token
|
|
oauth_request = create_oauth_request(consumer,
|
|
token=self.access_token_,
|
|
http_method='POST',
|
|
http_url=sub_url,
|
|
parameters=parameters)
|
|
|
|
signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
|
|
oauth_request.sign_request(signature_method_hmac_sha1, consumer,
|
|
self.access_token_)
|
|
|
|
connection = httplib.HTTPConnection(constants.DASHBOARD_SERVER)
|
|
|
|
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
|
|
connection.request('POST', sub_url, body=oauth_request.to_postdata(),
|
|
headers=headers)
|
|
|
|
response = connection.getresponse()
|
|
connection.close()
|
|
|
|
if response.status != 200:
|
|
message = ('Error: Failed to report to %s%s: got response %d (%s)' %
|
|
(constants.DASHBOARD_SERVER, sub_url, response.status,
|
|
response.reason))
|
|
raise FailedToReportToDashboard(message)
|
|
|
|
return response
|
|
|
|
def _read_access_token(self, filename):
|
|
input_file = shelve.open(filename)
|
|
|
|
if not input_file.has_key('access_token'):
|
|
raise FailedToReadRequiredInputFile('Missing correct %s file in current '
|
|
'directory. You may have to run '
|
|
'request_oauth_permission.py.' %
|
|
filename)
|
|
|
|
token = input_file['access_token']
|
|
input_file.close()
|
|
|
|
return oauth.OAuthToken.from_string(token)
|
|
|
|
def _read_consumer_secret(self, filename):
|
|
try:
|
|
input_file = open(filename, 'r')
|
|
except IOError as error:
|
|
raise FailedToReadRequiredInputFile(error)
|
|
|
|
whole_file = input_file.read()
|
|
if whole_file.count('\n') > 1 or not whole_file.strip():
|
|
raise FailedToReadRequiredInputFile('Expected a single line with the '
|
|
'consumer secret in file %s.' %
|
|
filename)
|
|
return whole_file
|
|
|