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

1"""Server control. 

2 

3Following workflows are supported: 

4 

51) Server start. This is called only once upon the container start. 

6 

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) 

12 

132) Server reconfigure. Can be called anytime, e.g. by the monitor 

14 

15 - configure 

16 - store the config 

17 - write server configs 

18 - empty the TRANSIENT_DIR 

19 - reload all backends 

20 - reload nginx 

21 

223) Server reload. Can be called anytime, e.g. by the monitor 

23 

24 - write server configs 

25 - empty the TRANSIENT_DIR 

26 - reload all backends 

27 - reload nginx 

28 

29 

304) Configure (debugging) 

31 

32 - configure 

33 - store the config 

34 

35 

365) Configtest (debugging) 

37 

38 - configure 

39 

40 

41 

42""" 

43 

44import gws 

45import gws.config 

46import gws.lib.datetimex 

47import gws.lib.osx 

48import gws.lib.watcher 

49import gws.lib.lock 

50 

51# see bin/gws 

52_SERVER_START_SCRIPT = f'{gws.c.VAR_DIR}/server.sh' 

53 

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} 

60 

61 

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) 

68 

69 

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() 

77 

78 

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 

83 

84 

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) 

91 

92 hooks = [] 

93 if is_starting: 

94 hooks.append(['preInitialize', _pre_init]) 

95 

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) 

106 

107 

108def config_test( 

109 manifest_path='', 

110 config_path='', 

111 dirs_to_watch='', 

112 with_parse_only=False, 

113 with_watch=False 

114): 

115 

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) 

125 

126 _check() 

127 

128 if not with_watch: 

129 return 

130 

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() 

136 

137 while True: 

138 gws.u.sleep(3) 

139 

140 

141 

142## 

143 

144def reload_all(): 

145 gws.lib.osx.run(['rm', '-fr', gws.c.TRANSIENT_DIR]) 

146 gws.u.ensure_system_dirs() 

147 

148 reload_app('spool') 

149 reload_app('mapproxy') 

150 reload_app('web') 

151 

152 reload_nginx() 

153 return True 

154 

155 

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]]) 

162 

163 

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']) 

167 

168 

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() 

179 

180 

181## 

182 

183 

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)