Revision e4ef4343 daemons/ganeti-rapi
b/daemons/ganeti-rapi | ||
---|---|---|
44 | 44 |
from ganeti import ssconf |
45 | 45 |
from ganeti import luxi |
46 | 46 |
from ganeti import serializer |
47 |
from ganeti import compat |
|
47 | 48 |
from ganeti.rapi import connector |
48 | 49 |
|
49 | 50 |
import ganeti.http.auth # pylint: disable-msg=W0611 |
... | ... | |
88 | 89 |
|
89 | 90 |
def __init__(self, *args, **kwargs): |
90 | 91 |
# pylint: disable-msg=W0233 |
91 |
# it seems pylint doesn't see the second parent class there |
|
92 |
# it seems pylint doesn't see the second parent class there
|
|
92 | 93 |
http.server.HttpServer.__init__(self, *args, **kwargs) |
93 | 94 |
http.auth.HttpServerRequestAuthentication.__init__(self) |
94 | 95 |
self._resmap = connector.Mapper() |
96 |
self._users = None |
|
95 | 97 |
|
96 |
# Load password file |
|
97 |
if os.path.isfile(constants.RAPI_USERS_FILE): |
|
98 |
wm = pyinotify.WatchManager() |
|
99 |
hdl = asyncnotifier.SingleFileEventHandler(wm, self._OnUsersFileUpdate, |
|
100 |
constants.RAPI_USERS_FILE) |
|
101 |
self._users_inotify_handler = hdl |
|
102 |
asyncnotifier.AsyncNotifier(wm, default_proc_fun=hdl) |
|
103 |
self._users = None |
|
104 |
self._OnUsersFileUpdate(False) |
|
105 |
else: |
|
106 |
self._users = None |
|
107 |
|
|
108 |
def _OnUsersFileUpdate(self, notifier_enabled): |
|
109 |
"""Called upon update of the RAPI users file by pyinotify. |
|
98 |
def LoadUsers(self, filename): |
|
99 |
"""Loads a file containing users and passwords. |
|
110 | 100 |
|
111 |
@type notifier_enabled: boolean
|
|
112 |
@param notifier_enabled: whether the notifier is still enabled
|
|
101 |
@type filename: string
|
|
102 |
@param filename: Path to file
|
|
113 | 103 |
|
114 | 104 |
""" |
115 |
logging.info("Reloading modified %s", constants.RAPI_USERS_FILE) |
|
105 |
if not os.path.isfile(constants.RAPI_USERS_FILE): |
|
106 |
logging.warning("Users file %s not found", filename) |
|
107 |
return False |
|
116 | 108 |
|
117 | 109 |
try: |
118 |
users = http.auth.ReadPasswordFile(constants.RAPI_USERS_FILE) |
|
119 |
self._users = users |
|
110 |
users = http.auth.ReadPasswordFile(filename) |
|
120 | 111 |
except Exception, err: # pylint: disable-msg=W0703 |
121 | 112 |
# We don't care about the type of exception |
122 |
logging.error("Error while reading %s: %s", constants.RAPI_USERS_FILE,
|
|
123 |
err)
|
|
113 |
logging.error("Error while reading %s: %s", filename, err)
|
|
114 |
return False
|
|
124 | 115 |
|
125 |
# Renable the watch again if we'd an atomic update of the file (e.g. mv) |
|
126 |
if not notifier_enabled: |
|
127 |
self._users_inotify_handler.enable() |
|
116 |
self._users = users |
|
117 |
return True |
|
128 | 118 |
|
129 | 119 |
def _GetRequestContext(self, req): |
130 | 120 |
"""Returns the context for a request. |
... | ... | |
236 | 226 |
return serializer.DumpJson(result) |
237 | 227 |
|
238 | 228 |
|
229 |
class FileWatcher: |
|
230 |
def __init__(self, filename, cb): |
|
231 |
"""Initializes this class. |
|
232 |
|
|
233 |
@type filename: string |
|
234 |
@param filename: File to watch |
|
235 |
@type cb: callable |
|
236 |
@param cb: Function called on file change |
|
237 |
|
|
238 |
""" |
|
239 |
self._filename = filename |
|
240 |
self._cb = cb |
|
241 |
|
|
242 |
wm = pyinotify.WatchManager() |
|
243 |
self._handler = asyncnotifier.SingleFileEventHandler(wm, self._OnInotify, |
|
244 |
filename) |
|
245 |
asyncnotifier.AsyncNotifier(wm, default_proc_fun=self._handler) |
|
246 |
self._handler.enable() |
|
247 |
|
|
248 |
def _OnInotify(self, notifier_enabled): |
|
249 |
"""Called upon update of the RAPI users file by pyinotify. |
|
250 |
|
|
251 |
@type notifier_enabled: boolean |
|
252 |
@param notifier_enabled: whether the notifier is still enabled |
|
253 |
|
|
254 |
""" |
|
255 |
logging.info("Reloading modified %s", self._filename) |
|
256 |
|
|
257 |
self._cb() |
|
258 |
|
|
259 |
# Renable the watch again if we'd an atomic update of the file (e.g. mv) |
|
260 |
if not notifier_enabled: |
|
261 |
self._handler.enable() |
|
262 |
|
|
263 |
|
|
239 | 264 |
def CheckRapi(options, args): |
240 | 265 |
"""Initial checks whether to run or exit with a failure. |
241 | 266 |
|
... | ... | |
265 | 290 |
ssl_params=options.ssl_params, |
266 | 291 |
ssl_verify_peer=False, |
267 | 292 |
request_executor_class=JsonErrorRequestExecutor) |
293 |
|
|
294 |
if os.path.exists(constants.RAPI_USERS_FILE): |
|
295 |
# Setup file watcher (it'll be driven by asyncore) |
|
296 |
FileWatcher(constants.RAPI_USERS_FILE, |
|
297 |
compat.partial(server.LoadUsers, constants.RAPI_USERS_FILE)) |
|
298 |
|
|
299 |
server.LoadUsers(constants.RAPI_USERS_FILE) |
|
300 |
|
|
268 | 301 |
# pylint: disable-msg=E1101 |
269 | 302 |
# it seems pylint doesn't see the second parent class there |
270 | 303 |
server.Start() |
Also available in: Unified diff