2
votes

I'm trying to build a GitLab-CI pipeline but Django doesn't seems to catch the ALLOWED_HOST variable passed as environment variable.

The project it self is a Django project running in a container. Django needs an ALLOWED_HOSTS and a SECRET_KEY value in its settings in order to work. On my development environment as well as on my production server, the variables are passed to Django via an env-file.

Django settings sample:

SECRET_KEY = os.environ.get('SECRET_KEY')

ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")

Env-file sample:

SECRET_KEY=mydummysecretkey

DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]

This works fine on my dev and my production machines.

But when I try to run it in my .gitlab-ci.yml, Django doesn't find the DJANGO_ALLOWED_HOSTS variable. I always got this error:

$ docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project

ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
AttributeError: 'NoneType' object has no attribute 'split'
ERROR: Job failed: exit code 1

This is quite strange because Django catches the SECRET_KEY variable well. As you can see in the code snippet bellow, I even did an echo on the variable which is well displayed.

FYI: Django is running in a Docker container and the CI-pipeline build the image (and pushes it to the Gitlab registery) on the first job in order to test it on the second job (and deploy it on the third job).

Here is my .gitlab-ci.yml:

image: docker:stable

services:
  - docker:19.03.0-dind

variables:
  SECRET_KEY: 'mydummysecretkey_gitlab-ci'
  DJANGO_ALLOWED_HOSTS: 'localhost 127.0.0.1 [::1]'

stages:
  - build
  - test

Build and push stage:
  stage: build
  script:
    - docker login --username $CI_REGISTRY_USER --password "$CI_BUILD_TOKEN" $CI_REGISTRY
    - docker pull $CI_REGISTRY_IMAGE:latest || true
    - docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA ./my_project
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Test stage:
  stage: test
  script:
    - echo $DJANGO_ALLOWED_HOSTS
    - docker login --username $CI_REGISTRY_USER --password "$CI_BUILD_TOKEN" $CI_REGISTRY
    - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project  # Fails here !
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:latest

Here is the output:

$ echo $DJANGO_ALLOWED_HOSTS
localhost 127.0.0.1 [::1]
$ docker login --username $CI_REGISTRY_USER --password "$CI_BUILD_TOKEN" $CI_REGISTRY
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

...

$ docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project
Traceback (most recent call last):
  
...

  File "/usr/src/app/my_project/settings.py", line 32, in <module>
    ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
AttributeError: 'NoneType' object has no attribute 'split'
ERROR: Job failed: exit code 1
1
Try to put the values in the env file in quotes.Klaus D.
@KlausD. There is no env-file in the pipeline. The env-variables are declared directly declared in it and they actually are quoted. So is the SECRET_KEY as well and this one works.Bravo2bad
os.environ.get retreives environment variables from the running system which is your docker container, not from the underlying gitlab-ci system. Gitlab CI vars (as your usual shell vars) are not automagically pushed to your container. SECRET_KEY does not issue a warning because it's simply null. DJANGO_ALLOWED_HOSTS does because you try to split it. You have to pass those env vars to your container, either with the -e docker option or through an env file you create on spot.Zeitounator
@Zeitounator That was it, indeed. So simple now that I have the answer. Thank you.Bravo2bad

1 Answers

3
votes

I got my answer thanks to @Zeitounator

I will simply quote his/her comment in order to make it simple:

os.environ.get retrieves environment variables from the running system which is your docker container, not from the underlying gitlab-ci system. Gitlab CI vars (as your usual shell vars) are not automagically pushed to your container. SECRET_KEY does not issue a warning because it's simply null. DJANGO_ALLOWED_HOSTS does because you try to split it. You have to pass those env vars to your container, either with the -e docker option or through an env file you create on spot.

So this definitely works:

...

Test stage:
  stage: test
  script:

...

    - docker run --rm -e SECRET_KEY=mydummysecretkey_gitlab-ci -e DJANGO_ALLOWED_HOSTS='localhost 127.0.0.1 [::1]' $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA pytest

...

I ended up with something like this:

docker run --rm -e SECRET_KEY='$SECRET_KEY' -e DJANGO_ALLOWED_HOSTS='$DJANGO_ALLOWED_HOSTS' $CI_COMMIT_SHA pytest