mirror of
https://git.anonymousland.org/anonymousland/synapse-product.git
synced 2024-10-01 08:25:44 -04:00
158d73ebdd
Revert "Sort internal changes in changelog" Revert "Update CHANGES.md" Revert "1.49.0rc1" Revert "Revert "Move `glob_to_regex` and `re_word_boundary` to `matrix-python-common` (#11505) (#11527)" Revert "Refactors in `_generate_sync_entry_for_rooms` (#11515)" Revert "Correctly register shutdown handler for presence workers (#11518)" Revert "Fix `ModuleApi.looping_background_call` for non-async functions (#11524)" Revert "Fix 'delete room' admin api to work on incomplete rooms (#11523)" Revert "Correctly ignore invites from ignored users (#11511)" Revert "Fix the test breakage introduced by #11435 as a result of concurrent PRs (#11522)" Revert "Stabilise support for MSC2918 refresh tokens as they have now been merged into the Matrix specification. (#11435)" Revert "Save the OIDC session ID (sid) with the device on login (#11482)" Revert "Add admin API to get some information about federation status (#11407)" Revert "Include bundled aggregations in /sync and related fixes (#11478)" Revert "Move `glob_to_regex` and `re_word_boundary` to `matrix-python-common` (#11505)" Revert "Update backward extremity docs to make it clear that it does not indicate whether we have fetched an events' `prev_events` (#11469)" Revert "Support configuring the lifetime of non-refreshable access tokens separately to refreshable access tokens. (#11445)" Revert "Add type hints to `synapse/tests/rest/admin` (#11501)" Revert "Revert accidental commits to develop." Revert "Newsfile" Revert "Give `tests.server.setup_test_homeserver` (nominally!) the same behaviour" Revert "Move `tests.utils.setup_test_homeserver` to `tests.server`" Revert "Convert one of the `setup_test_homeserver`s to `make_test_homeserver_synchronous`" Revert "Disambiguate queries on `state_key` (#11497)" Revert "Comments on the /sync tentacles (#11494)" Revert "Clean up tests.storage.test_appservice (#11492)" Revert "Clean up `tests.storage.test_main` to remove use of legacy code. (#11493)" Revert "Clean up `tests.test_visibility` to remove legacy code. (#11495)" Revert "Minor cleanup on recently ported doc pages (#11466)" Revert "Add most of the missing type hints to `synapse.federation`. (#11483)" Revert "Avoid waiting for zombie processes in `synctl stop` (#11490)" Revert "Fix media repository failing when media store path contains symlinks (#11446)" Revert "Add type annotations to `tests.storage.test_appservice`. (#11488)" Revert "`scripts-dev/sign_json`: support for signing events (#11486)" Revert "Add MSC3030 experimental client and federation API endpoints to get the closest event to a given timestamp (#9445)" Revert "Port wiki pages to documentation website (#11402)" Revert "Add a license header and comment. (#11479)" Revert "Clean-up get_version_string (#11468)" Revert "Link background update controller docs to summary (#11475)" Revert "Additional type hints for config module. (#11465)" Revert "Register the login redirect endpoint for v3. (#11451)" Revert "Update openid.md" Revert "Remove mention of OIDC certification from Dex (#11470)" Revert "Add a note about huge pages to our Postgres doc (#11467)" Revert "Don't start Synapse master process if `worker_app` is set (#11416)" Revert "Expose worker & homeserver as entrypoints in `setup.py` (#11449)" Revert "Bundle relations of relations into the `/relations` result. (#11284)" Revert "Fix `LruCache` corruption bug with a `size_callback` that can return 0 (#11454)" Revert "Eliminate a few `Any`s in `LruCache` type hints (#11453)" Revert "Remove unnecessary `json.dumps` from `tests.rest.admin` (#11461)" Revert "Merge branch 'master' into develop" This reverts commit26b5d2320f
. This reverts commitbce4220f38
. This reverts commit966b5d0fa0
. This reverts commit088d748f2c
. This reverts commit14d593f72d
. This reverts commit2a3ec6facf
. This reverts commiteccc49d755
. This reverts commitb1ecd19c5d
. This reverts commit9c55dedc8c
. This reverts commit2d42e586a8
. This reverts commit2f053f3f82
. This reverts commita15a893df8
. This reverts commit8b4b153c9e
. This reverts commit494ebd7347
. This reverts commita77c369897
. This reverts commit4eb77965cd
. This reverts commit637df95de6
. This reverts commite5f426cd54
. This reverts commit8cd68b8102
. This reverts commit6cae125e20
. This reverts commit7be88fbf48
. This reverts commitb3fd99b74a
. This reverts commitf7ec6e7d9e
. This reverts commit5640992d17
. This reverts commitd26808dd85
. This reverts commitf91624a595
. This reverts commit16d39a5490
. This reverts commit8a4c296987
. This reverts commit49e1356ee3
. This reverts commitd2279f471b
. This reverts commitb50e39df57
. This reverts commit858d80bf0f
. This reverts commit435f044807
. This reverts commitf61462e1be
. This reverts commita6f1a3abec
. This reverts commit84dc50e160
. This reverts commited635d3285
. This reverts commit7b62791e00
. This reverts commit153194c771
. This reverts commitf44d729d4c
. This reverts commita265fbd397
. This reverts commitb9fef1a7cd
. This reverts commitb0eb64ff7b
. This reverts commitf1795463bf
. This reverts commit70cbb1a5e3
. This reverts commit42bf020463
. This reverts commit379f2650cf
. This reverts commit7ff22d6da4
. This reverts commit5a0b652d36
. This reverts commit432a174bc1
. This reverts commitb14f8a1baf
, reversing changes made toe713855dca
.
351 lines
11 KiB
Python
Executable File
351 lines
11 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright 2014-2016 OpenMarket Ltd
|
|
# Copyright 2018 New Vector Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import argparse
|
|
import collections
|
|
import errno
|
|
import glob
|
|
import os
|
|
import os.path
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from typing import Iterable
|
|
|
|
import yaml
|
|
|
|
from synapse.config import find_config_files
|
|
|
|
MAIN_PROCESS = "synapse.app.homeserver"
|
|
|
|
GREEN = "\x1b[1;32m"
|
|
YELLOW = "\x1b[1;33m"
|
|
RED = "\x1b[1;31m"
|
|
NORMAL = "\x1b[m"
|
|
|
|
|
|
def pid_running(pid):
|
|
try:
|
|
os.kill(pid, 0)
|
|
return True
|
|
except OSError as err:
|
|
if err.errno == errno.EPERM:
|
|
return True
|
|
return False
|
|
|
|
|
|
def write(message, colour=NORMAL, stream=sys.stdout):
|
|
# Lets check if we're writing to a TTY before colouring
|
|
should_colour = False
|
|
try:
|
|
should_colour = stream.isatty()
|
|
except AttributeError:
|
|
# Just in case `isatty` isn't defined on everything. The python
|
|
# docs are incredibly vague.
|
|
pass
|
|
|
|
if not should_colour:
|
|
stream.write(message + "\n")
|
|
else:
|
|
stream.write(colour + message + NORMAL + "\n")
|
|
|
|
|
|
def abort(message, colour=RED, stream=sys.stderr):
|
|
write(message, colour, stream)
|
|
sys.exit(1)
|
|
|
|
|
|
def start(pidfile: str, app: str, config_files: Iterable[str], daemonize: bool) -> bool:
|
|
"""Attempts to start a synapse main or worker process.
|
|
Args:
|
|
pidfile: the pidfile we expect the process to create
|
|
app: the python module to run
|
|
config_files: config files to pass to synapse
|
|
daemonize: if True, will include a --daemonize argument to synapse
|
|
|
|
Returns:
|
|
True if the process started successfully or was already running
|
|
False if there was an error starting the process
|
|
"""
|
|
|
|
if os.path.exists(pidfile) and pid_running(int(open(pidfile).read())):
|
|
print(app + " already running")
|
|
return True
|
|
|
|
args = [sys.executable, "-m", app]
|
|
for c in config_files:
|
|
args += ["-c", c]
|
|
if daemonize:
|
|
args.append("--daemonize")
|
|
|
|
try:
|
|
subprocess.check_call(args)
|
|
write("started %s(%s)" % (app, ",".join(config_files)), colour=GREEN)
|
|
return True
|
|
except subprocess.CalledProcessError as e:
|
|
err = "%s(%s) failed to start (exit code: %d). Check the Synapse logfile" % (
|
|
app,
|
|
",".join(config_files),
|
|
e.returncode,
|
|
)
|
|
if daemonize:
|
|
err += ", or run synctl with --no-daemonize"
|
|
err += "."
|
|
write(err, colour=RED, stream=sys.stderr)
|
|
return False
|
|
|
|
|
|
def stop(pidfile: str, app: str) -> bool:
|
|
"""Attempts to kill a synapse worker from the pidfile.
|
|
Args:
|
|
pidfile: path to file containing worker's pid
|
|
app: name of the worker's appservice
|
|
|
|
Returns:
|
|
True if the process stopped successfully
|
|
False if process was already stopped or an error occured
|
|
"""
|
|
|
|
if os.path.exists(pidfile):
|
|
pid = int(open(pidfile).read())
|
|
try:
|
|
os.kill(pid, signal.SIGTERM)
|
|
write("stopped %s" % (app,), colour=GREEN)
|
|
return True
|
|
except OSError as err:
|
|
if err.errno == errno.ESRCH:
|
|
write("%s not running" % (app,), colour=YELLOW)
|
|
elif err.errno == errno.EPERM:
|
|
abort("Cannot stop %s: Operation not permitted" % (app,))
|
|
else:
|
|
abort("Cannot stop %s: Unknown error" % (app,))
|
|
return False
|
|
else:
|
|
write(
|
|
"No running worker of %s found (from %s)\nThe process might be managed by another controller (e.g. systemd)"
|
|
% (app, pidfile),
|
|
colour=YELLOW,
|
|
)
|
|
return False
|
|
|
|
|
|
Worker = collections.namedtuple(
|
|
"Worker", ["app", "configfile", "pidfile", "cache_factor", "cache_factors"]
|
|
)
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument(
|
|
"action",
|
|
choices=["start", "stop", "restart"],
|
|
help="whether to start, stop or restart the synapse",
|
|
)
|
|
parser.add_argument(
|
|
"configfile",
|
|
nargs="?",
|
|
default="homeserver.yaml",
|
|
help="the homeserver config file. Defaults to homeserver.yaml. May also be"
|
|
" a directory with *.yaml files",
|
|
)
|
|
parser.add_argument(
|
|
"-w", "--worker", metavar="WORKERCONFIG", help="start or stop a single worker"
|
|
)
|
|
parser.add_argument(
|
|
"-a",
|
|
"--all-processes",
|
|
metavar="WORKERCONFIGDIR",
|
|
help="start or stop all the workers in the given directory"
|
|
" and the main synapse process",
|
|
)
|
|
parser.add_argument(
|
|
"--no-daemonize",
|
|
action="store_false",
|
|
dest="daemonize",
|
|
help="Run synapse in the foreground for debugging. "
|
|
"Will work only if the daemonize option is not set in the config.",
|
|
)
|
|
|
|
options = parser.parse_args()
|
|
|
|
if options.worker and options.all_processes:
|
|
write('Cannot use "--worker" with "--all-processes"', stream=sys.stderr)
|
|
sys.exit(1)
|
|
if not options.daemonize and options.all_processes:
|
|
write('Cannot use "--no-daemonize" with "--all-processes"', stream=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
configfile = options.configfile
|
|
|
|
if not os.path.exists(configfile):
|
|
write(
|
|
f"Config file {configfile} does not exist.\n"
|
|
f"To generate a config file, run:\n"
|
|
f" {sys.executable} -m {MAIN_PROCESS}"
|
|
f" -c {configfile} --generate-config"
|
|
f" --server-name=<server name> --report-stats=<yes/no>\n",
|
|
stream=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
config_files = find_config_files([configfile])
|
|
config = {}
|
|
for config_file in config_files:
|
|
with open(config_file) as file_stream:
|
|
yaml_config = yaml.safe_load(file_stream)
|
|
if yaml_config is not None:
|
|
config.update(yaml_config)
|
|
|
|
pidfile = config["pid_file"]
|
|
cache_factor = config.get("synctl_cache_factor")
|
|
start_stop_synapse = True
|
|
|
|
if cache_factor:
|
|
os.environ["SYNAPSE_CACHE_FACTOR"] = str(cache_factor)
|
|
|
|
cache_factors = config.get("synctl_cache_factors", {})
|
|
for cache_name, factor in cache_factors.items():
|
|
os.environ["SYNAPSE_CACHE_FACTOR_" + cache_name.upper()] = str(factor)
|
|
|
|
worker_configfiles = []
|
|
if options.worker:
|
|
start_stop_synapse = False
|
|
worker_configfile = options.worker
|
|
if not os.path.exists(worker_configfile):
|
|
write(
|
|
"No worker config found at %r" % (worker_configfile,), stream=sys.stderr
|
|
)
|
|
sys.exit(1)
|
|
worker_configfiles.append(worker_configfile)
|
|
|
|
if options.all_processes:
|
|
# To start the main synapse with -a you need to add a worker file
|
|
# with worker_app == "synapse.app.homeserver"
|
|
start_stop_synapse = False
|
|
worker_configdir = options.all_processes
|
|
if not os.path.isdir(worker_configdir):
|
|
write(
|
|
"No worker config directory found at %r" % (worker_configdir,),
|
|
stream=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
worker_configfiles.extend(
|
|
sorted(glob.glob(os.path.join(worker_configdir, "*.yaml")))
|
|
)
|
|
|
|
workers = []
|
|
for worker_configfile in worker_configfiles:
|
|
with open(worker_configfile) as stream:
|
|
worker_config = yaml.safe_load(stream)
|
|
worker_app = worker_config["worker_app"]
|
|
if worker_app == "synapse.app.homeserver":
|
|
# We need to special case all of this to pick up options that may
|
|
# be set in the main config file or in this worker config file.
|
|
worker_pidfile = worker_config.get("pid_file") or pidfile
|
|
worker_cache_factor = (
|
|
worker_config.get("synctl_cache_factor") or cache_factor
|
|
)
|
|
worker_cache_factors = (
|
|
worker_config.get("synctl_cache_factors") or cache_factors
|
|
)
|
|
# The master process doesn't support using worker_* config.
|
|
for key in worker_config:
|
|
if key == "worker_app": # But we allow worker_app
|
|
continue
|
|
assert not key.startswith(
|
|
"worker_"
|
|
), "Main process cannot use worker_* config"
|
|
else:
|
|
worker_pidfile = worker_config["worker_pid_file"]
|
|
worker_cache_factor = worker_config.get("synctl_cache_factor")
|
|
worker_cache_factors = worker_config.get("synctl_cache_factors", {})
|
|
workers.append(
|
|
Worker(
|
|
worker_app,
|
|
worker_configfile,
|
|
worker_pidfile,
|
|
worker_cache_factor,
|
|
worker_cache_factors,
|
|
)
|
|
)
|
|
|
|
action = options.action
|
|
|
|
if action == "stop" or action == "restart":
|
|
has_stopped = True
|
|
for worker in workers:
|
|
if not stop(worker.pidfile, worker.app):
|
|
# A worker could not be stopped.
|
|
has_stopped = False
|
|
|
|
if start_stop_synapse:
|
|
if not stop(pidfile, MAIN_PROCESS):
|
|
has_stopped = False
|
|
if not has_stopped and action == "stop":
|
|
sys.exit(1)
|
|
|
|
# Wait for synapse to actually shutdown before starting it again
|
|
if action == "restart":
|
|
running_pids = []
|
|
if start_stop_synapse and os.path.exists(pidfile):
|
|
running_pids.append(int(open(pidfile).read()))
|
|
for worker in workers:
|
|
if os.path.exists(worker.pidfile):
|
|
running_pids.append(int(open(worker.pidfile).read()))
|
|
if len(running_pids) > 0:
|
|
write("Waiting for process to exit before restarting...")
|
|
for running_pid in running_pids:
|
|
while pid_running(running_pid):
|
|
time.sleep(0.2)
|
|
write("All processes exited; now restarting...")
|
|
|
|
if action == "start" or action == "restart":
|
|
error = False
|
|
if start_stop_synapse:
|
|
if not start(pidfile, MAIN_PROCESS, (configfile,), options.daemonize):
|
|
error = True
|
|
|
|
for worker in workers:
|
|
env = os.environ.copy()
|
|
|
|
if worker.cache_factor:
|
|
os.environ["SYNAPSE_CACHE_FACTOR"] = str(worker.cache_factor)
|
|
|
|
for cache_name, factor in worker.cache_factors.items():
|
|
os.environ["SYNAPSE_CACHE_FACTOR_" + cache_name.upper()] = str(factor)
|
|
|
|
if not start(
|
|
worker.pidfile,
|
|
worker.app,
|
|
(configfile, worker.configfile),
|
|
options.daemonize,
|
|
):
|
|
error = True
|
|
|
|
# Reset env back to the original
|
|
os.environ.clear()
|
|
os.environ.update(env)
|
|
|
|
if error:
|
|
exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|