Skip to content

Commit

Permalink
Merge pull request #23 from plgitlogin/1.0.0
Browse files Browse the repository at this point in the history
1.0.0
  • Loading branch information
nimdanor authored Feb 19, 2019
2 parents 3462193 + bd2b232 commit 7449b90
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 311 deletions.
2 changes: 1 addition & 1 deletion default_file/builder.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/usr/bin/env bash
python3 builder.py pl.json built_pl.json 2> stderr.log
python3 builder.py pl.json processed.json 2> stderr.log
2 changes: 1 addition & 1 deletion default_file/grader.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/usr/bin/env bash
python3 grader.py built_pl.json answers.json evaluated_pl.json feedback.html 2> stderr.log
python3 grader.py pl.json answers.json processed.json feedback.html 2> stderr.log
5 changes: 5 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@
"forget to activate a virtual environment?"
)
raise

if sys.argv[1] == "runserver":
sys.argv.append("--noreload")
print("--noreload enforced. You will have to restart the server to apply changes.")

execute_from_command_line(sys.argv)
5 changes: 0 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,3 @@ docker
pytz
requests
timeout-decorator

# The following should be in the dockerfile of exercices
sympy
matplotlib
psycopg2
115 changes: 46 additions & 69 deletions sandbox/container.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
import shutil
import tarfile
import threading
import time

Expand All @@ -12,10 +13,10 @@

CONTAINERS = None


lock = threading.Lock()



def create_container(name):
return docker.from_env().containers.run(
settings.DOCKER_IMAGE,
Expand All @@ -26,7 +27,8 @@ def create_container(name):
cpuset_cpus=settings.DOCKER_CPUSET_CPUS,
mem_limit=settings.DOCKER_MEM_LIMIT,
memswap_limit=settings.DOCKER_MEMSWAP_LIMIT,
name=name,
network_mode="none",
network_disabled=True,
volumes={
os.path.join(settings.DOCKER_VOLUME_HOST, name): {
"bind": settings.DOCKER_VOLUME_CONTAINER,
Expand All @@ -42,6 +44,11 @@ class ContainerWrapper:


def __init__(self, name, index, available=True):
path = os.path.join(settings.DOCKER_VOLUME_HOST, name)
if os.path.isdir(path):
shutil.rmtree(path, ignore_errors=True)
os.makedirs(path)

self.name = name
self.container = create_container(name)
self.index = index
Expand All @@ -52,30 +59,6 @@ def __init__(self, name, index, available=True):
self._get_default_file()


def _reset(self):
"""Reset a given container by ensuring it's killed and overwriting it's instance with a new
one."""
global CONTAINERS

try:
try:
self.container.kill()
except docker.errors.DockerException:
pass

docker.from_env().containers.prune()

cw = ContainerWrapper("c%d" % self.index, self.index)
with lock:
CONTAINERS[self.index] = cw

logger.info(
"Successfully restarted container '%s' of id '%d'" % (self.name, self.index))
except docker.errors.DockerException:
logger.exception(
"Error while restarting container '%s' of id '%d'" % (self.name, self.index))


def _get_default_file(self):
"""Copy every files and directory in DOCKER_DEFAULT_FILES into container environement."""
for item in os.listdir(settings.DOCKER_DEFAULT_FILES):
Expand All @@ -87,23 +70,39 @@ def _get_default_file(self):
shutil.copy2(s, d)


@property
def need_reset(self):
"""Return True if the container need to be reset, False otherwise."""
return self.container.status not in ["running", "restarting", "created"] or self.to_delete
def extract_env(self, envid, suffix, prefix="", test=False):
"""Retrieve the environment from the docker and write it to:
[settings.MEDIA_ROOT]/[prefix][env_id][suffix][ext]
"test_" is added before [prefix] if test is True
An integer (up to 100) can be added before [ext] if the path already exists."""
base = os.path.join(settings.MEDIA_ROOT,
("test_" if test else "") + prefix + envid + suffix)
path = base + ".tgz"

for i in range(1, 100):
if os.path.exists(path):
path = base + str(i) + ".tgz"

with tarfile.open(path, "w|gz") as tar:
for name in os.listdir(self.envpath):
tar.add(os.path.join(self.envpath, name), arcname=name)


@staticmethod
def acquire():
"""Return the first available container, None if none were available."""
global CONTAINERS

with lock:
cw = next((c for c in CONTAINERS if c.available), None)
if cw is not None:
CONTAINERS[cw.index].available = False
CONTAINERS[cw.index].used_since = time.time()
logger.info("Acquiring container '%s' of id '%d'" % (cw.name, cw.index))
lock.acquire()

cw = next((c for c in CONTAINERS if c.available), None)
if cw is not None:
CONTAINERS[cw.index].available = False
CONTAINERS[cw.index].used_since = time.time()
logger.info("Acquiring container '%s' of id '%d'" % (cw.name, cw.index))

lock.release()

return cw

Expand All @@ -122,40 +121,22 @@ def release(self):
with lock:
CONTAINERS[self.index].available = True
logger.info("Releasing container '%s' of id '%d'" % (self.name, self.index))


@classmethod
def refresh_containers(cls):
"""Check that each container are either running, restarting or being created. Reset them if
this is not the case."""
global CONTAINERS

with lock:
for i in range(settings.DOCKER_COUNT):
try:
CONTAINERS[i].reload()
except docker.errors.DockerException:
CONTAINERS[i].to_delete = True

for c in CONTAINERS:
if not c.need_reset:
continue

logger.info("Restarting container '%s' of id '%d'" % (c.name, c.index))
CONTAINERS[c.index].available = False
threading.Thread(target=c._reset).start()



def initialise_container():
"""Called by settings.py to initialize containers at server launch."""
global CONTAINERS

lock.acquire()

time.sleep(0.5)
# Kill stopped container created from DOCKER_IMAGE
logger.info("Purging existing containers using image : %s." % settings.DOCKER_IMAGE)
logger.info("Purging existing stopped containers using image : %s." % settings.DOCKER_IMAGE)
logger.info("Killed stopped container : %s." % str(docker.from_env().containers.prune()))
# Kill running container created from DOCKER_IMAGE

# Deleting running container created from DOCKER_IMAGE
CONTAINERS = []
for c in docker.from_env().containers.list({"ancestor": settings.DOCKER_IMAGE}):
logger.info("Killing container %s." % repr(c))
c.kill()
Expand All @@ -166,15 +147,11 @@ def initialise_container():
if os.path.isdir(settings.DOCKER_VOLUME_HOST):
shutil.rmtree(settings.DOCKER_VOLUME_HOST)

logger.info("Creating new containers environment.")
[os.makedirs(os.path.join(settings.DOCKER_VOLUME_HOST, "c%d" % i)) for i in
range(settings.DOCKER_COUNT)]

# Create containers.
logger.info("Initializing containers.")
with lock:
CONTAINERS = []
for i in range(settings.DOCKER_COUNT):
CONTAINERS.append(ContainerWrapper("c%d" % i, i))
logger.info("Container %d/%d initialized." % (i, settings.DOCKER_COUNT))
for i in range(settings.DOCKER_COUNT):
CONTAINERS.append(ContainerWrapper("c%d" % i, i))
logger.info("Container %d/%d initialized." % (i, settings.DOCKER_COUNT))
logger.info("Containers initialized.")

lock.release()
75 changes: 50 additions & 25 deletions sandbox/docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,74 @@ MAINTAINER Quentin COUMES <qcoumes@etud.u-pem.fr>

ENV DEBIAN_FRONTEND noninteractive


# Installing base requirements
RUN apt-get update
RUN apt-get install -y --no-install-recommends\
sudo\
gnupg2\
libasound2\
libasound2-data\
locales\
wget\
build-essential\
libssl-dev\
openssl\
unzip\
python3


# Installing pip
RUN apt-get install -y --no-install-recommends \
sudo \
gnupg2 \
libasound2 \
libasound2-data \
locales \
wget \
ca-certificates \
build-essential \
libssl-dev \
openssl \
unzip \
python3 \
git \
ocaml-nox \
ocaml \
perl \
perl-doc


# Installing pip3 and python's requirements
RUN wget --no-check-certificate https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py
RUN python3 /tmp/get-pip.py
RUN pip3 install jinja2 jsonpickle sympy matplotlib

# Adding sftp lib folder to pythonpath
ENV PYTHONPATH /var/lib/upem:$PYTHONPATH
RUN pip3 install wheel
RUN pip3 install \
jinja2 \
jsonpickle \
sympy \
matplotlib \
psycopg2


# Installing Java 11
RUN wget --no-check-certificate \
RUN wget \
-P /tmp \
--header "Cookie: oraclelicense=accept-securebackup-cookie"\
https://download.oracle.com/otn-pub/java/jdk/11.0.2+7/f51449fcd52f4d52b93a989c5c56ed3c/jdk-11.0.2_linux-x64_bin.deb
RUN dpkg -i jdk-11.0.2_linux-x64_bin.deb
RUN dpkg -i /tmp/jdk-11.0.2_linux-x64_bin.deb
RUN update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-11.0.2/bin/java 2
RUN update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk-11.0.2/bin/javac 2
RUN mkdir /utils
RUN wget --no-check-certificate \
https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.4.0-M1/junit-platform-console-standalone-1.4.0-M1.jar\
RUN wget \
https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.4.0-M1/junit-platform-console-standalone-1.4.0-M1.jar \
-O- > /utils/junit-platform-console-standalone.jar
RUN export JAVA_HOME=/usr/lib/jvm/jdk-11.0.2/


# Installing PL-Java
RUN wget https://github.com/forax/first-language/releases/download/1.0.2/pl-java-jdk-11.tar.gz -P /tmp
RUN tar -xvzf /tmp/pl-java-jdk-11.tar.gz -C /utils/
RUN ln -s /utils/pl-java/bin/pl-java /usr/bin/pl-java
RUN ln -s /utils/pl-java/bin/pl-javac /usr/bin/pl-javac


# Cleaning /tmp
RUN rm -Rf /tmp/*



ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV LC_TYPE en_US.UTF-8
RUN echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
RUN locale-gen "en_US.UTF-8" &&\
dpkg-reconfigure locales
RUN locale-gen "en_US.UTF-8" && dpkg-reconfigure locales

WORKDIR /home/docker

Expand Down
Loading

0 comments on commit 7449b90

Please sign in to comment.