コード例 #1
0
ファイル: views.py プロジェクト: SG345/ka-lite
def help_admin(request):
    context = {
        "wiki_url" : settings.CENTRAL_WIKI_URL,
        "ips": get_ip_addresses(include_loopback=False),
        "port": request.META.get("SERVER_PORT") or settings.USER_FACING_PORT(),
    }
    return context
コード例 #2
0
ファイル: views.py プロジェクト: zhudy/ka-lite
def help_admin(request):
    context = {
        "wiki_url": settings.CENTRAL_WIKI_URL,
        "ips": get_ip_addresses(include_loopback=False),
        "port": settings.USER_FACING_PORT,
    }
    return context
コード例 #3
0
ファイル: cli.py プロジェクト: ruimalheiro/ka-lite
def get_urls():
    """
    Fetch a list of urls
    :returns: STATUS_CODE, ['http://abcd:1234', ...]
    """
    try:
        __, __, port = get_pid()
        urls = []
        for addr in get_ip_addresses():
            urls.append("http://{}:{}/".format(addr, port))
        return STATUS_RUNNING, urls
    except NotRunning as e:
        return e.status_code, []
コード例 #4
0
ファイル: cli.py プロジェクト: arceduardvincent/ka-lite
def print_server_address(port):
    # Print output to user about where to find the server
    addresses = get_ip_addresses(include_loopback=False)
    print("To access KA Lite from another connected computer, try the following address(es):")
    for addr in addresses:
        print("\thttp://%s:%s/\n" % (addr, port))
    print("To access KA Lite from this machine, try the following address:")
    print("\thttp://127.0.0.1:%s/" % port)

    for addr in get_urls_proxy(output_pipe=sys.stdout):
        print("\t{}".format(addr))

    print("")
コード例 #5
0
ファイル: kalitectl.py プロジェクト: theaverageguy/ka-lite
def get_urls():
    """
    Fetch a list of urls
    :returns: STATUS_CODE, ['http://abcd:1234', ...]
    """
    try:
        __, __, port = get_pid()
        urls = []
        for addr in get_ip_addresses():
            urls.append("http://{}:{}/".format(addr, port))
        return STATUS_RUNNING, urls
    except NotRunning as e:
        return e.status_code, []
コード例 #6
0
ファイル: kalitectl.py プロジェクト: theaverageguy/ka-lite
def get_urls_proxy():
    """
    Get addresses of the server if we're using settings.PROXY_PORT

    :raises: Exception for sure if django.conf.settings isn't loaded
    """
    # Import settings and check if a proxy port exists
    from django.conf import settings
    if hasattr(settings, 'PROXY_PORT') and settings.PROXY_PORT:
        sys.stderr.write(
            "\nKA Lite configured behind another server, primary "
            "addresses are:\n\n"
        )
        for addr in get_ip_addresses():
            yield "http://{}:{}/".format(addr, settings.PROXY_PORT)
コード例 #7
0
def print_server_address(port):
    # Print output to user about where to find the server
    addresses = get_ip_addresses(include_loopback=False)
    print(
        "To access KA Lite from another connected computer, try the following address(es):"
    )
    for addr in addresses:
        print("\thttp://%s:%s/\n" % (addr, port))
    print("To access KA Lite from this machine, try the following address:")
    print("\thttp://127.0.0.1:%s/" % port)

    for addr in get_urls_proxy(output_pipe=sys.stdout):
        print("\t{}".format(addr))

    print("")
コード例 #8
0
ファイル: kalitectl.py プロジェクト: xuewenfei/ka-lite
def status():
    """
    Check the server's status. For possible statuses, see the status dictionary
    status.codes

    :returns: status_code, key has description in status.codes
    """
    try:
        __, __, port = get_pid()
        sys.stderr.write("{msg:s} (0)\n".format(msg=status.codes[0]))
        sys.stderr.write("KA Lite running on:\n\n")
        for addr in get_ip_addresses():
            sys.stderr.write("\thttp://%s:%s/\n" % (addr, port))
        return STATUS_RUNNING
    except NotRunning as e:
        status_code = e.status_code
        verbose_status = status.codes[status_code]
        sys.stderr.write("{msg:s} ({code:d})\n".format(
            code=status_code, msg=verbose_status))
        return status_code
コード例 #9
0
ファイル: kalitectl.py プロジェクト: glennhefley/ka-lite
def status():
    """
    Check the server's status. For possible statuses, see the status dictionary
    status.codes

    :returns: status_code, key has description in status.codes
    """
    try:
        __, __, port = get_pid()
        sys.stderr.write("{msg:s} (0)\n".format(msg=status.codes[0]))
        sys.stderr.write("KA Lite running on:\n\n")
        from fle_utils.internet.functions import get_ip_addresses
        for addr in get_ip_addresses():
            sys.stderr.write("\thttp://%s:%s/\n" % (addr, port))
        return 0
    except NotRunning as e:
        status_code = e.status_code
        verbose_status = status.codes[status_code]
        sys.stderr.write("{msg:s} ({code:d})\n".format(code=status_code,
                                                       msg=verbose_status))
        return status_code
コード例 #10
0
ファイル: kalitectl.py プロジェクト: rtibbles/ka-lite
def get_urls_proxy(output_pipe=sys.stderr):
    """
    Get addresses of the server if we're using settings.PROXY_PORT

    :raises: Exception for sure if django.conf.settings isn't loaded
    """
    # Import settings and check if a proxy port exists
    try:
        from django.conf import settings
    except Exception as e:
        output_pipe.write("\n\nWarning, exception fetching KA Lite settings module:\n\n" + str(e) + "\n\n")
        return
    if (
        hasattr(settings, "USER_FACING_PORT")
        and settings.USER_FACING_PORT
        and hasattr(settings, "HTTP_PORT")
        and not settings.USER_FACING_PORT == settings.HTTP_PORT
    ):
        output_pipe.write("\nKA Lite configured behind another server, primary " "addresses are:\n\n")
        for addr in get_ip_addresses():
            yield "http://{}:{}/".format(addr, settings.USER_FACING_PORT)
コード例 #11
0
def get_urls_proxy(output_pipe=sys.stderr):
    """
    Get addresses of the server if we're using settings.PROXY_PORT

    :raises: Exception for sure if django.conf.settings isn't loaded
    """
    # Import settings and check if a proxy port exists
    try:
        from django.conf import settings
    except Exception as e:
        output_pipe.write(
            "\n\nWarning, exception fetching KA Lite settings module:\n\n" +
            str(e) + "\n\n")
        return
    if hasattr(settings, 'USER_FACING_PORT') and settings.USER_FACING_PORT and \
       hasattr(settings, 'HTTP_PORT') and \
       not settings.USER_FACING_PORT == settings.HTTP_PORT:
        output_pipe.write(
            "\nKA Lite configured behind another server, primary "
            "addresses are:\n\n")
        for addr in get_ip_addresses():
            yield "http://{}:{}/".format(addr, settings.USER_FACING_PORT)
コード例 #12
0
ファイル: cli.py プロジェクト: ruimalheiro/ka-lite
def start(debug=False, daemonize=True, args=[], skip_job_scheduler=False, port=None):
    """
    Start the kalite server as a daemon

    :param args: List of options to parse to the django management command
    :param port: Non-default port to bind to. You cannot run kalite on
                 multiple ports at the same time.
    :param daemonize: Default True, will run in foreground if False
    :param skip_job_scheduler: Skips running the job scheduler in a separate thread
    """
    # TODO: Do we want to fail if running as root?

    port = int(port or DEFAULT_LISTEN_PORT)

    if not daemonize:
        sys.stderr.write("Running 'kalite start' in foreground...\n")
    else:
        sys.stderr.write("Running 'kalite start' as daemon (system service)\n")

    sys.stderr.write("\nStand by while the server loads its data...\n\n")

    if os.path.exists(STARTUP_LOCK):
        try:
            pid, __ = read_pid_file(STARTUP_LOCK)
            # Does the PID in there still exist?
            if pid_exists(pid):
                sys.stderr.write(
                    "Refusing to start: Start up lock exists: {0:s}\n".format(STARTUP_LOCK))
                sys.stderr.write("Remove the file and try again.\n")
                sys.exit(1)
        # Couldn't parse to int
        except TypeError:
            pass

        os.unlink(STARTUP_LOCK)

    try:
        if get_pid():
            sys.stderr.write("Refusing to start: Already running\n")
            sys.stderr.write("Use 'kalite stop' to stop the instance.\n")
            sys.exit(1)
    except NotRunning:
        pass

    # Check that the port is available by creating a simple socket and see
    # if it succeeds... if it does, the port is occupied.
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connection_error = sock.connect_ex(('127.0.0.1', port))
    if not connection_error:
        sys.stderr.write(
            "Port {0} is occupied. Please close the process that is using "
            "it.\n".format(port)
        )
        sys.exit(1)

    # Write current PID and optional port to a startup lock file
    with open(STARTUP_LOCK, "w") as f:
        f.write("%s\n%d" % (str(os.getpid()), port))

    # Remove the startup lock at this point
    if STARTUP_LOCK:
        os.unlink(STARTUP_LOCK)

    # Daemonize at this point, no more user output is needed
    if daemonize:

        from django.utils.daemonize import become_daemon
        kwargs = {}
        # Truncate the file
        open(SERVER_LOG, "w").truncate()
        print("Going to daemon mode, logging to {0}".format(SERVER_LOG))
        kwargs['out_log'] = SERVER_LOG
        kwargs['err_log'] = SERVER_LOG
        become_daemon(**kwargs)
        # Write the new PID
        with open(PID_FILE, 'w') as f:
            f.write("%d\n%d" % (os.getpid(), port))

    manage('initialize_kalite')

    # Print output to user about where to find the server
    addresses = get_ip_addresses(include_loopback=False)
    sys.stdout.write("To access KA Lite from another connected computer, try the following address(es):\n")
    for addr in addresses:
        sys.stdout.write("\thttp://%s:%s/\n" % (addr, port))
    sys.stdout.write("To access KA Lite from this machine, try the following address:\n")
    sys.stdout.write("\thttp://127.0.0.1:%s/\n" % port)

    for addr in get_urls_proxy(output_pipe=sys.stdout):
        sys.stdout.write("\t{}\n".format(addr))

    sys.stdout.write("\n")

    # Start the job scheduler (not Celery yet...)
    cron_thread = None
    if not skip_job_scheduler:
        cron_thread = manage(
            'cronserver_blocking',
            args=[],
            as_thread=True
        )

    # Start cherrypy service
    cherrypy.config.update({
        'server.socket_host': LISTEN_ADDRESS,
        'server.socket_port': port,
        'server.thread_pool': 18,
        'checker.on': False,
    })

    DjangoAppPlugin(cherrypy.engine).subscribe()

    # cherrypyserver automatically reloads if any modules change
    # Switch-off that functionality here to save cpu cycles
    # http://docs.cherrypy.org/stable/appendix/faq.html
    cherrypy.engine.autoreload.unsubscribe()

    try:
        cherrypy.quickstart()
    except KeyboardInterrupt:
        # Handled in cherrypy by waiting for all threads to join
        pass
    except SystemExit:
        print("KA Lite caught system exit signal, quitting.")

    print("FINISHED serving HTTP")

    if cron_thread:
        # Do not exit thread together with the main process, let it finish
        # cleanly
        print("Asking KA Lite job scheduler to terminate...")
        from fle_utils.chronograph.management.commands import cronserver_blocking
        cronserver_blocking.shutdown = True
        cron_thread.join()
        print("Job scheduler terminated.")
コード例 #13
0
ファイル: kaserve.py プロジェクト: SG345/ka-lite
    def handle(self, *args, **options):
        # Store base django settings and remove them from the options list
        # because we are proxying one type of option list to another format
        # where --foo=bar becomes foo=bar
        
        warnings.warn(
            "manage kaserve is deprecated, please use kalite start [--foreground] [...]",
            RemovedInKALite_v015_Warning
        )
        
        base_django_settings = {}
        for opt in BaseCommand.option_list:
            base_django_settings[opt.dest] = options[opt.dest]
            del options[opt.dest]

        # Parse the crappy way that runcherrypy takes args,
        #   or the host/port
        for arg in args:
            if "=" in arg:
                (key,val) = arg.split("=")
                options[key] = val
            elif ":" in arg:
                (options["host"], options["port"]) = arg.split(":")
            elif isnumeric(arg):
                options["port"] = arg
            else:
                raise CommandError("Unexpected argument format: %s" % arg)

        # In order to avoid doing this twice when the autoreloader
        #   loads this process again, only execute the initialization
        #   code if autoreloader won't be run (daemonize), or if
        #   RUN_MAIN is set (autoreloader has started)
        if options["daemonize"] or os.environ.get("RUN_MAIN"):
            self.setup_server_if_needed()

            # we do this on every server request,
            # as we don't know what happens when we're not looking.
            self.reinitialize_server()

        # In case any chronograph threads were interrupted the last time
        # the server was stopped, clear their is_running flags to allow
        # them to be started up again as needed.
        Job.objects.update(is_running=False)

        # Copy static media, one reason for not symlinking: It is not cross-platform and can cause permission issues
        # with many webservers
        logging.info("Copying static media...")
        call_command("collectstatic", interactive=False, verbosity=0)

        call_command("collectstatic_js_reverse", interactive=False)

        if options['startuplock']:
            os.unlink(options['startuplock'])
        
        # Now call the proper command
        if not options["production"]:
            call_command("runserver", "%s:%s" % (options["host"], options["port"]))
        else:
            del options["production"]
            addresses = get_ip_addresses(include_loopback=False)
            sys.stdout.write("To access KA Lite from another connected computer, try the following address(es):\n")
            for addr in addresses:
                sys.stdout.write("\thttp://%s:%s/\n" % (addr, settings.USER_FACING_PORT()))
            sys.stdout.write("To access KA Lite from this machine, try the following address:\n")
            sys.stdout.write("\thttp://127.0.0.1:%s/\n" % settings.USER_FACING_PORT())

            call_command("runcherrypyserver", *["%s=%s" % (key,val) for key, val in options.iteritems()], **base_django_settings)
コード例 #14
0
ファイル: kalitectl.py プロジェクト: xuewenfei/ka-lite
def diagnose():
    """
    This command diagnoses an installation of KA Lite
    
    It has to be able to work with instances of KA Lite that users do not
    actually own, however it's assumed that the path and the 'kalite' commands
    are configured and work.
    
    The function is currently non-robust, meaning that not all aspects of
    diagnose data collection is guaranteed to succeed, thus the command could
    potentially fail :(
    
    Example: KALITE_HOME=/home/otheruser/.kalite kalite diagnose --port=7007
    """
    
    print("")
    print("KA Lite diagnostics")
    print("")
    
    # Tell users we are calculating, because checking the size of the
    # content directory is slow. Flush immediately after.
    print("Calculating diagnostics...")
    sys.stdout.flush()
    print("")
    
    # Key, value store for diagnostics
    # Not using OrderedDict because of python 2.6
    diagnostics = []
    
    diag = lambda x, y: diagnostics.append((x, y))
    
    diag("KA Lite version", kalite.__version__)
    diag("python", sys.version)
    diag("platform", platform.platform())
    
    try:
        __, __, port = get_pid()
        for addr in get_ip_addresses():
            diag("server address", "http://%s:%s/" % (addr, port))
        status_code = STATUS_RUNNING
    except NotRunning as e:
        status_code = e.status_code
    
    diag("server status", status.codes[status_code])
    
    settings_imported = True  # Diagnostics from settings
    try:
        from django.conf import settings
        from django.template.defaultfilters import filesizeformat
    except:
        settings_imported = False
        diag("Settings failure", traceback.format_exc())
    
    if settings_imported:
        diag("installed in", os.path.dirname(kalite.__file__))
        diag("content root", settings.CONTENT_ROOT)
        diag("content size", filesizeformat(get_size(settings.CONTENT_ROOT)))
        diag("user database", settings.DATABASES['default']['NAME'])
        diag("assessment database", settings.DATABASES['assessment_items']['NAME'])
        try:
            from securesync.models import Device
            device = Device.get_own_device()
            sync_sessions = device.client_sessions.all()
            zone = device.get_zone()
            diag("device name", str(device.name))
            diag("device ID", str(device.id))
            diag("device registered", str(device.is_registered()))
            diag("synced", str(sync_sessions.latest('timestamp').timestamp if sync_sessions.exists() else "Never"))
            diag("sync result", ("OK" if sync_sessions.latest('timestamp').errors == 0 else "Error") if sync_sessions.exists() else "-")
            diag("zone ID", str(zone.id) if zone else "Unset")
        except:
            diag("Device failure", traceback.format_exc())
    
    for k, v in diagnostics:
        
        # Pad all the values to match the key column
        values = str(v).split("\n")
        values = "\n".join([values[0]] + map(lambda x: (" " * 22) + x, values[1:]))
        
        print((k.upper() + ": ").ljust(21), values)
コード例 #15
0
ファイル: kalitectl.py プロジェクト: theaverageguy/ka-lite
def start(debug=False, watch=False, daemonize=True, args=[], skip_job_scheduler=False, port=None):
    """
    Start the kalite server as a daemon

    :param args: List of options to parse to the django management command
    :param port: Non-default port to bind to. You cannot run kalite on
                 multiple ports at the same time.
    :param daemonize: Default True, will run in foreground if False
    :param skip_job_scheduler: Skips running the job scheduler in a separate thread
    """
    # TODO: Do we want to fail if running as root?

    port = int(port or DEFAULT_LISTEN_PORT)

    if not daemonize:
        sys.stderr.write("Running 'kalite start' in foreground...\n")
    else:
        sys.stderr.write("Running 'kalite start' as daemon (system service)\n")

    sys.stderr.write("\nStand by while the server loads its data...\n\n")

    if os.path.exists(STARTUP_LOCK):
        try:
            pid, __ = read_pid_file(STARTUP_LOCK)
            # Does the PID in there still exist?
            if pid_exists(pid):
                sys.stderr.write(
                    "Refusing to start: Start up lock exists: {0:s}\n".format(STARTUP_LOCK))
                sys.stderr.write("Remove the file and try again.\n")
                sys.exit(1)
        # Couldn't parse to int
        except TypeError:
            pass

        os.unlink(STARTUP_LOCK)

    try:
        if get_pid():
            sys.stderr.write("Refusing to start: Already running\n")
            sys.stderr.write("Use 'kalite stop' to stop the instance.\n")
            sys.exit(1)
    except NotRunning:
        pass

    # Check that the port is available by creating a simple socket and see
    # if it succeeds... if it does, the port is occupied.
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connection_error = sock.connect_ex(('127.0.0.1', port))
    if not connection_error:
        sys.stderr.write(
            "Port {0} is occupied. Please close the process that is using "
            "it.\n".format(port)
        )
        sys.exit(1)

    # Write current PID and optional port to a startup lock file
    with open(STARTUP_LOCK, "w") as f:
        f.write("%s\n%d" % (str(os.getpid()), port))

    manage('initialize_kalite')

    if watch:
        watchify_thread = Thread(target=start_watchify)
        watchify_thread.daemon = True
        watchify_thread.start()

    # Remove the startup lock at this point
    if STARTUP_LOCK:
        os.unlink(STARTUP_LOCK)

    # Print output to user about where to find the server
    addresses = get_ip_addresses(include_loopback=False)
    print("To access KA Lite from another connected computer, try the following address(es):")
    for addr in addresses:
        print("\thttp://%s:%s/" % (addr, port))
    print("To access KA Lite from this machine, try the following address:")
    print("\thttp://127.0.0.1:%s/\n" % port)

    # Daemonize at this point, no more user output is needed
    if daemonize:

        from django.utils.daemonize import become_daemon
        kwargs = {}
        # Truncate the file
        open(SERVER_LOG, "w").truncate()
        print("Going to daemon mode, logging to {0}".format(SERVER_LOG))
        kwargs['out_log'] = SERVER_LOG
        kwargs['err_log'] = SERVER_LOG
        become_daemon(**kwargs)
        # Write the new PID
        with open(PID_FILE, 'w') as f:
            f.write("%d\n%d" % (os.getpid(), port))

    # Start the job scheduler (not Celery yet...)
    cron_thread = None
    if not skip_job_scheduler:
        cron_thread = manage(
            'cronserver_blocking',
            args=[],
            as_thread=True
        )

    # Start cherrypy service
    cherrypy.config.update({
        'server.socket_host': LISTEN_ADDRESS,
        'server.socket_port': port,
        'server.thread_pool': 18,
        'checker.on': False,
    })

    DjangoAppPlugin(cherrypy.engine).subscribe()
    if not watch:
        # cherrypyserver automatically reloads if any modules change
        # Switch-off that functionality here to save cpu cycles
        # http://docs.cherrypy.org/stable/appendix/faq.html
        cherrypy.engine.autoreload.unsubscribe()

    try:
        cherrypy.quickstart()
    except KeyboardInterrupt:
        # Handled in cherrypy by waiting for all threads to join
        pass
    except SystemExit:
        print("KA Lite caught system exit signal, quitting.")

    print("FINISHED serving HTTP")

    if cron_thread:
        # Do not exit thread together with the main process, let it finish
        # cleanly
        print("Asking KA Lite job scheduler to terminate...")
        from fle_utils.chronograph.management.commands import cronserver_blocking
        cronserver_blocking.shutdown = True
        cron_thread.join()
        print("Job scheduler terminated.")
コード例 #16
0
ファイル: kalitectl.py プロジェクト: SG345/ka-lite
def start(debug=False, daemonize=True, args=[], skip_job_scheduler=False, port=None):
    """
    Start the kalite server as a daemon

    :param args: List of options to parse to the django management command
    :param port: Non-default port to bind to. You cannot run kalite on
                 multiple ports at the same time.
    :param daemonize: Default True, will run in foreground if False
    :param skip_job_scheduler: Skips running the job scheduler in a separate thread
    """
    # TODO: Do we want to fail if running as root?
    
    port = int(port or DEFAULT_LISTEN_PORT)
    
    if not daemonize:
        sys.stderr.write("Running 'kalite start' in foreground...\n")
    else:
        sys.stderr.write("Running 'kalite start' as daemon (system service)\n")
    
    sys.stderr.write("\nStand by while the server loads its data...\n\n")
    
    if os.path.exists(STARTUP_LOCK):
        try:
            pid, __ = read_pid_file(STARTUP_LOCK)
            # Does the PID in there still exist?
            if pid_exists(pid):
                sys.stderr.write(
                    "Refusing to start: Start up lock exists: {0:s}\n".format(STARTUP_LOCK))
                sys.exit(1)
        # Couldn't parse to int
        except TypeError:
            pass

        os.unlink(STARTUP_LOCK)

    try:
        if get_pid():
            sys.stderr.write("Refusing to start: Already running\n")
            sys.exit(1)
    except NotRunning:
        pass

    # Write current PID and optional port to a startup lock file
    with open(STARTUP_LOCK, "w") as f:
        f.write("%s\n%d" % (str(os.getpid()), port))
    
    manage('initialize_kalite')

    # Start the job scheduler (not Celery yet...)
    # This command is run before starting the server, in case the server
    # should be configured to not run in daemon mode or in case the
    # server fails to go to daemon mode.
    if not skip_job_scheduler:
        manage(
            'cronserver_blocking',
            args=[],
            as_thread=True
        )

    # Remove the startup lock at this point
    if STARTUP_LOCK:
        os.unlink(STARTUP_LOCK)
    
    # Print output to user about where to find the server
    addresses = get_ip_addresses(include_loopback=False)
    sys.stdout.write("To access KA Lite from another connected computer, try the following address(es):\n")
    for addr in addresses:
        sys.stdout.write("\thttp://%s:%s/\n" % (addr, port))
    sys.stdout.write("To access KA Lite from this machine, try the following address:\n")
    sys.stdout.write("\thttp://127.0.0.1:%s/\n" % port)
    
    # Daemonize at this point, no more user output is needed
    if daemonize:
        
        from django.utils.daemonize import become_daemon
        kwargs = {}
        # Truncate the file
        open(SERVER_LOG, "w").truncate()
        print("Going to daemon mode, logging to {0}".format(SERVER_LOG))
        kwargs['out_log'] = SERVER_LOG
        kwargs['err_log'] = SERVER_LOG
        become_daemon(**kwargs)
        # Write the new PID
        with open(PID_FILE, 'w') as f:
            f.write("%d\n%d" % (os.getpid(), port))
    
    # Start cherrypy service
    cherrypy.config.update({
        'server.socket_host': LISTEN_ADDRESS,
        'server.socket_port': port,
        'server.thread_pool': 18,
        'checker.on': False,
    })

    DjangoAppPlugin(cherrypy.engine).subscribe()
    if not debug:
        # cherrypyserver automatically reloads if any modules change
        # Switch-off that functionality here to save cpu cycles
        # http://docs.cherrypy.org/stable/appendix/faq.html
        cherrypy.engine.autoreload.unsubscribe()
    
    cherrypy.quickstart()

    print("FINISHED serving HTTP")