mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 20:13:46 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			111 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| import argparse
 | |
| import filecmp
 | |
| import json
 | |
| import os
 | |
| import subprocess
 | |
| import sys
 | |
| from typing import Any, Dict
 | |
| 
 | |
| BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 | |
| sys.path.append(BASE_DIR)
 | |
| from scripts.lib.setup_path import setup_path
 | |
| 
 | |
| setup_path()
 | |
| 
 | |
| from scripts.lib.zulip_tools import get_config_file, get_tornado_ports
 | |
| 
 | |
| 
 | |
| def write_realm_nginx_config_line(f: Any, host: str, port: str) -> None:
 | |
|     f.write(
 | |
|         f"""if ($host = '{host}') {{
 | |
|     set $tornado_server http://tornado{port};
 | |
| }}\n"""
 | |
|     )
 | |
| 
 | |
| 
 | |
| # Basic system to do Tornado sharding.  Writes two output .tmp files that need
 | |
| # to be renamed to the following files to finalize the changes:
 | |
| # * /etc/zulip/nginx_sharding.conf; nginx needs to be reloaded after changing.
 | |
| # * /etc/zulip/sharding.json; supervisor Django process needs to be reloaded
 | |
| # after changing.  TODO: We can probably make this live-reload by statting the file.
 | |
| #
 | |
| # TODO: Restructure this to automatically generate a sharding layout.
 | |
| def write_updated_configs() -> None:
 | |
|     config_file = get_config_file()
 | |
|     ports = get_tornado_ports(config_file)
 | |
| 
 | |
|     expected_ports = list(range(9800, max(ports) + 1))
 | |
|     assert (
 | |
|         sorted(ports) == expected_ports
 | |
|     ), f"ports ({sorted(ports)}) must be contiguous, starting with 9800"
 | |
| 
 | |
|     with open("/etc/zulip/nginx_sharding.conf.tmp", "w") as nginx_sharding_conf_f, open(
 | |
|         "/etc/zulip/sharding.json.tmp", "w"
 | |
|     ) as sharding_json_f:
 | |
| 
 | |
|         if len(ports) == 1:
 | |
|             nginx_sharding_conf_f.write("set $tornado_server http://tornado;\n")
 | |
|             sharding_json_f.write("{}\n")
 | |
|             return
 | |
| 
 | |
|         nginx_sharding_conf_f.write("set $tornado_server http://tornado9800;\n")
 | |
|         shard_map: Dict[str, int] = {}
 | |
|         external_host = subprocess.check_output(
 | |
|             [os.path.join(BASE_DIR, "scripts/get-django-setting"), "EXTERNAL_HOST"],
 | |
|             universal_newlines=True,
 | |
|         ).strip()
 | |
|         for port in config_file["tornado_sharding"]:
 | |
|             shards = config_file["tornado_sharding"][port].strip()
 | |
| 
 | |
|             if shards:
 | |
|                 for shard in shards.split(" "):
 | |
|                     if "." in shard:
 | |
|                         host = shard
 | |
|                     else:
 | |
|                         host = f"{shard}.{external_host}"
 | |
|                     assert host not in shard_map, f"host {host} duplicated"
 | |
|                     shard_map[host] = int(port)
 | |
|                     write_realm_nginx_config_line(nginx_sharding_conf_f, host, port)
 | |
|             nginx_sharding_conf_f.write("\n")
 | |
| 
 | |
|         sharding_json_f.write(json.dumps(shard_map) + "\n")
 | |
| 
 | |
| 
 | |
| parser = argparse.ArgumentParser(
 | |
|     description="Adjust Tornado sharding configuration",
 | |
| )
 | |
| parser.add_argument(
 | |
|     "--errors-ok",
 | |
|     action="store_true",
 | |
|     help="Exits 1 if there are no changes; if there are errors or changes, exits 0.",
 | |
| )
 | |
| options = parser.parse_args()
 | |
| 
 | |
| config_file_path = "/etc/zulip"
 | |
| base_files = ["nginx_sharding.conf", "sharding.json"]
 | |
| full_real_paths = [f"{config_file_path}/{filename}" for filename in base_files]
 | |
| full_new_paths = [f"{filename}.tmp" for filename in full_real_paths]
 | |
| try:
 | |
|     write_updated_configs()
 | |
|     for old, new in zip(full_real_paths, full_new_paths):
 | |
|         if not filecmp.cmp(old, new):
 | |
|             # There are changes; leave .tmp files and exit 0
 | |
|             if "SUPPRESS_SHARDING_NOTICE" not in os.environ:
 | |
|                 print("===> Updated sharding; run scripts/refresh-sharding-and-restart")
 | |
|             sys.exit(0)
 | |
|     # No changes; clean up and exit 1
 | |
|     for filename in full_new_paths:
 | |
|         os.unlink(filename)
 | |
|     sys.exit(1)
 | |
| except AssertionError as e:
 | |
|     # Clean up whichever files we made
 | |
|     for filename in full_new_paths:
 | |
|         if os.path.exists(filename):
 | |
|             os.unlink(filename)
 | |
|     if options.errors_ok:
 | |
|         sys.exit(0)
 | |
|     else:
 | |
|         print(e, file=sys.stderr)
 | |
|         sys.exit(2)
 |