10 # shell path -> account class association
12 # account type -> account class association
15 def register_class(acct_class):
16 """Call once for each account class. This method adds the class to the dictionaries used to ook up account classes by shell and type."""
17 shell_acct_class[acct_class.SHELL] = acct_class
18 type_acct_class[acct_class.TYPE] = acct_class
21 # private account name -> worker object association and associated lock
22 _name_worker_lock = threading.Lock()
26 """Returns a list of all NM accounts on the system. Format is (type, username)."""
27 pw_ents = pwd.getpwall()
28 for pw_ent in pw_ents:
29 if pw_ent[6] in shell_acct_class:
30 yield shell_acct_class[pw_ent[6]].TYPE, pw_ent[0]
33 """Return the worker object for a particular username. If no such object exists, create it first."""
34 _name_worker_lock.acquire()
36 if name not in _name_worker: _name_worker[name] = Worker(name)
37 return _name_worker[name]
38 finally: _name_worker_lock.release()
41 def install_ssh_keys(rec):
42 """Write <rec['ssh_keys']> to <rec['name']>'s authorized_keys file."""
43 dot_ssh = '/home/%s/.ssh' % rec['name']
44 def do_installation():
45 if not os.access(dot_ssh, os.F_OK): os.mkdir(dot_ssh)
46 tools.write_file(dot_ssh + '/authorized_keys',
47 lambda thefile: thefile.write(rec['ssh_keys']))
48 logger.log('%s: installing ssh keys' % rec['name'])
49 tools.fork_as(rec['name'], do_installation)
53 # these semaphores are acquired before creating/destroying an account
54 _create_sem = threading.Semaphore(1)
55 _destroy_sem = threading.Semaphore(1)
57 def __init__(self, name):
60 # the account object currently associated with this worker
63 # outsiders request operations by putting (fn, args...) tuples on _q
64 # the worker thread (created below) will perform these operations in order
65 self._q = Queue.Queue()
66 tools.as_daemon_thread(self._run)
68 def ensure_created(self, rec):
69 """Caused the account specified by <rec> to exist if it doesn't already."""
70 self._q.put((self._ensure_created, tools.deepcopy(rec)))
72 def _ensure_created(self, rec):
73 curr_class = self._get_class()
74 next_class = type_acct_class[rec['account_type']]
75 if next_class != curr_class:
76 self._destroy(curr_class)
77 self._create_sem.acquire()
78 try: next_class.create(self.name)
79 finally: self._create_sem.release()
81 self._acct.configure(rec)
82 if next_class != curr_class: self._acct.start()
84 def ensure_destroyed(self): self._q.put((self._ensure_destroyed,))
85 def _ensure_destroyed(self): self._destroy(self._get_class())
87 def start(self): self._q.put((self._start,))
92 def stop(self): self._q.put((self._stop,))
97 def _destroy(self, curr_class):
100 self._destroy_sem.acquire()
101 try: curr_class.destroy(self.name)
102 finally: self._destroy_sem.release()
104 def _get_class(self):
105 try: shell = pwd.getpwnam(self.name)[6]
106 except KeyError: return None
107 return shell_acct_class[shell]
109 def _make_acct_obj(self):
110 curr_class = self._get_class()
111 if not isinstance(self._acct, curr_class):
112 self._acct = curr_class(self.name)
119 except: logger.log_exc()