diff --git a/Dockerfile b/Dockerfile index 089d7a92..b5eea22d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,8 +26,8 @@ RUN printf "Package: *\nPin: release a=testing\nPin-Priority: 750\n" > /etc/apt/ RUN printf "deb http://mirror.steadfast.net/debian/ stable main contrib non-free\ndeb-src http://mirror.steadfast.net/debian/ stable main contrib non-free" > /etc/apt/sources.list.d/stable.list RUN printf "deb http://mirror.steadfast.net/debian/ testing main contrib non-free\ndeb-src http://mirror.steadfast.net/debian/ testing main contrib non-free" > /etc/apt/sources.list.d/testing.list -# Install GDAL -RUN apt-get update && apt-get install -t testing -y binutils libproj-dev gdal-bin +# Install GDAL, nginx +RUN apt-get update && apt-get install -t testing -y binutils libproj-dev gdal-bin nginx WORKDIR /webodm/nodeodm/external/node-OpenDroneMap RUN npm install diff --git a/app/boot.py b/app/boot.py index 501a8d44..5310a556 100644 --- a/app/boot.py +++ b/app/boot.py @@ -6,14 +6,24 @@ from django.db.utils import ProgrammingError from guardian.shortcuts import assign_perm from nodeodm.models import ProcessingNode -from . import signals, scheduler -import logging, os +from . import scheduler +import logging from .models import Task from webodm import settings +from webodm.wsgi import booted def boot(): + # booted is a shared memory variable to keep track of boot status + # as multiple workers could trigger the boot sequence twice + if booted.value: return + + booted.value = True logger = logging.getLogger('app.logger') + logger.info("Booting...") + + if settings.DEBUG: + logger.warning("Debug mode is ON (for development this is OK)") # Check default group try: diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/build/.gitignore @@ -0,0 +1 @@ +* diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 00000000..5a4e7e85 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,66 @@ +worker_processes 1; + +# Change this if running outside docker! +user root root; +pid /tmp/nginx.pid; +error_log /tmp/nginx.error.log; + +events { + worker_connections 1024; # increase if you have lots of clients + accept_mutex off; # set to 'on' if nginx worker_processes > 1 + use epoll; +} + +http { + include /etc/nginx/mime.types; + + # fallback in case we can't determine a type + default_type application/octet-stream; + access_log /tmp/nginx.access.log combined; + sendfile on; + + upstream app_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response + + # for UNIX domain socket setups + server unix:/tmp/gunicorn.sock fail_timeout=0; + } + + server { + listen 8000 deferred; + client_max_body_size 20G; + + # set the correct host(s) for your site + server_name webodm.localhost; + + keepalive_timeout 5; + + # path for static files + location /static { + root /webodm/build; + } + + location / { + # CORS settings + + # These settings are VERY permissive, consider tightening them + + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; + add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; + + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # enable this if and only if you use HTTPS + # proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + proxy_pass http://app_server; + } + } +} diff --git a/requirements.txt b/requirements.txt index d571f183..653ac3cd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ appdirs==1.4.0 APScheduler==3.2.0 coreapi==2.0.9 Django==1.10.5 +django-cors-headers==2.0.2 django-debug-toolbar==1.6 django-filter==0.15.3 django-guardian==1.4.6 @@ -12,6 +13,7 @@ djangorestframework-jwt==1.9.0 drf-nested-routers==0.11.1 funcsigs==1.0.2 futures==3.0.5 +gunicorn==19.7.1 itypes==1.1.0 Markdown==2.6.7 openapi-codec==1.1.7 @@ -31,4 +33,3 @@ strict-rfc3339==0.7 tzlocal==1.3 uritemplate==3.0.0 webcolors==1.5 -django-cors-headers==2.0.2 diff --git a/start.sh b/start.sh index 67194d4b..17d534a6 100755 --- a/start.sh +++ b/start.sh @@ -58,6 +58,9 @@ fi echo Running migrations python manage.py migrate +echo Collecting static assets +python manage.py collectstatic --noinput + if [[ $1 = "--create-default-pnode" ]]; then echo "from nodeodm.models import ProcessingNode; ProcessingNode.objects.update_or_create(hostname='node-odm-1', defaults={'hostname': 'node-odm-1', 'port': 3000})" | python manage.py shell fi @@ -73,7 +76,12 @@ echo Open a web browser and navigate to http://localhost:8000 echo -e "\033[39m" echo -e "\033[91mNOTE:\033[39m Windows users using docker should replace localhost with the IP of their docker machine's IP. To find what that is, run: docker-machine ip") & -python manage.py runserver 0.0.0.0:8000 +if [ $1 = "--setup-devenv" ] || [ $2 = "--setup-devenv" ]; then + python manage.py runserver 0.0.0.0:8000 +else + nginx -c /webodm/nginx/nginx.conf + gunicorn webodm.wsgi --bind unix:/tmp/gunicorn.sock --preload +fi # If this is executed, it means the previous command failed, don't display the congratulations message kill %1 diff --git a/webodm/settings.py b/webodm/settings.py index d9a74c1e..b8041758 100644 --- a/webodm/settings.py +++ b/webodm/settings.py @@ -26,7 +26,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SECRET_KEY = 'gmarsutd!fee6_58=6k)2je#o2^&&)ovu1svjg8k^(a!7qa7r&' # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +TESTING = sys.argv[1:2] == ['test'] +DEBUG = sys.argv[1:2] == ['runserver'] or TESTING INTERNAL_IPS = ['127.0.0.1'] ALLOWED_HOSTS = ['*'] @@ -142,6 +143,7 @@ USE_TZ = True # https://docs.djangoproject.com/en/1.10/howto/static-files/ STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'build', 'static') STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'app', 'static'), ] @@ -239,7 +241,6 @@ JWT_AUTH = { 'JWT_EXPIRATION_DELTA': datetime.timedelta(hours=6), } -TESTING = sys.argv[1:2] == ['test'] if TESTING: MEDIA_ROOT = os.path.join(BASE_DIR, 'app', 'media_test') diff --git a/webodm/wsgi.py b/webodm/wsgi.py index 89f6e873..1dd13d4e 100644 --- a/webodm/wsgi.py +++ b/webodm/wsgi.py @@ -8,9 +8,11 @@ https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ """ import os - +from multiprocessing import Value from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webodm.settings") application = get_wsgi_application() + +booted = Value('b', False) \ No newline at end of file