File indexing completed on 2026-04-09 07:58:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 """
0012 Post-install / startup helper: resolve and rewrite iDDS path templates.
0013
0014 Run this script on the target machine AFTER pip-installing the iDDS server
0015 package (or at container startup via start-daemon.sh). It uses the *running*
0016 Python interpreter's prefix/site-packages/bin paths so that no build-time
0017 temporary paths are ever embedded.
0018
0019 Usage
0020 -----
0021 python3 /opt/idds/tools/env/setup_idds_path.py [--prefix /opt/idds]
0022
0023 Two things are done:
0024
0025 1. replace_python_path
0026 For every ``*.conf.template`` found under ``<prefix>/etc/idds/rest/``,
0027 expand ``{python_site_packages_path}``, ``{python_site_home_path}``, and
0028 ``{python_site_bin_path}`` and write a ``*.conf.install_template`` beside it.
0029 The install_template can then be copied to ``/etc/httpd/conf.d/``.
0030
0031 2. replace_data_path
0032 Copy ``<prefix>/bin/idds.wsgi.template`` → ``<prefix>/bin/idds.wsgi``.
0033 The template already computes ``IDDS_CONFIG`` from ``sys.prefix`` at runtime,
0034 so no paths are hard-coded.
0035 """
0036
0037 import argparse
0038 import glob
0039 import io
0040 import os
0041 import sys
0042 import sysconfig
0043
0044
0045
0046
0047
0048
0049 def get_python_lib():
0050 return sysconfig.get_paths()["purelib"]
0051
0052
0053 def get_python_bin_path():
0054 return sysconfig.get_paths()["scripts"]
0055
0056
0057 def get_python_home():
0058 return sys.exec_prefix
0059
0060
0061 def get_data_path():
0062 return sysconfig.get_paths()["data"]
0063
0064
0065
0066
0067
0068
0069 def replace_python_path(conf_files, python_lib_path, install_bin_path, install_home_path):
0070 """Expand Python path placeholders in Apache conf templates.
0071
0072 For each ``*.conf.template`` file in *conf_files*, substitute:
0073 - ``{python_site_packages_path}`` → *python_lib_path*
0074 - ``{python_site_home_path}`` → *install_home_path*
0075 - ``{python_site_bin_path}`` → *install_bin_path*
0076
0077 and write the result as a ``*.conf.install_template`` beside the source.
0078 """
0079 for conf_file in conf_files:
0080 if not os.path.exists(conf_file):
0081 print(f" [skip] {conf_file} (not found)")
0082 continue
0083 new_file = conf_file.replace('.template', '.install_template')
0084 with io.open(conf_file, 'r', encoding='utf8') as f:
0085 template = f.read()
0086 rendered = template.format(
0087 python_site_packages_path=python_lib_path,
0088 GLOBAL='GLOBAL',
0089 REQUEST_METHOD='REQUEST_METHOD',
0090 python_site_home_path=install_home_path,
0091 python_site_bin_path=install_bin_path,
0092 )
0093 with io.open(new_file, 'w', encoding='utf8') as f:
0094 f.write(rendered)
0095 print(f" [ok] {conf_file}")
0096 print(f" -> {new_file}")
0097
0098
0099 def replace_data_path(wsgi_file, install_data_path=None):
0100 """Generate the WSGI entry-point from its template.
0101
0102 Simply copies ``idds.wsgi.template`` → ``idds.wsgi``. The template itself
0103 computes ``IDDS_CONFIG`` from ``sys.prefix`` at runtime, so no build-time
0104 path is baked in. *install_data_path* is accepted for API compatibility but
0105 is not used.
0106 """
0107 if not os.path.exists(wsgi_file):
0108 print(f" [skip] {wsgi_file} (not found)")
0109 return
0110 new_file = wsgi_file.replace('.template', '')
0111 with io.open(wsgi_file, 'r', encoding='utf8') as f:
0112 template = f.read()
0113 with io.open(new_file, 'w', encoding='utf8') as f:
0114 f.write(template)
0115 print(f" [ok] {wsgi_file}")
0116 print(f" -> {new_file}")
0117
0118
0119
0120
0121
0122
0123 def main():
0124 parser = argparse.ArgumentParser(
0125 description="Rewrite iDDS Apache conf and WSGI templates with installed Python paths."
0126 )
0127 parser.add_argument(
0128 "--prefix",
0129 default=None,
0130 help=(
0131 "iDDS install prefix (default: sys.prefix of the running interpreter). "
0132 "Activate the correct conda env / venv before running so that "
0133 "site-packages and bin paths are resolved correctly."
0134 ),
0135 )
0136 args = parser.parse_args()
0137
0138 prefix = args.prefix or sys.prefix
0139
0140 python_lib_path = get_python_lib()
0141 install_bin_path = get_python_bin_path()
0142 install_home_path = get_python_home()
0143
0144 print("=== iDDS path setup ===")
0145 print(f"Install prefix : {prefix}")
0146 print(f"Site-packages : {python_lib_path}")
0147 print(f"Bin path : {install_bin_path}")
0148 print(f"Python home : {install_home_path}")
0149 print()
0150
0151
0152 template_glob = os.path.join(prefix, "etc", "idds", "rest", "*.conf.template")
0153 conf_files = sorted(glob.glob(template_glob))
0154
0155 if conf_files:
0156 print(f"Generating Apache conf .install_template files ({len(conf_files)} found):")
0157 replace_python_path(conf_files, python_lib_path, install_bin_path, install_home_path)
0158 else:
0159 print(f"[info] No *.conf.template files found under {template_glob}")
0160
0161 print()
0162
0163
0164 wsgi_template = os.path.join(install_bin_path, "idds.wsgi.template")
0165 print("Generating idds.wsgi from template:")
0166 replace_data_path(wsgi_template)
0167
0168 print()
0169 print("Done.")
0170 if conf_files:
0171 print("Copy the desired .install_template to /etc/httpd/conf.d/ to activate, e.g.:")
0172 print(f" cp {prefix}/etc/idds/rest/httpd-idds-443-py39-cc7.conf.install_template \\")
0173 print(" /etc/httpd/conf.d/httpd-idds-443-py39-cc7.conf")
0174
0175
0176 if __name__ == "__main__":
0177 main()