Signed-off-by: Richard Marko <rmarko(a)redhat.com>
---
configure.ac | 1 +
faf.spec.in | 23 ++++++++-
pyfaf/Makefile.am | 2 +-
pyfaf/emergency/Makefile.am | 10 ++++
pyfaf/emergency/__init__.py | 0
pyfaf/emergency/emergency.wsgi | 88 +++++++++++++++++++++++++++++++++++
pyfaf/emergency/faf-emergency.conf.in | 16 +++++++
7 files changed, 137 insertions(+), 3 deletions(-)
create mode 100644 pyfaf/emergency/Makefile.am
create mode 100644 pyfaf/emergency/__init__.py
create mode 100644 pyfaf/emergency/emergency.wsgi
create mode 100644 pyfaf/emergency/faf-emergency.conf.in
diff --git a/configure.ac b/configure.ac
index b0117a9..4e39ba1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -52,6 +52,7 @@ AC_CONFIG_FILES([
tests/utils/Makefile
pyfaf/client/Makefile
pyfaf/client/commands/Makefile
+ pyfaf/emergency/Makefile
pyfaf/hub/Makefile
pyfaf/hub/common/Makefile
pyfaf/hub/problems/Makefile
diff --git a/faf.spec.in b/faf.spec.in
index 6effe3e..5ffa84c 100644
--- a/faf.spec.in
+++ b/faf.spec.in
@@ -93,6 +93,20 @@ Requires(postun): systemd-units httpd
%description hub
Kobo hub for %{name} tasks
+%package emergency
+Summary: Emergency WSGI application
+Group: System Environment/Libraries
+Requires: %{name} = %{version}
+Requires: httpd
+Requires: mod_wsgi
+BuildArch: noarch
+
+%description emergency
+Provides emergency WSGI application
+capable of saving reports to disk
+to work as a backup in case of server
+issues.
+
%package worker
Summary: Kobo worker for %{name} tasks
Group: System Environment/Libraries
@@ -145,9 +159,10 @@ mkdir -p %{buildroot}%{_localstatedir}/log/faf/build
mkdir -p %{buildroot}%{_datadir}/faf/hub/static
# On Fedora, the Python WSGI module is loaded by wsgi.conf in the
# conf.d HTTPD configuration directory. faf-hub.conf requires WSGI to
-# be already active. Here we rename the faf-hub.conf to be loaded
-# after wsgi.conf and not before.
+# be already active. Here we rename the faf-hub.conf and
+# faf-emergency.conf to be loaded after wsgi.conf and not before.
mv %{buildroot}%{_sysconfdir}/httpd/conf.d/{,wsgi-}faf-hub.conf
+mv %{buildroot}%{_sysconfdir}/httpd/conf.d/{,wsgi-}faf-emergency.conf
%check
@@ -297,6 +312,10 @@ fi
%dir %attr(0770, faf, faf) %{_localstatedir}/spool/faf/hub/upload
%{_datadir}/faf/hub
+%files emergency
+%config(noreplace) %{_sysconfdir}/httpd/conf.d/wsgi-faf-emergency.conf
+%{python_sitelib}/pyfaf/emergency
+
%files worker
%config(noreplace) %{_sysconfdir}/faf/worker.conf
%{python_sitelib}/pyfaf/worker
diff --git a/pyfaf/Makefile.am b/pyfaf/Makefile.am
index 533ccd4..c97b1a8 100644
--- a/pyfaf/Makefile.am
+++ b/pyfaf/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = client hub worker storage
+SUBDIRS = client emergency hub worker storage
pyfaf_PYTHON = \
__init__.py \
diff --git a/pyfaf/emergency/Makefile.am b/pyfaf/emergency/Makefile.am
new file mode 100644
index 0000000..26bfc90
--- /dev/null
+++ b/pyfaf/emergency/Makefile.am
@@ -0,0 +1,10 @@
+emergency_PYTHON = emergency.wsgi __init__.py
+emergencydir = $(pythondir)/pyfaf/emergency
+
+httpdconf_DATA = faf-emergency.conf
+httpdconfdir = ${sysconfdir}/httpd/conf.d
+
+EXTRA_DIST = faf-emergency.conf.in
+
+faf-emergency.conf: faf-emergency.conf.in
+ sed -e "s|@PYTHONDIR@|$(pythondir)|g" $< > $@
diff --git a/pyfaf/emergency/__init__.py b/pyfaf/emergency/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyfaf/emergency/emergency.wsgi b/pyfaf/emergency/emergency.wsgi
new file mode 100644
index 0000000..205d796
--- /dev/null
+++ b/pyfaf/emergency/emergency.wsgi
@@ -0,0 +1,88 @@
+#! /usr/bin/env python
+
+import os
+import cgi
+import json
+import uuid
+import logging
+
+from wsgiref.simple_server import make_server
+
+import pyfaf
+
+
+def application(environ, start_response):
+ """
+ WSGI application capable of saving incoming uReports to
+ directory, to be used as a backup handler.
+ """
+
+ def is_post_request(environ):
+ """
+ Return True if this request is valid POST request
+ with correct content type
+ """
+
+ if environ["REQUEST_METHOD"].upper() != "POST":
+ return False
+
+ content_type = environ.get("CONTENT_TYPE",
"application/x-www-form-urlencoded")
+ return content_type.startswith("multipart/form-data")
+
+ def bad_request():
+ """
+ Respond with HTTP 400 Bad Reqeust.
+ """
+
+ start_response("400 BAD REQUEST",
+ [("Content-Type", "application/json")])
+ return [""]
+
+ def method_not_allowed():
+ """
+ Respond with HTTP 405 Method Not Allowed.
+ """
+
+ start_response("405 METHOD NOT ALLOWED",
+ [("Content-Type", "application/json"),
+ ("Allow", "POST")])
+ return [""]
+
+ spool_dir = pyfaf.config.get("Report.SpoolDirectory")
+
+ if not is_post_request(environ):
+ logging.debug('Not a POST request or content type'
+ ' is not mulitpart/form-data.')
+
+ return method_not_allowed()
+
+ inp = environ["wsgi.input"]
+ fs = cgi.FieldStorage(fp=inp, environ=environ)
+
+ try:
+ fs = fs.list.pop()
+ ureport = fs.file.read()
+ except (IndexError, AttributeError):
+ logging.debug('Unable to parse input.')
+ return bad_request()
+
+ fname = str(uuid.uuid4())
+ with open(os.path.join(spool_dir, "incoming", fname), "w") as
fil:
+ fil.write(ureport)
+ logging.info('Report saved as {0}'.format(fname))
+
+ status = "202 ACCEPTED"
+ response_body = json.dumps({"result": False})
+ response_headers = [("Content-Type", "application/json"),
+ ("Content-Length", str(len(response_body)))]
+ start_response(status, response_headers)
+
+ return [response_body]
+
+if __name__ == "__main__":
+ # possible to run as standalone server,
+ # mainly for debugging purposes
+
+ logging.basicConfig(level=logging.DEBUG)
+ server = make_server("0.0.0.0", 8000, application)
+ server.serve_forever()
diff --git a/pyfaf/emergency/faf-emergency.conf.in
b/pyfaf/emergency/faf-emergency.conf.in
new file mode 100644
index 0000000..1a14c15
--- /dev/null
+++ b/pyfaf/emergency/faf-emergency.conf.in
@@ -0,0 +1,16 @@
+#WSGISocketPrefix /var/spool/faf/wsgi
+#WSGIDaemonProcess faf user=faf group=faf processes=1 threads=5
+#WSGIProcessGroup faf
+#WSGIScriptAlias /faf @PYTHONDIR(a)/pyfaf/emergency/emergency.wsgi
+
+#<Directory "@PYTHONDIR@/pyfaf/emergency/">
+# <IfModule mod_authz_core.c>
+# # Apache 2.4
+# Require all granted
+# </IfModule>
+# <IfModule !mod_authz_core.c>
+# # Apache 2.2
+# Order allow,deny
+# Allow from all
+# </IfModule>
+#</Directory>
--
1.8.1.4