diff options
| author | 2018-05-21 18:02:07 +0200 | |
|---|---|---|
| committer | 2018-05-21 18:02:07 +0200 | |
| commit | 964054baf1e02fb017deec9d2f4cd8b65f19944a (patch) | |
| tree | 6ce672a025c5f8c59109888f2299b4cfdf21be9b | |
| parent | Initial commit (diff) | |
init commit
Diffstat (limited to '')
| -rw-r--r-- | Pipfile | 18 | ||||
| -rw-r--r-- | Pipfile.lock | 29 | ||||
| -rw-r--r-- | README.md | 55 | ||||
| -rw-r--r-- | docker/Dockerfile | 23 | ||||
| -rw-r--r-- | runner/config.py | 8 | ||||
| -rw-r--r-- | runner/consume.py | 68 | ||||
| -rw-r--r-- | runner/publish.py | 42 | ||||
| -rw-r--r-- | runner/test.py | 21 | 
8 files changed, 264 insertions, 0 deletions
| @@ -0,0 +1,18 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +pika = "*" + +[dev-packages] + +[requires] +python_version = "3.6" + +[scripts] +consume = "python consume.py" +publish = "python publish.py" +build = "docker build -t runner:latest -f docker/Dockerfile ." +docker = "docker run --network=host runner" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..00a32d2 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,29 @@ +{ +    "_meta": { +        "hash": { +            "sha256": "7374d59c23f8adb4d87cd3533f6a7e8f95cc7d7e2e1f5bc1c9dcb49a02459bbd" +        }, +        "pipfile-spec": 6, +        "requires": { +            "python_version": "3.6" +        }, +        "sources": [ +            { +                "name": "pypi", +                "url": "https://pypi.org/simple", +                "verify_ssl": true +            } +        ] +    }, +    "default": { +        "pika": { +            "hashes": [ +                "sha256:15f485eb68ec56b5a2673c01d518d16f7c371809ca42c72a2da42d4d8190fa4f", +                "sha256:ded1cf12810f909099a3a698cc5adf495b73fd2da1d8f669f8b267664653122d" +            ], +            "index": "pypi", +            "version": "==0.11.2" +        } +    }, +    "develop": {} +} @@ -1,2 +1,57 @@  # snekbox  Python sandbox runners for executing code in isolation + +# Dependencies + +| dep    | version (or greater) | +|--------|----------------------| +| python | 3.6.5                | +| pip    | 10.0.1               | +| pipenv | 2018.05.18           | +| docker | 18.03.1-ce           | + + +## Setup local test + +install python packages + +```bash +pipenv sync +``` + +Start a rabbitmq instance and get the container IP + +```bash +docker run --name rmq -d rabbitmq:3.7.5-alpine +docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' rmq +# expected output with default setting: 172.17.0.2 +# If not, change the runner/config.py file to match +``` + +## Test the code + +use two terminals! + +```bash +#terminal 1 +pipenv run python runner/consume.py + +#terminal 2 +pipenv run python runner/publish.py +``` + +The publish will put a message on the message queue +and the consumer will pick it up and do stuff + +## Build and run the consumer in a container + +```bash +docker build -t snekbox:latest -f docker/Dockerfile . + +#terminal 1 +docker run --name snekbox -d snekbox:latest +docker logs snekbox -f + +#terminal 2 +pipenv run python runner/publish.py +``` diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..cbf1b49 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.6-alpine3.7 + +RUN apk add --update tini +RUN apk add --update build-base + +ENV PIPENV_VENV_IN_PROJECT=1 +ENV PIPENV_IGNORE_VIRTUALENVS=1 +ENV PIPENV_NOSPIN=1 +ENV PIPENV_HIDE_EMOJIS=1 +ENV PYTHONPATH=/runner + +RUN pip install pipenv + +RUN mkdir -p /runner +COPY Pipfile /runner +COPY Pipfile.lock /runner +COPY runner /runner +WORKDIR /runner + +RUN pipenv sync + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["pipenv", "run", "consume"] diff --git a/runner/config.py b/runner/config.py new file mode 100644 index 0000000..75b3c28 --- /dev/null +++ b/runner/config.py @@ -0,0 +1,8 @@ +USERNAME      = 'guest' +PASSWORD      = 'guest' +HOST          = '172.17.0.2' +PORT          = 5672 +EXCHANGE      = 'exchange' +EXCHANGE_TYPE = 'direct' +QUEUE         = 'text' +ROUTING_KEY   = 'bacon' diff --git a/runner/consume.py b/runner/consume.py new file mode 100644 index 0000000..0e4d79a --- /dev/null +++ b/runner/consume.py @@ -0,0 +1,68 @@ +import pika +import traceback +import sys +from io import StringIO + +from config import ( +    USERNAME, +    PASSWORD, +    HOST, +    PORT, +    EXCHANGE, +    EXCHANGE_TYPE, +    QUEUE, +    ROUTING_KEY, +) + +def execute(snippet): +    old_stdout = sys.stdout +    redirected_output = sys.stdout = StringIO() +    failed = False +    try: +        exec(snippet) +    except Exception as e: +        failed = e +    finally: +        sys.stdout = old_stdout + +    if failed: +        return failed +    return redirected_output.getvalue() + + +def message_handler(ch, method, properties, body): +    msg = body.decode('utf-8') + +    # Execute code snippets here +    print(f"incoming: {msg}", flush=True) +    result = execute(msg) +    print(result, flush=True) + +    ch.basic_ack(delivery_tag = method.delivery_tag) + +def rabbitmq_consume(): +    credentials = pika.PlainCredentials(USERNAME, PASSWORD) +    connection = pika.BlockingConnection(pika.ConnectionParameters(HOST, PORT, '/', credentials)) + +    channel = connection.channel() +    channel.queue_declare(queue=QUEUE, durable=False) +    channel.basic_qos(prefetch_count=1) +    channel.basic_consume(message_handler, queue=QUEUE) + +    try: +        print(f"""Connecting to +            host: {HOST} +            port: {PORT} +            exchange: {EXCHANGE} +            queue: {QUEUE}""", flush=True) + +        channel.start_consuming() + +    except Exception: +        exc = traceback.format_exc() +        print(exc, flush=True) + +    finally: +        connection.close() + +rabbitmq_consume() diff --git a/runner/publish.py b/runner/publish.py new file mode 100644 index 0000000..fc18d03 --- /dev/null +++ b/runner/publish.py @@ -0,0 +1,42 @@ +import pika +from config import ( +    USERNAME, +    PASSWORD, +    HOST, +    PORT, +    EXCHANGE, +    EXCHANGE_TYPE, +    QUEUE, +    ROUTING_KEY, +) + +def send(message): +    credentials = pika.PlainCredentials(USERNAME, PASSWORD) +    connection = pika.BlockingConnection(pika.ConnectionParameters(HOST, PORT, '/', credentials)) +    properties = pika.BasicProperties(content_type='text/plain', delivery_mode=1) + +    channel = connection.channel() +    channel.queue_declare(queue=QUEUE, durable=False) +    channel.exchange_declare(exchange=EXCHANGE, exchange_type=EXCHANGE_TYPE) +    channel.queue_bind(exchange=EXCHANGE, queue=QUEUE, routing_key=ROUTING_KEY) + +    result = channel.basic_publish( +                exchange=EXCHANGE, +                routing_key=ROUTING_KEY, +                body=message, +                properties=properties +    ) + +    if result: +        print(f"""Connecting to +            host: {HOST} +            port: {PORT} +            exchange: {EXCHANGE} +            queue: {QUEUE}""", flush=True) +        print(f"Sent: '{message}'") +    else: +        print("not delivered") + +    connection.close() + +send('print "bacon is delicious"') diff --git a/runner/test.py b/runner/test.py new file mode 100644 index 0000000..08f0441 --- /dev/null +++ b/runner/test.py @@ -0,0 +1,21 @@ +import sys +from io import StringIO + +def execute(snippet): +    old_stdout = sys.stdout +    redirected_output = sys.stdout = StringIO() +    try: +        exec(snippet) +    except: +        raise +    finally: +        sys.stdout = old_stdout + +    return redirected_output.getvalue() + + +code = """ +i = [0,1,2] +for j in i: +    print(j) +""" | 
