Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:58:23

0001 #!/usr/bin/env python3
0002 #
0003 # Licensed under the Apache License, Version 2.0 (the "License");
0004 # You may not use this file except in compliance with the License.
0005 # You may obtain a copy of the License at
0006 # http://www.apache.org/licenses/LICENSE-2.0OA
0007 #
0008 # Authors:
0009 # - Wen Guan, <wen.guan@cern.ch>, 2019 - 2025
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 # Path helpers
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 # Template rewrite functions
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 # Main entry point
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     # 1. Apache httpd conf templates
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     # 2. WSGI entry-point
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()