diff options
| author | Michal Toman <mtoman@redhat.com> | 2010-10-12 16:04:25 +0200 |
|---|---|---|
| committer | Michal Toman <mtoman@redhat.com> | 2010-10-12 16:04:25 +0200 |
| commit | bce30a209e7b823f67b4651e671faa64cc2af79c (patch) | |
| tree | 7e5efb6da30da0e7872eb3ecc6f7e69ec33f3f3b | |
| parent | 354f20ef323c1670cb595feb1f3a19c260e8b7d6 (diff) | |
Retrace server interface
| -rw-r--r-- | retrace/interface/create.wsgi | 73 | ||||
| -rw-r--r-- | retrace/interface/retrace.py | 89 |
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] |
