forked from localstack/localstack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmultiserver.py
More file actions
122 lines (99 loc) · 3.65 KB
/
multiserver.py
File metadata and controls
122 lines (99 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import sys
import json
import logging
import subprocess
import requests
from requests.models import Response
from moto.server import main as moto_main
from localstack import constants
from localstack.utils.common import (
FuncThread, ShellCommandThread, TMP_THREADS, to_str, json_safe, wait_for_port_open, is_port_open)
from localstack.utils.bootstrap import setup_logging
from localstack.services.generic_proxy import ProxyListener, GenericProxy
LOG = logging.getLogger('localstack.multiserver')
# maps API names to server details
API_SERVERS = {}
# network port for multiserver instance
MULTI_SERVER_PORT = 51492
# API paths
API_PATH_SERVERS = '/servers'
# whether to start the multiserver in a separate process
RUN_SERVER_IN_PROCESS = False
def start_api_server_locally(request):
api = request.get('api')
port = request.get('port')
if api in API_SERVERS:
return API_SERVERS[api]
result = API_SERVERS[api] = {}
def thread_func(params):
return moto_main([api, '-p', str(port), '-H', constants.BIND_HOST])
thread = FuncThread(thread_func)
thread.start()
TMP_THREADS.append(thread)
result['port'] = port
result['thread'] = thread
return result
def start_server(port, asynchronous=False):
if is_port_open(port):
LOG.debug('API Multiserver appears to be already running.')
return
class ConfigListener(ProxyListener):
def forward_request(self, method, path, data, **kwargs):
response = Response()
response.status_code = 200
response._content = '{}'
try:
if path == API_PATH_SERVERS:
if method == 'POST':
start_api_server_locally(json.loads(to_str(data)))
elif method == 'GET':
response._content = json.dumps(json_safe(API_SERVERS))
except Exception as e:
LOG.error('Unable to process request: %s' % e)
response.status_code = 500
response._content = str(e)
return response
proxy = GenericProxy(port, update_listener=ConfigListener())
proxy.start()
if asynchronous:
return proxy
proxy.join()
def start_api_server(api, port, server_port=None):
server_port = server_port or MULTI_SERVER_PORT
thread = start_server_process(server_port)
url = 'http://localhost:%s%s' % (server_port, API_PATH_SERVERS)
payload = {
'api': api,
'port': port
}
result = requests.post(url, json=payload)
if result.status_code >= 400:
raise Exception('Unable to start API in multi server (%s): %s' %
(result.status_code, result.content))
return thread
def start_server_process(port):
if '__server__' in API_SERVERS:
return API_SERVERS['__server__']['thread']
port = port or MULTI_SERVER_PORT
API_SERVERS['__server__'] = config = {'port': port}
LOG.info('Starting multi API server process on port %s' % port)
if RUN_SERVER_IN_PROCESS:
cmd = '"%s" "%s" %s' % (sys.executable, __file__, port)
env_vars = {
'PYTHONPATH': '.:%s' % constants.LOCALSTACK_ROOT_FOLDER
}
thread = ShellCommandThread(cmd, outfile=subprocess.PIPE, env_vars=env_vars,
inherit_cwd=True)
thread.start()
else:
thread = start_server(port, asynchronous=True)
TMP_THREADS.append(thread)
config['thread'] = thread
wait_for_port_open(port, retries=20, sleep_time=1)
return thread
def main():
setup_logging()
port = int(sys.argv[1]) if len(sys.argv) > 0 else MULTI_SERVER_PORT
start_server(port)
if __name__ == '__main__':
main()