Skip to content

Commit

Permalink
Merge pull request #2 from tiangolo/add-prestart-sh
Browse files Browse the repository at this point in the history
Add support for /app/prestart.sh
  • Loading branch information
tiangolo committed Feb 8, 2019
2 parents 262c5f1 + 93f1587 commit 30478e5
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 16 deletions.
40 changes: 37 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,16 +405,50 @@ It uses the environment variables declared above to set all the configurations.

You can override it by including a file in:

* `/app/gunicorn_conf.py`,
* `/app/app/gunicorn_conf.py` or replacing the one in
* `/gunicorn_conf.py` or replacing the one in
* `/app/gunicorn_conf.py`
* `/app/app/gunicorn_conf.py`
* `/gunicorn_conf.py`


### Custom `/app/prestart.sh`

If you need to run anything before starting the app, you can add a file `prestart.sh` to the directory `/app`. The image will automatically detect and run it before starting everything.

For example, if you want to add Alembic SQL migrations (with SQLALchemy), you could create a `./app/prestart.sh` file in your code directory (that will be copied by your `Dockerfile`) with:

```bash
#! /usr/bin/env bash

# Let the DB start
sleep 10;
# Run migrations
alembic upgrade head
```

and it would wait 10 seconds to give the database some time to start and then run that `alembic` command.

If you need to run a Python script before starting the app, you could make the `/app/prestart.sh` file run your Python script, with something like:

```bash
#! /usr/bin/env bash

# Run custom Python script before starting
python /app/my_custom_prestart_script.py
```


## Tests

All the image tags, configurations, environment variables and application options are tested.


## Release Notes

### 0.1.0

* Add support for `/app/prestart.sh`.


## License

This project is licensed under the terms of the MIT license.
39 changes: 27 additions & 12 deletions tests/test_01_main/test_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,30 @@
import pytest
import requests

from ..utils import CONTAINER_NAME, get_config, stop_previous_container
from ..utils import CONTAINER_NAME, get_config, get_logs, remove_previous_container

client = docker.from_env()


def verify_container(container, response_text):
config_data = get_config(container)
assert config_data["workers_per_core"] == 2
assert config_data["host"] == "0.0.0.0"
assert config_data["port"] == "80"
assert config_data["loglevel"] == "info"
assert config_data["workers"] > 2
assert config_data["bind"] == "0.0.0.0:80"
logs = get_logs(container)
assert "Checking for script in /app/prestart.sh" in logs
assert "Running script /app/prestart.sh" in logs
assert (
"Running inside /app/prestart.sh, you could add migrations to this file" in logs
)
response = requests.get("http://127.0.0.1:8000")
data = response.json()
assert data["message"] == response_text


@pytest.mark.parametrize(
"image,response_text",
[
Expand All @@ -35,20 +54,16 @@
],
)
def test_defaults(image, response_text):
stop_previous_container(client)
remove_previous_container(client)
container = client.containers.run(
image, name=CONTAINER_NAME, ports={"80": "8000"}, detach=True
)
time.sleep(1)
config_data = get_config(container)
assert config_data["workers_per_core"] == 2
assert config_data["host"] == "0.0.0.0"
assert config_data["port"] == "80"
assert config_data["loglevel"] == "info"
assert config_data["workers"] > 2
assert config_data["bind"] == "0.0.0.0:80"
response = requests.get("http://127.0.0.1:8000")
data = response.json()
assert data["message"] == response_text
verify_container(container, response_text)
container.stop()
# Test that everything works after restarting too
container.start()
time.sleep(1)
verify_container(container, response_text)
container.stop()
container.remove()
7 changes: 6 additions & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,15 @@ def get_config(container):
return json.loads(result.output.decode())


def stop_previous_container(client):
def remove_previous_container(client):
try:
previous = client.containers.get(CONTAINER_NAME)
previous.stop()
previous.remove()
except NotFound:
return None


def get_logs(container):
logs: str = container.logs()
return logs.decode("utf-8")

0 comments on commit 30478e5

Please sign in to comment.