class EnumResult:
    UNKNOW = 0
    ABOART = 1
    WAIT = 2
    WARN = 3
    FAIL = 4
    PASS = 5
    NEW = 6
    CANCEL = 7
    SCHEDULED = 8
    PANIC = 9
    FAILINSTALL = 10
    SKIP = 11

    def __init__(self):
        self.enums = dict(RESULT_CHOICES)

    def _get(self, value):
        if isinstance(value, int):
            return self.enums.get(value)
        elif isinstance(value, str):
            return [it[0] for it in self.enums.items() if it[1] == value.lower()][0]

    @staticmethod
    def choices():
        er = EnumResult()
        return er.enums.items()

    @staticmethod
    def get(value):
        er = EnumResult()
        return er._get(value)

    @staticmethod
    def broken_list():
        return [EnumResult.FAIL, EnumResult.FAILINSTALL, EnumResult.ABOART, EnumResult.PANIC, EnumResult.WARN] RETURNWHENGREEN = 1 class Arch(models.Model):
    name = models.CharField(max_length=32, unique=True)

    def __unicode__(self):
        return self.name class Author(models.Model):
    DEFAULT_AUTHOR = ("Unknown", "unknow@redhat.com")
    name = models.CharField(max_length=255, unique=False,
                            default=DEFAULT_AUTHOR[0], db_index=True)
    email = models.EmailField(default=DEFAULT_AUTHOR[1], db_index=True)
    is_enabled = models.BooleanField(default=True)

    def __unicode__(self):
        return "%s <%s>" % (self.name, self.email)

    @staticmethod
    def FromUser(user):
        if user.is_anonymous():
            return None
        try:
            return Author.objects.get(email=user.email)
        except Author.DoesNotExist:
            return None

    @staticmethod
    def passiveParseAuthor(row):
        """
           Parse author from line "name <email@exmaple.com>"
           return dict
        """
        rr = re.search(r"((?P<name>[^@<]*)(\s|$)\s*)?"
                       r"<?((?P<email>[A-z0-9_\.\+]+"
                       r"@[A-z0-9_\.]+\.[A-z]{2,3}))?>?", row)
        if rr is None:
            return None
        res = dict()
        # Parse owner
        if rr.group('name'):
            res['name'] = rr.group('name').strip()
        if rr.group('email'):
            res['email'] = rr.group('email').strip()
        return res

    @staticmethod
    def parseAuthor(row):
        """
           Parse author from line "name <email@exmaple.com>"
           return object
        """
        res = Author.passiveParseAuthor(row)
        if res is not None:
            auths = Author.objects.filter(**res)
            if len(auths) > 0:
                return auths[0]
        else:
            res = dict()
        email = res.get('email', Author.DEFAULT_AUTHOR[1])
        name = res.get('name', Author.DEFAULT_AUTHOR[0])
        owner, status = Author.objects\
            .get_or_create(email=email, defaults={'name': name})
        return owner class Distro(models.Model):
    name = models.CharField(max_length=255, unique=True)

    def __unicode__(self):
        return self.name class Job(models.Model):
    template = models.ForeignKey(JobTemplate)
    uid = models.CharField("Job ID", max_length=12, unique=True)
    date = models.DateTimeField(auto_now_add=True, db_index=True)
    schedule = models.ForeignKey(TaskPeriodSchedule, null=True, blank=True)
    is_running = models.BooleanField(default=False)
    # this is for checking (no used for data from beaker)
    is_finished = models.BooleanField(default=False)

    def __unicode__(self):
        return self.uid

    def get_uid(self):
        return self.uid.replace("J:","")

    def get_url_beaker(self):
        return "%s/%s/" % (settings.BEAKER_SERVER, self.uid)

    def get_original_job(self):
        Job.objects.filter(schedule=self.schedule, template=self.template,
                           uid__gt=self.uid).order_by('uid')[:1] class JobTemplate(models.Model):
    whiteboard = models.CharField(max_length=255, unique=True)
    is_enable = models.BooleanField(default=False)
    event_finish = models.SmallIntegerField(
        choices=EVENT_FINISH_ENUM, default=RETURN)
    schedule = models.ForeignKey(TaskPeriod, null=True, blank=True)
    position = models.SmallIntegerField(default=0)
    grouprecipes = models.CharField(
        max_length=255, null=False, blank=True, default="{{ whiteboard }}",
        help_text="example: {{arch}} {{whiteboard|nostartsdate}}")
    tags = TaggableManager(blank=True)
    group = settings.BEAKER_JOB_GROUP
    is_set_recipe = False

    def __unicode__(self):
        return self.whiteboard

    def save(self, *args, **kwargs):
        model = self.__class__

        if self.position is None:
            # Append
            try:
                last = model.objects.order_by("period", "-position")[0]
                self.position = last.position + 1
            except IndexError:
                # First row
                self.position = 0

        return super(model, self).save(*args, **kwargs)

    class Meta:
        ordering = ('schedule', 'position',)

    @models.permalink
    def get_absolute_url(self):
        return ("beaker-xml", [self.id])

    def admin_url(self):
        content_type = ContentType.objects.get_for_model(self.__class__)
        return reverse("admin:%s_%s_change" % (
            content_type.app_label, content_type.model), args=(self.id,))

    def is_return(self):
        return (self.event_finish == RETURN)

    def get_tags(self):
        return ", ".join([it.name for it in self.tags.all()])

    def clone(self):
        recipes = list(self.trecipes.all())
        tags = self.tags.all()
        self.pk = None
        label = "Clone %s" % self.whiteboard
        tmp_label = "%s" % label
        for it in range(100):
            if len(JobTemplate.objects.filter(whiteboard=label)) > 0:
                label = "%s v. %s" % (tmp_label, it)
                continue
            break

        self.whiteboard = label
        self.save()
        for recipe in recipes:
            recipe.clone(self)
        for it in tags:
            self.tags.add(str(it))

    def check_set_recipe(self):
        """
        The method checks parameters for beaker's recipe. If recipes contain
        same hostname then the recipe has to be used in own recipeSet.
        The property is set as attribute 'is_set_recipe'.
        """
        hostnames = []
        for it in self.trecipes.all():
            if not it.hostname:
                continue
            if it.hostname in hostnames:
                self.is_set_recipe = True
                return True
            hostnames.append(it.hostname)
        return False class Recipe(models.Model):
    UNKNOW = 0
    RUNNING = 1
    COMPLETED = 2
    WAITING = 3
    QUEUED = 4
    ABORTED = 5
    CANCELLED = 6
    NEW = 7
    SCHEDULED = 8
    PROCESSED = 9
    RESERVED = 10
    INSTALLING = 11
    STATUS_CHOICES = (
        (UNKNOW, u"Unknow"),
        (NEW, u"New"),
        (SCHEDULED, u"Scheduled"),
        (RUNNING, u"Running"),
        (COMPLETED, u"Completed"),
        (WAITING, u"Waiting"),
        (QUEUED, u"Queued"),
        (ABORTED, u"Aborted"),
        (CANCELLED, u"Cancelled"),
        (PROCESSED, u"Processed"),
        (RESERVED, u"Reserved"),
        (INSTALLING, u"Installing")
    )
    job = models.ForeignKey(Job, related_name="recipes")
    uid = models.CharField("Recipe ID", max_length=12, unique=True)
    whiteboard = models.CharField(
        "Whiteboard",
        max_length=256,
        blank=True,
        null=True)
    status = models.SmallIntegerField(choices=STATUS_CHOICES, default=UNKNOW)
    result = models.SmallIntegerField(
        choices=EnumResult.choices(), default=UNKNOW)
    resultrate = models.FloatField(default=-1.)
    system = models.ForeignKey(System,)
    arch = models.ForeignKey(Arch,)
    distro = models.ForeignKey(Distro,)
    parentrecipe = models.ForeignKey("Recipe", null=True, blank=True)
    statusbyuser = models.SmallIntegerField(
        choices=USERSTATUS_CHOICES, default=NONE)

    def __unicode__(self):
        return self.uid

    def get_template(self):
        return self.job.template

    def set_result(self, value):
        try:
            self.result = \
                [it[0] for it in RESULT_CHOICES if it[1] == value.lower()][0]
        except IndexError:
            logger.error("IndexError: result %s %s %s" %
                         (value, self.result, EnumResult.choices()))

    def get_uid(self):
        return self.uid.replace("R:", "")

    def get_result(self):
        if self.statusbyuser == WAIVED:
            return [it[1] for it in USERSTATUS_CHOICES if it[0] == WAIVED][0]
        return [it[1] for it in RESULT_CHOICES if it[0] == self.result][0]

    def set_status(self, value):
        status = self.status
        try:
            self.status = [it[0]
                           for it in self.STATUS_CHOICES if it[1] == value][0]
        except IndexError:
            logger.error("IndexError: status '%s' (actual status: %s) %s" %
                         (value, self.status, self.STATUS_CHOICES))
            return

        if status != self.status:
            if self.status in (self.COMPLETED, self.ABORTED,
                               self.RESERVED, self.CANCELLED):
                recipe_finished.send(sender="models:Recipe", recipe=self)
            else:
                recipe_changed.send(sender="models:Recipe", recipe=self)

    def get_status(self):
        try:
            return [it[1]
                    for it in self.STATUS_CHOICES if it[0] == self.status][0]
        except IndexError:
            return "uknow-%s" % self.status

    def set_waived(self):
        self.statusbyuser = WAIVED
        self.save()

    def recount_result(self):
        # result = Task.objects.values('result', "statusbyuser").filter(
        #    recipe=self).annotate(Count('result')).order_by("uid")
        total, total_ok, waived = 0, 0, False
        running = None
        failed_test = []
        i = 0
        for it in Task.objects.filter(recipe=self).order_by("uid"):
            if i == 0 and it.result in [EnumResult.FAIL, EnumResult.WARN, EnumResult.ABOART]:
                self.result = FAILINSTALL
                # self.save()
            i += 1

            if it.result in [EnumResult.PASS, EnumResult.SKIP] or it.statusbyuser == WAIVED:
                total_ok += 1
            total += 1

            if it.statusbyuser == WAIVED:
                waived = True

            if it.result in [EnumResult.WARN, EnumResult.FAIL] and it.statusbyuser != WAIVED:
                failed_test.append(it)

            if it.result == NEW and not running:
                running = it

        if waived:
            if failed_test:
                self.result = failed_test[0].result
            else:
                self.result = EnumResult.PASS
            if running and running.test.name == settings.RESERVE_TEST \
               and total_ok + 1 == total:
                self.set_waived()
        if total != 0:
            self.resultrate = total_ok * 100. / total
        else:
            self.resultrate = 0
        if waived and total_ok == total:
            self.set_waived()

    def get_date(self):
        return self.job.date

    def get_distro_label(self):
        dn = self.distro.name
        raw = dn.split("-")
        if len(raw) > 2:
            return "-".join(raw[:-1])
        else:
            return dn

    def get_dict(self):
        return {
            "arch": self.arch.name,
            "distro": self.distro.name,
            "distro_label": self.get_distro_label(),
            "whiteboard": self.whiteboard,
        }

    def get_label(self):
        return render_label(self.get_dict(), self.job.template.grouprecipes)

    def is_running(self):
        # this makes about 1000 requests into DB, I think it is not necessary here.
        # self.recount_result()
        return (self.status in (self.RUNNING, self.RESERVED))

    def is_result_pass(self):
        return (EnumResult.PASS == self.result)

    def reschedule(self):
        # TODO
        pass class RecipeTemplate(models.Model, ObjParams):
    NONE, RECIPE_MEMBERS, STANDALONE = 0, 1, 2
    ROLE_ENUM = (
        (NONE, "None"),
        (RECIPE_MEMBERS, "RECIPE_MEMBERS"),
        (STANDALONE, "STANDALONE"),
    )

    jobtemplate = models.ForeignKey(JobTemplate, related_name="trecipes")
    name = models.CharField(max_length=255, blank=True)
    kernel_options = models.CharField(max_length=255, blank=True)
    kernel_options_post = models.CharField(max_length=255, blank=True)
    ks_meta = models.CharField(max_length=255, blank=True)
    role = models.SmallIntegerField(choices=ROLE_ENUM, default=NONE)
    arch = models.ManyToManyField(Arch)
    memory = models.CharField(max_length=255, blank=True)
    disk = models.CharField(
        max_length=255, blank=True, help_text="Value is in GB")
    hostname = models.CharField(
        max_length=255, blank=True,
        help_text="Set to '= system42.beaker.example.com' if you want your recipe to run on exactly this system")
    labcontroller = models.CharField(
        max_length=255, blank=True, help_text="= hostname.lab.example.com")
    hvm = models.BooleanField(_("Support virtualizaion"), default=False)
    params = models.TextField(_("Extra XML parameter"), blank=True)
    # generator = models.TextField(_("Recipe generator"), blank=True, help_text="rules for generating recipes")
    packages = models.CharField(
        _("Extra packages"), max_length=256, blank=True,
        help_text="Separate by white space. For example: vim xen")
    distro = models.ForeignKey(DistroTemplate)
    is_virtualguest = models.BooleanField(default=False)
    virtualhost = models.ForeignKey("RecipeTemplate", null=True, blank=True,
                                    related_name="virtualguests")
    schedule = models.CharField(
        _("Schedule period"), max_length=255, blank=True,
        help_text="For example: s390x: 0,2,4; x86_64: 1,3,5,6")
    external_repos = models.ManyToManyField(Repository, blank=True)

    def __unicode__(self):
        name = self.name
        if not self.name:
            name = "(empty)"
        return "%s - %s" % (self.id, name)

    def set_role(self, value):
        try:
            self.role = [it[0] for it in self.ROLE_ENUM if value == it[1]][0]
        except IndexError:
            print "VALUE %s isn't possible to set as ROLE" % value

    def get_role(self):
        return [it[1] for it in self.ROLE_ENUM if self.role == it[0]][0]

    def get_arch(self):
        return self.arch.all()

    def archs(self):
        return ", ".join([it.name for it in self.get_arch()])

    def get_extra_packages(self):
        default_packages = list(settings.BEAKER_DEFAULT_PACKAGES)
        return self.packages.split() + default_packages

    def get_extra_repos(self):
        return self.external_repos.all()

    def get_tasks(self):
        return self.tasks.filter(test__is_enable=True).select_related(
            "test").order_by("priority")

    # TODO: Remove Arch rotation
    # This solution of rotation of Arch is not good idea.
    # Better idea is TasksList.
    def getArchsForToday(self):
        """
            Return list of architecures for today
        """

        # Weekday as a decimal number [0(Sunday),6].
        weekday = int(timezone.now().strftime("%w"))
        # archs = [it.name for it in self.arch.all()]
        schedule = self.__parse_schedule_period(self.schedule)

        res = list()
        for it in schedule:
            if ((it[2] == weekday and it[1]) or
                    (it[2] != weekday and not it[1])):
                res.append(Arch.objects.get(name=it[0]))
        if res:
            return res

        # if empty return all archs
        return self.get_arch()

    def parse(self, st):
        return self.__parse_schedule_period(st)

    def __parse_schedule_period(self, string):
        # i386: 1; s390x: 2; x86_64: 3; i386: 4; x86_64: 5,6,0
        # x86_64: !5; i386: 5
        if not string:
            return []
        data = []
        for it in string.split(";"):
            if not it.strip():
                continue
            try:
                key, val = it.split(":")
            except ValueError:
                raise ValueError("Parse error: %s" % it)
            val = val.strip()
            op = True
            if val.startswith("!"):
                # negation - complement [0-6] for example
                # !1 - run every day expect monday
                val = val[1:]
                op = False
            vals = [it.strip() for it in val.split(",")]
            key = key.strip()
            for val in vals:
                if not val:
                    continue
                data.append((key, op, int(val.strip())))
        return data

    def save(self, *args, **kwargs):
        self.__parse_schedule_period(self.schedule)
        super(self.__class__, self).save(*args, **kwargs)

    class Meta:
        ordering = ('name',)

    def is_return(self):
        return self.jobtemplate.is_return()

    def is_reserve(self):
        return not self.is_return()

    def is_enabled(self):
        return self.jobtemplate.is_enable

    def clone(self, jobtemplate=None):
        groups = self.grouptemplates.all()
        tasks = self.tasks.all()
        archs = self.arch.all()
        self.pk = None
        if jobtemplate:
            self.jobtemplate = jobtemplate
        self.save()
        for arch in archs:
            self.arch.add(arch)
        for it in groups:
            it.pk = None
            it.recipe = self
            it.save()
        for it in tasks:
            it.pk = None
            it.recipe = self
            it.save() class System(models.Model):
    hostname = models.CharField(max_length=255, blank=True, db_index=True)
    ram = models.IntegerField(null=True, blank=True)
    cpu = models.CharField(max_length=255, blank=True)
    hdd = models.CharField(max_length=255, blank=True)
    parent = models.ForeignKey("System", null=True, blank=True)
    group = models.SmallIntegerField(null=True, blank=True)

    def __unicode__(self):
        return self.hostname class Task(models.Model):
    uid = models.CharField("Task ID", max_length=12, unique=True)
    recipe = models.ForeignKey(Recipe, related_name="tasks")
    test = models.ForeignKey(Test)
    result = models.SmallIntegerField(choices=RESULT_CHOICES,
                                      default=UNKNOW, db_index=True)
    status = models.SmallIntegerField(
        choices=Recipe.STATUS_CHOICES, default=UNKNOW)
    duration = models.FloatField(default=-1.)
    datestart = models.DateTimeField(null=True, blank=True)
    statusbyuser = models.SmallIntegerField(
        choices=USERSTATUS_CHOICES, default=NONE)
    alias = models.CharField(max_length=32, blank=True, null=True)

    def __unicode__(self):
        return self.uid

    def logfiles(self):
        return list(FileLog.objects.filter(task=self).values("path"))

    def set_result(self, value):
        try:
            self.result = [it[0]
                           for it in RESULT_CHOICES if it[1] == value.lower()][0]
        except IndexError:
            logger.error("IndexError: Task result %s %s %s" %
                         (value, self.result, RESULT_CHOICES))

    def get_result(self):
        if self.statusbyuser == WAIVED:
            return [it[1] for it in USERSTATUS_CHOICES if it[0] == WAIVED][0]
        return [it[1] for it in RESULT_CHOICES if it[0] == self.result][0]

    def set_status(self, value):
        try:
            self.status = [it[0]
                           for it in Recipe.STATUS_CHOICES if it[1].lower() == value.lower()][0]
        except IndexError:
            logger.error("IndexError: Task status %s %s %s" %
                         (value, self.status, Recipe.STATUS_CHOICES))

    def is_completed(self):
        return (self.status == Recipe.COMPLETED)

    def set_waived(self):
        self.statusbyuser = WAIVED
        self.save()
        self.recipe.recount_result()
        self.recipe.save()

    def get_uid(self):
        return self.uid.replace("T:", "") class TaskTemplate(ObjParams, models.Model):
    BEGIN, PRE_GROUP, POST_GROUP, END = 0, 1, 2, 3
    ENUM_POSTION = (
        (BEGIN, "Begin"),
        (PRE_GROUP, "Pre"),
        (POST_GROUP, "Post"),
        (END, "End"), )
    test = models.ForeignKey(Test)
    recipe = models.ForeignKey(RecipeTemplate, related_name="tasks")
    params = models.TextField(blank=True)
    priority = models.SmallIntegerField(default=0)
    role = models.ForeignKey(TaskRoleEnum, null=True, blank=True)
    position = models.SmallIntegerField(
        default=POST_GROUP, choices=ENUM_POSTION)

    def __unicode__(self):
        return self.test.name

    def get_role(self):
        if self.role:
            return self.role.name

    def set_role(self, value):
        if value in ["None", ""]:
            self.role = None
        else:
            self.role, status = TaskRoleEnum.objects.get_or_create(name=value)
        self.save() class Test(models.Model):
    name = models.CharField(max_length=255, unique=True, db_index=True)
    git = models.ForeignKey(Git, blank=True, null=True, db_index=True)
    owner = models.ForeignKey(Author, blank=True, null=True, db_index=True)
    description = models.TextField(blank=True, null=True)
    external_links = models.TextField(
        blank=True, null=True,
        help_text="external links which separated by ';'")
    dependencies = models.ManyToManyField("Test", blank=True)
    time = models.CharField(max_length=6, blank=True, null=True)
    type = models.CharField(max_length=32, blank=True, null=True)
    folder = models.CharField(
        max_length=256, blank=True, null=True, db_index=True)
    is_enable = models.BooleanField("enable", default=True, db_index=True)
    groups = models.ManyToManyField(GroupOwner, blank=True)
    bugs = models.ManyToManyField(Bug, blank=True)
    apps = models.ManyToManyField(AppTag, blank=True, related_name="tests")

    class Meta:
        ordering = ["-is_enable", "name"]

    def __unicode__(self):
        return self.name

    def __eq__(self, other):
        # if not isinstance(other, self.__class__):
        #        return False
        if not isinstance(other, models.Model):
            return False
        if self._meta.concrete_model != other._meta.concrete_model:
            return False
        if self.id and other.id:
            return self.id == other.id
        return self.name == other.name and self.git == other.git

    def get_absolute_url(self):
        return "%s?test_id=%s" % (reverse("tests-list"), self.id)

    def get_detail_url(self):
        return "%s" % reverse("test-detail", args=[self.id])

    def get_reposituory_url(self):
        if not self.git:
            return None
        return settings.GIT_TREE_PARRENT % (self.git.localurl, self.folder)

    def delete(self, *args, **kwargs):
        # not possible to remove test
        # dependencies on old runs
        self.is_enable = False
        self.save()

    def save(self, *args, **kwargs):
        if not self.owner:
            self.owner = Author.parseAuthor("")
        return super(Test, self).save(*args, **kwargs)

    def get_external_links(self):
        if not self.external_links:
            return []
        return [it.strip() for it in self.external_links.split() if it]
import logging
import os
import random
import re
import subprocess
import sys
import urllib2
import xml.dom.minidom
import xmlrpclib
    import ssl
from datetime import datetime, timedelta
from urlparse import urlparse
from django.conf import settings
from django.template import Context, Template
from django.template.defaultfilters import slugify
from apps.core.models import (EnumResult, RETURNWHENGREEN, Arch, Author, Distro, Job,
                              JobTemplate, Recipe, RecipeTemplate, System,
                              Task, TaskTemplate, Test)
        # show task from groups of task
        for taskG in recipeT.grouptemplates.order_by("priority"):
            params = taskG.get_params()
            for taskT in taskG.group.grouptests.order_by("priority"):
                if not taskT.test.is_enable:
                    continue
                params2 = taskT.get_params()
                params2.update(params)
                taskT.parent_params = params2
                if taskG.role is not None and taskT.role is None:
                    taskT.role = taskG.role
                cache_tasks.append(self.__generateTask(taskT))

        # other tasks show after groups
        # TaskTemplate.POST_GROUP and TaskTemplate.END
        tasksT = TaskTemplate.objects.filter(recipe=recipeT)\
            .filter(position__in=(TaskTemplate.POST_GROUP, TaskTemplate.END))\
            .select_related("test").order_by("priority").distinct()
        for taskT in tasksT:
            if not taskT.test.is_enable:
                continue
            cache_tasks.append(self.__generateTask(taskT))
        return cache_tasks

    def __generateTask(self, taskT):
        params = taskT.get_params()
        hasattr(taskT, "parent_params") and params.update(taskT.parent_params)
        return {"name": taskT.test.name,
                "params": params,
                "priority": taskT.priority,
                "role": taskT.role,
                "get_role": taskT.get_role,
                }


def parse_task(taskxml, recipe):
    testname = taskxml.getAttribute("name")
    test, status = Test.objects.get_or_create(name=testname, defaults={
        "owner": Author.parseAuthor("")
    })

    uid = taskxml.getAttribute("id")
    status_str = taskxml.getAttribute("status")
    result = taskxml.getAttribute("result")
    task_alias = None
    for params in taskxml.getElementsByTagName("params"):
        for param in params.getElementsByTagName("param"):
            if param.getAttribute("name") == "TASK_ALIAS":
                task_alias = param.getAttribute("value")

    task, status = Task.objects.get_or_create(
        uid="T:%s" % uid,
        defaults={
            "recipe": recipe,
            "test": test,
            "alias": task_alias,
        }
    )
    task.set_result(result)
    task.set_status(status_str)

    if task.is_completed():
        duration = taskxml.getAttribute("duration")
        if duration:
            task.duration = float(strToSec(duration))
    task.save()


def parse_recipe(recipexml, job, guestrecipe=None):
    uid = recipexml.getAttribute("id")
    hostname = recipexml.getAttribute("system")
    str_arch = recipexml.getAttribute("arch")
    str_distro = recipexml.getAttribute("distro")
    whiteboard = recipexml.getAttribute("whiteboard")
    str_status = recipexml.getAttribute("status")
    str_result = recipexml.getAttribute("result")

    system, status = System.objects.get_or_create(
        hostname=hostname,
    )

    arch, status = Arch.objects.get_or_create(
        name=str_arch,
    )

    distro, status = Distro.objects.get_or_create(
        name=str_distro,
    )

    recipe, status = Recipe.objects.get_or_create(
        uid="R:%s" % uid,
        defaults={
            "job": job,
            "system": system,
            "whiteboard": whiteboard,
            "distro": distro,
            "arch": arch}
    )
    recipe.system = system
    recipe.set_result(str_result)

    recipe.set_status(str_status)
    if status:
        recipe.save()

    for dataxml in recipexml.childNodes:
        if dataxml.tagName == "guestrecipe" and not guestrecipe:
            parse_recipe(dataxml, job, recipe)
        if dataxml.tagName == "task":
            parse_task(dataxml, recipe)

    recipe.recount_result()
    recipe.save()

    reserve = Task.objects.filter(
        test__name=settings.RESERVE_TEST, recipe=recipe)

    logger.debug("%s status:  %s result %s" %
                 (recipe.uid, recipe.status, recipe.result))
    if reserve or recipe.status == Recipe.RESERVED:

        if recipe.result in [EnumResult.PASS, EnumResult.SKIP] and job.template.event_finish == RETURNWHENGREEN: