source: branches/fc15-dev/host/credit-card/host.py @ 2036

Last change on this file since 2036 was 1999, checked in by ezyang, 13 years ago
Initial commit of credential cloning code.
File size: 4.4 KB
Line 
1import os
2import optparse
3import logging
4import socket
5import tempfile
6import shutil
7import errno
8
9import shell
10
11HOST = socket.gethostname()
12
13# XXX test server and wizard server
14
15ROOT_UID = 0
16SIGNUP_UID = 102
17SQL_UID = 537704221
18FEDORA_DS_UID = 103 # XXX ACTUALLY CONFIGURE SERVERS TO USE THIS
19LOGVIEW_UID = 501 # XXX Autogenerated, I don't like this...
20
21COMMON_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
34COMMON_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
51MACHINE_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
57def 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
65class 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
97def 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
146if __name__ == "__main__":
147    main()
Note: See TracBrowser for help on using the repository browser.