models.py 5.68 KB
Newer Older
Kálmán Viktor committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
Kálmán Viktor committed
17 18 19
from django.db.models import (
    Model, CharField, IntegerField, TextField, ForeignKey, ManyToManyField,
)
Kálmán Viktor committed
20 21
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
Kálmán Viktor committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
from django.contrib.auth.models import User
from django.core.validators import MinValueValidator
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse

from model_utils.models import TimeStampedModel
from model_utils import Choices

from vm.models import Instance, InstanceTemplate, Lease


class RequestAction(Model):

    def accept(self):
        raise NotImplementedError

Kálmán Viktor committed
38 39 40
    class Meta:
        abstract = True

Kálmán Viktor committed
41 42 43 44 45 46 47

class RequestType(Model):
    name = CharField(max_length=25)

    def __unicode__(self):
        return self.name

Kálmán Viktor committed
48 49 50
    class Meta:
        abstract = True

Kálmán Viktor committed
51 52 53 54 55 56 57 58 59 60

class Request(TimeStampedModel):
    STATUSES = Choices(
        ('UNSEEN', _("unseen")),
        ('PENDING', _('pending')),
        ('ACCEPTED', _('accepted')),
        ('DECLINED', _('declined')),
    )
    status = CharField(choices=STATUSES, default=STATUSES.UNSEEN,
                       max_length=10)
61 62
    user = ForeignKey(User, related_name="user")
    closed_by = ForeignKey(User, related_name="closed_by", null=True)
Kálmán Viktor committed
63 64 65 66 67 68
    TYPES = Choices(
        ('resource', _('resource request')),
        ('lease', _("lease request")),
        ('template', _("template access")),
    )
    type = CharField(choices=TYPES, max_length=10)
69
    reason = TextField(verbose_name=_("Reason"))
Kálmán Viktor committed
70 71 72 73 74

    content_type = ForeignKey(ContentType)
    object_id = IntegerField()
    action = GenericForeignKey("content_type", "object_id")

75 76 77
    def get_absolute_url(self):
        return reverse("request.views.request-detail", kwargs={'pk': self.pk})

Kálmán Viktor committed
78 79 80
    def get_readable_status(self):
        return self.STATUSES[self.status]

81 82 83
    def get_readable_type(self):
        return self.TYPES[self.type]

84
    def get_request_icon(self):
Kálmán Viktor committed
85 86 87 88 89 90 91 92 93 94 95 96 97
        return {
            'resource': "tasks",
            'lease': "clock-o",
            'template': "puzzle-piece"
        }.get(self.type)

    def get_effect(self):
        return {
            "UNSEEN": "primary",
            "PENDING": "warning",
            "ACCEPTED": "success",
            "DECLINED": "danger",
        }.get(self.status)
Kálmán Viktor committed
98

99 100 101 102 103 104 105 106
    def get_status_icon(self):
        return {
            "UNSEEN": "eye-slash",
            "PENDING": "exclamation-triangle",
            "ACCEPTED": "check",
            "DECLINED": "times",
        }.get(self.status)

107 108
    def accept(self, user):
        self.action.accept(user)
109
        self.status = "ACCEPTED"
110
        self.closed_by = user
111 112
        self.save()

113
    def decline(self, user):
114
        self.status = "DECLINED"
115
        self.closed_by = user
116 117
        self.save()

Kálmán Viktor committed
118 119 120 121

class LeaseType(RequestType):
    lease = ForeignKey(Lease)

122 123 124 125 126 127
    def __unicode__(self):
        return _("%(name)s (suspend: %(s)s, remove: %(r)s)") % {
            'name': self.name,
            's': self.lease.get_readable_suspend_time(),
            'r': self.lease.get_readable_delete_time()}

Kálmán Viktor committed
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    def get_absolute_url(self):
        return reverse("request.views.lease-type-detail",
                       kwargs={'pk': self.pk})


class TemplateAccessType(RequestType):
    templates = ManyToManyField(InstanceTemplate)

    def get_absolute_url(self):
        return reverse("request.views.template-type-detail",
                       kwargs={'pk': self.pk})


class ResourceChangeAction(RequestAction):
    instance = ForeignKey(Instance)
    num_cores = IntegerField(verbose_name=_('number of cores'),
                             help_text=_('Number of virtual CPU cores '
                                         'available to the virtual machine.'),
                             validators=[MinValueValidator(0)])
    ram_size = IntegerField(verbose_name=_('RAM size'),
                            help_text=_('Mebibytes of memory.'),
                            validators=[MinValueValidator(0)])
    priority = IntegerField(verbose_name=_('priority'),
                            help_text=_('CPU priority.'),
                            validators=[MinValueValidator(0)])

154 155
    def accept(self, user):
        self.instance.resources_request.async(user=user, resource_request=self)
Kálmán Viktor committed
156 157 158 159 160 161


class ExtendLeaseAction(RequestAction):
    instance = ForeignKey(Instance)
    lease_type = ForeignKey(LeaseType)

162 163 164
    def accept(self, user):
        self.instance.renew(lease=self.lease_type.lease, save=True, force=True,
                            user=user)
Kálmán Viktor committed
165 166 167 168 169 170 171 172 173 174 175 176


class TemplateAccessAction(RequestAction):
    template_type = ForeignKey(TemplateAccessType)
    LEVELS = Choices(
        ('user', _('user')),
        ('operator', _('operator')),
    )
    level = CharField(choices=LEVELS, default=LEVELS.user,
                      max_length=10)
    user = ForeignKey(User)

Kálmán Viktor committed
177 178 179
    def get_readable_level(self):
        return self.LEVELS[self.level]

180 181 182
    def accept(self, user):
        for t in self.template_type.templates.all():
            t.set_user_level(self.user, self.level)