PageRenderTime 98ms CodeModel.GetById 40ms app.highlight 14ms RepoModel.GetById 36ms app.codeStats 6ms

/silverlining/mgr-scripts/rewrite-map.py

https://bitbucket.org/ianb/silverlining/
Python | 127 lines | 109 code | 14 blank | 4 comment | 41 complexity | 3dad6c898ab816a62c8a26b70486345d MD5 | raw file
  1#!/usr/bin/env python
  2import sys
  3import os
  4
  5glob_hostnames = {}
  6abs_hostnames = {}
  7filename = '/var/www/appdata.map'
  8mtime = 0
  9
 10
 11def loop():
 12    global mtime
 13    while 1:
 14        try:
 15            line = sys.stdin.readline()
 16            if not line:
 17                break
 18            line = line.strip()
 19            cur_mtime = os.path.getmtime(filename)
 20            if cur_mtime > mtime:
 21                mtime = cur_mtime
 22                read_file()
 23            hostname, path = line.split('^', 1)
 24            hostname = hostname.split(':', 1)[0]
 25            if not path:
 26                path = '/'
 27        except:
 28            import traceback
 29            sys.stderr.write('Odd exception in rewrite-map:\n')
 30            traceback.print_exc()
 31            sys.stdout.write('error:something odd happened\n')
 32            sys.stdout.flush()
 33            continue
 34        try:
 35            path_match, data, rest = lookup(hostname, path)
 36            if path_match:
 37                data = '%s|%s|%s' % (path_match, data, rest)
 38        except LookupError, e:
 39            sys.stderr.write('Error with hostname=%r, path=%r: %s\n'
 40                             % (hostname, path, e))
 41            sys.stderr.flush()
 42            data = 'error:' + str(e)
 43        sys.stdout.write(data.strip() + '\n')
 44        sys.stdout.flush()
 45
 46
 47def lookup(hostname, path):
 48    record = lookup_hostname(hostname)
 49    path_match, data, rest = lookup_path(record, path)
 50    return path_match, data, rest
 51
 52
 53def lookup_hostname(hostname, seen=None):
 54    record = None
 55    if hostname in abs_hostnames:
 56        record = abs_hostnames[hostname]
 57    elif glob_hostnames:
 58        parts = hostname.split('.')
 59        while parts:
 60            part_hostname = '.'+'.'.join(parts)
 61            if part_hostname in glob_hostnames:
 62                record = glob_hostnames[part_hostname]
 63            parts.pop(0)
 64    if record is None:
 65        if '*' in glob_hostnames:
 66            record = glob_hostnames['*']
 67        elif 'not-found' in abs_hostnames:
 68            record = abs_hostnames['not-found']
 69        else:
 70            ## FIXME: better failover?
 71            raise LookupError('No not-found application listed')
 72    if record and record[0][0] == 'seeother':
 73        name = record[0][1]
 74        if seen and name in seen:
 75            raise LookupError('Infinite loop of domains: %s' % seen)
 76        if seen is None:
 77            seen = [name]
 78        else:
 79            seen += [name]
 80        return lookup_hostname(name, seen)
 81    return record
 82
 83
 84def lookup_path(record, path):
 85    for path_prefix, data in record:
 86        if path == path_prefix[:-1] and path_prefix.endswith('/'):
 87            # We need a / redirect
 88            return None, 'addslash', None
 89        if path.startswith(path_prefix):
 90            path_prefix = path_prefix.rstrip('/') or '/'
 91            if path_prefix == '/':
 92                rest = path
 93            else:
 94                rest = path[len(path_prefix):]
 95            return path_prefix, data, rest
 96    else:
 97        ## FIXME: how should this fail?
 98        raise LookupError('No application mounted to /')
 99
100
101def read_file():
102    fp = open(filename, 'rb')
103    try:
104        read_file_data(fp)
105    finally:
106        fp.close()
107
108
109def read_file_data(fp):
110    global glob_hostnames, abs_hostnames
111    glob_hostnames = {}
112    abs_hostnames = {}
113    for line in fp:
114        line = line.strip()
115        if not line or line.startswith('#'):
116            continue
117        hostname, path, rest = line.split(None, 2)
118        if hostname.startswith('.') or hostname == '*':
119            glob_hostnames.setdefault(hostname, []).append((path, rest))
120        else:
121            abs_hostnames.setdefault(hostname, []).append((path, rest))
122    for s in glob_hostnames, abs_hostnames:
123        for value in s.itervalues():
124            value.sort(key=lambda x: -len(x[0]))
125
126if __name__ == '__main__':
127    loop()