summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Toman <mtoman@redhat.com>2010-10-12 16:04:25 +0200
committerMichal Toman <mtoman@redhat.com>2010-10-12 16:04:25 +0200
commitbce30a209e7b823f67b4651e671faa64cc2af79c (patch)
tree7e5efb6da30da0e7872eb3ecc6f7e69ec33f3f3b
parent354f20ef323c1670cb595feb1f3a19c260e8b7d6 (diff)
Retrace server interface
-rw-r--r--retrace/interface/create.wsgi73
-rw-r--r--retrace/interface/retrace.py89
2 files changed, 162 insertions, 0 deletions
diff --git a/retrace/interface/create.wsgi b/retrace/interface/create.wsgi
new file mode 100644
index 00000000..81947d64
--- /dev/null
+++ b/retrace/interface/create.wsgi
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+import sys
+sys.path = ["/usr/share/abrt-retrace"] + sys.path
+
+from retrace import *
+from tempfile import *
+
+def application(environ, start_response):
+ read_config()
+
+ request = Request(environ)
+
+ if request.method != "POST":
+ return response(start_response, "405 Method Not Allowed")
+
+ if not request.content_type in ["application/x-xz", "application/x-xz-compressed-tar"]:
+ return response(start_response, "415 Unsupported Media Type")
+
+ if not request.content_length:
+ return response(start_response, "411 Length Required")
+
+ if request.content_length > CONFIG["MaxPackedSize"] * 1048576:
+ return response(start_response, "413 Request Entity Too Large")
+
+ space = free_space(CONFIG["WorkDir"])
+ if not space:
+ return response(start_response, "500 Internal Server Error", "Unable to obtain disk free space")
+
+ if space - request.content_length < CONFIG["MinStorageLeft"] * 1048576:
+ return response(start_response, "507 Insufficient Storage")
+
+ try:
+ archive = NamedTemporaryFile(mode = "wb", delete = False, suffix = ".tar.xz")
+ archive.write(request.body)
+ archive.close()
+ except:
+ return response(start_response, "500 Internal Server Error", "Unable to save archive")
+
+ size = unpacked_size(archive.name)
+ if not size:
+ os.unlink(archive.name)
+ return response(start_response, "500 Internal Server Error", "Unable to obtain unpacked size")
+
+ if size > CONFIG["MaxUnpackedSize"] * 1048576:
+ os.unlink(archive.name)
+ return response(start_response, "413 Request Entity Too Large")
+
+ if space - size < CONFIG["MinStorageLeft"] * 1048576:
+ os.unlink(archive.name)
+ return response(start_response, "507 Insufficient Storage")
+
+ crashid, crashdir = new_crash()
+ if not crashid or not crashdir:
+ return response(start_response, "500 Internal Server Error", "Unable to create new crash")
+
+ os.chdir(crashdir)
+ unpack_retcode = unpack(archive.name)
+ os.unlink(archive.name)
+
+ if unpack_retcode != 0:
+ os.chdir("/")
+ os.system("rm -rf " + crashdir)
+ return response(start_response, "500 Internal Server Error", "Unable to unpack archive")
+
+ files = os.listdir(".")
+
+ for required_file in REQUIRED_FILES:
+ if not required_file in files:
+ os.chdir("/")
+ os.system("rm -rf " + crashdir)
+ return response(start_response, "403 Forbidden")
+
+ return response(start_response, "201 Created", "", [("X-Task-Id", str(crashid)), ("X-Task-Password", get_task_password(crashdir)), ("X-Task-Est-Time", str(get_task_est_time(crashdir)))]) \ No newline at end of file
diff --git a/retrace/interface/retrace.py b/retrace/interface/retrace.py
new file mode 100644
index 00000000..87f48c53
--- /dev/null
+++ b/retrace/interface/retrace.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+import os
+import re
+import ConfigParser
+from webob import Request
+from subprocess import *
+
+REQUIRED_FILES = ["architecture", "coredump", "package"] #, "packages"]
+
+DF_OUTPUT_PARSER = re.compile("^([^ ^\t]*)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+%)[ \t]+(.*)$")
+XZ_OUTPUT_PARSER = re.compile("^totals[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+\.[0-9]+)[ \t]+([^ ^\t]+)[ \t]+([0-9]+)[ \t]+([0-9]+)$")
+
+CONFIG_FILE = "/etc/abrt/retrace.conf"
+CONFIG = {
+ "MaxParallelTasks": 2,
+ "MaxPackedSize": 30,
+ "MaxUnpackedSize": 600,
+ "MinStorageLeft": 10240,
+ "WorkDir": "/var/spool/abrt-retrace",
+}
+
+def read_config():
+ parser = ConfigParser.ConfigParser()
+ parser.read(CONFIG_FILE)
+ for key in CONFIG.keys():
+ vartype = type(CONFIG[key])
+ if vartype is int:
+ get = parser.getint
+ elif vartype is bool:
+ get = parser.getbool
+ elif vartype is float:
+ get = parser.getfloat
+ else:
+ get = parser.get
+
+ try:
+ CONFIG[key] = get("retrace", key)
+ except:
+ pass
+
+def free_space(path):
+ pipe = Popen(["df", path], stdout=PIPE).stdout
+ for line in pipe.readlines():
+ match = DF_OUTPUT_PARSER.match(line)
+ if match:
+ pipe.close()
+ return 1024 * int(match.group(4))
+
+ pipe.close()
+ return None
+
+def unpacked_size(archive):
+ pipe = Popen(["/usr/local/bin/xz", "--list", "--robot", archive], stdout=PIPE).stdout
+ for line in pipe.readlines():
+ match = XZ_OUTPUT_PARSER.match(line)
+ if match:
+ pipe.close()
+ return int(match.group(4))
+
+ pipe.close()
+ return None
+
+def new_crash():
+ i = 1
+ newdir = CONFIG["WorkDir"] + "/0"
+ while os.path.exists(newdir):
+ i += 1
+ newdir = CONFIG["WorkDir"] + "/" + str(i)
+
+ try:
+ os.mkdir(newdir)
+ return i, newdir
+ except:
+ return None, None
+
+def unpack(archive):
+ pipe = Popen(["tar", "xJf", archive])
+ pipe.wait()
+ return pipe.returncode
+
+def get_task_password(crashdir):
+ return "Password for " + crashdir
+
+def get_task_est_time(crashdir):
+ return 10
+
+def response(start_response, status, body="", extra_headers=[]):
+ start_response(status, [("Content-Type", "text/plain"), ("Content-Length", str(len(body)))] + extra_headers)
+ return [body]