PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/silversupport/appdata.py

https://bitbucket.org/ianb/silverlining/
Python | 194 lines | 152 code | 16 blank | 26 comment | 44 complexity | 34613d07fd503c9d17f4a7e3d6d0ed18 MD5 | raw file
Possible License(s): GPL-2.0
  1. """Routines for handling /var/www/appdata.map"""
  2. import os
  3. from silversupport.appconfig import AppConfig
  4. APPDATA_MAP = '/var/www/appdata.map'
  5. __all__ = ['add_appdata', 'normalize_location',
  6. 'remove_host', 'instance_for_location', 'all_app_instances',
  7. 'list_instances']
  8. def add_appdata(app_config, locations, debug_single_process=False,
  9. add_prev=True):
  10. """Adds new application deployment to appdata.map
  11. This adds the given instance name for all the given locations. If
  12. `add_prev` is true then any old instances at these locations will
  13. be moved to a prev.* hostname
  14. """
  15. if isinstance(app_config, basestring):
  16. app_config = AppConfig.from_instance_name(app_config)
  17. if debug_single_process:
  18. process_group = 'general_debug'
  19. else:
  20. process_group = 'general'
  21. locations = [normalize_location(l) for l in locations]
  22. new_lines = rewrite_lines(appdata_lines(), locations, add_prev, dict(
  23. instance_name=app_config.instance_name, platform=app_config.platform,
  24. process_group=process_group, php_root=app_config.php_root.rstrip('/'),
  25. write_root=app_config.writable_root_location))
  26. fp = open(APPDATA_MAP, 'w')
  27. fp.writelines(new_lines)
  28. fp.close()
  29. def rewrite_lines(existing, locations, add_prev, vars):
  30. """Rewrite the lines in appdata.map"""
  31. if isinstance(existing, basestring):
  32. existing = existing.splitlines(True)
  33. lines = []
  34. for line in existing:
  35. if not line.strip() or line.strip().startswith('#'):
  36. lines.append(line)
  37. continue
  38. ex_hostname, ex_path, ex_data = line.split(None, 2)
  39. for hostname, path in locations:
  40. if add_prev:
  41. if 'prev.' + hostname == ex_hostname and path == ex_path:
  42. # Overwrite the old (non-prev) hostname
  43. break
  44. elif hostname == ex_hostname and path == ex_path:
  45. # Rewrite matching lines to prev.
  46. lines.append('prev.' + line)
  47. break
  48. else:
  49. if hostname == ex_hostname and path == ex_path:
  50. # Overwrite!
  51. break
  52. else:
  53. lines.append(line)
  54. data = '%(instance_name)s|%(process_group)s|%(write_root)s|%(platform)s|%(php_root)s' % vars
  55. for hostname, path in locations:
  56. lines.append('%s %s %s\n' % (hostname, path, data))
  57. return ''.join(lines)
  58. def normalize_location(location, empty_path='/'):
  59. """Normalize a string location into (hostname, path).
  60. In most cases if no path is given, then ``/`` is implied, but some
  61. commands may want to distinguish this and so can use
  62. ``empty_path=None`` to note the difference
  63. """
  64. if isinstance(location, (list, tuple)) and len(location) == 2:
  65. # Already normalized
  66. return location
  67. if location.startswith('http://'):
  68. location = location[len('http://'):]
  69. if location.startswith('https://'):
  70. location = location[len('https://'):]
  71. if '/' in location:
  72. hostname, path = location.split('/', 1)
  73. path = '/' + path
  74. else:
  75. hostname = location
  76. path = empty_path
  77. return hostname, path
  78. def remove_host(hostname, keep_prev=False, path=None):
  79. """Updates /var/www/appdata.map to remove the given hostname.
  80. If `keep_prev` is True, then the prev.* hostname will be left
  81. in place, otherwise it will be deleted at the same time.
  82. If path is given the deletions will be limited to that path
  83. (or if it is a list, to those paths).
  84. This returns the list of lines removed.
  85. """
  86. new_lines = []
  87. if path and isinstance(path, basestring):
  88. path = [path]
  89. removed = []
  90. for line in appdata_lines():
  91. if not line.strip() or line.strip().startswith('#'):
  92. new_lines.append(line)
  93. continue
  94. line_hostname, line_path, data = line.split(None, 2)
  95. if (hostname == line_hostname
  96. or (not keep_prev and 'prev.'+hostname == line_hostname)):
  97. if not path or line_path in path:
  98. removed.append(line)
  99. continue
  100. new_lines.append(line)
  101. fp = open(APPDATA_MAP, 'w')
  102. fp.writelines(new_lines)
  103. fp.close()
  104. return removed
  105. def appdata_lines():
  106. """Returns all lines in /var/www/appdata.map"""
  107. fp = open(APPDATA_MAP)
  108. try:
  109. return fp.readlines()
  110. finally:
  111. fp.close()
  112. def instance_for_location(hostname, path='/'):
  113. """Returns the instance name for the given hostname/path.
  114. Returns None if no instance found"""
  115. for line in appdata_lines():
  116. if not line.strip() or line.strip().startswith('#'):
  117. continue
  118. line_hostname, line_path, data = line.split(None, 2)
  119. if (line_hostname == hostname and line_path == path):
  120. instance_name = data.split('|')[0]
  121. return instance_name
  122. return None
  123. def instance_for_app_name(hostname, app_name):
  124. """Returns the instance name for a given hostname and app_name
  125. Returns None if no instance found"""
  126. for line in appdata_lines():
  127. if not line.strip() or line.strip().startswith('#'):
  128. continue
  129. line_hostname, line_path, data = line.split(None, 2)
  130. if line_hostname != hostname:
  131. continue
  132. line_instance_name = data.split('|')[0]
  133. line_app_name = line_instance_name.split('.')[0]
  134. if line_app_name == app_name:
  135. return line_instance_name
  136. return None
  137. def all_app_instances():
  138. """Returns a dictionary of all app instances.
  139. The dictionary is {instance_name: [(hostname, path), ...]}
  140. Instances that have no active mappings will also be returned,
  141. with empty lists."""
  142. results = {}
  143. for instance_name in list_instances():
  144. results[instance_name] = []
  145. for line in appdata_lines():
  146. if not line.strip() or line.strip().startswith('#'):
  147. continue
  148. hostname, path, data = line.split(None, 2)
  149. instance_name = data.split('|')[0]
  150. results[instance_name].append((hostname, path))
  151. return results
  152. def list_instances():
  153. """Returns a list of all instance names"""
  154. base_dir = '/var/www'
  155. results = []
  156. for name in os.listdir(base_dir):
  157. if name.startswith('.'):
  158. continue
  159. if not os.path.isdir(os.path.join(base_dir, name)):
  160. continue
  161. if name == 'support':
  162. # We're not using this now, but have in the past
  163. continue
  164. results.append(name)
  165. return results