()
This script intercepts the --show-progress-page flag, but all other flags
    are passed through to the TLJH installer script.

    The --show-progress-page flag indicates that the bootstrap script should
    start a local webserver temporarily and report its installation progress via
    a web site served locally on port 80.
This script intercepts the --show-progress-page flag, but all other flags
    are passed through to the TLJH installer script.
This script intercepts the -- show - progress - page flag but all other flags are passed through to the TLJH installer script .
def main():
    """
    This script intercepts the --show-progress-page flag, but all other flags
    are passed through to the TLJH installer script.

    The --show-progress-page flag indicates that the bootstrap script should
    start a local webserver temporarily and report its installation progress via
    a web site served locally on port 80.
    """
    ensure_host_system_can_install_tljh()

    # Various related constants
    install_prefix = os.environ.get("TLJH_INSTALL_PREFIX", "/opt/tljh")
    hub_prefix = os.path.join(install_prefix, "hub")
    python_bin = os.path.join(hub_prefix, "bin", "python3")
    pip_bin = os.path.join(hub_prefix, "bin", "pip")
    initial_setup = not os.path.exists(python_bin)

    # Attempt to start a web server to serve a progress page reporting
    # installation progress.
    tljh_installer_flags = sys.argv[1:]
    if "--show-progress-page" in tljh_installer_flags:
        # Remove the bootstrap specific flag and let all other flags pass
        # through to the installer.
        tljh_installer_flags.remove("--show-progress-page")

        # Write HTML and a favicon to be served by our webserver
        with open("/var/run/index.html", "w+") as f:
            f.write(progress_page_html)
        urllib.request.urlretrieve(progress_page_favicon_url, "/var/run/favicon.ico")

        # If TLJH is already installed and Traefik is already running, port 80
        # will be busy and we will get an "Address already in use" error. This
        # is acceptable and we can ignore the error.
        try:
            # Serve the loading page until manually aborted or until the TLJH
            # installer terminates the process
            def serve_forever(server):
                try:
                    server.serve_forever()
                except KeyboardInterrupt:
                    pass

            progress_page_server = HTTPServer(("", 80), ProgressPageRequestHandler)
            p = multiprocessing.Process(
                target=serve_forever, args=(progress_page_server,)
            )
            p.start()

            # Pass the server's pid to the installer for later termination
            tljh_installer_flags.extend(["--progress-page-server-pid", str(p.pid)])
        except OSError:
            pass

    # Set up logging to print to a file and to stderr
    os.makedirs(install_prefix, exist_ok=True)
    file_logger_path = os.path.join(install_prefix, "installer.log")
    file_logger = logging.FileHandler(file_logger_path)
    # installer.log should be readable only by root
    os.chmod(file_logger_path, 0o500)

    file_logger.setFormatter(logging.Formatter("%(asctime)s %(message)s"))
    file_logger.setLevel(logging.DEBUG)
    logger.addHandler(file_logger)

    stderr_logger = logging.StreamHandler()
    stderr_logger.setFormatter(logging.Formatter("%(message)s"))
    stderr_logger.setLevel(logging.INFO)
    logger.addHandler(stderr_logger)

    logger.setLevel(logging.DEBUG)

    if not initial_setup:
        logger.info("Existing TLJH installation detected, upgrading...")
    else:
        logger.info("Existing TLJH installation not detected, installing...")
        logger.info("Setting up hub environment...")
        logger.info("Installing Python, venv, pip, and git via apt-get...")

        # In some very minimal base VM images, it looks like the "universe" apt
        # package repository is disabled by default, causing bootstrapping to
        # fail. We install the software-properties-common package so we can get
        # the add-apt-repository command to make sure the universe repository is
        # enabled, since that's where the python3-pip package lives.
        #
        # In Ubuntu 21.10 DEBIAN_FRONTEND has found to be needed to avoid
        # getting stuck on an input prompt during apt-get install.
        #
        apt_get_adjusted_env = os.environ.copy()
        apt_get_adjusted_env["DEBIAN_FRONTEND"] = "noninteractive"
        run_subprocess(["apt-get", "update"])
        run_subprocess(
            ["apt-get", "install", "--yes", "software-properties-common"],
            env=apt_get_adjusted_env,
        )
        run_subprocess(["add-apt-repository", "universe", "--yes"])
        run_subprocess(["apt-get", "update"])
        run_subprocess(
            [
                "apt-get",
                "install",
                "--yes",
                "python3",
                "python3-venv",
                "python3-pip",
                "git",
            ],
            env=apt_get_adjusted_env,
        )

        logger.info("Setting up virtual environment at {}".format(hub_prefix))
        os.makedirs(hub_prefix, exist_ok=True)
        run_subprocess(["python3", "-m", "venv", hub_prefix])

    # Upgrade pip
    # Keep pip version pinning in sync with the one in unit-test.yml!
    # See changelog at https://pip.pypa.io/en/latest/news/#changelog
    logger.info("Upgrading pip...")
    run_subprocess([pip_bin, "install", "--upgrade", "pip==21.3.*"])

    # Install/upgrade TLJH installer
    tljh_install_cmd = [pip_bin, "install", "--upgrade"]
    if os.environ.get("TLJH_BOOTSTRAP_DEV", "no") == "yes":
        tljh_install_cmd.append("--editable")
    tljh_install_cmd.append(
        os.environ.get(
            "TLJH_BOOTSTRAP_PIP_SPEC",
            "git+https://github.com/jupyterhub/the-littlest-jupyterhub.git",
        )
    )
    if initial_setup:
        logger.info("Installing TLJH installer...")
    else:
        logger.info("Upgrading TLJH installer...")
    run_subprocess(tljh_install_cmd)

    # Run TLJH installer
    logger.info("Running TLJH installer...")
    os.execv(python_bin, [python_bin, "-m", "tljh.installer"] + tljh_installer_flags)
def main ( ) : ensure_host_system_can_install_tljh ( ) # Various related constants install_prefix = os . environ . get ( "TLJH_INSTALL_PREFIX" , "/opt/tljh" ) hub_prefix = os . path . join ( install_prefix , "hub" ) python_bin = os . path . join ( hub_prefix , "bin" , "python3" ) pip_bin = os . path . join ( hub_prefix , "bin" , "pip" ) initial_setup = not os . path . exists ( python_bin ) # Attempt to start a web server to serve a progress page reporting # installation progress. tljh_installer_flags = sys . argv [ 1 : ] if "--show-progress-page" in tljh_installer_flags : # Remove the bootstrap specific flag and let all other flags pass # through to the installer. tljh_installer_flags . remove ( "--show-progress-page" ) # Write HTML and a favicon to be served by our webserver with open ( "/var/run/index.html" , "w+" ) as f : f . write ( progress_page_html ) urllib . request . urlretrieve ( progress_page_favicon_url , "/var/run/favicon.ico" ) # If TLJH is already installed and Traefik is already running, port 80 # will be busy and we will get an "Address already in use" error. This # is acceptable and we can ignore the error. try : # Serve the loading page until manually aborted or until the TLJH # installer terminates the process def serve_forever ( server ) : try : server . serve_forever ( ) except KeyboardInterrupt : pass progress_page_server = HTTPServer ( ( "" , 80 ) , ProgressPageRequestHandler ) p = multiprocessing . Process ( target = serve_forever , args = ( progress_page_server , ) ) p . start ( ) # Pass the server's pid to the installer for later termination tljh_installer_flags . extend ( [ "--progress-page-server-pid" , str ( p . pid ) ] ) except OSError : pass # Set up logging to print to a file and to stderr os . makedirs ( install_prefix , exist_ok = True ) file_logger_path = os . path . join ( install_prefix , "installer.log" ) file_logger = logging . FileHandler ( file_logger_path ) # installer.log should be readable only by root os . chmod ( file_logger_path , 0o500 ) file_logger . setFormatter ( logging . Formatter ( "%(asctime)s %(message)s" ) ) file_logger . setLevel ( logging . DEBUG ) logger . addHandler ( file_logger ) stderr_logger = logging . StreamHandler ( ) stderr_logger . setFormatter ( logging . Formatter ( "%(message)s" ) ) stderr_logger . setLevel ( logging . INFO ) logger . addHandler ( stderr_logger ) logger . setLevel ( logging . DEBUG ) if not initial_setup : logger . info ( "Existing TLJH installation detected, upgrading..." ) else : logger . info ( "Existing TLJH installation not detected, installing..." ) logger . info ( "Setting up hub environment..." ) logger . info ( "Installing Python, venv, pip, and git via apt-get..." ) # In some very minimal base VM images, it looks like the "universe" apt # package repository is disabled by default, causing bootstrapping to # fail. We install the software-properties-common package so we can get # the add-apt-repository command to make sure the universe repository is # enabled, since that's where the python3-pip package lives. # # In Ubuntu 21.10 DEBIAN_FRONTEND has found to be needed to avoid # getting stuck on an input prompt during apt-get install. # apt_get_adjusted_env = os . environ . copy ( ) apt_get_adjusted_env [ "DEBIAN_FRONTEND" ] = "noninteractive" run_subprocess ( [ "apt-get" , "update" ] ) run_subprocess ( [ "apt-get" , "install" , "--yes" , "software-properties-common" ] , env = apt_get_adjusted_env , ) run_subprocess ( [ "add-apt-repository" , "universe" , "--yes" ] ) run_subprocess ( [ "apt-get" , "update" ] ) run_subprocess ( [ "apt-get" , "install" , "--yes" , "python3" , "python3-venv" , "python3-pip" , "git" , ] , env = apt_get_adjusted_env , ) logger . info ( "Setting up virtual environment at {}" . format ( hub_prefix ) ) os . makedirs ( hub_prefix , exist_ok = True ) run_subprocess ( [ "python3" , "-m" , "venv" , hub_prefix ] ) # Upgrade pip # Keep pip version pinning in sync with the one in unit-test.yml! # See changelog at https://pip.pypa.io/en/latest/news/#changelog logger . info ( "Upgrading pip..." ) run_subprocess ( [ pip_bin , "install" , "--upgrade" , "pip==21.3.*" ] ) # Install/upgrade TLJH installer tljh_install_cmd = [ pip_bin , "install" , "--upgrade" ] if os . environ . get ( "TLJH_BOOTSTRAP_DEV" , "no" ) == "yes" : tljh_install_cmd . append ( "--editable" ) tljh_install_cmd . append ( os . environ . get ( "TLJH_BOOTSTRAP_PIP_SPEC" , "git+https://github.com/jupyterhub/the-littlest-jupyterhub.git" , ) ) if initial_setup : logger . info ( "Installing TLJH installer..." ) else : logger . info ( "Upgrading TLJH installer..." ) run_subprocess ( tljh_install_cmd ) # Run TLJH installer logger . info ( "Running TLJH installer..." ) os . execv ( python_bin , [ python_bin , "-m" , "tljh.installer" ] + tljh_installer_flags )