diff options
Diffstat (limited to 'google-daemon/usr/share/google/google_daemon/accounts_manager.py')
-rw-r--r-- | google-daemon/usr/share/google/google_daemon/accounts_manager.py | 127 |
1 files changed, 0 insertions, 127 deletions
diff --git a/google-daemon/usr/share/google/google_daemon/accounts_manager.py b/google-daemon/usr/share/google/google_daemon/accounts_manager.py deleted file mode 100644 index 5932796..0000000 --- a/google-daemon/usr/share/google/google_daemon/accounts_manager.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2013 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Main driver logic for managing accounts on GCE instances.""" - -import logging -import os -import pwd -import time - -LOCKFILE = '/var/lock/manage-accounts.lock' - - -class AccountsManager(object): - """Create accounts on a machine.""" - - def __init__(self, accounts_module, desired_accounts, system, lock_file, - lock_fname, single_pass=True): - """Construct an AccountsFromMetadata with the given module injections.""" - if not lock_fname: - lock_fname = LOCKFILE - self.accounts = accounts_module - self.desired_accounts = desired_accounts - self.lock_file = lock_file - self.lock_fname = lock_fname - self.system = system - self.single_pass = single_pass - - def Main(self): - logging.debug('AccountsManager main loop') - # If this is a one-shot execution, then this can be run normally. - # Otherwise, run the actual operations in a subprocess so that any - # errors don't kill the long-lived process. - if self.single_pass: - self.RegenerateKeysAndUpdateAccounts() - return - # Run this forever in a loop. - while True: - # Fork and run the key regeneration and account update while the - # parent waits for the subprocess to finish before continuing. - - # Create a pipe used to get the new etag value from child - reader, writer = os.pipe() # these are file descriptors, not file objects - pid = os.fork() - if pid: - # We are the parent. - os.close(writer) - reader = os.fdopen(reader) # turn reader into a file object - etag = reader.read() - if etag: - self.desired_accounts.etag = etag - reader.close() - logging.debug('New etag: %s', self.desired_accounts.etag) - os.waitpid(pid, 0) - else: - # We are the child. - os.close(reader) - writer = os.fdopen(writer, 'w') - try: - self.RegenerateKeysAndUpdateAccounts() - except Exception as e: - logging.warning('error while trying to update accounts: %s', e) - # An error happened while trying to update the accounts. - # Sleep for five seconds before trying again. - time.sleep(5) - - # Write the etag to pass to parent. - etag = self.desired_accounts.etag or '' - writer.write(etag) - writer.close() - - # The use of os._exit here is recommended for subprocesses spawned - # by forking to avoid issues with running the cleanup tasks that - # sys.exit() runs by preventing issues from the cleanup being run - # once by the subprocess and once by the parent process. - os._exit(0) - - def RegenerateKeysAndUpdateAccounts(self): - """Regenerate the keys and update accounts as needed.""" - logging.debug('RegenerateKeysAndUpdateAccounts') - if self.system.IsExecutable('/usr/share/google/first-boot'): - self.system.RunCommand('/usr/share/google/first-boot') - - self.lock_file.RunExclusively(self.lock_fname, self.UpdateAccounts) - - def UpdateAccounts(self): - """Update all accounts that should be present or exist already.""" - - # Note GetDesiredAccounts() returns a dict of username->sshKeys mappings. - desired_accounts = self.desired_accounts.GetDesiredAccounts() - - # Plan a processing pass for extra accounts existing on the system with a - # ~/.ssh/authorized_keys file, even if they're not otherwise in the metadata - # server; this will only ever remove the last added-by-Google key from - # accounts which were formerly in the metadata server but are no longer. - all_accounts = pwd.getpwall() - keyfile_suffix = os.path.join('.ssh', 'authorized_keys') - sshable_usernames = [ - entry.pw_name - for entry in all_accounts - if os.path.isfile(os.path.join(entry.pw_dir, keyfile_suffix))] - extra_usernames = set(sshable_usernames) - set(desired_accounts.keys()) - - if desired_accounts: - for username, ssh_keys in desired_accounts.iteritems(): - if not username: - continue - - self.accounts.UpdateUser(username, ssh_keys) - - for username in extra_usernames: - # If a username is present in extra_usernames, it is no longer reflected - # in the metadata server but has an authorized_keys file. Therefore, we - # should pass the empty list for sshKeys to ensure that any Google-managed - # keys are no longer authorized. - self.accounts.UpdateUser(username, []) |