Coverage for gws-app/gws/server/control.py: 21%
86 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 12:46 +0200
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 12:46 +0200
1"""Server control.
3Following workflows are supported:
51) Server start. This is called only once upon the container start.
7 - (empty TMP_DIR completely in bin/gws)
8 - configure
9 - store the config
10 - write server configs
11 - (the actual invocation of the server start script takes place in bin/gws)
132) Server reconfigure. Can be called anytime, e.g. by the monitor
15 - configure
16 - store the config
17 - write server configs
18 - empty the TRANSIENT_DIR
19 - reload all backends
20 - reload nginx
223) Server reload. Can be called anytime, e.g. by the monitor
24 - write server configs
25 - empty the TRANSIENT_DIR
26 - reload all backends
27 - reload nginx
304) Configure (debugging)
32 - configure
33 - store the config
365) Configtest (debugging)
38 - configure
42"""
44import gws
45import gws.config
46import gws.lib.datetimex
47import gws.lib.osx
48import gws.lib.watcher
49import gws.lib.lock
51# see bin/gws
52_SERVER_START_SCRIPT = f'{gws.c.VAR_DIR}/server.sh'
54_PID_PATHS = {
55 'web': f'{gws.c.PIDS_DIR}/web.uwsgi.pid',
56 'spool': f'{gws.c.PIDS_DIR}/spool.uwsgi.pid',
57 'mapproxy': f'{gws.c.PIDS_DIR}/mapproxy.uwsgi.pid',
58 'nginx': f'{gws.c.PIDS_DIR}/nginx.pid',
59}
62def start(manifest_path='', config_path=''):
63 if app_is_running('web'):
64 gws.log.error(f'server already running')
65 gws.u.exit(1)
66 root = configure_and_store(manifest_path, config_path, is_starting=True)
67 root.app.serverMgr.create_server_configs(gws.c.SERVER_DIR, _SERVER_START_SCRIPT, _PID_PATHS)
70def reconfigure(manifest_path='', config_path=''):
71 if not app_is_running('web'):
72 gws.log.error(f'server not running')
73 gws.u.exit(1)
74 root = configure_and_store(manifest_path, config_path, is_starting=False)
75 root.app.serverMgr.create_server_configs(gws.c.SERVER_DIR, _SERVER_START_SCRIPT, _PID_PATHS)
76 reload_all()
79def configure_and_store(manifest_path='', config_path='', is_starting=False):
80 root = configure(manifest_path, config_path, is_starting)
81 gws.config.store(root)
82 return root
85def configure(manifest_path='', config_path='', is_starting=False):
86 def _pre_init(ld: gws.config.loader.Object):
87 autorun = gws.u.get(ld.config, 'server.autoRun')
88 if autorun:
89 gws.log.info(f'AUTORUN: {autorun!r}')
90 gws.lib.osx.run(autorun, echo=True)
92 hooks = []
93 if is_starting:
94 hooks.append(['preInitialize', _pre_init])
96 cr = gws.config.configure(
97 manifest_path=manifest_path,
98 config_path=config_path,
99 fallback_config=_FALLBACK_CONFIG,
100 hooks=hooks,
101 )
102 gws.config.log_report(cr)
103 if not cr.root:
104 raise gws.ConfigurationError('configuration failed')
105 return gws.u.require(cr.root)
108def config_test(
109 manifest_path='',
110 config_path='',
111 dirs_to_watch='',
112 with_parse_only=False,
113 with_watch=False
114):
116 def _check(*args):
117 gws.log.info('=' * 80)
118 gws.log.info(f'TESTING CONFIGURATION...')
119 gws.log.info('=' * 80)
120 if with_parse_only:
121 cr = gws.config.parse(manifest_path, config_path)
122 else:
123 cr = gws.config.configure(manifest_path, config_path)
124 gws.config.log_report(cr)
126 _check()
128 if not with_watch:
129 return
131 w = gws.lib.watcher.new(_check)
132 dirs = gws.u.to_list(dirs_to_watch or '/data')
133 for d in dirs:
134 w.add_directory(d, recursive=True)
135 w.start()
137 while True:
138 gws.u.sleep(3)
142##
144def reload_all():
145 gws.lib.osx.run(['rm', '-fr', gws.c.TRANSIENT_DIR])
146 gws.u.ensure_system_dirs()
148 reload_app('spool')
149 reload_app('mapproxy')
150 reload_app('web')
152 reload_nginx()
153 return True
156def reload_app(srv):
157 if not app_is_running(srv):
158 gws.log.debug(f'reload: {srv=} not running')
159 return
160 gws.log.info(f'reloading {srv}...')
161 gws.lib.osx.run(['uwsgi', '--reload', _PID_PATHS[srv]])
164def reload_nginx():
165 gws.log.info(f'reloading nginx...')
166 gws.lib.osx.run(['nginx', '-c', gws.c.SERVER_DIR + '/nginx.conf', '-s', 'reload'])
169def app_is_running(srv):
170 try:
171 with open(_PID_PATHS[srv]) as fp:
172 pid = int(fp.read())
173 except (FileNotFoundError, ValueError):
174 pid = 0
175 if pid == 0:
176 return False
177 gws.log.debug(f'found {pid=} for {srv=}')
178 return pid in gws.lib.osx.running_pids()
181##
184_FALLBACK_CONFIG = gws.Config(
185 server=gws.Config(
186 timeZone="Europe/Berlin",
187 mapproxy=gws.Config(disabled=True),
188 monitor=gws.Config(disabled=True),
189 log=gws.Config(level='INFO'),
190 qgis=gws.Config(host='qgis', port=80),
191 spool=gws.Config(disabled=True),
192 web=gws.Config(disabled=False, workers=1, timeout=60, maxRequestLength=10),
193 )
194)