1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
##############################################################################
# Copyright (c) 2016 Max Breitenfeldt and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
from django.contrib.auth.models import User
from django.db import models
from django.apps import apps
import json
import random
from collections import Counter
class LabStatus(object):
"""
A Poor man's enum for the status of a lab.
If everything is working fine at a lab, it is UP.
If it is down temporarily e.g. for maintenance, it is TEMP_DOWN
If its broken, its DOWN
"""
UP = 0
TEMP_DOWN = 100
DOWN = 200
def upload_to(object, filename):
return object.user.username + '/' + filename
class UserProfile(models.Model):
"""Extend the Django User model."""
user = models.OneToOneField(User, on_delete=models.CASCADE)
timezone = models.CharField(max_length=100, blank=False, default='UTC')
email_addr = models.CharField(max_length=300, blank=False, default='email@mail.com')
oauth_token = models.CharField(max_length=1024, blank=False)
oauth_secret = models.CharField(max_length=1024, blank=False)
full_name = models.CharField(max_length=100, null=True, blank=True, default='')
booking_privledge = models.BooleanField(default=False)
public_user = models.BooleanField(default=False)
ipa_username = models.CharField(max_length=100, null=True, blank=True)
class Meta:
db_table = 'user_profile'
def __str__(self):
return self.user.username
class Lab(models.Model):
"""
Model representing a Hosting Lab.
Anybody that wants to host resources for LaaS needs to have a Lab model
We associate hardware with Labs so we know what is available and where.
"""
lab_user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=200, primary_key=True, unique=True, null=False, blank=False)
contact_email = models.EmailField(max_length=200, null=True, blank=True)
contact_phone = models.CharField(max_length=20, null=True, blank=True)
status = models.IntegerField(default=LabStatus.UP)
location = models.TextField(default="unknown")
# This token must apear in API requests from this lab
api_token = models.CharField(max_length=50)
description = models.CharField(max_length=240)
lab_info_link = models.URLField(null=True)
project = models.CharField(default='LaaS', max_length=100)
@staticmethod
def make_api_token():
"""Generate random 45 character string for API token."""
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
key = ""
for i in range(45):
key += random.choice(alphabet)
return key
def __str__(self):
return self.name
class Downtime(models.Model):
"""
A Downtime event.
Labs can create Downtime objects so the dashboard can
alert users that the lab is down, etc
"""
start = models.DateTimeField()
end = models.DateTimeField()
lab = models.ForeignKey(Lab, on_delete=models.CASCADE)
description = models.TextField(default="This lab will be down for maintenance")
def save(self, *args, **kwargs):
if self.start >= self.end:
raise ValueError('Start date is after end date')
# check for overlapping downtimes
overlap_start = Downtime.objects.filter(lab=self.lab, start__gt=self.start, start__lt=self.end).exists()
overlap_end = Downtime.objects.filter(lab=self.lab, end__lt=self.end, end__gt=self.start).exists()
if overlap_start or overlap_end:
raise ValueError('Overlapping Downtime')
return super(Downtime, self).save(*args, **kwargs)
|