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

Side by Side Diff: appengine/swarming/swarming_bot/bot_code/remote_client.py

Issue 2024313003: Send authorization headers when calling Swarming backend. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@master
Patch Set: rebase Created 4 years, 6 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
(Empty)
1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file.
4
5 import logging
6 import threading
7 import time
8 import traceback
9
10 from utils import net
11
12
13 # RemoteClient will attempt to refresh the authentication headers once they are
14 # this close to the expiration.
15 AUTH_HEADERS_EXPIRATION_SEC = 6*60
16
17
18 # How long to wait for a response from the server. Must not be greater than
19 # AUTH_HEADERS_EXPIRATION_SEC, since otherwise there's a chance auth headers
20 # will expire while we wait for connection.
21 NET_CONNECTION_TIMEOUT_SEC = 5*60
22
23
24 class InitializationError(Exception):
25 """Raised by RemoteClient.initialize on fatal errors."""
26 def __init__(self, last_error):
27 super(InitializationError, self).__init__('Failed to grab auth headers')
28 self.last_error = last_error
29
30
31 class RemoteClient(object):
32 """RemoteClient knows how to make authenticated calls to the backend.
33
34 It also holds in-memory cache of authentication headers and periodically
35 refreshes them (by calling supplied callback, that usually is implemented in
36 terms of bot_config.get_authentication_headers() function).
37
38 If the callback is None, skips authentication (this is used during initial
39 stages of the bot bootstrap).
40 """
41
42 def __init__(self, server, auth_headers_callback):
43 self._server = server
44 self._auth_headers_callback = auth_headers_callback
45 self._lock = threading.Lock()
46 self._headers = None
47 self._exp_ts = None
48 self._disabled = not auth_headers_callback
49
50 def initialize(self, quit_bit):
51 """Grabs initial auth headers, retrying on errors a bunch of times.
52
53 Raises InitializationError if all attempts fail. Aborts attempts and returns
54 if quit_bit is signaled.
55 """
56 attempts = 30
57 while not quit_bit.is_set():
58 try:
59 self._get_headers_or_throw()
60 return
61 except Exception as e:
62 last_error = '%s\n%s' % (e, traceback.format_exc()[-2048:])
63 logging.exception('Failed to grab initial auth headers')
64 attempts -= 1
65 if not attempts:
66 raise InitializationError(last_error)
67 time.sleep(2)
68
69 @property
70 def uses_auth(self):
71 """Returns True if get_authentication_headers() returns some headers.
72
73 If bot_config.get_authentication_headers() is not implement it will return
74 False.
75 """
76 return bool(self.get_authentication_headers())
77
78 def get_authentication_headers(self):
79 """Returns a dict with the headers, refreshing them if necessary.
80
81 Will always return a dict (perhaps empty if no auth headers are provided by
82 the callback or it has failed).
83 """
84 try:
85 return self._get_headers_or_throw()
86 except Exception:
M-A Ruel 2016/06/03 20:00:49 I wish the kind of exceptions trapped was scoped.
Vadim Sh. 2016/06/03 23:37:55 bot_config.py callback can through whatever it wan
87 logging.exception('Failed to refresh auth headers, using cached ones')
88 return self._headers or {}
89
90 def _get_headers_or_throw(self):
91 if self._disabled:
92 return {}
93 with self._lock:
94 if (self._exp_ts is None or
95 self._exp_ts - time.time() < AUTH_HEADERS_EXPIRATION_SEC):
96 self._headers, self._exp_ts = self._auth_headers_callback()
97 if self._exp_ts is None:
98 logging.info('Not using auth headers')
99 self._disabled = True
100 self._headers = {}
101 else:
102 logging.info(
103 'Refreshed auth headers, they expire in %d sec',
104 self._exp_ts - time.time())
105 return self._headers or {}
106
107 def url_read_json(self, url_path, data=None):
108 """Does POST (if data is not None) or GET request to a JSON endpoint."""
109 return net.url_read_json(
110 self._server + url_path,
111 data=data,
112 headers=self.get_authentication_headers(),
113 timeout=NET_CONNECTION_TIMEOUT_SEC,
114 follow_redirects=False)
115
116 def url_retrieve(self, filepath, url_path):
117 """Fetches the file from the given URL path on the server."""
118 return net.url_retrieve(
119 filepath,
120 self._server + url_path,
121 headers=self.get_authentication_headers(),
122 timeout=NET_CONNECTION_TIMEOUT_SEC)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698