[1999] | 1 | import os |
---|
| 2 | import optparse |
---|
| 3 | import logging |
---|
| 4 | import socket |
---|
| 5 | import tempfile |
---|
| 6 | import shutil |
---|
| 7 | import errno |
---|
| 8 | |
---|
| 9 | import shell |
---|
| 10 | |
---|
| 11 | HOST = socket.gethostname() |
---|
| 12 | |
---|
| 13 | # XXX test server and wizard server |
---|
| 14 | |
---|
| 15 | ROOT_UID = 0 |
---|
| 16 | SIGNUP_UID = 102 |
---|
| 17 | SQL_UID = 537704221 |
---|
| 18 | FEDORA_DS_UID = 103 # XXX ACTUALLY CONFIGURE SERVERS TO USE THIS |
---|
| 19 | LOGVIEW_UID = 501 # XXX Autogenerated, I don't like this... |
---|
| 20 | |
---|
| 21 | COMMON_CREDS = [ |
---|
| 22 | (ROOT_UID, 0o600, 'root/.bashrc'), |
---|
| 23 | (ROOT_UID, 0o600, 'root/.screenrc'), |
---|
| 24 | (ROOT_UID, 0o600, 'root/.ssh/authorized_keys'), |
---|
| 25 | (ROOT_UID, 0o600, 'root/.ssh/authorized_keys2'), |
---|
| 26 | (ROOT_UID, 0o600, 'root/.vimrc'), |
---|
| 27 | (ROOT_UID, 0o600, 'root/.k5login'), |
---|
| 28 | # punted /root/.ssh/known_hosts |
---|
| 29 | |
---|
| 30 | # XXX must be created in Kickstart |
---|
| 31 | (LOGVIEW_UID, 0o600, 'home/logview/.k5login'), |
---|
| 32 | ] |
---|
| 33 | |
---|
| 34 | COMMON_PROD_CREDS = [ # important: no leading slashes! |
---|
| 35 | (ROOT_UID, 0o600, 'root/.ldapvirc'), |
---|
| 36 | (ROOT_UID, 0o600, 'etc/ssh/ssh_host_dsa_key'), |
---|
| 37 | (ROOT_UID, 0o600, 'etc/ssh/ssh_host_key'), |
---|
| 38 | (ROOT_UID, 0o600, 'etc/ssh/ssh_host_rsa_key'), |
---|
| 39 | (ROOT_UID, 0o600, 'etc/pki/tls/private/scripts.key'), |
---|
| 40 | (ROOT_UID, 0o600, 'etc/whoisd-password'), |
---|
| 41 | (ROOT_UID, 0o600, 'etc/daemon.keytab'), |
---|
| 42 | |
---|
| 43 | (ROOT_UID, 0o644, 'etc/ssh/ssh_host_dsa_key.pub'), |
---|
| 44 | (ROOT_UID, 0o644, 'etc/ssh/ssh_host_key.pub'), |
---|
| 45 | (ROOT_UID, 0o644, 'etc/ssh/ssh_host_rsa_key.pub'), |
---|
| 46 | |
---|
| 47 | (SQL_UID, 0o600, 'etc/sql-mit-edu.cfg.php'), |
---|
| 48 | (SIGNUP_UID, 0o600, 'etc/signup-ldap-pw'), |
---|
| 49 | ] |
---|
| 50 | |
---|
| 51 | MACHINE_PROD_CREDS = [ |
---|
| 52 | # XXX NEED TO CHECK THAT THESE ARE SENSIBLE |
---|
| 53 | (ROOT_UID, 0o600, 'etc/krb5.keytab'), |
---|
| 54 | (FEDORA_DS_UID, 0o600, 'etc/dirsrv/keytab') |
---|
| 55 | ] |
---|
| 56 | |
---|
| 57 | def mkdir_p(path): |
---|
| 58 | try: |
---|
| 59 | os.makedirs(path) |
---|
| 60 | except OSError as exc: # Python >2.5 |
---|
| 61 | if exc.errno == errno.EEXIST: |
---|
| 62 | pass |
---|
| 63 | else: raise |
---|
| 64 | |
---|
| 65 | class WithMount(object): |
---|
| 66 | """Context for running code with an extra mountpoint.""" |
---|
| 67 | guest = None |
---|
| 68 | mount = None |
---|
| 69 | dev = None |
---|
| 70 | def __init__(self, guest): |
---|
| 71 | self.guest = guest |
---|
| 72 | def __enter__(self): |
---|
| 73 | self.dev = "/dev/%s/%s-root" % (HOST, self.guest) |
---|
| 74 | |
---|
| 75 | mapper_name = shell.eval("kpartx", "-l", self.dev).split()[0] |
---|
| 76 | shell.call("kpartx", "-a", self.dev) |
---|
| 77 | mapper = "/dev/mapper/%s" % mapper_name |
---|
| 78 | |
---|
| 79 | # this is why bracketing functions and hanging lambdas are a good idea |
---|
| 80 | try: |
---|
| 81 | self.mount = tempfile.mkdtemp("-%s" % self.guest, 'vm-', '/mnt') # no trailing slash |
---|
| 82 | try: |
---|
| 83 | shell.call("mount", mapper, self.mount) |
---|
| 84 | except: |
---|
| 85 | os.rmdir(self.mount) |
---|
| 86 | raise |
---|
| 87 | except: |
---|
| 88 | shell.call("kpartx", "-d", self.dev) |
---|
| 89 | raise |
---|
| 90 | |
---|
| 91 | return self.mount |
---|
| 92 | def __exit__(self, *args): |
---|
| 93 | shell.call("umount", self.mount) |
---|
| 94 | os.rmdir(self.mount) |
---|
| 95 | shell.call("kpartx", "-d", self.dev) |
---|
| 96 | |
---|
| 97 | def main(): |
---|
| 98 | usage = """usage: %prog [ARGS]""" |
---|
| 99 | |
---|
| 100 | parser = optparse.OptionParser(usage) |
---|
| 101 | _, args = parser.parse_args() |
---|
| 102 | |
---|
| 103 | creds = "/root/creds" # XXX check exists, check owned by root |
---|
| 104 | # make an option |
---|
| 105 | if not os.path.isdir(creds): |
---|
| 106 | raise Exception("/root/creds does not exist") |
---|
| 107 | |
---|
| 108 | os.umask(0o077) # overly restrictive |
---|
| 109 | |
---|
| 110 | # XXX error handling |
---|
| 111 | |
---|
| 112 | if len(args) != 2: |
---|
| 113 | raise Exception("Wrong number of arguments") |
---|
| 114 | |
---|
| 115 | command = args[0] |
---|
| 116 | guest = args[1] |
---|
| 117 | |
---|
| 118 | with WithMount(guest) as tmp_mount: |
---|
| 119 | def push_files(files, type): |
---|
| 120 | for (ugid, perms, f) in files: |
---|
| 121 | # assumes directories exist |
---|
| 122 | dest = "%s/%s" % (tmp_mount, f) |
---|
| 123 | # assuming OK to overwrite |
---|
| 124 | shutil.copyfile("%s/%s/%s" % (creds, type, f), dest) |
---|
| 125 | os.chown(dest, ugid, ugid) |
---|
| 126 | os.chmod(dest, perms) |
---|
| 127 | def pull_files(files, type): |
---|
| 128 | for (_, _, f) in files: |
---|
| 129 | dest = "%s/%s/%s" % (creds, type, f) |
---|
| 130 | mkdir_p(os.path.dirname(dest)) |
---|
| 131 | # error if doesn't exist |
---|
| 132 | shutil.copyfile("%s/%s" % (tmp_mount, f), dest) |
---|
| 133 | |
---|
| 134 | # push case |
---|
| 135 | if command == "push": |
---|
| 136 | push_files(COMMON_CREDS, 'common') |
---|
| 137 | push_files(COMMON_PROD_CREDS, 'common') |
---|
| 138 | push_files(MACHINE_PROD_CREDS, 'machine/%s' % guest) |
---|
| 139 | elif command == "pull": |
---|
| 140 | # check if /root/creds exists |
---|
| 141 | pull_files(MACHINE_PROD_CREDS, 'machine/%s' % guest) |
---|
| 142 | elif command == "pull-common": |
---|
| 143 | pull_files(COMMON_CREDS, 'common') |
---|
| 144 | pull_files(COMMON_PROD_CREDS, 'common') |
---|
| 145 | |
---|
| 146 | if __name__ == "__main__": |
---|
| 147 | main() |
---|