Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check if port is occupied before starting Kolibri #3302

Merged
merged 2 commits into from
Mar 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions kolibri/utils/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

from . import server # noqa
from .system import become_daemon # noqa
from .sanity_checks import check_other_kolibri_running # noqa

USAGE = """
Kolibri
Expand Down Expand Up @@ -262,12 +263,9 @@ def start(port=None, daemon=True):
# https://github.com/learningequality/kolibri/issues/1615
update()

if port is None:
try:
port = int(os.environ['KOLIBRI_LISTEN_PORT'])
except ValueError:
logger.error("Invalid KOLIBRI_LISTEN_PORT, must be an integer")
raise
# In case that some tests run start() function only
if not isinstance(port, int):
port = _get_port(port)

if not daemon:
logger.info("Running 'kolibri start' in foreground...")
Expand Down Expand Up @@ -314,6 +312,7 @@ def stop():
pid, __, __ = server.get_status()
server.stop(pid=pid)
stopped = True
logger.info("Kolibri server has successfully been stoppped.")
except server.NotRunning as e:
verbose_status = "{msg:s} ({code:d})".format(
code=e.status_code,
Expand Down Expand Up @@ -576,6 +575,17 @@ def parse_args(args=None):
return docopt(USAGE, **docopt_kwargs), django_args


def _get_port(port):
port = int(port) if port else None
if port is None:
try:
port = int(os.environ['KOLIBRI_LISTEN_PORT'])
except ValueError:
logger.error("Invalid KOLIBRI_LISTEN_PORT, must be an integer")
raise
return port


def main(args=None):
"""
Kolibri's main function. Parses arguments and calls utility functions.
Expand All @@ -589,6 +599,10 @@ def main(args=None):

debug = arguments['--debug']

if arguments['start']:
port = _get_port(arguments['--port'])
check_other_kolibri_running(port)

initialize(debug=debug)

# Alias
Expand All @@ -607,8 +621,6 @@ def main(args=None):
return

if arguments['start']:
port = arguments['--port']
port = int(port) if port else None
daemon = not arguments['--foreground']
if sys.platform == 'darwin':
daemon = False
Expand Down
44 changes: 44 additions & 0 deletions kolibri/utils/sanity_checks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import logging
import socket
import sys

from .server import get_status
from .server import NotRunning

logger = logging.getLogger(__name__)

def check_other_kolibri_running(port):
try:
# Check if there are other kolibri instances running
# If there are, then we need to stop users from starting kolibri again.
pid, listen_address, listen_port = get_status()
logger.error(
"There is another Kolibri server running. "
"Please use `kolibri stop` and try again."
)
sys.exit(1)

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.


except NotRunning:
# In case that something other than Kolibri occupies the port,
# check the port's availability.
check_port_availability('127.0.0.1', port)


def check_port_availability(host, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# This is to prevent the previous execution has left the socket
# in a TIME_WAIT start, and can't be immediately reused.
# From the bottom of https://docs.python.org/2/library/socket.html#example
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.bind((host, port))
s.close()
except socket.error:
# Port is occupied
logger.error(
"Port {} is occupied.\n"
"Please check that you do not have other processes "
"running on this port and try again.\n".format(port)
)
s.close()
sys.exit(1)