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

Side by Side Diff: client/third_party/infra_libs/httplib2_utils.py

Issue 2708113002: Revert of Add field_specs to all metrics in luci-py (Closed)
Patch Set: Created 3 years, 10 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
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium 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 import base64
6 import collections 5 import collections
7 import copy 6 import copy
8 import json 7 import json
9 import logging 8 import logging
10 import os 9 import os
11 import re 10 import re
12 import socket 11 import socket
13 import sys 12 import sys
14 import time 13 import time
15 14
16 import httplib2 15 import httplib2
17 import oauth2client.client 16 import oauth2client.client
18 17
19 from googleapiclient import errors 18 from googleapiclient import errors
20 from infra_libs.ts_mon.common import http_metrics 19 from infra_libs.ts_mon.common import http_metrics
21 from oauth2client import util
22 20
23 DEFAULT_SCOPES = ['email'] 21 DEFAULT_SCOPES = ['email']
24 22
25 # default timeout for http requests, in seconds 23 # default timeout for http requests, in seconds
26 DEFAULT_TIMEOUT = 30 24 DEFAULT_TIMEOUT = 30
27 25
28 # This is part of the API. 26 # This is part of the API.
29 if sys.platform.startswith('win'): # pragma: no cover 27 if sys.platform.startswith('win'): # pragma: no cover
30 SERVICE_ACCOUNTS_CREDS_ROOT = 'C:\\creds\\service_accounts' 28 SERVICE_ACCOUNTS_CREDS_ROOT = 'C:\\creds\\service_accounts'
31 else: 29 else:
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 credentials_filename, 155 credentials_filename,
158 scope=scope, 156 scope=scope,
159 service_accounts_creds_root=service_accounts_creds_root) 157 service_accounts_creds_root=service_accounts_creds_root)
160 158
161 if http_identifier: 159 if http_identifier:
162 http = InstrumentedHttp(http_identifier, timeout=timeout) 160 http = InstrumentedHttp(http_identifier, timeout=timeout)
163 else: 161 else:
164 http = httplib2.Http(timeout=timeout) 162 http = httplib2.Http(timeout=timeout)
165 return creds.authorize(http) 163 return creds.authorize(http)
166 164
167
168 class DelegateServiceAccountCredentials(
169 oauth2client.client.AssertionCredentials):
170 """Authorizes an HTTP client with a service account for which we are an actor.
171
172 This class uses the IAM API to sign a JWT with the private key of another
173 service account for which we have the "Service Account Actor" role.
174 """
175
176 MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
177 _SIGN_BLOB_URL = 'https://iam.googleapis.com/v1/%s:signBlob'
178
179 def __init__(self, http, service_account_email, scopes, project='-'):
180 """
181 Args:
182 http: An httplib2.Http object that is authorized by another
183 oauth2client.client.OAuth2Credentials with credentials that have the
184 service account actor role on the service_account_email.
185 service_account_email: The email address of the service account for which
186 to obtain an access token.
187 scopes: The desired scopes for the token.
188 project: The cloud project to which service_account_email belongs. The
189 default of '-' makes the IAM API figure it out for us.
190 """
191
192 super(DelegateServiceAccountCredentials, self).__init__(None)
193 self._service_account_email = service_account_email
194 self._scopes = util.scopes_to_string(scopes)
195 self._http = http
196 self._name = 'projects/%s/serviceAccounts/%s' % (
197 project, service_account_email)
198
199 def sign_blob(self, blob):
200 response, content = self._http.request(
201 self._SIGN_BLOB_URL % self._name,
202 method='POST',
203 body=json.dumps({'bytesToSign': base64.b64encode(blob)}),
204 headers={'Content-Type': 'application/json'})
205 if response.status != 200:
206 raise AuthError('Failed to sign blob as %s: %d %s' % (
207 self._service_account_email, response.status, response.reason))
208
209 data = json.loads(content)
210 return data['keyId'], data['signature']
211
212 def _generate_assertion(self):
213 # This is copied with small modifications from
214 # oauth2client.service_account._ServiceAccountCredentials.
215
216 header = {
217 'alg': 'RS256',
218 'typ': 'JWT',
219 }
220
221 now = int(time.time())
222 payload = {
223 'aud': self.token_uri,
224 'scope': self._scopes,
225 'iat': now,
226 'exp': now + self.MAX_TOKEN_LIFETIME_SECS,
227 'iss': self._service_account_email,
228 }
229
230 assertion_input = (
231 self._urlsafe_b64encode(header) + b'.' +
232 self._urlsafe_b64encode(payload))
233
234 # Sign the assertion.
235 _, rsa_bytes = self.sign_blob(assertion_input)
236 signature = rsa_bytes.rstrip(b'=')
237
238 return assertion_input + b'.' + signature
239
240 def _urlsafe_b64encode(self, data):
241 # Copied verbatim from oauth2client.service_account.
242 return base64.urlsafe_b64encode(
243 json.dumps(data, separators=(',', ':')).encode('UTF-8')).rstrip(b'=')
244
245
246 class RetriableHttp(object): 165 class RetriableHttp(object):
247 """A httplib2.Http object that retries on failure.""" 166 """A httplib2.Http object that retries on failure."""
248 167
249 def __init__(self, http, max_tries=5, backoff_time=1, 168 def __init__(self, http, max_tries=5, backoff_time=1,
250 retrying_statuses_fn=None): 169 retrying_statuses_fn=None):
251 """ 170 """
252 Args: 171 Args:
253 http: an httplib2.Http instance 172 http: an httplib2.Http instance
254 max_tries: a number of maximum tries 173 max_tries: a number of maximum tries
255 backoff_time: a number of seconds to sleep between retries 174 backoff_time: a number of seconds to sleep between retries
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 def __getattr__(self, name): 209 def __getattr__(self, name):
291 return getattr(self._http, name) 210 return getattr(self._http, name)
292 211
293 def __setattr__(self, name, value): 212 def __setattr__(self, name, value):
294 if name in ('request', '_http', '_max_tries', '_backoff_time', 213 if name in ('request', '_http', '_max_tries', '_backoff_time',
295 '_retrying_statuses_fn'): 214 '_retrying_statuses_fn'):
296 self.__dict__[name] = value 215 self.__dict__[name] = value
297 else: 216 else:
298 setattr(self._http, name, value) 217 setattr(self._http, name, value)
299 218
300
301 class InstrumentedHttp(httplib2.Http): 219 class InstrumentedHttp(httplib2.Http):
302 """A httplib2.Http object that reports ts_mon metrics about its requests.""" 220 """A httplib2.Http object that reports ts_mon metrics about its requests."""
303 221
304 def __init__(self, name, time_fn=time.time, timeout=DEFAULT_TIMEOUT, 222 def __init__(self, name, time_fn=time.time, timeout=DEFAULT_TIMEOUT,
305 **kwargs): 223 **kwargs):
306 """ 224 """
307 Args: 225 Args:
308 name: An identifier for the HTTP requests made by this object. 226 name: An identifier for the HTTP requests made by this object.
309 time_fn: Function returning the current time in seconds. Use for testing 227 time_fn: Function returning the current time in seconds. Use for testing
310 purposes only. 228 purposes only.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 self.requests_made.append(self.HttpCall(uri, method, body, headers)) 311 self.requests_made.append(self.HttpCall(uri, method, body, headers))
394 headers = None 312 headers = None
395 body = None 313 body = None
396 for candidate in self._uris: 314 for candidate in self._uris:
397 if candidate[0].match(uri): 315 if candidate[0].match(uri):
398 _, headers, body = candidate 316 _, headers, body = candidate
399 break 317 break
400 if not headers: 318 if not headers:
401 raise AssertionError("Unexpected request to %s" % uri) 319 raise AssertionError("Unexpected request to %s" % uri)
402 return httplib2.Response(headers), body 320 return httplib2.Response(headers), body
OLDNEW
« no previous file with comments | « client/third_party/infra_libs/event_mon/protos/goma_stats_pb2.py ('k') | client/third_party/infra_libs/logs/logs.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698