Source code for schrodinger.job.server
"""
Interact with a Job Server.
"""
import json
import os
from typing import NamedTuple
from typing import Union
from schrodinger.utils import subprocess
[docs]def ensure_localhost_server_running():
    """
    Makes sure there is a localhost jobserver running to do devtests.
    This server is configured in the default location.
    """
    proc = subprocess.run(
        [jsc(os.environ["SCHRODINGER"]), "local-server-start"],
        stderr=subprocess.STDOUT,
        stdout=subprocess.PIPE)
    if proc.returncode != 0:
        raise RuntimeError(
            f"localhost job server failed to start with error {proc.stdout}") 
[docs]def jsc(schrodinger):
    return f"{schrodinger}/jsc" 
[docs]class ServerInfo(NamedTuple):
    """
    ServerInfo is a serialization of a jobs protobuf ServerInfoResponse.
    See "jobs.proto" for more up-to-date details on each of these fields.
    It is created manually instead of generated by protoc because this is
    currently a niche data structure only used for generating a cert. It's not
    worth the time to incorporate the generation into our build steps or to wrap
    from c++ using SWIG because the raw data must come serialized from jsc
    anyway - see "get_server_info" for details.
    """
    # webServerSecret is a deprecated field not relevant to most users.
    webServerSecret: str
    # hasLicenseChecking indicates whether the server has license checking.
    hasLicenseChecking: bool
    # hasServerAuth indicates whether the server has LDAP Authentication enabled.
    hasServerAuth: bool
    # hasSocketAuth indicates whether the server has Unix socket authentication enabled.
    hasSocketAuth: bool
    # authSocketPath is the path to the unix socket on the job server, if hasSocketAuth is True.
    authSocketPath: str
    # versionString is the version string for the job server, of the form "55000 revision={git_hash}"
    versionString: str
    # APIVersion is the API version of the jobserver.
    APIVersion: str
    # hostname is the hostname of the jobserver as specified on its TLS certificate.
    # It must be DNS-resolvable from a client machine in order to make a connection.
    hostname: str
    # databaseType is the database system used by the job server (either "sqlite" or "postgres")
    databaseType: str
    # schrodingerInstallation is a path to ANY schrodinger installation known by the job server.
    schrodingerInstallation: str
[docs]    @classmethod
    def from_dict(cls, data: dict) -> "ServerInfo":
        """
        Convert a dict to a ServerInfo.
        """
        return ServerInfo(**{field: data[field] for field in cls._fields}) 
[docs]    def has_authenticator(self) -> bool:
        return self.hasServerAuth or self.hasSocketAuth  
[docs]def get_server_info(schrodinger: str, address: str) -> ServerInfo:
    """
    Subprocess '$SCHRODINGER/jsc server-info' to get server information.
    This must be collected from jsc (the Go gRPC JobServerClient cli) because
    the c++ gRPC client doesn't support TLS connections to jobserver until we
    already have a cert.
    """
    server_info_command = [jsc(schrodinger), "server-info", "--json", address]
    proc = subprocess.run(server_info_command,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.STDOUT)
    if proc.returncode:
        raise RuntimeError(
            f"Could not get server info from job server: {address}.\n"
            f"Ran command: '{server_info_command}' with output: '{proc.stdout!r}'"
            f"with exit code: '{proc.returncode}.'")
    info = decode_to_server_info(proc.stdout)
    return info 
[docs]def decode_to_server_info(data: Union[str, bytes]) -> ServerInfo:
    info_json = json.loads(data)
    server_info = ServerInfo.from_dict(info_json)
    return server_info