X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=accounts.py;h=df339770d41d1a23266bbf0a35dbc8949ae57b58;hb=05f19f00117ab12afcba505f969799ee544f750b;hp=6bffdbe8ae725061ee626f7cf08245b96910052f;hpb=abe5b6479e9964d43166d731a04beac83c9d34c5;p=nodemanager.git diff --git a/accounts.py b/accounts.py index 6bffdbe..df33977 100644 --- a/accounts.py +++ b/accounts.py @@ -10,12 +10,20 @@ code. For no particular reason, TYPE is divided hierarchically by periods; at the moment the only convention is that all sliver accounts have type that begins with sliver. +There are any number of race conditions that may result from the fact +that account names are not unique over time. Moreover, it's a bad +idea to perform lengthy operations while holding the database lock. +In order to deal with both of these problems, we use a worker thread +for each account name that ever exists. On 32-bit systems with large +numbers of accounts, this may cause the NM process to run out of +*virtual* memory! This problem may be remedied by decreasing the +maximum stack size. """ import Queue import os import pwd -from grp import getgrnam +import grp import threading import logger @@ -41,7 +49,6 @@ def register_class(acct_class): # private account name -> worker object association and associated lock name_worker_lock = threading.Lock() -# dict of account_name: name_worker = {} def allpwents(): @@ -55,9 +62,7 @@ def get(name): """Return the worker object for a particular username. If no such object exists, create it first.""" name_worker_lock.acquire() try: - if name not in name_worker: - logger.verbose("Accounts:get(%s) new Worker" % name) - name_worker[name] = Worker(name) + if name not in name_worker: name_worker[name] = Worker(name) return name_worker[name] finally: name_worker_lock.release() @@ -80,16 +85,35 @@ class Account: logger.verbose('%s: in accounts:configure'%self.name) new_keys = rec['keys'] if new_keys != self.keys: - self.keys = new_keys - dot_ssh = '/home/%s/.ssh' % self.name - if not os.access(dot_ssh, os.F_OK): os.mkdir(dot_ssh) + # get the unix account info + gid = grp.getgrnam("slices")[2] + pw_info = pwd.getpwnam(self.name) + uid = pw_info[2] + pw_dir = pw_info[5] + + # write out authorized_keys file and conditionally create + # the .ssh subdir if need be. + dot_ssh = os.path.join(pw_dir,'.ssh') + if not os.path.isdir(dot_ssh): + if not os.path.isdir(pw_dir): + logger.verbose('WARNING: homedir %s does not exist for %s!'%(pw_dir,self.name)) + os.mkdir(pw_dir) + os.chown(pw_dir, uid, gid) + os.mkdir(dot_ssh) + + auth_keys = os.path.join(dot_ssh,'authorized_keys') + tools.write_file(auth_keys, lambda f: f.write(new_keys)) + + # set access permissions and ownership properly os.chmod(dot_ssh, 0700) - tools.write_file(dot_ssh + '/authorized_keys', lambda f: f.write(new_keys)) - logger.log('%s: installing ssh keys' % self.name) - user = pwd.getpwnam(self.name)[2] - group = getgrnam("slices")[2] - os.chown(dot_ssh, user, group) - os.chown(dot_ssh + '/authorized_keys', user, group) + os.chown(dot_ssh, uid, gid) + os.chmod(auth_keys, 0600) + os.chown(auth_keys, uid, gid) + + # set self.keys to new_keys only when all of the above ops succeed + self.keys = new_keys + + logger.log('%s: installed ssh keys' % self.name) def start(self, delay=0): pass def stop(self): pass @@ -127,7 +151,7 @@ class Worker: def stop(self): self._acct.stop() def is_running(self): - if self._acct.is_running(): + if (self._acct != None) and self._acct.is_running(): status = True else: status = False