From bb29b60263e25ad55a4212ef91b6501bee3a25e7 Mon Sep 17 00:00:00 2001 From: Denys Zhdanov Date: Sun, 19 Apr 2015 18:58:49 +0200 Subject: [PATCH 1/5] Backport of #1188 "Serve staticfiles in the webapp if whitenoise is installed". This avoids the collectstatic step & apache configuration. It's probably slightly less optimal than serving files with apache/nginx but much easier to start with. Whitenoise until recent versions (>2.0.2) was compatible with Django 1.4 and above but requires python 2.7 --- .travis.yml | 12 +++---- check-dependencies.py | 7 ++++ conf/graphite.wsgi.example | 53 +++++++++++++++++----------- docs/config-local-settings.rst | 3 ++ examples/example-graphite-vhost.conf | 7 ++++ requirements.txt | 1 + 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index fb6919eea..e8b5077d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ python: - "2.7" env: - - REQUIREMENTS="Django<1.5 django-discover-runner" - - REQUIREMENTS="Django<1.6 django-discover-runner" - - REQUIREMENTS="Django<1.7" - - REQUIREMENTS="Django<1.8" + - REQUIREMENTS="Django<1.5 django-tagging<0.4 django-discover-runner" + - REQUIREMENTS="Django<1.6 django-tagging<0.4 django-discover-runner" + - REQUIREMENTS="Django<1.7 django-tagging<0.4" + - REQUIREMENTS="Django<1.8 django-tagging<0.4" before_install: - sudo apt-get -y install libcairo2-dev @@ -21,7 +21,7 @@ install: - pip install https://github.com/graphite-project/ceres/tarball/master - pip install https://github.com/graphite-project/whisper/tarball/master - pip install $REQUIREMENTS - - pip install django-tagging pytz pyparsing==1.5.7 http://cairographics.org/releases/py2cairo-1.8.10.tar.gz + - pip install pytz pyparsing==1.5.7 http://cairographics.org/releases/py2cairo-1.8.10.tar.gz script: - PYTHONPATH=. python graphite/manage.py syncdb --noinput @@ -30,4 +30,4 @@ script: matrix: exclude: - python: "2.6" - env: REQUIREMENTS="Django<1.8" + env: REQUIREMENTS="Django<1.8 django-tagging<0.4" \ No newline at end of file diff --git a/check-dependencies.py b/check-dependencies.py index 357d53f16..64495f66c 100755 --- a/check-dependencies.py +++ b/check-dependencies.py @@ -165,6 +165,13 @@ print "Note that txamqp requires python 2.5 or greater." warning += 1 +# Test for whitenoise +try: + import whitenoise +except ImportError: + print "[INFO]" + print "Unable to import the 'whitenoise' module." + print "This is useful for serving static files." if fatal: print "%d necessary dependencies not met. Graphite will not function until these dependencies are fulfilled." % fatal diff --git a/conf/graphite.wsgi.example b/conf/graphite.wsgi.example index fd9a6868a..bbc1e7152 100755 --- a/conf/graphite.wsgi.example +++ b/conf/graphite.wsgi.example @@ -1,25 +1,38 @@ -import os, sys -sys.path.append('/opt/graphite/webapp') -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'graphite.settings') +import os +import sys -import django +try: + from importlib import import_module +except ImportError: + from django.utils.importlib import import_module -if django.VERSION < (1, 4): - from django.core.handlers.wsgi import WSGIHandler - application = WSGIHandler() -else: - # From 1.4 wsgi support was improved and since 1.7 old style WSGI script - # causes AppRegistryNotReady exception - # https://docs.djangoproject.com/en/dev/releases/1.7/#wsgi-scripts - from django.core.wsgi import get_wsgi_application - application = get_wsgi_application() +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'graphite.settings') # noqa - -# READ THIS -# Initializing the search index can be very expensive, please include -# the WSGIImportScript directive pointing to this script in your vhost -# config to ensure the index is preloaded before any requests are handed -# to the process. +from django.conf import settings +from django.core.wsgi import get_wsgi_application from graphite.logger import log + +application = get_wsgi_application() + +# whitenoise working only in python >= 2.7 +if sys.version_info[0] >= 2 and sys.version_info[1] >= 7: + try: + from whitenoise.django import DjangoWhiteNoise + except ImportError: + pass + else: + application = DjangoWhiteNoise(application) + prefix = "/".join((settings.URL_PREFIX.strip('/'), 'static')) + for directory in settings.STATICFILES_DIRS: + application.add_files(directory, prefix=prefix) + for app_path in settings.INSTALLED_APPS: + module = import_module(app_path) + directory = os.path.join(os.path.dirname(module.__file__), 'static') + if os.path.isdir(directory): + application.add_files(directory, prefix=prefix) + +# Initializing the search index can be very expensive. The import below +# ensures the index is preloaded before any requests are handed to the +# process. log.info("graphite.wsgi - pid %d - reloading search index" % os.getpid()) -import graphite.metrics.search +import graphite.metrics.search # noqa diff --git a/docs/config-local-settings.rst b/docs/config-local-settings.rst index a2763e27f..fdef63959 100644 --- a/docs/config-local-settings.rst +++ b/docs/config-local-settings.rst @@ -112,6 +112,9 @@ STATIC_ROOT alias /opt/graphite/static/; } + Alternatively, static files can be served directly by the Graphite webapp if + you install the ``whitenoise`` Python package. + DASHBOARD_CONF `Default: CONF_DIR/dashboard.conf` The location of the Graphite-web Dashboard configuration diff --git a/examples/example-graphite-vhost.conf b/examples/example-graphite-vhost.conf index 95b19f668..89fca2298 100644 --- a/examples/example-graphite-vhost.conf +++ b/examples/example-graphite-vhost.conf @@ -36,6 +36,13 @@ WSGISocketPrefix run/wsgi # file in this directory that you can safely use, just copy it to graphite.wgsi WSGIScriptAlias / /opt/graphite/conf/graphite.wsgi + # XXX To serve static files, either: + # django-admin.py collectstatic --noinput --settings=graphite.settings + # * Install the whitenoise Python package (pip install whitenoise) + # or + # * Collect static files in a directory by running: + # django-admin.py collectstatic --noinput --settings=graphite.settings + # And set an alias to serve static files with Apache: Alias /content/ /opt/graphite/webapp/content/ SetHandler None diff --git a/requirements.txt b/requirements.txt index c502d0ce5..f45883db6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,3 +41,4 @@ sphinx sphinx_rtd_theme cairocffi git+git://github.com/graphite-project/whisper.git@0.9.13#egg=whisper +whitenoise \ No newline at end of file From 8df177d83a5547ea5b28e84c657fccc271df3d0f Mon Sep 17 00:00:00 2001 From: obfuscurity Date: Thu, 28 May 2015 00:30:45 -0400 Subject: [PATCH 2/5] remove pytz dependency check, fixes #1081 --- check-dependencies.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/check-dependencies.py b/check-dependencies.py index 64495f66c..d83414bd8 100755 --- a/check-dependencies.py +++ b/check-dependencies.py @@ -87,14 +87,6 @@ fatal += 1 -# Test for a pytz module -try: - import pytz -except ImportError: - print "[FATAL] Unable to import the 'pytz' module, do you have pytz installed for python %s?" % py_version - fatal += 1 - - # Test for zope.interface try: from zope.interface import Interface From bcc86e48404748b783a2923fe6964a00dea12fc1 Mon Sep 17 00:00:00 2001 From: Jack Neely Date: Thu, 2 Jul 2015 13:44:02 -0400 Subject: [PATCH 3/5] Supply a default timezone if none exists. This fixes #1142. --- webapp/graphite/util.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webapp/graphite/util.py b/webapp/graphite/util.py index 0885bab4d..1ccd0a35e 100644 --- a/webapp/graphite/util.py +++ b/webapp/graphite/util.py @@ -31,6 +31,7 @@ from os import environ from django.core.exceptions import ObjectDoesNotExist from django.contrib.auth.models import User +from django.utils.timezone import get_current_timezone from graphite.account.models import Profile from graphite.logger import log @@ -52,6 +53,8 @@ def epoch(dt): """ Returns the epoch timestamp of a timezone-aware datetime object. """ + if dt.tzinfo is None: + dt = dt.replace(tzinfo=get_current_timezone()) return calendar.timegm(dt.astimezone(pytz.utc).timetuple()) def getProfile(request,allowDefault=True): From bbd2c7f8d5827a21a63a6e94000c57c06bcf62d2 Mon Sep 17 00:00:00 2001 From: Jason Stangroome Date: Thu, 2 Jul 2015 20:32:48 +1000 Subject: [PATCH 4/5] Re-exclude Python 2.6 for Django 1.7 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e8b5077d5..87c0fbf2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,4 +30,5 @@ script: matrix: exclude: - python: "2.6" - env: REQUIREMENTS="Django<1.8 django-tagging<0.4" \ No newline at end of file + env: REQUIREMENTS="Django<1.8 django-tagging<0.4" + From 3696e1daeafcedd18001b33d2b0b899dcaa2ea79 Mon Sep 17 00:00:00 2001 From: Denys Zhdanov Date: Sun, 16 Aug 2015 22:08:23 +0200 Subject: [PATCH 5/5] Whitenoise check --- check-dependencies.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/check-dependencies.py b/check-dependencies.py index c400c8038..b5bd678d4 100755 --- a/check-dependencies.py +++ b/check-dependencies.py @@ -157,6 +157,14 @@ print "Note that txamqp requires python 2.5 or greater." warning += 1 +# Test for whitenoise +try: + import whitenoise +except ImportError: + print "[INFO]" + print "Unable to import the 'whitenoise' module." + print "This is useful for serving static files." + if fatal: print "%d necessary dependencies not met. Graphite will not function until these dependencies are fulfilled." % fatal