Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """ | 5 """ |
| 6 Utilities for requesting information for a gerrit server via https. | 6 Utilities for requesting information for a gerrit server via https. |
| 7 | 7 |
| 8 https://gerrit-review.googlesource.com/Documentation/rest-api.html | 8 https://gerrit-review.googlesource.com/Documentation/rest-api.html |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import base64 | 11 import base64 |
| 12 import httplib | 12 import httplib |
| 13 import json | 13 import json |
| 14 import logging | 14 import logging |
| 15 import netrc | 15 import netrc |
| 16 import os | 16 import os |
| 17 import re | |
| 17 import time | 18 import time |
| 18 import urllib | 19 import urllib |
| 19 from cStringIO import StringIO | 20 from cStringIO import StringIO |
| 20 | 21 |
| 21 try: | 22 try: |
| 22 NETRC = netrc.netrc() | 23 NETRC = netrc.netrc() |
| 23 except (IOError, netrc.NetrcParseError): | 24 except (IOError, netrc.NetrcParseError): |
| 24 NETRC = netrc.netrc(os.devnull) | 25 NETRC = netrc.netrc(os.devnull) |
| 25 LOGGER = logging.getLogger() | 26 LOGGER = logging.getLogger() |
| 26 TRY_LIMIT = 5 | 27 TRY_LIMIT = 5 |
| 27 | 28 |
| 28 # Controls the transport protocol used to communicate with gerrit. | 29 # Controls the transport protocol used to communicate with gerrit. |
| 29 # This is parameterized primarily to enable GerritTestCase. | 30 # This is parameterized primarily to enable GerritTestCase. |
| 30 GERRIT_PROTOCOL = 'https' | 31 GERRIT_PROTOCOL = 'https' |
| 31 | 32 |
| 32 | 33 |
| 33 class GerritError(Exception): | 34 class GerritError(Exception): |
| 34 """Exception class for errors commuicating with the gerrit-on-borg service.""" | 35 """Exception class for errors commuicating with the gerrit-on-borg service.""" |
| 35 def __init__(self, http_status, *args, **kwargs): | 36 def __init__(self, http_status, *args, **kwargs): |
| 36 super(GerritError, self).__init__(*args, **kwargs) | 37 super(GerritError, self).__init__(*args, **kwargs) |
| 37 self.http_status = http_status | 38 self.http_status = http_status |
| 38 self.message = '(%d) %s' % (self.http_status, self.message) | 39 self.message = '(%d) %s' % (self.http_status, self.message) |
| 39 | 40 |
| 40 | 41 |
| 42 class GerritAuthenticationError(GerritError): | |
| 43 """Exception class for authentication errors during Gerrit communication.""" | |
| 44 | |
| 45 | |
| 41 def _QueryString(param_dict, first_param=None): | 46 def _QueryString(param_dict, first_param=None): |
| 42 """Encodes query parameters in the key:val[+key:val...] format specified here: | 47 """Encodes query parameters in the key:val[+key:val...] format specified here: |
| 43 | 48 |
| 44 https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#lis t-changes | 49 https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#lis t-changes |
| 45 """ | 50 """ |
| 46 q = [urllib.quote(first_param)] if first_param else [] | 51 q = [urllib.quote(first_param)] if first_param else [] |
| 47 q.extend(['%s:%s' % (key, val) for key, val in param_dict.iteritems()]) | 52 q.extend(['%s:%s' % (key, val) for key, val in param_dict.iteritems()]) |
| 48 return '+'.join(q) | 53 return '+'.join(q) |
| 49 | 54 |
| 50 | 55 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 req_host = conn.req_host | 138 req_host = conn.req_host |
| 134 req_params = conn.req_params | 139 req_params = conn.req_params |
| 135 conn = GetConnectionClass()(req_host) | 140 conn = GetConnectionClass()(req_host) |
| 136 conn.req_host = req_host | 141 conn.req_host = req_host |
| 137 conn.req_params = req_params | 142 conn.req_params = req_params |
| 138 conn.request(**req_params) | 143 conn.request(**req_params) |
| 139 LOGGER.warn(msg) | 144 LOGGER.warn(msg) |
| 140 if ignore_404 and response.status == 404: | 145 if ignore_404 and response.status == 404: |
| 141 return StringIO() | 146 return StringIO() |
| 142 if response.status != expect_status: | 147 if response.status != expect_status: |
| 148 # Check if this is an authentication issue. | |
|
szager1
2014/05/12 08:50:35
Check this in the retry loop. No sense in trying
nodir
2014/05/12 18:11:21
Indeed. Done.
| |
| 149 www_authenticate = response.getheader('www-authenticate') | |
| 150 if (response.status in (httplib.UNAUTHORIZED, httplib.FOUND) and | |
| 151 www_authenticate): | |
| 152 auth_match = re.search('realm="([^"]+)"', www_authenticate, re.I) | |
| 153 host = auth_match.group(1) if auth_match else req_host | |
| 154 reason = ('Authentication failed. Please make sure your .netrc file ' | |
| 155 'has credentials for %s' % host) | |
| 156 raise GerritAuthenticationError(response.status, reason) | |
| 157 | |
| 143 reason = '%s: %s' % (response.reason, response.read()) | 158 reason = '%s: %s' % (response.reason, response.read()) |
| 144 raise GerritError(response.status, reason) | 159 raise GerritError(response.status, reason) |
| 145 return StringIO(response.read()) | 160 return StringIO(response.read()) |
| 146 | 161 |
| 147 | 162 |
| 148 def ReadHttpJsonResponse(conn, expect_status=200, ignore_404=True): | 163 def ReadHttpJsonResponse(conn, expect_status=200, ignore_404=True): |
| 149 """Parses an https response as json.""" | 164 """Parses an https response as json.""" |
| 150 fh = ReadHttpResponse( | 165 fh = ReadHttpResponse( |
| 151 conn, expect_status=expect_status, ignore_404=ignore_404) | 166 conn, expect_status=expect_status, ignore_404=ignore_404) |
| 152 # The first line of the response should always be: )]}' | 167 # The first line of the response should always be: )]}' |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 430 username = review.get('email', jmsg.get('name', '')) | 445 username = review.get('email', jmsg.get('name', '')) |
| 431 raise GerritError(200, 'Unable to set %s label for user "%s"' | 446 raise GerritError(200, 'Unable to set %s label for user "%s"' |
| 432 ' on change %s.' % (label, username, change)) | 447 ' on change %s.' % (label, username, change)) |
| 433 jmsg = GetChangeCurrentRevision(host, change) | 448 jmsg = GetChangeCurrentRevision(host, change) |
| 434 if not jmsg: | 449 if not jmsg: |
| 435 raise GerritError( | 450 raise GerritError( |
| 436 200, 'Could not get review information for change "%s"' % change) | 451 200, 'Could not get review information for change "%s"' % change) |
| 437 elif jmsg[0]['current_revision'] != revision: | 452 elif jmsg[0]['current_revision'] != revision: |
| 438 raise GerritError(200, 'While resetting labels on change "%s", ' | 453 raise GerritError(200, 'While resetting labels on change "%s", ' |
| 439 'a new patchset was uploaded.' % change) | 454 'a new patchset was uploaded.' % change) |
| OLD | NEW |