PageRenderTime 30ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/silversupport/requests.py

https://bitbucket.org/ianb/silverlining/
Python | 133 lines | 107 code | 6 blank | 20 comment | 4 complexity | 8dc4807d8567f88c701a27a8b12d5bee MD5 | raw file
Possible License(s): GPL-2.0
  1. """For running internal requests in production"""
  2. from cStringIO import StringIO
  3. import os
  4. import sys
  5. import urllib
  6. from silversupport.shell import run
  7. __all__ = ['internal_request']
  8. def internal_request(app_config, hostname, path, body=None, environ=None,
  9. capture_stdout=True):
  10. if app_config.platform == 'python':
  11. func = wsgi_internal_request
  12. elif app_config.platform == 'php':
  13. func = php_internal_request
  14. else:
  15. assert 0
  16. assert not body or isinstance(body, basestring), (
  17. "Incorrect body argument: %r" % body)
  18. return func(
  19. app_config, hostname, path, body, environ,
  20. capture_stdout=capture_stdout)
  21. def wsgi_internal_request(app_config, hostname, path,
  22. body=None, environ=None, capture_stdout=True):
  23. """Make an internal request:
  24. ``wsgi_app``: The application to request from (use
  25. ``create_wsgi_app`` to get this)
  26. ``hostname``: the hostname to request agains
  27. ``path``: the request path
  28. ``body``: any request body
  29. ``environ``: any extra WSGI environment you want to add
  30. This makes an entirely internal request. appdata.map does not
  31. need to be updated to run this command, you can run it on an old
  32. app or an application that has not been entirely deployed.
  33. This returns ``(status, header_list, body_as_str)``
  34. """
  35. os.environ['SILVER_CANONICAL_HOSTNAME'] = hostname
  36. wsgi_app = app_config.get_app_from_runner()
  37. basic_environ = {
  38. 'PATH_INFO': urllib.unquote(str(path)),
  39. 'SCRIPT_NAME': '',
  40. 'SERVER_NAME': hostname,
  41. 'SERVER_PORT': '80',
  42. 'REQUEST_METHOD': 'GET',
  43. 'HTTP_HOST': '%s:80' % hostname,
  44. 'CONTENT_LENGTH': '0',
  45. 'REMOTE_ADDR': '127.0.0.1',
  46. 'SERVER_PROTOCOL': 'HTTP/1.0',
  47. 'wsgi.input': StringIO(''),
  48. 'wsgi.errors': sys.stderr,
  49. 'wsgi.version': (1, 0),
  50. 'wsgi.multithread': False,
  51. 'wsgi.multiprocess': False,
  52. 'wsgi.run_once': True,
  53. 'wsgi.url_scheme': 'http',
  54. 'silverlining.internal': True,
  55. }
  56. if body:
  57. basic_environ['wsgi.input'] = StringIO(body)
  58. basic_environ['CONTENT_LENGTH'] = len(body)
  59. basic_environ['REQUEST_METHOD'] = 'POST'
  60. if environ:
  61. basic_environ.update(environ)
  62. basic_environ['SILVER_INSTANCE_NAME'] = app_config.instance_name
  63. ## FIXME: This isn't a very good guess of the path:
  64. basic_environ['SILVER_MATCH_PATH'] = ''
  65. out = StringIO()
  66. info = []
  67. def start_response(status, headers, exc_info=None):
  68. if exc_info is not None:
  69. raise exc_info[0], exc_info[1], exc_info[2]
  70. info[:] = [status, headers]
  71. if capture_stdout:
  72. return out.write
  73. else:
  74. return sys.stdout.write
  75. app_iter = wsgi_app(basic_environ, start_response)
  76. try:
  77. for item in app_iter:
  78. if capture_stdout:
  79. sys.stdout.write(item)
  80. else:
  81. out.write(item)
  82. finally:
  83. if hasattr(app_iter, 'close'):
  84. app_iter.close()
  85. status, headers = info
  86. return status, headers, out.getvalue()
  87. def create_wsgi_app(instance_name, hostname):
  88. ## FIXME: should this even exist?
  89. os.environ['SITE'] = instance_name
  90. fn = '/usr/local/share/silverlining/mgr-scripts/master-runner.py'
  91. ns = {'__file__': fn,
  92. '__name__': '__main__'}
  93. execfile(fn, ns)
  94. wsgi_app = ns['application']
  95. return wsgi_app
  96. def php_internal_request(app_config, hostname, path, body=None, environ=None, capture_stdout=True):
  97. assert app_config.platform == 'php'
  98. env = {}
  99. env['SILVER_SCRIPT_NAME'] = env['SCRIPT_NAME'] = urllib.unquote(path)
  100. env['SILVER_INSTANCE_NAME'] = app_config.instance_name
  101. env['SILVER_CANONICAL_HOSTNAME'] = hostname
  102. ## FIXME: nice if this was more... intelligent:
  103. env['SILVER_MATCH_PATH'] = '/'
  104. if body:
  105. env['REQUEST_METHOD'] = 'POST'
  106. else:
  107. env['REQUEST_METHOD'] = 'GET'
  108. env.update(environ)
  109. for key, value in env.items():
  110. if not isinstance(value, str):
  111. env[key] = str(value)
  112. stdout, stderr, returncode = run(
  113. ['php5', '/usr/local/share/silverlining/mgr-scripts/master-runner.php'], capture_stdout=capture_stdout,
  114. extra_env=env, stdin=body)
  115. return '200 OK', [], stdout