Skip to content
This repository was archived by the owner on Mar 10, 2021. It is now read-only.

Commit 9fb8b88

Browse files
authored
Merge branch 'main' into refactor/dockerfile
2 parents a1d30e5 + 7c4467f commit 9fb8b88

17 files changed

+4335
-43
lines changed

.flake8

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
[flake8]
3+
# Explicitly ignore rules to maintain better compatibility with black.
4+
#
5+
# F403: import *
6+
# F811: redefinition of unused `name` from line `N`
7+
# F821: undefined name
8+
# F841: local variable assigned but never used
9+
# E402: module level import not at top of file
10+
# I100: your import statements are in the wrong order.
11+
# I101: the names in your from import are in the wrong order.
12+
# D400: first line should end with a period.
13+
# E203: colons should not have any space before them.
14+
# E231: missing whitespace after ','
15+
# E501: line lengths are recommended to be no greater than 79 characters.
16+
# E503: there is no need for backslashes between brackets.
17+
# E731: do not assign a lambda expression, use a def
18+
# W293: line break before binary operator
19+
# W293: blank line contains whitespace
20+
select = E,F,W,C
21+
ignore = F403, F811, F821, F841, E231, E402, I100, I101, D400, E501, E501, E503, E731, W293, W503
22+
extend-ignore = E203
23+
max-complexity = 15
24+
# https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
25+
max-line-length = 119
26+
builtins = c, get_config
27+
exclude =
28+
.ansible,
29+
.cache,
30+
__pycache__,
31+
.github,
32+
.ipynb_checkpoints,
33+
.pytest_cache,
34+
.travis,
35+
.vscode,
36+
ansible,
37+
docs,
38+
node_modules,
39+
venv

.hadolint.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
ignored:
3+
- DL3000
4+
- DL3004
5+
- DL3006
6+
- DL3007
7+
- DL3008
8+
- DL3015
9+
- DL3016
10+
- DL4006
11+
- SC2035

.travis.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
dist: bionic
3+
language: python
4+
python:
5+
- 3.8
6+
sudo: required
7+
services:
8+
- docker
9+
10+
jobs:
11+
include:
12+
- stage: full-test
13+
install:
14+
- pip install --upgrade pip
15+
- make venv
16+
script:
17+
- set -e
18+
- make test
19+
20+
stages:
21+
- name: full-test
22+
if: branch = main
23+

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include LICENSE

Makefile

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# inspiration from https://github.com/jupyter/docker-stacks
2+
.PHONY: dev
3+
4+
# Use bash for inline if-statements in target
5+
SHELL:=bash
6+
TAG:=latest
7+
OWNER:=illumidesk
8+
VENV_NAME?=venv
9+
VENV_BIN=$(shell pwd)/${VENV_NAME}/bin
10+
VENV_ACTIVATE=. ${VENV_BIN}/activate
11+
12+
PYTHON=${VENV_BIN}/python3
13+
14+
# Linter
15+
HADOLINT="${HOME}/hadolint"
16+
17+
help:
18+
# credits:
19+
# http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
20+
# http://github.com/jupyter/docker-stacks
21+
@echo "illumidesk/jupyter-pgweb-proxy"
22+
@echo "====================="
23+
@echo "Run one of the commands below with the 'make ...' command, i.e. 'make dev'."
24+
@echo
25+
@grep -E '^[a-zA-Z0-9_%/-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
26+
27+
build: ## build the latest image for a stack
28+
${VENV_BIN}/jupyter-repo2docker --no-run --user-id 1000 --user-name jovyan --image-name $(OWNER)/pgweb:$(TAG) .
29+
@echo -n "Built image size: "
30+
@docker images $(OWNER)/pgweb:$(TAG) --format "{{.Size}}"
31+
32+
clean-all: ## remove built images and running containers (including those w/ exit status)
33+
@docker rm -f $(shell docker ps -aq)
34+
35+
dev: venv ## run one of the containers (stacks) on port 8889
36+
docker-compose -f docker-compose.yaml up -d --build
37+
38+
dev-down:venv ## stop (down) the docker-compose services
39+
docker-compose -f docker-compose.yaml down
40+
41+
lint: venv ## lint the dockerfile(s)
42+
@echo "Linting Dockerfiles with Hadolint in ..."
43+
@git ls-files --exclude='Dockerfile*' --ignored docker-compose.yaml | grep -v ppc64 | xargs -L 1 $(HADOLINT) --config .hadolint.yml
44+
@echo "Linting with Hadolint done!"
45+
@echo "Linting tests with flake8 ..."
46+
${VENV_BIN}/flake8
47+
@echo "Linting with flake8 done!"
48+
@echo "Applying black updates to test files..."
49+
${VENV_BIN}/black .
50+
@echo "Source formatting with black done!"
51+
52+
lint-install: ## install hadolint
53+
@echo "Installing hadolint at $(HADOLINT) ..."
54+
@curl -sL -o $(HADOLINT) "https://github.com/hadolint/hadolint/releases/download/v1.18.0/hadolint-$(shell uname -s)-$(shell uname -m)"
55+
@chmod 700 $(HADOLINT)
56+
@echo "Hadolint nstallation done!"
57+
@$(HADOLINT) --version
58+
59+
test: ## test images as running containers
60+
${VENV_BIN}/pytest -v
61+
62+
venv: lint-install ## install hadolint and create virtual environment
63+
test -d $(VENV_NAME) || virtualenv -p python3 $(VENV_NAME)
64+
${PYTHON} -m pip install -r dev-requirements.txt
65+
${PYTHON} -m pip install --upgrade pip

README.md

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# jupyter-pgweb-proxy
22

3-
This package was built using the [`illumidesk/jupyter-server-proxy` cookiecutter template](https://github.com/illumidesk/cookiecutter-jupyter-server-proxy).
3+
This package was built from the [`illumidesk/cookiecutter-jupyter-server-proxy`](https://github.com/illumidesk/cookiecutter-jupyter-server-proxy) template.
44

55
## Requirements
66

@@ -10,27 +10,86 @@ This package was built using the [`illumidesk/jupyter-server-proxy` cookiecutter
1010

1111
This package executes the standard `pgweb` command. This command assumes the `pgweb` command is available in the environment's `PATH`.
1212

13-
### Install jupyter-pgweb-proxy
13+
## What?
14+
15+
Check it out, [it's pretty sweet](https://github.com/sosedoff/pgweb).
16+
17+
## Quick Starts
18+
19+
### Launch with `binder`
20+
21+
This test requires you to have a database instance available as a public endpoint or installed within the notebook container itself.
22+
23+
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/illumidesk/jupyter-pgweb-proxy/main?urlpath=pgweb)
24+
25+
### Run locally with `docker-compose`
26+
27+
```bash
28+
make dev
29+
```
30+
31+
1. Open your browser: http://localhost:8889
32+
1. Click the `pgweb` item from the `New` dropdown in `Jupyter Classic` or click on the green `pgweb` icon in the Notebooks section in `Jupyter Lab`.
33+
1. Connect with the `Scheme` or `Standard` option.
34+
35+
For example, with the `Scheme` option the string would look like so:
36+
37+
```bash
38+
postgres://postgres:postgres@testdb:5432/postgres?sslmode=disable
39+
```
40+
41+
### Cleanup
42+
43+
Stop services:
44+
45+
```bash
46+
make dev-down
47+
```
48+
49+
Remove images and running containers:
50+
51+
> **NOTE**: this will stop all running containers on the local, including those with the exit status.
52+
53+
```bash
54+
make clean-all
55+
```
56+
57+
## The Hard Way
1458

15-
Install the package with pip:
59+
### Create and Activate Environment
1660

61+
```bash
62+
virtualenv -p python3 venv
63+
source venv/bin/activate
1764
```
65+
66+
### Install jupyter-pgweb-proxy
67+
68+
```bash
1869
pip install git+https://github.com/illumidesk/jupyter-pgweb-proxy.git
1970
```
2071

21-
## Example
72+
### Enable jupyter-pgweb-proxy Extensions
2273

23-
Try with binder:
74+
1. For Jupyter Classic, activate the `jupyter-server-proxy` extension:
2475

25-
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/illumidesk/jupyter-pgweb-proxy/main?urlpath=pgweb)
76+
```bash
77+
jupyter serverextension enable --sys-prefix jupyter_server_proxy
78+
```
2679

27-
Test locally:
80+
2. For Jupyter Lab, install the `@jupyterlab/server-proxy` extension:
2881

2982
```bash
30-
docker build -t jupyter/pgweb .
31-
docker build -it --rm -p 8888:8888 jupyter/pgweb
83+
jupyter labextension install @jupyterlab/server-proxy
84+
jupyter lab build
3285
```
3386

87+
3. Start Jupyter Classic or Jupyter Lab
88+
89+
4. Click on the `pgweb` icon from the Jupyter Lab Launcher or the `pgweb` item from the `New` dropdown in Jupyter Classic.
90+
91+
5. Connect to your database as instructed in the [Quickstart](#quickstart) section.
92+
3493
## Credits
3594

3695
- [`jupyter-server-proxy`](https://github.com/jupyterhub/jupyter-server-proxy)

conftest.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# sourced from:
2+
# https://github.com/jupyter/docker-stacks
3+
#
4+
# Copyright (c) Jupyter Development Team.
5+
# Distributed under the terms of the Modified BSD License.
6+
#
7+
import os
8+
import logging
9+
10+
import docker
11+
12+
import pytest
13+
14+
import requests
15+
16+
from requests.packages.urllib3.util.retry import Retry
17+
from requests.adapters import HTTPAdapter
18+
19+
from typing import Container
20+
21+
22+
LOGGER = logging.getLogger(__name__)
23+
24+
25+
@pytest.fixture(scope="session")
26+
def http_client() -> requests.Session:
27+
"""Requests session with retries and backoff."""
28+
s = requests.Session()
29+
retries = Retry(total=5, backoff_factor=1)
30+
s.mount("http://", HTTPAdapter(max_retries=retries))
31+
s.mount("https://", HTTPAdapter(max_retries=retries))
32+
return s
33+
34+
35+
@pytest.fixture(scope="session")
36+
def docker_client() -> docker.client:
37+
"""Docker client configured based on the host environment"""
38+
return docker.from_env()
39+
40+
41+
@pytest.fixture(scope="session")
42+
def image_name() -> str:
43+
"""Image name to test"""
44+
return os.getenv("TEST_IMAGE", "illumidesk/base-notebook")
45+
46+
47+
class TrackedContainer:
48+
"""Wrapper that collects docker container configuration and delays
49+
container creation/execution.
50+
51+
Parameters
52+
----------
53+
docker_client: docker.DockerClient
54+
Docker client instance
55+
image_name: str
56+
Name of the docker image to launch
57+
**kwargs: dict, optional
58+
Default keyword arguments to pass to docker.DockerClient.containers.run
59+
"""
60+
61+
def __init__(
62+
self, docker_client: docker.client, image_name: str, **kwargs: str
63+
) -> None:
64+
self.container = None
65+
self.docker_client = docker_client
66+
self.image_name = image_name
67+
self.kwargs = kwargs
68+
69+
def run(self, **kwargs: str) -> Container:
70+
"""Runs a docker container using the preconfigured image name
71+
and a mix of the preconfigured container options and those passed
72+
to this method.
73+
74+
Keeps track of the docker.Container instance spawned to kill it
75+
later.
76+
77+
Parameters
78+
----------
79+
**kwargs: dict, optional
80+
Keyword arguments to pass to docker.DockerClient.containers.run
81+
extending and/or overriding key/value pairs passed to the constructor
82+
83+
Returns
84+
-------
85+
docker.Container
86+
"""
87+
all_kwargs = {}
88+
all_kwargs.update(self.kwargs)
89+
all_kwargs.update(kwargs)
90+
LOGGER.info(f"Running {self.image_name} with args {all_kwargs} ...")
91+
self.container = self.docker_client.containers.run(
92+
self.image_name, **all_kwargs
93+
)
94+
return self.container
95+
96+
def remove(self) -> None:
97+
"""Kills and removes the tracked docker container."""
98+
if self.container:
99+
self.container.remove(force=True)
100+
101+
102+
@pytest.fixture(scope="function")
103+
def container(docker_client, image_name) -> None:
104+
"""Notebook container with initial configuration appropriate for testing
105+
(e.g., HTTP port exposed to the host for HTTP calls).
106+
107+
Yields the container instance and kills it when the caller is done with it.
108+
"""
109+
container = TrackedContainer(
110+
docker_client, image_name, detach=True, ports={"8888/tcp": 8888}
111+
)
112+
yield container

dev-requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
black
2+
docker
3+
docker-compose
4+
flake8
5+
pytest

docker-compose.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: "3.8"
2+
3+
services:
4+
jupyter:
5+
image: jupyter/pgweb
6+
build:
7+
context: .
8+
container_name: notebook
9+
restart: always
10+
ports:
11+
- 8889:8888
12+
testdb:
13+
image: postgres:12.3-alpine
14+
container_name: postgres-labs
15+
restart: always
16+
environment:
17+
- POSTGRES_DB=postgres
18+
- POSTGRES_USER=postgres
19+
- POSTGRES_PASSWORD=postgres
20+
volumes:
21+
- db:/var/lib/postgresql/data
22+
- ./schema.sql:/docker-entrypoint-initdb.d/schema.sql
23+
24+
volumes:
25+
db:
26+
name: db

0 commit comments

Comments
 (0)