Skip to content

Commit

Permalink
Run all tests dockerized *and* podified (#219)
Browse files Browse the repository at this point in the history
  • Loading branch information
ig248 authored and jacobtomlinson committed Jan 17, 2020
1 parent 2930660 commit add93d5
Show file tree
Hide file tree
Showing 13 changed files with 356 additions and 267 deletions.
98 changes: 18 additions & 80 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,94 +2,32 @@ version: 2

jobs:
build:
machine: true
environment:
MINIKUBE_WANTUPDATENOTIFICATION: false
MINIKUBE_WANTREPORTERRORPROMPT: false
CHANGE_MINIKUBE_NONE_USER: true
PYTHON: "3.7"
ENV_NAME: "dask-kubernetes-test"
machine:
image: ubuntu-1604:201903-01

steps:
- checkout
- run:
command: |
curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.8.4/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
# Use minikube v0.25.2 as v0.26.0 requires systemd to manage the daemons which
# is not available in the Ubuntu 14.04 image used by Circle CI with the
# "machine: true" option.
name: Install kubectl
command: sudo make kubectl-bootstrap BIN_PATH=/usr/local/bin
- run:
command: |
curl -Lo minikube https://github.com/kubernetes/minikube/releases/download/v0.25.2/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
name: Install kind
command: sudo make kind-bootstrap BIN_PATH=/usr/local/bin
- run:
command: |
sudo -E minikube start --vm-driver=none --extra-config=kubelet.MaxPods=20
name: Start local Kubernetes Cluster and create context in ~/.kube/config
command: make kind-start
- run:
command: |
sudo -E minikube addons enable kube-dns
name: Build docker image for testing
command: make build
- run:
command: |
sudo -E minikube update-context
name: Lint containerized code
command: make docker-make COMMAND=lint
- run:
command: |
JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'; until sudo kubectl get nodes -o jsonpath="$JSONPATH" 2>&1 | grep -q "Ready=True"; do sleep 1; done
name: Make docker image available in-cluster
command: make push-kind
- run:
command: |
sudo kubectl cluster-info
name: Create K8S resources needed for testing in-cluster
command: make k8s-deploy
- run:
command: |
sudo kubectl run circleci-example --image=nginx
sudo kubectl expose deployment circleci-example --port 80 --type=ClusterIP --name=circleci-example
- run:
command: |
sudo kubectl get deployment
sudo kubectl get service
- run:
command: |
KUBEDNS=`sudo kubectl get svc -o json kube-dns --namespace=kube-system | jq -r '.spec.clusterIP'`
echo "nameserver $KUBEDNS" | sudo tee -a /etc/resolvconf/resolv.conf.d/head > /dev/null
echo "search default.svc.cluster.local svc.cluster.local cluster.local" | sudo tee -a /etc/resolvconf/resolv.conf.d/base > /dev/null
echo "options ndots:5" | sudo tee -a /etc/resolvconf/resolv.conf.d/base > /dev/null
sudo resolvconf -u
- run:
command: |
until nslookup circleci-example.default; do
sleep 1
done
curl circleci-example.default
- run:
name: install miniconda
command: |
if [ ! -d "/home/circleci/miniconda" ]; then
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh
bash miniconda.sh -b -p $HOME/miniconda
export PATH="$HOME/miniconda/bin:$PATH"
conda config --set always_yes yes --set changeps1 no
fi
sudo chown -R $USER.$USER $HOME
- run:
name: configure conda
command: |
export PATH="$HOME/miniconda/bin:$PATH"
if [ ! -d "/home/circleci/miniconda/envs/dask-kubernetes-test" ]; then
conda install pip # create a record for conda, to avoid removing setuptools. See #192 for more.
conda update -q conda
conda env create -f ci/environment-${PYTHON}.yml --name=${ENV_NAME}
source activate ${ENV_NAME}
pip install --no-deps --quiet -e .
fi
conda env list
conda list ${ENV_NAME}
- run:
name: build docker
command: |
# eval $(minikube docker-env)
docker build -t daskdev/dask:dev docker/
- run:
command: |
# eval $(minikube docker-env)
/home/circleci/miniconda/envs/dask-kubernetes-test/bin/py.test dask_kubernetes -s --verbose --worker-image daskdev/dask:dev
- run:
command: |
/home/circleci/miniconda/envs/dask-kubernetes-test/bin/flake8 dask-kubernetes
/home/circleci/miniconda/envs/dask-kubernetes-test/bin/black --check dask_kubernetes setup.py
name: Test containerized code in-cluster
command: make k8s-make COMMAND=test
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.*
Dockerfile
102 changes: 102 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
IMAGE_NAME ?= dask-kubernetes
IMAGE_TAG ?= test

# kind-kind OR minikibe
K8S_TEST_CONTEXT ?= kind-kind
# must have a serviceaccount, e.g. defined via `make k8s-set-up`
K8S_TEST_NAMESPACE ?= dask-kubernetes-test
COMMAND ?= test
WORKER_IMAGE ?= ${IMAGE_NAME}:${IMAGE_TAG}
EXTRA_TEST_ARGS ?=

# Path to install binaries to
BIN_PATH ?= ~/.local/bin/

# Versions to install by default
OS ?= linux
ARCHITECTURE ?= amd64
KUBECTL_VERSION ?= v1.17.0
KIND_VERSION ?= v0.6.1
MINIKUBE_VERSION ?= v0.25.2

# Pure python commands
.PHONY: install format lint test

install:
pip install -e .
pip install -r requirements-dev.txt

format:
black dask_kubernetes setup.py

lint:
flake8 dask-kubernetes
black --check dask_kubernetes setup.py

test:
py.test dask_kubernetes -vvv \
--namespace=${K8S_TEST_NAMESPACE} --worker-image=${WORKER_IMAGE} ${EXTRA_TEST_ARGS}

# Docker commands
.PHONY: build docker-make

build:
docker build -t ${IMAGE_NAME}:${IMAGE_TAG} -f ci/Dockerfile .

docker-make:
docker run -it --entrypoint make ${IMAGE_NAME}:${IMAGE_TAG} ${COMMAND}

# Make test image available in-cluster.
# This is the only step that is not cluster-agnostic.
.PHONY: push-kind

push-kind:
kind load docker-image ${IMAGE_NAME}:${IMAGE_TAG}

# Kubernetes commands
.PHONY: k8s-deploy k8s-test k8s-clean

k8s-deploy:
kubectl --context=${K8S_TEST_CONTEXT} apply -f kubernetes/test-runner-setup.yaml

k8s-make: # having to set USER is actually a bug
kubectl --context=${K8S_TEST_CONTEXT} -n ${K8S_TEST_NAMESPACE} \
run -i --tty --restart=Never \
dask-kubernetes-test \
--serviceaccount=test-runner \
--image=${IMAGE_NAME}:${IMAGE_TAG} \
--image-pull-policy=Never \
--env="USER=tester" \
--env="K8S_TEST_NAMESPACE=${K8S_TEST_NAMESPACE}" \
--env="EXTRA_TEST_ARGS=--in-cluster" \
--rm=true \
--command -- make ${COMMAND}

k8s-clean:
kubectl --context=${K8S_TEST_CONTEXT} -n ${K8S_TEST_NAMESPACE} delete all --all

# Install kubectl and local cluster
.PHONY: kubectl-bootstrap kind-bootstrap minikube-bootstrap

kubectl-bootstrap:
curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/${OS}/${ARCHITECTURE}/kubectl && \
chmod +x kubectl && \
mv kubectl ${BIN_PATH}

kind-bootstrap: # https://github.com/kubernetes-sigs/kind
curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-${OS}-${ARCHITECTURE} && \
chmod +x ./kind && \
mv kind ${BIN_PATH}

kind-start:
kind create cluster && \
kind export kubeconfig

minikube-bootstrap:
curl -Lo minikube https://github.com/kubernetes/minikube/releases/download/${MINIKUBE_VERSION}/minikube-${OS}-${ARCHITECTURE} && \
chmod +x minikube && \
mv minikube ${BIN_PATH}

minikube-start: # this needs to be run before `build` to use locally built image in minikube
minikube start --vm-driver=none --extra-config=kubelet.MaxPods=20 && \
eval $(shell minikube docker-env)
11 changes: 11 additions & 0 deletions ci/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM daskdev/dask:latest

RUN apt-get update && apt-get install -y --no-install-recommends \
make \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /usr/local/src/dask_kubernetes
COPY . .

RUN make install
34 changes: 0 additions & 34 deletions ci/environment-3.7.yml

This file was deleted.

49 changes: 44 additions & 5 deletions dask_kubernetes/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,52 @@
import asyncio

import pytest

import kubernetes

from dask_kubernetes.auth import ClusterAuth, KubeConfig, InCluster


def pytest_addoption(parser):
parser.addoption("--worker-image", help="Worker image to use for testing")
parser.addoption(
"--worker-image",
default="daskdev/dask:latest",
help="Worker image to use for testing",
)
parser.addoption("--context", default=None, help="kubectl context to use")
parser.addoption(
"--in-cluster", action="store_true", default=False, help="are we in cluster?"
)
parser.addoption("--namespace", default="default", help="Cluster namespace to use")


@pytest.fixture
def image_name(request):
worker_image = request.config.getoption("--worker-image")
if not worker_image:
return "daskdev/dask:dev"
return worker_image
return request.config.getoption("--worker-image")


@pytest.fixture(scope="session")
def context(request):
return request.config.getoption("--context")


@pytest.fixture(scope="session")
def in_cluster(request):
return request.config.getoption("--in-cluster")


@pytest.fixture(scope="session")
def auth(in_cluster, context):
if in_cluster:
auth = [InCluster()]
elif context:
auth = [KubeConfig(context=context)]
else:
auth = None
return auth


@pytest.fixture(scope="module")
def ns(request):
"""Use this fixture in all integration tests that need live K8S cluster."""
return request.config.getoption("--namespace")

0 comments on commit add93d5

Please sign in to comment.