import os import optparse import logging import socket import tempfile import shutil import errno import shell HOST = socket.gethostname() # XXX test server and wizard server ROOT_UID = 0 SIGNUP_UID = 102 SQL_UID = 537704221 FEDORA_DS_UID = 103 # XXX ACTUALLY CONFIGURE SERVERS TO USE THIS LOGVIEW_UID = 501 # XXX Autogenerated, I don't like this... COMMON_CREDS = [ (ROOT_UID, 0o600, 'root/.bashrc'), (ROOT_UID, 0o600, 'root/.screenrc'), (ROOT_UID, 0o600, 'root/.ssh/authorized_keys'), (ROOT_UID, 0o600, 'root/.ssh/authorized_keys2'), (ROOT_UID, 0o600, 'root/.vimrc'), (ROOT_UID, 0o600, 'root/.k5login'), # punted /root/.ssh/known_hosts # XXX must be created in Kickstart (LOGVIEW_UID, 0o600, 'home/logview/.k5login'), ] COMMON_PROD_CREDS = [ # important: no leading slashes! (ROOT_UID, 0o600, 'root/.ldapvirc'), (ROOT_UID, 0o600, 'etc/ssh/ssh_host_dsa_key'), (ROOT_UID, 0o600, 'etc/ssh/ssh_host_key'), (ROOT_UID, 0o600, 'etc/ssh/ssh_host_rsa_key'), (ROOT_UID, 0o600, 'etc/pki/tls/private/scripts.key'), (ROOT_UID, 0o600, 'etc/whoisd-password'), (ROOT_UID, 0o600, 'etc/daemon.keytab'), (ROOT_UID, 0o644, 'etc/ssh/ssh_host_dsa_key.pub'), (ROOT_UID, 0o644, 'etc/ssh/ssh_host_key.pub'), (ROOT_UID, 0o644, 'etc/ssh/ssh_host_rsa_key.pub'), (SQL_UID, 0o600, 'etc/sql-mit-edu.cfg.php'), (SIGNUP_UID, 0o600, 'etc/signup-ldap-pw'), ] MACHINE_PROD_CREDS = [ # XXX NEED TO CHECK THAT THESE ARE SENSIBLE (ROOT_UID, 0o600, 'etc/krb5.keytab'), (FEDORA_DS_UID, 0o600, 'etc/dirsrv/keytab') ] def mkdir_p(path): try: os.makedirs(path) except OSError as exc: # Python >2.5 if exc.errno == errno.EEXIST: pass else: raise class WithMount(object): """Context for running code with an extra mountpoint.""" guest = None mount = None dev = None def __init__(self, guest): self.guest = guest def __enter__(self): self.dev = "/dev/%s/%s-root" % (HOST, self.guest) mapper_name = shell.eval("kpartx", "-l", self.dev).split()[0] shell.call("kpartx", "-a", self.dev) mapper = "/dev/mapper/%s" % mapper_name # this is why bracketing functions and hanging lambdas are a good idea try: self.mount = tempfile.mkdtemp("-%s" % self.guest, 'vm-', '/mnt') # no trailing slash try: shell.call("mount", mapper, self.mount) except: os.rmdir(self.mount) raise except: shell.call("kpartx", "-d", self.dev) raise return self.mount def __exit__(self, *args): shell.call("umount", self.mount) os.rmdir(self.mount) shell.call("kpartx", "-d", self.dev) def main(): usage = """usage: %prog [ARGS]""" parser = optparse.OptionParser(usage) _, args = parser.parse_args() creds = "/root/creds" # XXX check exists, check owned by root # make an option if not os.path.isdir(creds): raise Exception("/root/creds does not exist") os.umask(0o077) # overly restrictive # XXX error handling if len(args) != 2: raise Exception("Wrong number of arguments") command = args[0] guest = args[1] with WithMount(guest) as tmp_mount: def push_files(files, type): for (ugid, perms, f) in files: # assumes directories exist dest = "%s/%s" % (tmp_mount, f) # assuming OK to overwrite shutil.copyfile("%s/%s/%s" % (creds, type, f), dest) os.chown(dest, ugid, ugid) os.chmod(dest, perms) def pull_files(files, type): for (_, _, f) in files: dest = "%s/%s/%s" % (creds, type, f) mkdir_p(os.path.dirname(dest)) # error if doesn't exist shutil.copyfile("%s/%s" % (tmp_mount, f), dest) # push case if command == "push": push_files(COMMON_CREDS, 'common') push_files(COMMON_PROD_CREDS, 'common') push_files(MACHINE_PROD_CREDS, 'machine/%s' % guest) elif command == "pull": # check if /root/creds exists pull_files(MACHINE_PROD_CREDS, 'machine/%s' % guest) elif command == "pull-common": pull_files(COMMON_CREDS, 'common') pull_files(COMMON_PROD_CREDS, 'common') if __name__ == "__main__": main()