PageRenderTime 27ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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