blob: 33642162aafa9d71d9e92b82f9a0d2da3c93883e [file] [log] [blame]
Philipp Schraderd0e33a42022-01-22 21:55:15 -08001"""Starts up Apache to provide HTTPS + LDAP for another web server.
2
3This script is used by the apache_wrapper() rule as the main entrypoint for its
4"executable". This script sets up a minimal Apache environment in a directory
5in /tmp.
6
7Both Apache and the wrapped server binary are started by this script. The
8wrapped server should bind to the port specified by the APACHE_WRAPPED_PORT
9environment variable.
10
11See the documentation for apache_wrapper() for more information.
12"""
13
14import argparse
15import json
16import os
17from pathlib import Path
18import signal
19import subprocess
20import sys
21import tempfile
22
23import jinja2
24
25DUMMY_CERT_ANSWERS = """\
26US
27California
28Mountain View
29FRC971
30Software
31frc971.org
32dummy@frc971.org
33"""
34
35def main(argv):
36 parser = argparse.ArgumentParser()
37 parser.add_argument("--binary", type=str, required=True)
38 parser.add_argument("--https_port", type=int, default=7000)
39 parser.add_argument("--wrapped_port", type=int, default=7500)
40 parser.add_argument(
41 "--ldap_info",
42 type=str,
43 help="JSON file containing 'ldap_bind_dn', 'ldap_url', and 'ldap_password' entries.",
44 default="",
45 )
46 args = parser.parse_args(argv[1:])
47
48 if not args.ldap_info:
49 args.ldap_info = os.path.join(os.environ["BUILD_WORKSPACE_DIRECTORY"], "ldap.json")
50
51 with open("tools/build_rules/apache_template.conf", "r") as file:
52 template = jinja2.Template(file.read())
53
54 with open(args.ldap_info, "r") as file:
55 substitutions = json.load(file)
56
57 for key in ("ldap_bind_dn", "ldap_url", "ldap_password"):
58 if key not in substitutions:
59 raise KeyError(f"The ldap_info JSON file must contain key '{key}'.")
60
61 substitutions.update({
62 "https_port": args.https_port,
63 "wrapped_port": args.wrapped_port,
64 })
65
66 config_text = template.render(substitutions)
67
68 with tempfile.TemporaryDirectory() as temp_dir:
69 temp_dir = Path(temp_dir)
70 with open(temp_dir / "apache2.conf", "w") as file:
71 file.write(config_text)
72
73 # Create a directory for error logs and such.
74 logs_dir = temp_dir / "logs"
75 os.mkdir(logs_dir)
76
77 print("-" * 60)
78 print(f"Logs are in {logs_dir}/")
79 print("-" * 60)
80
81 # Make modules available.
82 modules_path = Path("external/apache2/usr/lib/apache2/modules")
83 os.symlink(modules_path.resolve(), temp_dir / "modules")
84
85 # Generate a testing cert.
86 subprocess.run([
87 "openssl",
88 "req",
89 "-x509",
90 "-nodes",
91 "-days=365",
92 "-newkey=rsa:2048",
93 "-keyout=" + str(temp_dir / "apache-selfsigned.key"),
94 "-out=" + str(temp_dir / "apache-selfsigned.crt"),
95 ],
96 check=True,
97 input=DUMMY_CERT_ANSWERS,
98 text=True,
99 )
100
101 # Start the wrapped binary in the background.
102 # Tell it via the environment what port to listen on.
103 env = os.environ.copy()
104 env["APACHE_WRAPPED_PORT"] = str(args.wrapped_port)
105 wrapped_binary = subprocess.Popen([args.binary], env=env)
106
107 # Start the apache server.
108 env = os.environ.copy()
109 env["LD_LIBRARY_PATH"] = "external/apache2/usr/lib/x86_64-linux-gnu"
110 try:
111 subprocess.run(
112 ["external/apache2/usr/sbin/apache2", "-X", "-d", str(temp_dir)],
113 check=True,
114 env=env,
115 )
116 finally:
117 wrapped_binary.send_signal(signal.SIGINT)
118 wrapped_binary.wait()
119
120if __name__ == "__main__":
121 sys.exit(main(sys.argv))