Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: gerrit_util.py

Issue 278203002: gerrit_util is aware of auth errors (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: moved auth check into the retry loop Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | trychange.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 expect_status: Success is indicated by this status in the response. 113 expect_status: Success is indicated by this status in the response.
109 ignore_404: For many requests, gerrit-on-borg will return 404 if the request 114 ignore_404: For many requests, gerrit-on-borg will return 404 if the request
110 doesn't match the database contents. In most such cases, we 115 doesn't match the database contents. In most such cases, we
111 want the API to return None rather than raise an Exception. 116 want the API to return None rather than raise an Exception.
112 Returns: A string buffer containing the connection's reply. 117 Returns: A string buffer containing the connection's reply.
113 """ 118 """
114 119
115 sleep_time = 0.5 120 sleep_time = 0.5
116 for idx in range(TRY_LIMIT): 121 for idx in range(TRY_LIMIT):
117 response = conn.getresponse() 122 response = conn.getresponse()
123
124 # Check if this is an authentication issue.
125 www_authenticate = response.getheader('www-authenticate')
126 if (response.status in (httplib.UNAUTHORIZED, httplib.FOUND) and
127 www_authenticate):
128 auth_match = re.search('realm="([^"]+)"', www_authenticate, re.I)
129 host = auth_match.group(1) if auth_match else conn.req_host
130 reason = ('Authentication failed. Please make sure your .netrc file '
131 'has credentials for %s' % host)
132 raise GerritAuthenticationError(response.status, reason)
133
118 # If response.status < 500 then the result is final; break retry loop. 134 # If response.status < 500 then the result is final; break retry loop.
119 if response.status < 500: 135 if response.status < 500:
120 break 136 break
121 # A status >=500 is assumed to be a possible transient error; retry. 137 # A status >=500 is assumed to be a possible transient error; retry.
122 http_version = 'HTTP/%s' % ('1.1' if response.version == 11 else '1.0') 138 http_version = 'HTTP/%s' % ('1.1' if response.version == 11 else '1.0')
123 msg = ( 139 msg = (
124 'A transient error occured while querying %s:\n' 140 'A transient error occured while querying %s:\n'
125 '%s %s %s\n' 141 '%s %s %s\n'
126 '%s %d %s' % ( 142 '%s %d %s' % (
127 conn.host, conn.req_params['method'], conn.req_params['url'], 143 conn.host, conn.req_params['method'], conn.req_params['url'],
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 username = review.get('email', jmsg.get('name', '')) 446 username = review.get('email', jmsg.get('name', ''))
431 raise GerritError(200, 'Unable to set %s label for user "%s"' 447 raise GerritError(200, 'Unable to set %s label for user "%s"'
432 ' on change %s.' % (label, username, change)) 448 ' on change %s.' % (label, username, change))
433 jmsg = GetChangeCurrentRevision(host, change) 449 jmsg = GetChangeCurrentRevision(host, change)
434 if not jmsg: 450 if not jmsg:
435 raise GerritError( 451 raise GerritError(
436 200, 'Could not get review information for change "%s"' % change) 452 200, 'Could not get review information for change "%s"' % change)
437 elif jmsg[0]['current_revision'] != revision: 453 elif jmsg[0]['current_revision'] != revision:
438 raise GerritError(200, 'While resetting labels on change "%s", ' 454 raise GerritError(200, 'While resetting labels on change "%s", '
439 'a new patchset was uploaded.' % change) 455 'a new patchset was uploaded.' % change)
OLDNEW
« no previous file with comments | « no previous file | trychange.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698