diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml index 93cd1840..5757be6c 100644 --- a/.github/workflows/container-image.yml +++ b/.github/workflows/container-image.yml @@ -31,13 +31,22 @@ jobs: name: Test needs: build runs-on: ubuntu-latest + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: mreg + POSTGRES_PASSWORD: mreg + # Set health checks to wait until postgres has started + options: >- + --health-cmd "pg_isready --username=mreg" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Map the containerized port to localhost. + - 5432:5432 steps: - - name: Start PostgreSQL - run: | - docker network create mreg - docker run --rm --network mreg -h postgres --name postgres -e POSTGRES_PASSWORD=mreg -e POSTGRES_USER=mreg --detach postgres - sleep 3s - docker exec postgres psql -U mreg -h localhost -c 'CREATE EXTENSION IF NOT EXISTS citext;' -d template1 - name: Checkout uses: actions/checkout@v3 - name: Download artifact @@ -48,10 +57,8 @@ jobs: run: docker load --input mreg.tgz - name: Run tests run: | - docker run --rm -t --network mreg --entrypoint /app/entrypoint-test.sh \ - --mount type=bind,source=${{github.workspace}}/mregsite,target=/app/mregsite,ro=true \ - --mount type=tmpfs,target=/app/logs \ - -e MREG_DB_HOST=postgres -e MREG_DB_PASSWORD=mreg -e MREG_DB_USER=mreg \ + docker run --rm -t --network host --entrypoint /app/entrypoint-test.sh \ + -e MREG_DB_HOST=localhost -e MREG_DB_PASSWORD=mreg -e MREG_DB_USER=mreg \ mreg publish: diff --git a/Dockerfile b/Dockerfile index 4e9f7e2c..6fecaca0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,8 @@ EXPOSE 8000 COPY requirements*.txt entrypoint* manage.py /app/ COPY mreg /app/mreg/ +COPY mregsite /app/mregsite/ +RUN mkdir /app/logs COPY hostpolicy /app/hostpolicy/ COPY --from=builder /usr/src/mreg/wheels /wheels RUN apk update && apk upgrade \ diff --git a/README.md b/README.md index 8094f2aa..c4859518 100644 --- a/README.md +++ b/README.md @@ -5,64 +5,66 @@ An associated project for a command line interface using the mreg API is availab ## Getting Started - ### Prerequisites -Fork the project from github. -You need a terminal, `python3`, and access to a package manager that can install the necessary requirements -from `requirements.txt`. We use pip. +If you want to set up your own PostgreSQL server by installing the necessary packages manually, you might need to install dependencies for setting up the citext extension. On Fedora, the package is called [`postgresql-contrib`](https://packages.fedoraproject.org/pkgs/postgresql/postgresql-contrib/). ### Installing #### Using Docker. Pre-built Docker images are available from [`ghcr.io/unioslo/mreg`](https://ghcr.io/unioslo/mreg): - ``` docker pull ghcr.io/unioslo/mreg ``` +You can also build locally, from the source: +``` +docker build -t mreg . +``` It is expected that you mount a custom "mregsite" directory on /app/mregsite: ``` docker run \ --mount type=bind,source=$HOME/customsettings,destination=/app/mregsite,readonly \ - ghcr.io/unioslo/mreg:latest --workers=4 --bind=0.0.0.0 + ghcr.io/unioslo/mreg:latest ``` To access application logs outside the container, also mount `/app/logs`. -The Docker image can be reproduced locally by installing [GNU Guix](https://guix.gnu.org) and running: - +It is also possible to not mount a settings directory, and to supply database login details in environment variables instead, overriding the default values found in `mregsite/settings.py`. ``` -guix time-machine -C ci/channels.scm -- pack -f docker \ - -S /app=app -S /etc/profile=etc/profile \ - --entry-point=bin/mreg-wrapper \ - -m ci/manifest.scm +docker run --network host \ + -e MREG_DB_HOST=my_postgres_host -e MREG_DB_NAME=mreg -e MREG_DB_USER=mreg -e MREG_DB_PASSWORD=mreg \ + ghcr.io/unioslo/mreg:latest ``` +For a full example, see `docker-compose.yml`. + #### Manually -A step by step series of examples that tell you how to get a development env running +##### A step by step series of examples that tell you how to get a development env running: + +Start by cloning the project from github. You need a terminal, `python3`, and access to a package manager that can install the necessary requirements from `requirements.txt`. We use pip. -When you've got your copy of the mreg directory, setup you virtual environment. +When you've got your copy of the mreg directory, setup you virtual environment: ``` > python3 -m venv venv > source venv/bin/activate ``` -Then install the required packages +Then install the required packages: ``` > pip install -r requirements.txt ``` -Perform database migrations +Perform database migrations: ``` > python manage.py migrate ``` -Load sample data from fixtures into the now migrated database +Load sample data from fixtures into the now migrated database: ``` > python manage.py loaddata mreg/fixtures/fixtures.json ``` -And finally, run the server. +And finally, run the server: ``` > python manage.py runserver ``` @@ -121,6 +123,9 @@ DATABASES = { * **Nicolay Mohebi** * **Magnus Hirth** * **Marius Bakke** +* **Safet Amedov** +* **Tannaz Roshandel** +* **Terje Kvernes** ## License diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..33e78738 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +# THIS DOCKER COMPOSE FILE IS ONLY PROVIDED AS AN EXAMPLE, IT IS NOT SUITABLE FOR PRODUCTION AS IS. +services: + postgres: + # If you want the data in the database to remain after the container is stopped, + # you should mount a directory into /var/lib/postgresql/data, or use a volume. See the documentation: + # https://github.com/docker-library/docs/blob/master/postgres/README.md#where-to-store-data + image: postgres + environment: + - POSTGRES_USER=mreg + - POSTGRES_DB=mreg + - POSTGRES_PASSWORD=mreg + healthcheck: + test: ["CMD", "pg_isready", "--username=mreg"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 5s + + # Uncomment this if you want a RabbitMQ server to send events to. See also MQ config in settings.py + # rabbitmq: + # image: rabbitmq + # ports: + # - 5672:5672 + + mreg: + depends_on: + postgres: + condition: service_healthy + #rabbitmq: + # condition: service_started + build: . + ports: + - 8000:8000 + environment: + - MREG_DB_HOST=postgres + - MREG_DB_NAME=mreg + - MREG_DB_USER=mreg + - MREG_DB_PASSWORD=mreg diff --git a/entrypoint-test.sh b/entrypoint-test.sh index fc5f32d8..0bbb9a4f 100644 --- a/entrypoint-test.sh +++ b/entrypoint-test.sh @@ -1,4 +1,5 @@ #!/bin/sh set -e cd /app +./manage.py create_citext_extension --database template1 ./manage.py test --noinput --failfast diff --git a/entrypoint.sh b/entrypoint.sh index b443caa8..ce483d1e 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,7 @@ #!/bin/sh set -e cd /app +./manage.py create_citext_extension ./manage.py migrate #./manage.py runserver 0.0.0.0:8000 diff --git a/mreg/management/commands/create_citext_extension.py b/mreg/management/commands/create_citext_extension.py new file mode 100644 index 00000000..95e2862d --- /dev/null +++ b/mreg/management/commands/create_citext_extension.py @@ -0,0 +1,38 @@ +from django.core.management.base import BaseCommand, CommandError +from django.db import connection +from sys import stdout +from django.conf import settings +from psycopg2 import connect + +class Command(BaseCommand): + help = 'Create the CITEXT extension in the database.' + + def add_arguments(self, parser): + # optional argument + parser.add_argument( + '--database', + type=str, + help='Database name', + ) + + def handle(self, *args, **options): + stdout.write("Attempting to create the CITEXT extension in the database...\n") + stdout.flush() + try: + con = connection + if options['database']: + stdout.write(f"Connecting to database {options['database']}\n") + stdout.flush() + con = connect(host=settings.DATABASES['default']['HOST'], + user=settings.DATABASES['default']['USER'], + password=settings.DATABASES['default']['PASSWORD'], + database=options['database']) + with con.cursor() as cursor: + cursor.execute("CREATE EXTENSION IF NOT EXISTS citext") + stdout.write(cursor.statusmessage+"\n") + stdout.flush() + con.commit() + except Exception as e: + stdout.write(e.__str__()) + stdout.flush() + raise CommandError('Failed to create the CITEXT extension in the database.')