Coverage for gws-app/gws/server/control.py: 21%

84 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-16 22:59 +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 root = gws.config.configure( 

97 manifest_path=manifest_path, 

98 config_path=config_path, 

99 fallback_config=_FALLBACK_CONFIG, 

100 hooks=hooks, 

101 ) 

102 if not root: 

103 raise gws.ConfigurationError('configuration failed') 

104 return root 

105 

106 

107def config_test( 

108 manifest_path='', 

109 config_path='', 

110 dirs_to_watch='', 

111 with_parse_only=False, 

112 with_watch=False 

113): 

114 

115 def _check(*args): 

116 gws.log.info('=' * 80) 

117 gws.log.info(f'TESTING CONFIGURATION...') 

118 gws.log.info('=' * 80) 

119 if with_parse_only: 

120 gws.config.parse(manifest_path, config_path) 

121 else: 

122 gws.config.configure(manifest_path, config_path) 

123 

124 _check() 

125 

126 if not with_watch: 

127 return 

128 

129 w = gws.lib.watcher.new(_check) 

130 dirs = gws.u.to_list(dirs_to_watch or '/data') 

131 for d in dirs: 

132 w.add_directory(d, recursive=True) 

133 w.start() 

134 

135 while True: 

136 gws.u.sleep(3) 

137 

138 

139 

140## 

141 

142def reload_all(): 

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

144 gws.u.ensure_system_dirs() 

145 

146 reload_app('spool') 

147 reload_app('mapproxy') 

148 reload_app('web') 

149 

150 reload_nginx() 

151 return True 

152 

153 

154def reload_app(srv): 

155 if not app_is_running(srv): 

156 gws.log.debug(f'reload: {srv=} not running') 

157 return 

158 gws.log.info(f'reloading {srv}...') 

159 gws.lib.osx.run(['uwsgi', '--reload', _PID_PATHS[srv]]) 

160 

161 

162def reload_nginx(): 

163 gws.log.info(f'reloading nginx...') 

164 gws.lib.osx.run(['nginx', '-c', gws.c.SERVER_DIR + '/nginx.conf', '-s', 'reload']) 

165 

166 

167def app_is_running(srv): 

168 try: 

169 with open(_PID_PATHS[srv]) as fp: 

170 pid = int(fp.read()) 

171 except (FileNotFoundError, ValueError): 

172 pid = 0 

173 if pid == 0: 

174 return False 

175 gws.log.debug(f'found {pid=} for {srv=}') 

176 return pid in gws.lib.osx.running_pids() 

177 

178 

179## 

180 

181 

182_FALLBACK_CONFIG = gws.Config( 

183 server=gws.Config( 

184 timeZone="Europe/Berlin", 

185 mapproxy=gws.Config(disabled=True), 

186 monitor=gws.Config(disabled=True), 

187 log=gws.Config(level='INFO'), 

188 qgis=gws.Config(host='qgis', port=80), 

189 spool=gws.Config(disabled=True), 

190 web=gws.Config(disabled=False, workers=1, timeout=60, maxRequestLength=10), 

191 ) 

192)