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

Add support for Julia buildpack #29

Merged
merged 1 commit into from
Jun 15, 2017
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
4 changes: 2 additions & 2 deletions repo2docker/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

from .detectors import (
BuildPack, PythonBuildPack, DockerBuildPack, LegacyBinderDockerBuildPack,
CondaBuildPack, DefaultBuildPack
CondaBuildPack, DefaultBuildPack, JuliaBuildPack
)
from .utils import execute_cmd
from . import __version__
Expand Down Expand Up @@ -93,7 +93,7 @@ def _default_log_level(self):

buildpacks = List(
Type(BuildPack),
[LegacyBinderDockerBuildPack, DockerBuildPack, CondaBuildPack, PythonBuildPack, DefaultBuildPack],
[LegacyBinderDockerBuildPack, DockerBuildPack, CondaBuildPack, PythonBuildPack, JuliaBuildPack, DefaultBuildPack],
config=True,
help="""
Ordered list of BuildPacks to try to use to build a git repository.
Expand Down
8 changes: 8 additions & 0 deletions repo2docker/detectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ def detect(self, workdir):
return os.path.exists(os.path.join(workdir, 'environment.yml'))


class JuliaBuildPack(S2IBuildPack):
name = Unicode('julia')
build_image = Unicode('jupyterhub/singleuser-builder-julia:v0.2.1', config=True)

def detect(self, workdir):
return os.path.exists(os.path.join(workdir, 'REQUIRE'))


class PythonBuildPack(S2IBuildPack):
"""Build Pack for installing from a pip requirements.txt using S2I"""
name = Unicode('python-pip')
Expand Down
63 changes: 63 additions & 0 deletions s2i-builders/julia/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
FROM ubuntu:17.04

MAINTAINER Yuvi Panda <[email protected]>

LABEL io.openshift.s2i.scripts-url=image:///usr/libexec/s2i

ENV APP_DIR /srv/app
ENV JULIA_PATH /usr/local/julia
ENV PATH ${APP_DIR}/venv/bin:$PATH

RUN apt-get update && \
apt-get install --yes \
python3 \
python3-venv \
python3-dev \
build-essential \
pkg-config \
libfreetype6-dev \
libpng-dev \
tar \
git \
curl \
locales && \
apt-get purge && apt-get clean

RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && \
locale-gen

ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8

RUN adduser --disabled-password --gecos "Default Jupyter user" jovyan

RUN mkdir -p ${APP_DIR} && chown -R jovyan:jovyan ${APP_DIR}

# Install Julia
ENV JULIA_PATH /usr/local/julia
ENV JULIA_VERSION 0.5.2

RUN mkdir $JULIA_PATH && \
curl -sSL "https://julialang-s3.julialang.org/bin/linux/x64/${JULIA_VERSION%[.-]*}/julia-${JULIA_VERSION}-linux-x86_64.tar.gz" | tar -xz -C ${JULIA_PATH} --strip-components 1

WORKDIR /home/jovyan

USER jovyan
RUN python3 -m venv ${APP_DIR}/venv

RUN pip install --no-cache-dir notebook==5.0.0 jupyterhub==0.7.2 ipywidgets==5.2.3 jupyterlab==0.22.1 && \
jupyter nbextension enable --py widgetsnbextension --sys-prefix && \
jupyter serverextension enable --py jupyterlab --sys-prefix

ENV JUPYTER ${APP_DIR}/venv/bin/jupyter
ENV PATH ${APP_DIR}/venv/bin:$PATH:${JULIA_PATH}/bin
ENV JULIA_PKGDIR ${APP_DIR}/.julia

RUN julia -e 'Pkg.init(); Pkg.add("IJulia")' && \
mv ${HOME}/.local/share/jupyter/kernels/julia-0.5/ ${APP_DIR}/venv/share/jupyter/kernels/julia-0.5


COPY ./s2i/bin/ /usr/libexec/s2i

EXPOSE 8888
9 changes: 9 additions & 0 deletions s2i-builders/julia/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
IMAGE_PREFIX = jupyterhub/singleuser-builder-julia
VERSION = $(shell cat version)

.PHONY: build
build:
docker build -t $(IMAGE_PREFIX):$(VERSION) . -f Dockerfile

push:
docker push "$(IMAGE_PREFIX):$(VERSION)"
12 changes: 12 additions & 0 deletions s2i-builders/julia/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

# JupyterHub singleuser builder

This is a builder image for use with [s2i](https://github.com/openshift/source-to-image). It
builds a source repository (such as a github repository) into a docker image that is suitable
for use with [JupyterHub](http://github.com/jupyterhub/jupyterhub).

It is based off Ubuntu 17.04, and uses [virtualenv](https://pypi.python.org/pypi/virtualenv) to
provide a custom python3.5 environment.

It looks for a `requirements.txt` file in the source repository, and installs it into the virtualenv.
It also installs a number of default notebook related modules in there
160 changes: 160 additions & 0 deletions s2i-builders/julia/test/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/bin/bash
#
# The 'run' performs a simple test that verifies the S2I image.
# The main focus here is to exercise the S2I scripts.
#
# For more information see the documentation:
# https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md
#
# IMAGE_NAME specifies a name of the candidate image used for testing.
# The image has to be available before this script is executed.
#
IMAGE_NAME=${IMAGE_NAME-ubuntu1610-python35-venv-candidate}

# Determining system utility executables (darwin compatibility check)
READLINK_EXEC="readlink"
MKTEMP_EXEC="mktemp"
if [[ "$OSTYPE" =~ 'darwin' ]]; then
! type -a "greadlink" &>"/dev/null" || READLINK_EXEC="greadlink"
! type -a "gmktemp" &>"/dev/null" || MKTEMP_EXEC="gmktemp"
fi

test_dir="$($READLINK_EXEC -zf $(dirname "${BASH_SOURCE[0]}"))"
image_dir=$($READLINK_EXEC -zf ${test_dir}/..)
scripts_url="file://${image_dir}/.s2i/bin"
cid_file=$($MKTEMP_EXEC -u --suffix=.cid)

# Since we built the candidate image locally, we don't want S2I to attempt to pull
# it from Docker hub
s2i_args="--pull-policy=never --loglevel=2"

# Port the image exposes service to be tested
test_port=8080

image_exists() {
docker inspect $1 &>/dev/null
}

container_exists() {
image_exists $(cat $cid_file)
}

container_ip() {
if [ ! -z "$DOCKER_HOST" ] && [[ "$OSTYPE" =~ 'darwin' ]]; then
docker-machine ip
else
docker inspect --format="{{ .NetworkSettings.IPAddress }}" $(cat $cid_file)
fi
}

container_port() {
if [ ! -z "$DOCKER_HOST" ] && [[ "$OSTYPE" =~ 'darwin' ]]; then
docker inspect --format="{{(index .NetworkSettings.Ports \"$test_port/tcp\" 0).HostPort}}" "$(cat "${cid_file}")"
else
echo $test_port
fi
}

run_s2i_build() {
s2i build --incremental=true ${s2i_args} file://${test_dir}/test-app ${IMAGE_NAME} ${IMAGE_NAME}-testapp
}

prepare() {
if ! image_exists ${IMAGE_NAME}; then
echo "ERROR: The image ${IMAGE_NAME} must exist before this script is executed."
exit 1
fi
# s2i build requires the application is a valid 'Git' repository
pushd ${test_dir}/test-app >/dev/null
git init
git config user.email "build@localhost" && git config user.name "builder"
git add -A && git commit -m "Sample commit"
popd >/dev/null
run_s2i_build
}

run_test_application() {
docker run --rm --cidfile=${cid_file} -p ${test_port} ${IMAGE_NAME}-testapp
}

cleanup() {
if [ -f $cid_file ]; then
if container_exists; then
docker stop $(cat $cid_file)
fi
fi
if image_exists ${IMAGE_NAME}-testapp; then
docker rmi ${IMAGE_NAME}-testapp
fi
}

check_result() {
local result="$1"
if [[ "$result" != "0" ]]; then
echo "S2I image '${IMAGE_NAME}' test FAILED (exit code: ${result})"
cleanup
exit $result
fi
}

wait_for_cid() {
local max_attempts=10
local sleep_time=1
local attempt=1
local result=1
while [ $attempt -le $max_attempts ]; do
[ -f $cid_file ] && break
echo "Waiting for container to start..."
attempt=$(( $attempt + 1 ))
sleep $sleep_time
done
}

test_usage() {
echo "Testing 's2i usage'..."
s2i usage ${s2i_args} ${IMAGE_NAME} &>/dev/null
}

test_connection() {
echo "Testing HTTP connection (http://$(container_ip):$(container_port))"
local max_attempts=10
local sleep_time=1
local attempt=1
local result=1
while [ $attempt -le $max_attempts ]; do
echo "Sending GET request to http://$(container_ip):$(container_port)/"
response_code=$(curl -s -w %{http_code} -o /dev/null http://$(container_ip):$(container_port)/)
status=$?
if [ $status -eq 0 ]; then
if [ $response_code -eq 200 ]; then
result=0
fi
break
fi
attempt=$(( $attempt + 1 ))
sleep $sleep_time
done
return $result
}

# Build the application image twice to ensure the 'save-artifacts' and
# 'restore-artifacts' scripts are working properly
prepare
run_s2i_build
check_result $?

# Verify the 'usage' script is working properly
test_usage
check_result $?

# Verify that the HTTP connection can be established to test application container
run_test_application &

# Wait for the container to write its CID file
wait_for_cid

test_connection
check_result $?

cleanup

11 changes: 11 additions & 0 deletions s2i-builders/julia/test/test-app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

<!doctype html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

1 change: 1 addition & 0 deletions s2i-builders/julia/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v0.2.1